Added multi-file generation in one step using a prefix

* changed testcase to use second type of sprite
* added hand-coded 3x8 backing store
This commit is contained in:
Rob McMullen 2017-06-29 23:14:39 -07:00
parent 6c794b855e
commit 8951869372
6 changed files with 189 additions and 32 deletions

View File

@ -53,6 +53,8 @@ def slugify(s):
class AssemblerSyntax(object):
extension = "s"
def asm(self, text):
return "\t%s" % text
@ -74,6 +76,9 @@ class AssemblerSyntax(object):
def origin(self, text):
return self.asm("*= %s" % text)
def include(self, text):
return self.asm(".include \"%s\"" % text)
def binary_constant(self, value):
try:
# already a string
@ -97,6 +102,8 @@ class Mac65(AssemblerSyntax):
class CC65(AssemblerSyntax):
extension = "s"
def label(self, text):
return "%s:" % text
@ -108,11 +115,23 @@ class Listing(object):
self.current = None
self.desired_count = 1
self.stash_list = []
self.slug = "sprite-driver"
def __str__(self):
self.flush_stash()
return "\n".join(self.lines) + "\n"
def get_filename(self, basename):
return "%s-%s.%s" % (basename, self.slug.lower(), self.assembler.extension)
def write(self, basename, disclaimer):
filename = self.get_filename(basename)
print("Writing to %s" % filename)
with open(filename, "w") as fh:
fh.write(disclaimer + "\n\n")
fh.write(str(self))
return filename
def out(self, line):
self.flush_stash()
self.lines.append(line)
@ -135,6 +154,9 @@ class Listing(object):
def addr(self, text):
self.out(self.assembler.address(text))
def include(self, text):
self.out(self.assembler.include(text))
def flush_stash(self):
if self.current is not None and len(self.stash_list) > 0:
self.lines.append(self.current(", ".join(self.stash_list)))
@ -166,6 +188,8 @@ class Listing(object):
class Sprite(Listing):
backing_store_sizes = set()
def __init__(self, pngfile, assembler, screen, xdraw=False, use_mask=False, backing_store=False, processor="any", name=""):
Listing.__init__(self, assembler)
self.screen = screen
@ -179,7 +203,7 @@ class Sprite(Listing):
self.processor = processor
if not name:
name = os.path.splitext(pngfile)[0]
self.niceName = slugify(name)
self.slug = slugify(name)
self.width = pngdata[0]
self.height = pngdata[1]
self.pixelData = list(pngdata[2])
@ -189,7 +213,7 @@ class Sprite(Listing):
def jumpTable(self):
# Prologue
self.label("%s" % self.niceName)
self.label("%s" % self.slug)
self.comment("%d bytes per row" % self.screen.byteWidth(self.width))
if self.processor == "any":
@ -234,13 +258,13 @@ class Sprite(Listing):
self.asm("ldy PARAM0")
self.asm("ldx MOD%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel))
self.asm("jmp (%s_JMP,x)\n" % (self.niceName))
self.asm("jmp (%s_JMP,x)\n" % (self.slug))
offset_suffix = ""
# Bit-shift jump table for 65C02
self.label("%s_JMP" % (self.niceName))
self.label("%s_JMP" % (self.slug))
for shift in range(self.screen.numShifts):
self.addr("%s_SHIFT%d" % (self.niceName, shift))
self.addr("%s_SHIFT%d" % (self.slug, shift))
def jump6502(self):
self.save_axy_6502()
@ -248,16 +272,16 @@ class Sprite(Listing):
self.asm("ldx MOD%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel))
# Fast jump table routine; faster and smaller than self-modifying code
self.asm("lda %s_JMP+1,x" % (self.niceName))
self.asm("lda %s_JMP+1,x" % (self.slug))
self.asm("pha")
self.asm("lda %s_JMP,x" % (self.niceName))
self.asm("lda %s_JMP,x" % (self.slug))
self.asm("pha")
self.asm("rts\n")
# Bit-shift jump table for generic 6502
self.label("%s_JMP" % (self.niceName))
self.label("%s_JMP" % (self.slug))
for shift in range(self.screen.numShifts):
self.addr("%s_SHIFT%d-1" % (self.niceName,shift))
self.addr("%s_SHIFT%d-1" % (self.slug,shift))
def blitShift(self, shift):
# Blitting functions
@ -267,7 +291,7 @@ class Sprite(Listing):
# SAVE_AXY + RESTORE_AXY + rts + sprite jump table
cycleCount = 9 + 12 + 6 + 3 + 4 + 6
self.label("%s_SHIFT%d" % (self.niceName,shift))
self.label("%s_SHIFT%d" % (self.slug,shift))
colorStreams = self.screen.byteStreamsFromPixels(shift, self)
maskStreams = self.screen.byteStreamsFromPixels(shift, self, True)
@ -278,6 +302,7 @@ class Sprite(Listing):
if self.backing_store:
byteWidth = len(colorStreams[0])
self.asm("jsr savebg_%dx%d" % (byteWidth, self.height))
self.backing_store_sizes.add((byteWidth, self.height))
self.asm("ldx PARAM1")
cycleCount += 3
@ -594,6 +619,7 @@ class HGRBW(HGR):
class RowLookup(Listing):
def __init__(self, assembler, screen):
Listing.__init__(self, assembler)
self.slug = "hgrrows"
self.generate_y(screen)
def generate_y(self, screen):
@ -615,6 +641,7 @@ class RowLookup(Listing):
class ColLookup(Listing):
def __init__(self, assembler, screen):
Listing.__init__(self, assembler)
self.slug = "hgrcols-%dx%d" % (screen.numShifts, screen.bitsPerPixel)
self.generate_x(screen)
def generate_x(self, screen):
@ -648,6 +675,7 @@ if __name__ == "__main__":
parser.add_argument("-p", "--processor", default="any", choices=["any","6502", "65C02"], help="Processor type (default: %(default)s)")
parser.add_argument("-s", "--screen", default="hgrcolor", choices=["hgrcolor","hgrbw"], help="Screen format (default: %(default)s)")
parser.add_argument("-n", "--name", default="", help="Name for generated assembly function (default: based on image filename)")
parser.add_argument("-o", "--output-prefix", default="", help="Base name to create a set of output files. If not supplied, all code will be sent to stdout.")
parser.add_argument("files", metavar="IMAGE", nargs="*", help="a PNG image [or a list of them]. PNG files must not have an alpha channel!")
options, extra_args = parser.parse_known_args()
@ -670,6 +698,7 @@ if __name__ == "__main__":
sys.exit(1)
listings = []
luts = {}
for pngfile in options.files:
try:
@ -680,6 +709,13 @@ if __name__ == "__main__":
except png.Error, e:
print "%s: %s" % (pngfile, e)
sys.exit(1)
if options.output_prefix:
r = RowLookup(assembler, screen)
luts[r.slug] = r
c = ColLookup(assembler, screen)
luts[c.slug] = c
listings.extend([luts[k] for k in sorted(luts.keys())])
if options.rows:
listings.append(RowLookup(assembler, screen))
@ -688,7 +724,14 @@ if __name__ == "__main__":
listings.append(ColLookup(assembler, screen))
if listings:
print disclaimer
if options.output_prefix:
driver = Listing(assembler)
for source in listings:
genfile = source.write(options.output_prefix, disclaimer)
driver.include(genfile)
driver.write(options.output_prefix, disclaimer)
else:
print disclaimer
for section in listings:
print section
for section in listings:
print section

View File

@ -28,7 +28,10 @@ colortest.dsk: HiSprite.py colortest.s bwsprite.s
atasm -ocolortest.xex colortest.s -Lcolortest.var -gcolortest.lst
atrcopy colortest.dsk boot -b colortest.xex --brun 6000 -f
multitest.dsk: HiSprite.py multitest.s colorsprite.s bwsprite.s
multitest-sprite-driver.s: HiSprite.py $(BWSPRITE)
python HiSprite.py -a mac65 -p 6502 -s hgrbw -m -b -o multitest $(BWSPRITE) $(COLORSPRITE)
multitest.dsk: HiSprite.py multitest.s multitest-sprite-driver.s
atasm -omultitest.xex multitest.s -Lmultitest.var -gmultitest.lst
atrcopy multitest.dsk boot -b multitest.xex --brun 6000 -f
@ -36,4 +39,4 @@ clean:
rm -f rowlookup.s collookupbw.s collookupcolor.s
rm -f bwtest.dsk bwtest.xex bwtest.var bwtest.lst
rm -f colortest.dsk colortest.xex colortest.var colortest.lst
rm -f multitest.dsk multitest.xex multitest.var multitest.lst
rm -f multitest.dsk multitest.xex multitest.var multitest.lst multitest-sprite-driver.s multitest-bwsprite.s multitest-hgrcols-7x1.s multitest-hgrrows.s

View File

@ -26,6 +26,7 @@
SIZE_3X11 = 2 + 1 + 1 + 3*11
savebg_3x11
; reserve space in the backing store stack
sec
lda bgstore
sbc #SIZE_3X11
@ -33,8 +34,9 @@ savebg_3x11
lda bgstore+1
sbc #0
sta bgstore+1
ldy #0
; save the metadata
ldy #0
lda #<restorebg_3x11
sta (bgstore),y
iny
@ -45,12 +47,13 @@ savebg_3x11
sta (bgstore),y
iny
lda PARAM1
sta bgline
sta SCRATCH0
sta (bgstore),y
iny
savebg_3x11_line
ldx bgline ; Calculate Y line
; save a line, starting from the topmost and working down
ldx SCRATCH0 ; Calculate Y line
lda HGRROWS_H1,x ; Compute hires row
sta savebg_3x11_col0+2
@ -80,7 +83,7 @@ savebg_3x11_col2
sta (bgstore),y
iny
inc bgline
inc SCRATCH0
cpy #SIZE_3X11
bcc savebg_3x11_line
@ -131,3 +134,116 @@ restorebg_3x11_col2
cpy #SIZE_3X11
bcc restorebg_3x11
rts
SIZE_3X8 = 2 + 1 + 1 + 3*8
savebg_3X8
; reserve space in the backing store stack
sec
lda bgstore
sbc #SIZE_3X8
sta bgstore
lda bgstore+1
sbc #0
sta bgstore+1
; save the metadata
ldy #0
lda #<restorebg_3X8
sta (bgstore),y
iny
lda #>restorebg_3X8
sta (bgstore),y
iny
lda PARAM0
sta (bgstore),y
iny
lda PARAM1
sta SCRATCH0
sta (bgstore),y
iny
savebg_3X8_line
; save a line, starting from the topmost and working down
ldx SCRATCH0 ; Calculate Y line
lda HGRROWS_H1,x ; Compute hires row
sta savebg_3X8_col0+2
sta savebg_3X8_col1+2
sta savebg_3X8_col2+2
lda HGRROWS_L,x
sta savebg_3X8_col0+1
sta savebg_3X8_col1+1
sta savebg_3X8_col2+1
ldx PARAM0 ; Compute hires column
lda DIV7_1,x
tax
savebg_3X8_col0
lda $2000,x
sta (bgstore),y
iny
inx
savebg_3X8_col1
lda $2000,x
sta (bgstore),y
iny
inx
savebg_3X8_col2
lda $2000,x
sta (bgstore),y
iny
inc SCRATCH0
cpy #SIZE_3X8
bcc savebg_3X8_line
rts
; bgstore will be pointing right to the data to be blitted back to the screen,
; which is 4 bytes into the bgstore array. Everything before the data will have
; already been pulled off by the driver in order to figure out which restore
; routine to call. Y will be 4 upon entry, and PARAM0 and PARAM1 will be
; filled with the x & y values.
;
; also, no need to save registers because this is being called from a driver
; that will do all of that.
restorebg_3X8
ldx PARAM1 ; Calculate Y line
lda HGRROWS_H1,x ; Compute hires row
sta restorebg_3X8_col0+2
sta restorebg_3X8_col1+2
sta restorebg_3X8_col2+2
lda HGRROWS_L,x
sta restorebg_3X8_col0+1
sta restorebg_3X8_col1+1
sta restorebg_3X8_col2+1
ldx PARAM0 ; Compute hires column
lda DIV7_1,x
tax
lda (bgstore),y
restorebg_3X8_col0
sta $2000,x
iny
inx
lda (bgstore),y
restorebg_3X8_col1
sta $2000,x
iny
inx
lda (bgstore),y
restorebg_3X8_col2
sta $2000,x
iny
inc PARAM1
cpy #SIZE_3X8
bcc restorebg_3X8
rts

View File

@ -48,8 +48,8 @@ restorebg_jsr
jsr $ffff
clc
lda bgstore
adc #SIZE_3X11
tya ; y contains the number of bytes processed
adc bgstore
sta bgstore
lda bgstore+1
adc #0

Binary file not shown.

View File

@ -21,10 +21,9 @@ SCRATCH0 = $19
SCRATCH1 = $1a
SPRITEPTR_L = $1b
SPRITEPTR_H = $1c
BGSTORE = $fa
BGTOP = $c0 ; page number of first byte beyond top of backing store stack
bgstore = $80
bgline = $82
; constants
MAXPOSX = 250
@ -204,10 +203,10 @@ sprite_active
.byte 1, 1, 1, 1, 1, 1, 1, 1, $ff ; 1 = active, 0 = skip, $ff = end of list
sprite_l
.byte <BWSPRITE, <BWSPRITE, <BWSPRITE, <BWSPRITE, <BWSPRITE, <BWSPRITE, <BWSPRITE, <BWSPRITE
.byte <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <APPLE_SPRITE9X11, <MOLDY_BURGER, <MOLDY_BURGER
sprite_h
.byte >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE, >BWSPRITE
.byte >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >APPLE_SPRITE9X11, >MOLDY_BURGER, >MOLDY_BURGER
sprite_x
.byte 80, 164, 33, 245, 4, 9, 255, 18
@ -229,10 +228,6 @@ sprite_diry
.include colorsprite.s
.include bwsprite.s
.include rowlookup.s
.include collookupbw.s
.include collookupcolor.s
.include backingstore.s
.include backingstore-3x11.s
.include multitest-sprite-driver.s
.include backingstore.s
.include backingstore-3x11.s