generateBlitter: restructured to use self.asm and optimization to remove trailing iny when at the end of a row

This commit is contained in:
Rob McMullen 2017-06-30 12:25:49 -07:00
parent 8951869372
commit b3a4a5b5b4
2 changed files with 84 additions and 67 deletions

View File

@ -54,12 +54,13 @@ def slugify(s):
class AssemblerSyntax(object): class AssemblerSyntax(object):
extension = "s" extension = "s"
comment_char = ";"
def asm(self, text): def asm(self, text):
return "\t%s" % text return "\t%s" % text
def comment(self, text): def comment(self, text):
return "\t; %s" % text return "\t%s %s" % (self.comment_char, text)
def label(self, text): def label(self, text):
return text return text
@ -132,13 +133,25 @@ class Listing(object):
fh.write(str(self)) fh.write(str(self))
return filename return filename
def out(self, line): def out(self, line=""):
self.flush_stash() self.flush_stash()
self.lines.append(line) self.lines.append(line)
def out_append_last(self, line): def out_append_last(self, line):
self.lines[-1] += line self.lines[-1] += line
def pop_asm(self, cmd=""):
self.flush_stash()
if cmd:
search = self.assembler.asm(cmd)
i = -1
while self.lines[i].strip().startswith(self.assembler.comment_char):
i -= 1
if self.lines[i] == search:
self.lines.pop(i)
else:
self.lines.pop(-1)
def label(self, text): def label(self, text):
self.out(self.assembler.label(text)) self.out(self.assembler.label(text))
@ -303,18 +316,9 @@ class Sprite(Listing):
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.backing_store_sizes.add((byteWidth, self.height))
cycleCount += 6
self.asm("ldx PARAM1")
cycleCount += 3
rowStartCode,extraCycles = self.rowStartCalculatorCode();
self.out(rowStartCode)
cycleCount += extraCycles
spriteChunks, cycleCount, optimizationCount = self.generateBlitter(colorStreams, maskStreams, cycleCount) cycleCount, optimizationCount = self.generateBlitter(colorStreams, maskStreams, cycleCount)
for row in range(self.height):
for chunkIndex in range(len(spriteChunks)):
self.out(spriteChunks[chunkIndex][row])
if self.processor == "any": if self.processor == "any":
self.out(".ifpC02") self.out(".ifpC02")
@ -333,70 +337,83 @@ class Sprite(Listing):
def generateBlitter(self, colorStreams, maskStreams, baseCycleCount): def generateBlitter(self, colorStreams, maskStreams, baseCycleCount):
byteWidth = len(colorStreams[0]) byteWidth = len(colorStreams[0])
spriteChunks = [["" for y in range(self.height)] for x in range(byteWidth)]
cycleCount = baseCycleCount cycleCount = baseCycleCount
optimizationCount = 0 optimizationCount = 0
for row in range(self.height): for row in range(self.height):
cycleCount += self.rowStartCalculatorCode(row)
byteSplits = colorStreams[row] byteSplits = colorStreams[row]
maskSplits = maskStreams[row] maskSplits = maskStreams[row]
byteCount = len(byteSplits)
# Generate blitting code
for chunkIndex in range(len(byteSplits)):
# Optimization
if maskSplits[chunkIndex] == "01111111" and not self.backing_store:
optimizationCount += 1
else:
value = self.binary_constant(byteSplits[chunkIndex])
# Store byte into video memory # number of trailing iny to remove due to unchanged bytes at the
if self.xdraw: # end of the row
spriteChunks[chunkIndex][row] = \ skip_iny = 0
"\tlda (SCRATCH0),y\n" + \
"\teor %s\n" % value + \ # Generate blitting code
"\tsta (SCRATCH0),y\n"; for index, (value, mask) in enumerate(zip(byteSplits, maskSplits)):
cycleCount += 5 + 2 + 6 if index > 0:
elif self.use_mask: self.asm("iny")
mask = self.binary_constant(maskSplits[chunkIndex])
spriteChunks[chunkIndex][row] = \
"\tlda (SCRATCH0),y\n" + \
"\tand %s\n" % mask + \
"\tora %s\n" % value + \
"\tsta (SCRATCH0),y\n";
cycleCount += 5 + 2 + 6
else:
spriteChunks[chunkIndex][row] = \
"\tlda %s\n" % value + \
"\tsta (SCRATCH0),y\n";
cycleCount += 2 + 6
# Increment indices
if chunkIndex == len(byteSplits)-1:
spriteChunks[chunkIndex][row] += "\n"
else:
spriteChunks[chunkIndex][row] += "\tiny"
cycleCount += 2 cycleCount += 2
# Finish the row # Optimization
if row<self.height-1: if mask == "01111111":
rowStartCode, extraCycles = self.rowStartCalculatorCode() optimizationCount += 1
spriteChunks[chunkIndex][row] += "\tinx\n" + rowStartCode; self.comment_line("byte %d: skipping! unchanged byte (mask = %s)" % (index, mask))
cycleCount += 2 + extraCycles skip_iny += 1
else:
return spriteChunks, cycleCount, optimizationCount value = self.binary_constant(value)
skip_iny = 0
# Store byte into video memory
if self.xdraw:
self.asm("lda (SCRATCH0),y")
self.asm("eor %s" % value)
self.asm("sta (SCRATCH0),y");
cycleCount += 5 + 2 + 6
elif self.use_mask:
if mask == "00000000":
# replacing all the bytes; no need for and/or!
self.asm("lda %s" % value)
self.asm("sta (SCRATCH0),y");
cycleCount += 2 + 5
else:
mask = self.binary_constant(mask)
self.asm("lda (SCRATCH0),y")
self.asm("and %s" % mask)
self.asm("ora %s" % value)
self.asm("sta (SCRATCH0),y");
cycleCount += 5 + 2 + 2 + 6
else:
self.asm("lda %s" % value)
self.asm("sta (SCRATCH0),y");
cycleCount += 2 + 6
def rowStartCalculatorCode(self): while skip_iny > 0:
return \ self.pop_asm("iny")
"\tlda HGRROWS_H1,x\n" + \ skip_iny -= 1
"\tsta SCRATCH1\n" + \ cycleCount -= 2
"\tlda HGRROWS_L,x\n" + \
"\tsta SCRATCH0\n" + \ return cycleCount, optimizationCount
"\tldy PARAM0\n" + \
"\tlda DIV%d_%d,y\n" % (self.screen.numShifts, self.screen.bitsPerPixel) + \ def rowStartCalculatorCode(self, row):
"\ttay\n", 4 + 3 + 4 + 3 + 3 + 4 + 2; self.out()
self.comment_line("row %d" % row)
if row == 0:
self.asm("ldx PARAM1")
cycles = 3
else:
self.asm("inx")
cycles = 2
self.asm("lda HGRROWS_H1,x")
self.asm("sta SCRATCH1")
self.asm("lda HGRROWS_L,x")
self.asm("sta SCRATCH0")
self.asm("ldy PARAM0")
self.asm("lda DIV%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel))
self.asm("tay")
return cycles + 4 + 3 + 4 + 3 + 3 + 4 + 2;
def shiftStringRight(string, shift, bitsPerPixel, fillerBit): def shiftStringRight(string, shift, bitsPerPixel, fillerBit):
@ -698,7 +715,7 @@ if __name__ == "__main__":
sys.exit(1) sys.exit(1)
listings = [] listings = []
luts = {} luts = {} # dict of lookup tables to prevent duplication in output files
for pngfile in options.files: for pngfile in options.files:
try: try:

Binary file not shown.