Added processor and assembler syntax options
* added complete lookup table generation
This commit is contained in:
parent
d02300573d
commit
3afe35febe
176
HiSprite.py
176
HiSprite.py
|
@ -56,13 +56,47 @@ def slugify(s):
|
|||
return s
|
||||
|
||||
|
||||
class Syntax(object):
|
||||
def asm(self, text):
|
||||
return "\t%s" % text
|
||||
|
||||
def comment(self, text):
|
||||
return "\t; %s" % text
|
||||
|
||||
def label(self, text):
|
||||
return text
|
||||
|
||||
def byte(self, text):
|
||||
return self.asm(".byte %s" % text)
|
||||
|
||||
def word(self, text):
|
||||
return self.asm(".word %s" % text)
|
||||
|
||||
def address(self, text):
|
||||
return self.asm(".addr %s" % text)
|
||||
|
||||
def origin(self, text):
|
||||
return self.asm("*= %s" % text)
|
||||
|
||||
|
||||
class Mac65(Syntax):
|
||||
def address(self, text):
|
||||
return self.asm(".word %s" % text)
|
||||
|
||||
|
||||
class CC65(Syntax):
|
||||
def label(self, text):
|
||||
return "%s:" % text
|
||||
|
||||
|
||||
class Listing(object):
|
||||
disclaimer = '''
|
||||
; This file was generated by HiSprite.py, a sprite compiler by Quinn Dunki.
|
||||
; If you feel the need to modify this file, you are probably doing it wrong.
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, assembler):
|
||||
self.assembler = assembler
|
||||
self.lines = [self.disclaimer]
|
||||
|
||||
def __str__(self):
|
||||
|
@ -71,10 +105,31 @@ class Listing(object):
|
|||
def out(self, line):
|
||||
self.lines.append(line)
|
||||
|
||||
def out_append_last(self, line):
|
||||
self.lines[-1] += line
|
||||
|
||||
def label(self, text):
|
||||
self.out(self.assembler.label(text))
|
||||
|
||||
def comment(self, text):
|
||||
self.out_append_last(self.assembler.comment(text))
|
||||
|
||||
def asm(self, text):
|
||||
self.out(self.assembler.asm(text))
|
||||
|
||||
def addr(self, text):
|
||||
self.out(self.assembler.address(text))
|
||||
|
||||
def byte(self, text):
|
||||
self.out(self.assembler.byte(text))
|
||||
|
||||
def word(self, text):
|
||||
self.out(self.assembler.word(text))
|
||||
|
||||
|
||||
class Sprite(Listing):
|
||||
def __init__(self, pngfile, xdraw=False):
|
||||
Listing.__init__(self)
|
||||
def __init__(self, pngfile, assembler, xdraw=False, processor="any"):
|
||||
Listing.__init__(self, assembler)
|
||||
|
||||
reader = png.Reader(pngfile)
|
||||
try:
|
||||
|
@ -83,6 +138,7 @@ class Sprite(Listing):
|
|||
raise RuntimeError
|
||||
|
||||
self.xdraw = xdraw
|
||||
self.processor = processor
|
||||
self.niceName = slugify(os.path.splitext(pngfile)[0])
|
||||
self.width = pngdata[0]
|
||||
self.height = pngdata[1]
|
||||
|
@ -98,32 +154,46 @@ class Sprite(Listing):
|
|||
|
||||
def jumpTable(self):
|
||||
# Prologue
|
||||
self.out("%s: ;%d bytes per row" % (self.niceName, self.byteWidth))
|
||||
self.out("\tSAVE_AXY")
|
||||
self.out("\tldy PARAM0")
|
||||
self.out("\tldx MOD7_2,y")
|
||||
self.out(".ifpC02")
|
||||
self.out("\tjmp (%s_JMP,x)\n" % (self.niceName))
|
||||
self.label("%s" % self.niceName)
|
||||
self.comment("%d bytes per row" % self.byteWidth)
|
||||
self.asm("SAVE_AXY")
|
||||
self.asm("ldy PARAM0")
|
||||
self.asm("ldx MOD7_2,y")
|
||||
|
||||
if self.processor == "any":
|
||||
self.out(".ifpC02")
|
||||
self.jump65C02()
|
||||
self.out(".else")
|
||||
self.jump6502()
|
||||
self.out(".endif")
|
||||
elif self.processor == "65C02":
|
||||
self.jump65C02()
|
||||
elif self.processor == "6502":
|
||||
self.jump6502()
|
||||
else:
|
||||
raise RuntimeError("Processor %s not supported" % self.processor)
|
||||
|
||||
def jump65C02(self):
|
||||
self.asm("jmp (%s_JMP,x)\n" % (self.niceName))
|
||||
offset_suffix = ""
|
||||
|
||||
# Bit-shift jump table for 65C02
|
||||
self.out("%s_JMP:" % (self.niceName) )
|
||||
self.label("%s_JMP" % (self.niceName))
|
||||
for shift in range(self.numShifts):
|
||||
self.out("\t.addr %s_SHIFT%d" % (self.niceName, shift))
|
||||
self.addr("%s_SHIFT%d" % (self.niceName, shift))
|
||||
|
||||
self.out(".else")
|
||||
def jump6502(self):
|
||||
# Fast jump table routine; faster and smaller than self-modifying code
|
||||
self.out("\tlda %s_JMP+1,x" % (self.niceName))
|
||||
self.out("\tpha")
|
||||
self.out("\tlda %s_JMP,x" % (self.niceName))
|
||||
self.out("\tpha")
|
||||
self.out("\trts\n")
|
||||
self.asm("lda %s_JMP+1,x" % (self.niceName))
|
||||
self.asm("pha")
|
||||
self.asm("lda %s_JMP,x" % (self.niceName))
|
||||
self.asm("pha")
|
||||
self.asm("rts\n")
|
||||
|
||||
# Bit-shift jump table for generic 6502
|
||||
self.out("%s_JMP:" % (self.niceName))
|
||||
self.label("%s_JMP" % (self.niceName))
|
||||
for shift in range(self.numShifts):
|
||||
self.out("\t.addr %s_SHIFT%d-1" % (self.niceName,shift))
|
||||
self.out(".endif")
|
||||
self.addr("%s_SHIFT%d-1" % (self.niceName,shift))
|
||||
|
||||
def blitShift(self, shift):
|
||||
# Blitting functions
|
||||
|
@ -133,8 +203,8 @@ class Sprite(Listing):
|
|||
# SAVE_AXY + RESTORE_AXY + rts + sprite jump table
|
||||
cycleCount = 9 + 12 + 6 + 3 + 4 + 6
|
||||
|
||||
self.out("%s_SHIFT%d:" % (self.niceName,shift))
|
||||
self.out("\tldx PARAM1")
|
||||
self.label("%s_SHIFT%d" % (self.niceName,shift))
|
||||
self.asm("ldx PARAM1")
|
||||
cycleCount += 3
|
||||
rowStartCode,extraCycles = self.rowStartCalculatorCode();
|
||||
self.out(rowStartCode)
|
||||
|
@ -347,18 +417,45 @@ def pixelColor(pixelData,row,col):
|
|||
|
||||
|
||||
class HorizontalLookup(Listing):
|
||||
def __init__(self):
|
||||
Listing.__init__(self)
|
||||
def __init__(self, assembler):
|
||||
Listing.__init__(self, assembler)
|
||||
self.generate_hgr()
|
||||
self.generate_tables()
|
||||
|
||||
def generate_tables(self):
|
||||
self.out("DIV7_2:")
|
||||
for pixel in range(140):
|
||||
self.out("\t.byte $%02x" % ((pixel / 7)*2))
|
||||
def generate_hgr(self):
|
||||
offsets = []
|
||||
for y in range(192):
|
||||
# From Apple Graphics and Arcade Game Design
|
||||
a = y // 64
|
||||
d = y - (64 * a)
|
||||
b = d // 8
|
||||
c = d - 8 * b
|
||||
offsets.append((1024 * c) + (128 * b) + (40 * a))
|
||||
|
||||
self.out("\n\nMOD7_2:")
|
||||
self.label("HGRROWS_H1")
|
||||
for y in range(192):
|
||||
addr = 0x2000 + offsets[y]
|
||||
self.byte("$%02x" % (addr // 256))
|
||||
|
||||
self.label("HGRROWS_H2")
|
||||
for y in range(192):
|
||||
addr = 0x4000 + offsets[y]
|
||||
self.byte("$%02x" % (addr // 256))
|
||||
|
||||
self.label("HGRROWS_L")
|
||||
for y in range(192):
|
||||
addr = offsets[y]
|
||||
self.byte("$%02x" % (addr & 0xff))
|
||||
|
||||
def generate_tables(self):
|
||||
self.label("DIV7_2")
|
||||
for pixel in range(140):
|
||||
self.out("\t.byte $%02x" % ((pixel % 7)*2))
|
||||
self.byte("$%02x" % ((pixel / 7)*2))
|
||||
|
||||
self.out("\n")
|
||||
self.label("MOD7_2")
|
||||
for pixel in range(140):
|
||||
self.byte("$%02x" % ((pixel % 7)*2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -366,15 +463,26 @@ if __name__ == "__main__":
|
|||
parser.add_argument("-v", "--verbose", default=0, action="count")
|
||||
parser.add_argument("-t", "--tables", action="store_true", default=False, help="output only lookup tables for horizontal sprite shifts (division and modulus 7)")
|
||||
parser.add_argument("-x", "--xdraw", action="store_true", default=False, help="use XOR for sprite drawing")
|
||||
parser.add_argument("-s", "--syntax", default="cc65", nargs=1, choices=["cc65","mac65"], help="Assembler syntax (default: %(default)s)")
|
||||
parser.add_argument("-p", "--processor", default="any", nargs=1, choices=["any","6502", "65C02"], help="Processor type (default: %(default)s)")
|
||||
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()
|
||||
|
||||
if options.syntax[0].lower() == "cc65":
|
||||
syntax = CC65()
|
||||
elif options.syntax[0].lower() == "mac65":
|
||||
syntax = Mac65()
|
||||
else:
|
||||
print("Unknown assembler %s" % options.syntax)
|
||||
parser.print_help()
|
||||
|
||||
if options.tables:
|
||||
print HorizontalLookup()
|
||||
print HorizontalLookup(syntax)
|
||||
exit(0)
|
||||
|
||||
for pngfile in options.files:
|
||||
try:
|
||||
print Sprite(pngfile, options.xdraw)
|
||||
except RuntimeError:
|
||||
parser.usage()
|
||||
print Sprite(pngfile, syntax, options.xdraw, options.processor[0])
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
parser.print_help()
|
||||
|
|
Loading…
Reference in New Issue