changeset 3:97ec271a513f

Bunch of changes
author Mike Pavone <pavone@retrodev.com>
date Mon, 02 Sep 2013 21:22:47 -0700
parents bbfa7bf69620
children 1a7cac91f890
files Makefile genesis.s68 img2tiles.py mainboot.s68 subboot.s68 tiles2img.py
diffstat 6 files changed, 1502 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Tue May 01 20:43:25 2012 -0700
+++ b/Makefile	Mon Sep 02 21:22:47 2013 -0700
@@ -2,18 +2,33 @@
 ghero.iso : fs.iso boot.bin
 	tail -c +32769 fs.iso | cat boot.bin - > ghero.iso
 
-fs.iso : filesystem/*
+filesystem/slo.bin : slo.s68
+	vasmm68k_mot -Fbin -m68000 -spaces slo.s68 -o filesystem/slo.bin
+
+filesystem/transfer.bin : transfer.s68
+	vasmm68k_mot -Fbin -m68000 -spaces transfer.s68 -o filesystem/transfer.bin
+
+filesystem/slave.bin : slave.s68
+	vasmm68k_mot -Fbin -m68000 -spaces slave.s68 -o filesystem/slave.bin
+
+fs.iso : filesystem/* filesystem/slo.bin filesystem/transfer.bin filesystem/slave.bin
 	mkisofs -o fs.iso filesystem
 
 boot.bin : scd_header.s68 mainboot.bin subboot.bin security.bin
-	vasmm68k_mot -Fbin -m68000 scd_header.s68 -o boot.bin
-	
+	vasmm68k_mot -Fbin -m68000 -spaces scd_header.s68 -o boot.bin
+
 mainboot.bin : mainboot.s68
-	vasmm68k_mot -Fbin -m68000 mainboot.s68 -o mainboot.bin
+	vasmm68k_mot -Fbin -m68000 -spaces mainboot.s68 -o mainboot.bin
 
 subboot.bin : subboot.s68
-	vasmm68k_mot -Fbin -m68000 subboot.s68 -o subboot.bin
-	
+	vasmm68k_mot -Fbin -m68000 -spaces subboot.s68 -o subboot.bin
+
+genesis.bin : genesis.s68 sprites.s68
+	vasmm68k_mot -Fbin -m68000 -spaces genesis.s68 -o genesis.bin
+
 clean :
 	rm subboot.bin mainboot.bin boot.bin
 	rm *.iso
+
+run : ghero.iso
+	/home/mike/bin/gens ghero.iso
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genesis.s68	Mon Sep 02 21:22:47 2013 -0700
@@ -0,0 +1,393 @@
+	dc.l $0, start
+	dc.l empty_handler
+	dc.l empty_handler
+	;$10
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$20
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$30
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$40
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$50
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$60
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$70
+	dc.l HINT
+	dc.l empty_handler
+	dc.l VINT
+	dc.l empty_handler
+	;$80
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$90
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$A0
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$B0
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$C0
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$D0
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$E0
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	;$F0
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.l empty_handler
+	dc.b "SEGA"
+empty_handler:
+	rte
+start:
+;background and sprite test
+
+ButtonState	equ	$FFFFEFF0
+ButtonStateNew	equ	ButtonState+2
+PalAddress equ ButtonStateNew+2
+
+CRAMXferSizeCmd equ $9308
+CRAMDMACmd equ $C0100080
+StaticColors equ 8
+
+USE_HINT equ 0
+	move.b  #$40, $A10009
+	move.l	#$C00000, a4
+	move.l	#$c00004, a5
+
+	move.l	#$0, a7
+
+	move.w	#$8104, (a5)	;turn off display
+	move.w	#$8200, (a5)	;Table A = 0000
+	move.w	#$8400, (a5)	;Table B = 0000
+	move.w	#$857C, (a5)	;Sprite Table = F800
+	move.w	#$8B00, (a5)		;set full screen vertical and horizontal scrolling
+	move.w  #$8C01, (a5)    ;H40 mode, no shadow/hilight, no interlace
+	move.w	#$8D3F, (a5)	;H Scroll = FC00
+	move.w	#$9001, (a5)	;64x32 scroll tables
+
+
+
+	lea	BgData(pc), a0
+	move.w	(a0)+, d0	;size in words
+	move.w	(a0)+, d1	;width in cells
+	move.w	(a0)+, d2	;height in cells
+	move.w d2, d7
+
+	subq	#1, d0		;adjust for 68K dbra routine
+	move.w	#$8f02, (a5)	;autoincrement = 2
+	move.l	#$50200000, (a5);beginning of background tile area
+CopyTiles:
+	move.w	(a0)+, (a4)	;copy tiles to VRAM
+	dbra	d0, CopyTiles
+
+	move.l	#$40000000, d4	;beginning of Plane A Name table
+	move.l	#$00800000, d5	;delta between lines
+	move.w	#$81, d6
+	subq	#1, d1
+	subq	#1, d2
+	move.w	d1, d3
+WriteNamesY:
+	move.l	d4, (a5)
+	move.w	d3, d1
+
+WriteNamesX:
+	move.w	d6, (a4)
+	addq	#1, d6
+	dbra	d1, WriteNamesX
+
+	add.l	d5, d4
+	dbra	d2, WriteNamesY
+
+	move.l	#$C0000000, (a5)	;setup writes to CRAM
+	moveq	#(StaticColors-1), d0			;copy first 12 colors (static pallete)
+CopyColors:
+	move.w	(a0)+, (a4)
+	dbra	d0, CopyColors
+
+	move.l a0, (PalAddress).w
+
+
+	move.l	#$60000010, (a5)	;setup writes to VSRAM
+	move.w	#$0, (a4)		;vscroll = 0
+
+	move.l	#$7C000003, (a5)	;setup writes to HScroll Table FC00
+	move.w	#0, (a4)		;Plane A&B HScroll = 0;
+	move.w	#0, (a4)		;
+
+	move.l	#$78000003, (a5)	;clear sprite table
+	move.l	#0, (a4)
+	move.l	#0, (a4)
+
+	move.w	#$8114, (a5)		;turn on DMA
+
+	bsr	InitSprites
+	bsr	AddSprite
+
+	move.w	#$0, (a0)
+
+	bsr	LoadSpritePal
+	bsr	InitFrameBigSprite
+	moveq	#0, d3
+	bsr	ChangeFrameBigSprite
+
+
+
+
+	move.l	#CRAMDMACmd, d5		;setup DMA command word
+
+	move.w	#CRAMXferSizeCmd, (a5)		;set Transfer length
+	move.w	#$9400, (a5)
+
+	move.w	#$8114, d6
+	move.w	#$8174, d7
+
+	if USE_HINT
+
+		move.w	#$8014, (a5)
+		move.w	#$8A00, (a5)		;HINT occurs on every line
+	endif
+
+	move.w	#$8174, (a5)
+	move #$2300, SR
+
+
+Loop:
+	if USE_HINT
+		bra Loop
+	endif
+WaitTop:
+	cmpi.b  #$FF, 4(a5)
+	bne.s   WaitTop
+
+LineDone:
+	move.b	4(a5), d0
+WaitNextLine:
+	cmp.b	4(a5), d0
+	beq	WaitNextLine
+
+
+
+HINT:
+	;move.w	d6, (a5)
+	;move.l	d5, (a5)		;start DMA
+	;move.w	d7, (a5)
+	move.l d6, (a5)
+	move.l d7, (a5)
+	move.w	#CRAMXferSizeCmd, (a5)		;set Transfer length
+	move.w	#$9400, (a5)
+
+	if USE_HINT
+		rte
+	endif
+
+	cmp.b	#223, 4(a5)
+	beq	WaitTop
+
+	bra	LineDone
+
+VINT:
+	if USE_HINT
+		move.w	#$8144, (a5)
+	endif
+	bsr	SpriteCopyVRAM
+
+	bsr	ReadPad
+
+	bsr	Player1Vint
+
+	move.l	(PalAddress).w, d7			;setup DMA source address
+	move.w	#$9500, d6
+	ror.l	#1, d7
+	move.b	d7, d6
+	move.w	d6, (a5)
+	ror.l	#8, d7
+	move.b	d7, d6
+	add.w	#$100, d6
+	move.w	d6,(a5)
+	ror.l	#8, d7
+	move.b	d7, d6
+	add.w	#$100, d6
+	and.b	#$7F, d6
+	move.w	d6,(a5)
+
+	;move.l	d5, (a5)		;do DMA for first line
+
+	move.w	#CRAMXferSizeCmd, (a5)		;set Transfer length
+	move.w	#$9400, (a5)
+
+	move.w	#$8114, d6		;VDP commands to turn screen on and off during HBlank
+	swap d6
+	swap d5
+	move.w d5, d6
+	swap d5
+	move.w d5, d7
+	swap d7
+	move.w	#$8174, d7
+	if USE_HINT
+		move.w	d7, (a5)
+	endif
+	rte
+
+LoadSpritePal:
+	move.l	#$C0200000, (a5)
+	moveq	#$F, d0
+	lea	SpriteData, a0
+PalLoop:
+	move.w	(a0)+, (a4)
+	dbra	d0, PalLoop
+	rts
+
+Player1Vint:
+	move.b	(ButtonState).w, d2
+	move.b	(ButtonStateNew).w, d3
+
+	moveq	#0, d0
+	move.w	d0, d1
+
+	btst	#5, d2
+	bne	ScrollRight
+
+	btst	#7, d2
+	bne	ScrollLeft
+
+	btst	#4, d3
+	bne	IncrementFrame
+
+
+	btst	#6, d3
+	bne	DecrementFrame
+
+	btst	#2, d2
+	beq	PlayerShipNotLeft
+	subq	#1, d0
+PlayerShipNotLeft:
+
+	btst	#3, d2
+	beq	PlayerShipNotRight
+	addq	#1, d0
+PlayerShipNotRight:
+
+	btst	#0, d2
+	beq	PlayerShipNotDown
+	subq	#1, d1
+PlayerShipNotDown:
+
+	btst	#1, d2
+	beq	PlayerShipNotUp
+	addq	#1, d1
+PlayerShipNotUp:
+
+	bsr	MoveBigSprite
+
+	rts
+IncrementFrame:
+	move.w	(PlayerShipFrame), d3
+	addq	#1, d3
+	move.w	d3, (PlayerShipFrame)
+	bsr	ChangeFrameBigSprite
+
+	rts
+
+DecrementFrame:
+
+	move.w	(PlayerShipFrame), d3
+	subq	#1, d3
+	move.w	d3, (PlayerShipFrame)
+	bsr	ChangeFrameBigSprite
+
+	rts
+
+ScrollRight:
+	move.w	(ScrollValue), d0
+	subq	#1, d0
+	move.l	#$7C000003, (a5)	;setup writes to HScroll Table FC00
+	move.w	d0, (a4)
+	move.w	d0, (a4)
+	move.w	d0, (ScrollValue)
+
+	rts
+
+ScrollLeft:
+	move.w	(ScrollValue), d0
+	addq	#1, d0
+	move.l	#$7C000003, (a5)	;setup writes to HScroll Table FC00
+	move.w	d0, (a4)
+	move.w	d0, (a4)
+	move.w	d0, (ScrollValue)
+
+	rts
+
+	include	sprites.s68
+
+PlayerShipFrame:
+	dc.w 	0
+
+
+ScrollValue:
+	dc.w	0
+
+ReadPad:
+	move.b	#$FF, $a10003	;set TH for controller A
+	move.b	$a10003, d0	;CBRLUD
+	andi.b	#$3F, d0
+	move.b	#0, $a10003
+	move.b	$a10003, d1	;SA00UD
+	andi.b	#$30, d1
+	lsl.b	#2, d1
+	or.b	d1, d0		;SACBRLUD
+	not.b	d0
+	move.b	(ButtonState).w, d1
+	eor.b	d0, d1
+	and.b	d0, d1
+	move.b	d0, (ButtonState).w
+	move.b	d1, (ButtonStateNew).w
+
+	rts
+
+
+SpriteData:
+	incbin	bultest.bin
+BgData:
+	incbin  logo.bin
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/img2tiles.py	Mon Sep 02 21:22:47 2013 -0700
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+from PIL import Image
+
+def gchannel(Val):
+	return (Val >> 4) & 0xE
+
+threshold = 127
+
+def get_color_info(pixels, rng, threshold, exclude={}):
+	gencolors = {}
+	A = 255
+	for idx in rng:
+		color = pixels[idx]
+		if len(color) == 4:
+			(R, G, B, A) = color
+		else:
+			(R, G, B) = color
+		if A > threshold:
+			gcolor = (gchannel(R), gchannel(G), gchannel(B))
+			if not gcolor in exclude:
+				if gcolor in gencolors:
+					gencolors[gcolor] += 1
+				else:
+					gencolors[gcolor] = 1
+	glist = [(gencolors[color], color) for color in gencolors]
+	glist.sort()
+	glist.reverse()
+	return glist
+
+def totiles(im, palette):
+	pass
+
+def make_palette(im, trans_thresh, max_global, max_line):
+	pixels = im.getdata()
+	(width, height) = im.size
+	colors = get_color_info(pixels, xrange(0, height * width), trans_thresh)
+	glob_pal = {}
+	for idx in xrange(0, min(max_global, len(colors))):
+		(count, color) = colors[idx]
+		glob_pal[color] = idx
+	line_pals = []
+	if max_global < len(colors):
+		for line in xrange(0, height):
+			linestart = line * width
+			linecolors = get_color_info(pixels, xrange(linestart, linestart+width), trans_thresh, glob_pal)
+			line_pal = {}
+			for idx in xrange(0, min(max_line, len(linecolors))):
+				(count, color) = linecolors[idx]
+				line_pal[color] = idx
+			line_pals.append(line_pal)
+	return (glob_pal, line_pals, max_global, max_line)
+
+def color_dist(a, b):
+	(ra, ga, ba) = a
+	(rb, gb, bb) = b
+	return (ra-rb)**2 + (ga-gb)**2 + (ba-bb)**2
+
+def trans_image(im, trans_thresh, pal):
+	(global_pal, line_pals, _, _) = pal
+	pixels = im.getdata()
+	(width, height) = im.size
+	gpixels = []
+	A = 255
+	x = 0
+	y = 0
+	for pixel in pixels:
+		if x == width:
+			x = 0
+			y += 1
+			if width % 8:
+				for i in xrange(0, 8-(width%8)):
+					gpixels.append(0)
+		if len(pixel) == 4:
+			(R, G, B, A) = pixel
+		else:
+			(R, G, B) = pixel
+		if A > trans_thresh:
+			gpixel = (gchannel(R), gchannel(G), gchannel(B))
+			if gpixel in global_pal:
+				gpixels.append(global_pal[gpixel])
+			elif gpixel in line_pals[y]:
+				gpixels.append(line_pals[y][gpixel] + len(global_pal))
+			else:
+				bestdist = color_dist((0,0,0), (15, 15, 15))
+				bestpal = 0
+				for cur in global_pal:
+					curdist = color_dist(gpixel, cur)
+					if curdist < bestdist:
+						bestdist = curdist
+						bestpal = global_pal[cur]
+				for cur in line_pals[y]:
+					curdist = color_dist(gpixel, cur)
+					if curdist < bestdist:
+						bestdist = curdist
+						bestpal = line_pals[y][cur]
+				gpixels.append(bestpal)
+		else:
+			gpixels.append(0)
+		x += 1
+	if width % 8:
+		for i in xrange(0, 8-(width%8)):
+			gpixels.append(0)
+		width += 8-(width%8)
+	if height % 8:
+		for y in xrange(0, 8-(height%8)):
+			for x in xrange(0, width):
+				gpixels.append(0)
+		height += 8-(height%8)
+
+	return (width, height, gpixels)
+
+def appendword(b, word):
+	b.append(word >> 8)
+	b.append(word & 0xff)
+
+def to_tiles(palpix):
+	(width, height, pixels) = palpix
+	b = bytearray()
+	cwidth = width/8
+	cheight = height/8
+	words = len(pixels)/4
+	appendword(b, words)
+	appendword(b, cwidth)
+	appendword(b, cheight)
+
+	for cy in xrange(0, cheight):
+		ystart = cy*8*width
+		for cx in xrange(0, cwidth):
+			startoff = (cx*8) + ystart
+			for row in xrange(0, 8):
+				rowoff = startoff + row*width
+				for bytecol in xrange(0, 4):
+					boff = bytecol * 2 + rowoff
+					#print 'boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight
+					#print 'pixels[boff]:', pixels[boff]
+					b.append(pixels[boff] << 4 | pixels[boff+1])
+	return b
+
+def add_pal_entries(tiles, pal):
+	(global_pal, line_pals, max_global, max_line) = pal
+	pal_list = [(0, 0, 0)] * max_global
+	for entry in global_pal:
+		pal_list[global_pal[entry]] = entry
+	for entry in pal_list:
+		(R, G, B) = entry
+		tiles.append(B)
+		tiles.append(G << 4 | R)
+	for line in line_pals:
+		pal_list = [(0, 0, 0)] * max_line
+		for entry in line:
+			pal_list[line[entry]] = entry
+		for entry in pal_list:
+			(R, G, B) = entry
+			tiles.append(B)
+			tiles.append(G << 4 | R)
+
+
+
+def main(argv):
+	if len(argv) < 3:
+		print "Not enough arguments"
+		return
+	fname = argv[1]
+	im = Image.open(fname)
+	pal = make_palette(im, threshold, 8, 8)
+	palpix = trans_image(im, threshold, pal)
+	tiles = to_tiles(palpix)
+	bits = add_pal_entries(tiles, pal)
+	out = open(argv[2], 'wb')
+	out.write(tiles)
+
+if __name__ == '__main__':
+	import sys
+	main(sys.argv)
--- a/mainboot.s68	Tue May 01 20:43:25 2012 -0700
+++ b/mainboot.s68	Mon Sep 02 21:22:47 2013 -0700
@@ -1,4 +1,390 @@
 	org $FF0000
 	incbin security.bin
 Main
-	bra Main
+;background and sprite test
+
+ButtonState	equ	$FFFFEFF0
+ButtonStateNew	equ	ButtonState+2
+
+CRAMXferSizeCmd equ $9304
+StaticColors equ 12
+	
+USE_HINT equ 0
+
+Start
+	bsr ReadPad
+	
+	btst.b #7, (ButtonState).w
+	bne LoadSLO
+	
+	move.l	#$C00000, a4
+	move.l	#$c00004, a5
+
+	move.l	#$0, a7
+	
+	lea BgFile, a0
+	bsr FileByNameSimple
+
+	move.w	#$8104, (a5)	;turn off display
+	move.w	#$8200, (a5)	;Table A = 0000
+	move.w	#$8400, (a5)	;Table B = 0000
+	move.w	#$857C, (a5)	;Sprite Table = F800
+	move.w	#$8B00, (a5)		;set full screen vertical and horizontal scrolling
+	move.w	#$8D3F, (a5)	;H Scroll = FC00
+	move.w	#$9001, (a5)	;64x32 scroll tables
+	
+	
+
+	lea	$200000, a0
+	move.w	(a0)+, d0	;size in words
+	move.w	(a0)+, d1	;width in cells
+	move.w	(a0)+, d2	;height in cells
+	move.w d2, d7
+
+	subq	#1, d0		;adjust for 68K dbra routine
+	move.w	#$8f02, (a5)	;autoincrement = 2
+	move.l	#$50200000, (a5);beginning of background tile area
+CopyTiles:
+	move.w	(a0)+, (a4)	;copy tiles to VRAM
+	dbra	d0, CopyTiles
+
+	move.l	#$40000000, d4	;beginning of Plane A Name table
+	move.l	#$00800000, d5	;delta between lines
+	move.w	#$81, d6
+	subq	#1, d1
+	subq	#1, d2
+	move.w	d1, d3
+WriteNamesY:
+	move.l	d4, (a5)
+	move.w	d3, d1
+
+WriteNamesX:
+	move.w	d6, (a4)
+	addq	#1, d6
+	dbra	d1, WriteNamesX
+
+	add.l	d5, d4
+	dbra	d2, WriteNamesY
+
+	move.l	#$C0000000, (a5)	;setup writes to CRAM
+	moveq	#(StaticColors-1), d0			;copy first 12 colors (static pallete)
+CopyColors:
+	move.w	(a0)+, (a4)
+	dbra	d0, CopyColors
+	
+	move.w d7, d0
+	lsl.w #5, d0
+	subq #1, d0
+	lea PalData(pc), a1
+	;sub.l #2, a0
+.copypallines:
+	move.l (a0)+, (a1)+
+	dbra d0, .copypallines
+	
+
+	move.l	#$60000010, (a5)	;setup writes to VSRAM
+	move.w	#$0, (a4)		;vscroll = 0
+
+	move.l	#$7C000003, (a5)	;setup writes to HScroll Table FC00
+	move.w	#0, (a4)		;Plane A&B HScroll = 0;
+	move.w	#0, (a4)		;
+
+	move.l	#$78000003, (a5)	;clear sprite table
+	move.l	#0, (a4)
+	move.l	#0, (a4)
+
+	move.w	#$8114, (a5)		;turn on DMA
+
+	bsr	InitSprites
+	bsr	AddSprite
+
+	move.w	#$0, (a0)
+
+	bsr	LoadSpritePal
+	bsr	InitFrameBigSprite
+	moveq	#0, d3
+	bsr	ChangeFrameBigSprite
+
+
+
+
+	move.l	#$C0180080, d5		;setup DMA command word
+
+	move.w	#CRAMXferSizeCmd, (a5)		;set Transfer length
+	move.w	#$9400, (a5)
+
+	move.w	#$8114, d6
+	move.w	#$8174, d7
+
+
+
+	lea	VINT(pc), a1		;setup VINT handler
+	jsr	$368
+	
+	if USE_HINT
+		lea	HINT(pc), a1		;setup HINT handler and turn on HINTs
+		jsr	$314
+
+		move.w	#$8014, (a5)
+		move.w	#$8A00, (a5)		;HINT occurs on every line
+	endif
+
+	move.w	#$8174, (a5)
+
+
+
+Loop:
+	if USE_HINT
+		bra Loop
+	endif
+WaitTop:             
+	cmpi.b  #$FF, 4(a5)
+        bne.s   WaitTop
+
+LineDone:
+	move.b	4(a5), d0
+WaitNextLine:
+	cmp.b	4(a5), d0
+	beq	WaitNextLine
+	
+
+
+HINT:
+	;move.w	d6, (a5)
+	;move.l	d5, (a5)		;start DMA
+	;move.w	d7, (a5)
+	move.l d6, (a5)
+	move.l d7, (a5)
+	move.w	#CRAMXferSizeCmd, (a5)		;set Transfer length
+	move.w	#$9400, (a5)
+	
+	if USE_HINT
+		rte
+	endif
+
+	cmp.b	#223, 4(a5)
+	beq	WaitTop
+
+	bra	LineDone
+
+VINT:
+	move.b	#1, $A12000	;trigger interrupt on Sub CPU
+	if USE_HINT
+		move.w	#$8144, (a5)
+	endif
+	bsr	SpriteCopyVRAM
+
+	bsr	ReadPad
+
+	bsr	Player1Vint
+
+	move.l	PalData, d7			;setup DMA source address
+	move.w	#$9500, d6
+	ror.l	#1, d7
+	move.b	d7, d6
+	move.w	d6, (a5)
+	ror.l	#8, d7
+	move.b	d7, d6
+	add.w	#$100, d6
+	move.w	d6,(a5)
+	ror.l	#8, d7
+	move.b	d7, d6
+	add.w	#$100, d6
+	and.b	#$7F, d6
+	move.w	d6,(a5)
+
+	;move.l	d5, (a5)		;do DMA for first line
+
+	move.w	#CRAMXferSizeCmd, (a5)		;set Transfer length
+	move.w	#$9400, (a5)
+
+	move.w	#$8114, d6		;VDP commands to turn screen on and off during HBlank
+	swap d6
+	swap d5
+	move.w d5, d6
+	swap d5
+	move.w d5, d7
+	swap d7
+	move.w	#$8174, d7
+	if USE_HINT
+		move.w	d7, (a5)
+	endif
+	rte
+
+LoadSpritePal:
+	move.l	#$C0200000, (a5)
+	moveq	#$F, d0
+	lea	SpriteData, a0
+PalLoop:
+	move.w	(a0)+, (a4)
+	dbra	d0, PalLoop
+	rts
+
+PalAddress:
+	dc.l	0
+
+Player1Vint:
+	move.b	(ButtonState).w, d2
+	move.b	(ButtonStateNew).w, d3
+	
+	moveq	#0, d0
+	move.w	d0, d1
+
+	btst	#5, d2
+	bne	ScrollRight
+
+	btst	#7, d2
+	bne	ScrollLeft
+
+	btst	#4, d3
+	bne	IncrementFrame
+
+
+	btst	#6, d3
+	bne	DecrementFrame
+
+	btst	#2, d2
+	beq	PlayerShipNotLeft
+	subq	#1, d0
+PlayerShipNotLeft:
+
+	btst	#3, d2
+	beq	PlayerShipNotRight
+	addq	#1, d0
+PlayerShipNotRight:
+
+	btst	#0, d2
+	beq	PlayerShipNotDown
+	subq	#1, d1
+PlayerShipNotDown:
+	
+	btst	#1, d2
+	beq	PlayerShipNotUp
+	addq	#1, d1
+PlayerShipNotUp:
+
+	bsr	MoveBigSprite
+
+	rts
+IncrementFrame:
+	move.w	(PlayerShipFrame), d3
+	addq	#1, d3
+	move.w	d3, (PlayerShipFrame)
+	bsr	ChangeFrameBigSprite
+
+	rts
+
+DecrementFrame:
+
+	move.w	(PlayerShipFrame), d3
+	subq	#1, d3
+	move.w	d3, (PlayerShipFrame)
+	bsr	ChangeFrameBigSprite
+
+	rts
+
+ScrollRight:
+	move.w	(ScrollValue), d0
+	subq	#1, d0
+	move.l	#$7C000003, (a5)	;setup writes to HScroll Table FC00
+	move.w	d0, (a4)
+	move.w	d0, (a4)
+	move.w	d0, (ScrollValue)
+	
+	rts
+
+ScrollLeft:
+	move.w	(ScrollValue), d0
+	addq	#1, d0
+	move.l	#$7C000003, (a5)	;setup writes to HScroll Table FC00
+	move.w	d0, (a4)
+	move.w	d0, (a4)
+	move.w	d0, (ScrollValue)
+	
+	rts
+
+	include	sprites.s68
+
+PlayerShipFrame:
+	dc.w 	0
+
+
+ScrollValue:
+	dc.w	0	
+
+ReadPad:
+	move.b	#$FF, $a10003	;set TH for controller A
+	move.b	$a10003, d0	;CBRLUD
+	andi.b	#$3F, d0
+	move.b	#0, $a10003
+	move.b	$a10003, d1	;SA00UD
+	andi.b	#$30, d1
+	lsl.b	#2, d1
+	or.b	d1, d0		;SACBRLUD
+	not.b	d0
+	move.b	(ButtonState).w, d1
+	eor.b	d0, d1
+	and.b	d0, d1
+	move.b	d0, (ButtonState).w
+	move.b	d1, (ButtonStateNew).w
+
+	rts
+	
+FileByNameSimple:
+	move.b #0, $a1200e
+	lea $a12010, a1
+.copyname
+	move.b (a0), (a1)+
+	tst.b (a0)+
+	bne .copyname
+	
+	bset #1, $A12003; give SUB CPU control of WordRAM
+	
+.waitready
+	tst.b $a1200f
+	beq .waitready
+	
+	
+	move.b #3, $a1200e
+	
+.waitdone
+	cmp.b #$FF, $a1200f
+	beq .notfound
+	tst.b $a1200f
+	bne .waitdone
+	
+	bclr #1, $a12003; get control of WordRAM
+	rts
+	
+.notfound
+	bra .notfound
+	
+LoadSLO:
+	lea LoaderFile(pc), a0
+	bsr FileByNameSimple
+	move.w #(.copyEnd-.copy-1), d0
+	lea .copy(pc), a0
+	lea ($FFFF8000).w, a1
+	move.l a1, a2
+.copycopy
+	move.b (a0)+, (a1)+
+	dbra d0, .copycopy
+	move.w #$2000, d0; more than enough for slo.bin
+	lea $200000, a0
+	lea $FF0000, a1
+	jmp (a2)
+.copy
+	move.b (a0)+, (a1)+
+	dbra d0, .copy
+	jmp $FF0000
+.copyEnd
+
+SpriteData:
+	incbin	bultest.bin
+BgFile:
+	dc.b "LOGO.BIN",0
+LoaderFile:
+	dc.b "SLO.BIN",0
+
+PalData:
+
--- a/subboot.s68	Tue May 01 20:43:25 2012 -0700
+++ b/subboot.s68	Mon Sep 02 21:22:47 2013 -0700
@@ -1,19 +1,313 @@
 	org $6000
 SubHeaderStart
-	dc.b 'MAIN FOOBAR', 0
+	dc.b 'MAIN       ', 0
 	align 4
 	dc.l 0
 	dc.l End-SubHeaderStart
 	dc.l EntryPoints-SubHeaderStart
+	dc.l 0
 EntryPoints
 	dc.w Main-EntryPoints
-	dc.w Main-EntryPoints
-	dc.w Int2Handler-EntryPoints
+;	dc.w Main-EntryPoints
+;	dc.w Int2Handler-EntryPoints
 	dc.w 0
 Main
-	bra Main
+	andi.b	#$FA,$FF8003		;set 2Mbit mode
+
+	lea	Packet(pc),a5
+	jsr	ReadCD
+
+	move.l	$80A2,(a5)
+	move.l	(a5),d0
+	move.l	$80AA,d0
+	lsr.l	#8,d0
+	lsr.l	#3,d0
+	move.l	d0,4(a5)
+	move.l	#$8000,8(a5)
+	jsr	ReadCD
+
+	move.b	#0,$FF800F
+
+
+Wait:
+	tst.b	$FF800E
+	bne	Wait
+	move.b	#1,$FF800F
+Wait2:
+	tst.b	$FF800E
+	beq	Wait2
+
+	moveq	#0,d0
+	move.b	$FF800E,d0
+	cmpi.b	#8,d0
+	bgt	Wait
+	add.w	d0,d0
+	add.w	d0,d0
+	jmp	FuncTable(pc,d0)
+FuncTable:
+	bra.w	Wait				;0x0
+	bra.w	FileList			;0x1
+	bra.w	FileByNumber			;0x2
+	bra.w	FileByNameSimple		;0x3
+	bra.w	FileByNameExtended		;0x4
+	bra.w	SetExtended			;0x5
+	bra.w	Jump				;0x6
+	bra.w	JumpSub				;0x7
+	bra.w	PlayRAW				;0x8
+
+
+
+FileList:
+
+	move.l	#$8000,a0
+	move.l	#$80000,a1
+NextFile:
+	moveq	#0,d0
+	move.b	(a0),d0		;get record length
+	beq	EndList
+	move.l	6(a0),$20(a1)		;file location
+	move.l	$E(a0),$24(a1)		;file length
+	moveq	#0,d1
+	move.b	$20(a0),d1		;file name length
+	subi.w	#1,d1
+	beq	Terminate		;skip copy if length = 0		
+	lea	$21(a0),a2
+	movea.l	a1,a4
+CopyName:
+	move.b	(a2)+,(a4)+		;copy filename to new table
+	dbra	d1,CopyName
+Terminate:
+	move.b	#0,(a4)
+
+	adda.l	d0,a0
+	add.l	#$28,a1
+	bra	NextFile
+	
+EndList:
+	move.b	#$FF,(a1)
+	ori.b	#1,$FF8003
+	move.b	#0,$FF800F
+	bra	Wait
+
+
+
+
+
+FileByNumber:
+	lea	Packet(pc),a5
+	move.l	$FF8010,(a5)
+	move.l	$FF8014,d0
+	move.l	$FF8018,8(a5)
+File:
+	move.l	d0,$FF8020
+	move.l	d0,d1
+	lsr.l	#8,d1
+	lsr.l	#3,d1
+	andi.l	#$7FF,d0
+	beq	SectorAligned
+	addq	#1,d1
+
+SectorAligned:
+	move.l	d1,4(a5)
+
+	bsr	ReadCD
+
+	move.l	$8000,d7
+
+	ori.b	#1,$FF8003
+
+	move.b	#0,$FF800F
 	
+	bra	Wait
+
+
+
+
+FileByNameSimple:
+	lea	Packet(pc),a5
+	move.l	#$80000,8(a5)
+	move.l	#$40000,4(a5)
+	move.l	#0,(BeginOffset)
+
+FileByNameExtended:
+	move.l	#$FF8010,a0
+	bsr	FindFile
+	bcc	FileNotFound
+
+	lsl.l	#8,d1
+	lsl.l	#3,d1
+	add.l	(BeginOffset),d1
+	sub.l	(BeginOffset),d0
+	lsr.l	#8,d1
+	lsr.l	#3,d1
+
+	lea	Packet(pc),a5
+
+	move.l	4(a5),d3
+	cmp.l	d0,d3
+	bgt	TooBig			;File is either smaller than requested length or size of WordRAM
+
+	move.l	d3,d0
+TooBig:
+
+	move.l	d1,(a5)
+	bra	File
+
+FileNotFound:
+	ori.b	#1,$FF8003
+	move.b	#$FF,$FF800F
+	bra	Wait
+
+
+
+
+SetExtended:
+	lea	Packet(pc),a5
+	move.l	$FF8010,8(a5)
+	move.l	$FF8014,4(a5)
+	move.l	$FF8018,(BeginOffset)
+
+	move.b	#0,$FF800F
+	bra	Wait
+
+
+
+Jump:
+	move.l	$FF8010,a0
+	jmp	(a0)
+
+JumpSub:
+	move.l	$FF8010,a0
+	jsr	(a0)
+
+	move.b	#0,$FF800F
+	bra 	Wait
+
+PlayRAW:
+
+
+	move.l	$FF8010,a0		;get start address
+	move.w	$FF8014,d2		;get playback frequency
+
+
+	move.w	#$F,d6
+	move.b	#$FF,d1
+
+
+BankLoop:
+
+	addq	#1,d1			;increment bank
+	move.b	d1,$FF000F		;turn off sound production,and set waveform memory bank
+	move.l	#$FF2001,a1
+	move.w	#$FFF,d7
+
+MoveIt:
+	move.b	(a0)+,d0
+	move.b	d0,(a1)
+	addq	#2,a1
+	cmp.b	#$FF,d0
+	dbeq	d7,MoveIt
+
+	dbeq	d6,BankLoop
+
+	move.b	#$40,$FF000F		;set control to channel 0
+
+	move.b	#$FF,$FF0001		;set volume
+
+	move.b	#$FF,$FF0003		;set Pan
+
+	move.b	#$00,$FF0005		;set FDL (Playback frequency low order byte)
+
+	move.b	#$08,$FF0007		;set FDH (Playback frequency high order byte)
+
+	move.b	#$00,$FF0009		;LSL (Loop Start Address low order byte)
+
+	move.b	#$00,$FF000B		;LSH (Loop Start Address high order byte)
+
+	move.b	#$00,$FF000D		;ST (Start address high order byte,low order byte is always equal to 0)
+
+	move.b	#$FE,$FF0011		;turn on channel 0
+
+	move.b	#$80,$FF000F		;start sound playback
+
+	move.b	#0,$FF800F
+
+	bra	Wait
+
+
+
+FindFile:
+	move.l	#$8000,a2
+
+NextName:
+	moveq	#0,d3
+	move.b	(a2),d3
+	beq	NotFound
+
+	lea	$21(a2),a3
+	move.l	a0,a1
+Compare:
+	tst.b	(a1)
+	beq	Found
+	cmp.b	(a1)+,(a3)+
+	beq	Compare
+
+	add.l 	d3,a2
+	bra	NextName
+
+NotFound:	
+	move	#0,CCR
+	rts
+
+Found:
+	move.l	$E(a2),d0
+	move.l	6(a2),d1
+	move	#1,CCR
+	rts	
+
+
+
+
+ReadCD:	
+	movea.l	a5,a0
+	move.w	#$89,d0		;init CD controller
+	jsr 	$5f22
+	move.w	#$20,d0		;start read operation
+	jsr	$5f22
+
+Check:
+	move.w	#$8A,d0		;check for data
+	jsr	$5f22
+	bcs	Check
+
+Check2:
+	move.w	#$8B,d0
+	jsr	$5f22
+	bcc	Check2
+
+Check3:
+	move.w	#$8C,d0
+	movea.l	8(a5),a0
+	lea	$C(a5),a1
+	jsr	$5f22
+	bcc	Check3
+
+	move.w	#$8D,d0
+	jsr	$5f22
+
+	addi.l	#$800,8(a5)
+	addq.l	#1,(a5)
+	subq.l	#1,4(a5)
+	bne	Check
+	rts
 Int2Handler
 	rte
 	
+BeginOffset:
+	dc.l	$0
+Packet:
+	dc.l	$10, 1, $8000, ExtraJunk, 0
+ExtraJunk:
+	dc.b	0
+	
 End
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tiles2img.py	Mon Sep 02 21:22:47 2013 -0700
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+from PIL import Image
+
+def gchannel(Val):
+	return (Val >> 4) & 0xE
+	
+threshold = 127
+
+def get_color_info(pixels, rng, threshold, exclude={}):
+	gencolors = {}
+	A = 255
+	for idx in rng:
+		color = pixels[idx]
+		if len(color) == 4:
+			(R, G, B, A) = color
+		else:
+			(R, G, B) = color
+		if A > threshold:
+			gcolor = (gchannel(R), gchannel(G), gchannel(B))
+			if not gcolor in exclude:
+				if gcolor in gencolors:
+					gencolors[gcolor] += 1
+				else:
+					gencolors[gcolor] = 1
+	glist = [(gencolors[color], color) for color in gencolors]
+	glist.sort()
+	glist.reverse()
+	return glist
+	
+def totiles(im, palette):
+	pass
+	
+def make_palette(im, trans_thresh, max_global, max_line):
+	pixels = im.getdata()
+	(width, height) = im.size
+	colors = get_color_info(pixels, xrange(0, height * width), trans_thresh)
+	glob_pal = {}
+	for idx in xrange(0, min(max_global, len(colors))):
+		(count, color) = colors[idx]
+		glob_pal[color] = idx
+	line_pals = []
+	if max_global < len(colors):
+		for line in xrange(0, height):
+			linestart = line * width
+			linecolors = get_color_info(pixels, xrange(linestart, linestart+width), trans_thresh, glob_pal)
+			line_pal = {}
+			for idx in xrange(0, min(max_line, len(linecolors))):
+				(count, color) = linecolors[idx]
+				line_pal[color] = idx
+			line_pals.append(line_pal)
+	return (glob_pal, line_pals)
+	
+def color_dist(a, b):
+	(ra, ga, ba) = a
+	(rb, gb, bb) = b
+	return abs(ra-rb)**2 + abs(ga-gb)**2 + abs(ba-bb)**2
+
+def trans_image(im, trans_thresh, pal):
+	(global_pal, line_pals) = pal
+	pixels = im.getdata()
+	(width, height) = im.size
+	gpixels = []
+	A = 255
+	x = 0
+	y = 0
+	for pixel in pixels:
+		if x == width:
+			x = 0
+			y += 1
+			if width % 8:
+				for i in xrange(0, 8-(width%8)):
+					gpixels.append(0)
+		if len(pixel) == 4:
+			(R, G, B, A) = pixel
+		else:
+			(R, G, B) = pixel
+		if A > trans_thresh:
+			gpixel = (gchannel(R), gchannel(G), gchannel(B))
+			if gpixel in global_pal:
+				gpixels.append(global_pal[gpixel])
+			elif gpixel in line_pals[y]:
+				gpixels.append(line_pals[y][gpixel] + len(global_pal))
+			else:
+				bestdist = color_dist((0,0,0), (15, 15, 15))
+				bestpal = 0
+				for cur in global_pal:
+					curdist = color_dist(gpixel, cur)
+					if curdist < bestdist:
+						bestdist = curdist
+						bestpal = global_pal[cur]
+				for cur in line_pals[y]:
+					curdist = color_dist(gpixel, cur)
+					if curdist < bestdist:
+						bestdist = curdist
+						bestpal = line_pals[y][cur]
+				gpixels.append(bestpal)
+		else:
+			gpixels.append(0)
+		x += 1
+	if width % 8:
+		for i in xrange(0, 8-(width%8)):
+			gpixels.append(0)
+		width += 8-(width%8)
+	if height % 8:
+		for y in xrange(0, 8-(height%8)):
+			for x in xrange(0, width):
+				gpixels.append(0)
+		height += 8-(height%8)
+		
+	return (width, height, gpixels)
+	
+def appendword(b, word):
+	b.append(word >> 8)
+	b.append(word & 0xff)
+
+def to_tiles(palpix):
+	(width, height, pixels) = palpix
+	b = bytearray()
+	cwidth = width/8
+	cheight = height/8
+	words = len(pixels)/4
+	appendword(b, words)
+	appendword(b, cwidth)
+	appendword(b, cheight)
+	
+	for cy in xrange(0, cheight):
+		ystart = cy*8*width
+		for cx in xrange(0, cwidth):
+			startoff = (cx*8) + ystart
+			for row in xrange(0, 8):
+				rowoff = startoff + row*width
+				for bytecol in xrange(0, 4):
+					boff = bytecol * 2 + rowoff
+					#print 'boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight
+					#print 'pixels[boff]:', pixels[boff]
+					b.append(pixels[boff] << 4 | pixels[boff+1])
+	return b
+	
+def add_pal_entries(tiles, pal):
+	(global_pal, line_pals) = pal
+	pal_list = [()] * len(global_pal)
+	for entry in global_pal:
+		pal_list[global_pal[entry]] = entry
+	for entry in pal_list:
+		(R, G, B) = entry
+		tiles.append(B)
+		tiles.append(G << 4 | R)
+	for line in line_pals:
+		pal_list = [()] * len(line)
+		for entry in line:
+			pal_list[line[entry]] = entry
+		for entry in pal_list:
+			(R, G, B) = entry
+			tiles.append(B)
+			tiles.append(G << 4 | R)
+
+def getcolor(tiles, fixedpal, linepals, width, x, y):
+	celly = y/8
+	cellx = x/8
+	resty = y%8
+	restx = x%8
+	cellwidth = width / 8
+	offset = celly * 32 * cellwidth + resty * 4 + cellx * 32 + restx / 2
+	if restx & 1:
+		palidx = tiles[offset] & 0xF
+	else:
+		palidx = (tiles[offset] >> 4) & 0xF
+	if palidx < len(fixedpal):
+		return fixedpal[palidx]
+	return linepals[y][palidx - len(fixedpal)]
+			
+def to_pixels(tiles, im):
+	(_, width, height), tiles, (fixedpal, linepals) = tiles
+	for y in xrange(0, height):
+		for x in xrange(0, width):
+			color = getcolor(tiles, fixedpal, linepals, width, x, y)
+			im.putpixel((x,y), color)
+	return im
+	
+def expand_pal(pal):
+	def expand_pal_int(pal):
+		return ((pal << 4) & 0xE0, pal & 0xE0, (pal >> 4) & 0xE0)
+	fixedpal, linepals = pal
+	fixedpal = [expand_pal_int(color) for color in fixedpal]
+	linepals = [[expand_pal_int(color) for color in linepal] for linepal in linepals]
+	return (fixedpal, linepals)
+			
+def open_tiles(name):
+	from struct import unpack, unpack_from
+	f = open(name, 'rb')
+	header = f.read(6)
+	words,width,height = unpack('>HHH', header)
+	width *= 8
+	height *= 8
+	meta = (words, width, height)
+	pixels = bytearray(f.read(words * 2))
+	numfixed = 12
+	numdynamic = 4
+	fixedpalb = f.read(numfixed*2)
+	fixedpal = []
+	for offset in xrange(0, numfixed*2, 2):
+		color, = unpack_from('>H', fixedpalb, offset)
+		fixedpal.append(color)
+	linepals = []
+	linepalsize = numdynamic * height * 2
+	linepalb = f.read(linepalsize)
+	for baseoffset in xrange(0, linepalsize, numdynamic * 2):
+		linepal = []
+		for offset in xrange(baseoffset, baseoffset + numdynamic * 2, 2):
+			color, = unpack_from('>H', linepalb, offset)
+			linepal.append(color)
+		linepals.append(linepal)
+	return (meta, pixels, (fixedpal, linepals))
+
+def main(argv):
+	if len(argv) < 3:
+		print "Not enough arguments"
+		return
+	fname = argv[1]
+	tiles = open_tiles(fname)
+	im = Image.new('RGB', (tiles[0][1], tiles[0][2]))
+	tiles = (tiles[0], tiles[1], expand_pal(tiles[2]))
+	to_pixels(tiles, im)
+	out = open(argv[2], 'wb')
+	im.save(out)
+	
+if __name__ == '__main__':
+	import sys
+	main(sys.argv)