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): class AssemblerSyntax(object):
extension = "s"
def asm(self, text): def asm(self, text):
return "\t%s" % text return "\t%s" % text
@ -74,6 +76,9 @@ class AssemblerSyntax(object):
def origin(self, text): def origin(self, text):
return self.asm("*= %s" % text) return self.asm("*= %s" % text)
def include(self, text):
return self.asm(".include \"%s\"" % text)
def binary_constant(self, value): def binary_constant(self, value):
try: try:
# already a string # already a string
@ -97,6 +102,8 @@ class Mac65(AssemblerSyntax):
class CC65(AssemblerSyntax): class CC65(AssemblerSyntax):
extension = "s"
def label(self, text): def label(self, text):
return "%s:" % text return "%s:" % text
@ -108,11 +115,23 @@ class Listing(object):
self.current = None self.current = None
self.desired_count = 1 self.desired_count = 1
self.stash_list = [] self.stash_list = []
self.slug = "sprite-driver"
def __str__(self): def __str__(self):
self.flush_stash() self.flush_stash()
return "\n".join(self.lines) + "\n" 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): def out(self, line):
self.flush_stash() self.flush_stash()
self.lines.append(line) self.lines.append(line)
@ -135,6 +154,9 @@ class Listing(object):
def addr(self, text): def addr(self, text):
self.out(self.assembler.address(text)) self.out(self.assembler.address(text))
def include(self, text):
self.out(self.assembler.include(text))
def flush_stash(self): def flush_stash(self):
if self.current is not None and len(self.stash_list) > 0: if self.current is not None and len(self.stash_list) > 0:
self.lines.append(self.current(", ".join(self.stash_list))) self.lines.append(self.current(", ".join(self.stash_list)))
@ -166,6 +188,8 @@ class Listing(object):
class Sprite(Listing): class Sprite(Listing):
backing_store_sizes = set()
def __init__(self, pngfile, assembler, screen, xdraw=False, use_mask=False, backing_store=False, processor="any", name=""): def __init__(self, pngfile, assembler, screen, xdraw=False, use_mask=False, backing_store=False, processor="any", name=""):
Listing.__init__(self, assembler) Listing.__init__(self, assembler)
self.screen = screen self.screen = screen
@ -179,7 +203,7 @@ class Sprite(Listing):
self.processor = processor self.processor = processor
if not name: if not name:
name = os.path.splitext(pngfile)[0] name = os.path.splitext(pngfile)[0]
self.niceName = slugify(name) self.slug = slugify(name)
self.width = pngdata[0] self.width = pngdata[0]
self.height = pngdata[1] self.height = pngdata[1]
self.pixelData = list(pngdata[2]) self.pixelData = list(pngdata[2])
@ -189,7 +213,7 @@ class Sprite(Listing):
def jumpTable(self): def jumpTable(self):
# Prologue # Prologue
self.label("%s" % self.niceName) self.label("%s" % self.slug)
self.comment("%d bytes per row" % self.screen.byteWidth(self.width)) self.comment("%d bytes per row" % self.screen.byteWidth(self.width))
if self.processor == "any": if self.processor == "any":
@ -234,13 +258,13 @@ class Sprite(Listing):
self.asm("ldy PARAM0") self.asm("ldy PARAM0")
self.asm("ldx MOD%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel)) 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 = "" offset_suffix = ""
# Bit-shift jump table for 65C02 # 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): 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): def jump6502(self):
self.save_axy_6502() self.save_axy_6502()
@ -248,16 +272,16 @@ class Sprite(Listing):
self.asm("ldx MOD%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel)) self.asm("ldx MOD%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel))
# Fast jump table routine; faster and smaller than self-modifying code # 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("pha")
self.asm("lda %s_JMP,x" % (self.niceName)) self.asm("lda %s_JMP,x" % (self.slug))
self.asm("pha") self.asm("pha")
self.asm("rts\n") self.asm("rts\n")
# Bit-shift jump table for generic 6502 # 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): 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): def blitShift(self, shift):
# Blitting functions # Blitting functions
@ -267,7 +291,7 @@ class Sprite(Listing):
# SAVE_AXY + RESTORE_AXY + rts + sprite jump table # SAVE_AXY + RESTORE_AXY + rts + sprite jump table
cycleCount = 9 + 12 + 6 + 3 + 4 + 6 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) colorStreams = self.screen.byteStreamsFromPixels(shift, self)
maskStreams = self.screen.byteStreamsFromPixels(shift, self, True) maskStreams = self.screen.byteStreamsFromPixels(shift, self, True)
@ -278,6 +302,7 @@ class Sprite(Listing):
if self.backing_store: if self.backing_store:
byteWidth = len(colorStreams[0]) byteWidth = len(colorStreams[0])
self.asm("jsr savebg_%dx%d" % (byteWidth, self.height)) self.asm("jsr savebg_%dx%d" % (byteWidth, self.height))
self.backing_store_sizes.add((byteWidth, self.height))
self.asm("ldx PARAM1") self.asm("ldx PARAM1")
cycleCount += 3 cycleCount += 3
@ -594,6 +619,7 @@ class HGRBW(HGR):
class RowLookup(Listing): class RowLookup(Listing):
def __init__(self, assembler, screen): def __init__(self, assembler, screen):
Listing.__init__(self, assembler) Listing.__init__(self, assembler)
self.slug = "hgrrows"
self.generate_y(screen) self.generate_y(screen)
def generate_y(self, screen): def generate_y(self, screen):
@ -615,6 +641,7 @@ class RowLookup(Listing):
class ColLookup(Listing): class ColLookup(Listing):
def __init__(self, assembler, screen): def __init__(self, assembler, screen):
Listing.__init__(self, assembler) Listing.__init__(self, assembler)
self.slug = "hgrcols-%dx%d" % (screen.numShifts, screen.bitsPerPixel)
self.generate_x(screen) self.generate_x(screen)
def generate_x(self, 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("-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("-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("-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!") 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() options, extra_args = parser.parse_known_args()
@ -670,6 +698,7 @@ if __name__ == "__main__":
sys.exit(1) sys.exit(1)
listings = [] listings = []
luts = {}
for pngfile in options.files: for pngfile in options.files:
try: try:
@ -680,6 +709,13 @@ if __name__ == "__main__":
except png.Error, e: except png.Error, e:
print "%s: %s" % (pngfile, e) print "%s: %s" % (pngfile, e)
sys.exit(1) 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: if options.rows:
listings.append(RowLookup(assembler, screen)) listings.append(RowLookup(assembler, screen))
@ -688,7 +724,14 @@ if __name__ == "__main__":
listings.append(ColLookup(assembler, screen)) listings.append(ColLookup(assembler, screen))
if listings: 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: for section in listings:
print section 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 atasm -ocolortest.xex colortest.s -Lcolortest.var -gcolortest.lst
atrcopy colortest.dsk boot -b colortest.xex --brun 6000 -f 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 atasm -omultitest.xex multitest.s -Lmultitest.var -gmultitest.lst
atrcopy multitest.dsk boot -b multitest.xex --brun 6000 -f 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 rowlookup.s collookupbw.s collookupcolor.s
rm -f bwtest.dsk bwtest.xex bwtest.var bwtest.lst rm -f bwtest.dsk bwtest.xex bwtest.var bwtest.lst
rm -f colortest.dsk colortest.xex colortest.var colortest.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 SIZE_3X11 = 2 + 1 + 1 + 3*11
savebg_3x11 savebg_3x11
; reserve space in the backing store stack
sec sec
lda bgstore lda bgstore
sbc #SIZE_3X11 sbc #SIZE_3X11
@ -33,8 +34,9 @@ savebg_3x11
lda bgstore+1 lda bgstore+1
sbc #0 sbc #0
sta bgstore+1 sta bgstore+1
ldy #0
; save the metadata
ldy #0
lda #<restorebg_3x11 lda #<restorebg_3x11
sta (bgstore),y sta (bgstore),y
iny iny
@ -45,12 +47,13 @@ savebg_3x11
sta (bgstore),y sta (bgstore),y
iny iny
lda PARAM1 lda PARAM1
sta bgline sta SCRATCH0
sta (bgstore),y sta (bgstore),y
iny iny
savebg_3x11_line 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 lda HGRROWS_H1,x ; Compute hires row
sta savebg_3x11_col0+2 sta savebg_3x11_col0+2
@ -80,7 +83,7 @@ savebg_3x11_col2
sta (bgstore),y sta (bgstore),y
iny iny
inc bgline inc SCRATCH0
cpy #SIZE_3X11 cpy #SIZE_3X11
bcc savebg_3x11_line bcc savebg_3x11_line
@ -131,3 +134,116 @@ restorebg_3x11_col2
cpy #SIZE_3X11 cpy #SIZE_3X11
bcc restorebg_3x11 bcc restorebg_3x11
rts 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 jsr $ffff
clc clc
lda bgstore tya ; y contains the number of bytes processed
adc #SIZE_3X11 adc bgstore
sta bgstore sta bgstore
lda bgstore+1 lda bgstore+1
adc #0 adc #0

Binary file not shown.

View File

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