Since I now have an approved fork rather than contributing back to Quinn, changing to more PEP-8 python style

* changed some assembly variables and categorized them by address to hopefully make debugging easier
This commit is contained in:
Rob McMullen 2017-07-05 12:50:22 -07:00
parent e04491e324
commit 527cd2226c
3 changed files with 264 additions and 247 deletions

View File

@ -225,15 +225,15 @@ class Sprite(Listing):
self.slug = 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.pixel_data = list(pngdata[2])
self.jumpTable() self.jump_table()
for i in range(self.screen.numShifts): for i in range(self.screen.num_shifts):
self.blitShift(i) self.blit_shift(i)
def jumpTable(self): def jump_table(self):
# Prologue # Prologue
self.label("%s" % self.slug) self.label("%s" % self.slug)
self.comment("%d bytes per row" % self.screen.byteWidth(self.width)) self.comment("%d bytes per row" % self.screen.byte_width(self.width))
if self.processor == "any": if self.processor == "any":
self.out(".ifpC02") self.out(".ifpC02")
@ -275,22 +275,22 @@ class Sprite(Listing):
def jump65C02(self): def jump65C02(self):
if not self.clobber: if not self.clobber:
self.save_axy_65C02() self.save_axy_65C02()
self.asm("ldy PARAM0") self.asm("ldy param_x")
self.asm("ldx MOD%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel)) self.asm("ldx MOD%d_%d,y" % (self.screen.num_shifts, self.screen.bits_per_pixel))
self.asm("jmp (%s_JMP,x)\n" % (self.slug)) 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.slug)) self.label("%s_JMP" % (self.slug))
for shift in range(self.screen.numShifts): for shift in range(self.screen.num_shifts):
self.addr("%s_SHIFT%d" % (self.slug, shift)) self.addr("%s_SHIFT%d" % (self.slug, shift))
def jump6502(self): def jump6502(self):
if not self.clobber: if not self.clobber:
self.save_axy_6502() self.save_axy_6502()
self.asm("ldy PARAM0") self.asm("ldy param_x")
self.asm("ldx MOD%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel)) self.asm("ldx MOD%d_%d,y" % (self.screen.num_shifts, self.screen.bits_per_pixel))
# 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.slug)) self.asm("lda %s_JMP+1,x" % (self.slug))
@ -301,33 +301,33 @@ class Sprite(Listing):
# Bit-shift jump table for generic 6502 # Bit-shift jump table for generic 6502
self.label("%s_JMP" % (self.slug)) self.label("%s_JMP" % (self.slug))
for shift in range(self.screen.numShifts): for shift in range(self.screen.num_shifts):
self.addr("%s_SHIFT%d-1" % (self.slug,shift)) self.addr("%s_SHIFT%d-1" % (self.slug,shift))
def blitShift(self, shift): def blit_shift(self, shift):
# Blitting functions # Blitting functions
self.out("\n") self.out("\n")
# Track cycle count of the blitter. We start with fixed overhead: # Track cycle count of the blitter. We start with fixed overhead:
# SAVE_AXY + RESTORE_AXY + rts + sprite jump table # SAVE_AXY + RESTORE_AXY + rts + sprite jump table
cycleCount = 9 + 12 + 6 + 3 + 4 + 6 cycle_count = 9 + 12 + 6 + 3 + 4 + 6
baselabel = "%s_SHIFT%d" % (self.slug,shift) baselabel = "%s_SHIFT%d" % (self.slug,shift)
self.label(baselabel) self.label(baselabel)
colorStreams = self.screen.byteStreamsFromPixels(shift, self) color_streams = self.screen.byte_streams_from_pixels(shift, self)
maskStreams = self.screen.byteStreamsFromPixels(shift, self, True) mask_streams = self.screen.byte_streams_from_pixels(shift, self, True)
for c, m in zip(colorStreams, maskStreams): for c, m in zip(color_streams, mask_streams):
self.comment_line(str(c) + " " + str(m)) self.comment_line(str(c) + " " + str(m))
self.out("") self.out("")
if self.backing_store: if self.backing_store:
byteWidth = len(colorStreams[0]) byte_width = len(color_streams[0])
self.asm("jsr savebg_%dx%d" % (byteWidth, self.height)) self.asm("jsr savebg_%dx%d" % (byte_width, self.height))
self.backing_store_sizes.add((byteWidth, self.height)) self.backing_store_sizes.add((byte_width, self.height))
cycleCount += 6 cycle_count += 6
cycleCount, optimizationCount = self.generateBlitter(colorStreams, maskStreams, cycleCount, baselabel) cycle_count, optimization_count = self.generate_blitter(color_streams, mask_streams, cycle_count, baselabel)
if not self.clobber: if not self.clobber:
if self.processor == "any": if self.processor == "any":
@ -343,46 +343,46 @@ class Sprite(Listing):
else: else:
raise RuntimeError("Processor %s not supported" % self.processor) raise RuntimeError("Processor %s not supported" % self.processor)
if self.damage: if self.damage:
# the caller knows PARAM0 and PARAM1 for location, so no need to # the caller knows param_x and param_y for location, so no need
# report those again. But the size varies by sprite (and perhaps by # to report those again. But the size varies by sprite (and perhaps
# shift amount?) so store it here # by shift amount?) so store it here
byteWidth = len(colorStreams[0]) byte_width = len(color_streams[0])
self.asm("lda #%d" % byteWidth) self.asm("lda #%d" % byte_width)
self.asm("sta DAMAGE_W") self.asm("sta DAMAGE_W")
self.asm("lda #%d" % self.height) self.asm("lda #%d" % self.height)
self.asm("sta DAMAGE_H") self.asm("sta DAMAGE_H")
self.out() self.out()
self.asm("rts") self.asm("rts")
self.comment("Cycle count: %d, Optimized %d rows." % (cycleCount,optimizationCount)) self.comment("Cycle count: %d, Optimized %d rows." % (cycle_count,optimization_count))
def generateBlitter(self, colorStreams, maskStreams, baseCycleCount, baselabel): def generate_blitter(self, color_streams, mask_streams, base_cycle_count, baselabel):
byteWidth = len(colorStreams[0]) byte_width = len(color_streams[0])
cycleCount = baseCycleCount cycle_count = base_cycle_count
optimizationCount = 0 optimization_count = 0
order = list(range(self.height)) order = list(range(self.height))
for row in order: for row in order:
cycleCount += self.rowStartCalculatorCode(row, baselabel) cycle_count += self.row_start_calculator_code(row, baselabel)
byteSplits = colorStreams[row] byte_splits = color_streams[row]
maskSplits = maskStreams[row] mask_splits = mask_streams[row]
byteCount = len(byteSplits) byte_count = len(byte_splits)
# number of trailing iny to remove due to unchanged bytes at the # number of trailing iny to remove due to unchanged bytes at the
# end of the row # end of the row
skip_iny = 0 skip_iny = 0
# Generate blitting code # Generate blitting code
for index, (value, mask) in enumerate(zip(byteSplits, maskSplits)): for index, (value, mask) in enumerate(zip(byte_splits, mask_splits)):
if index > 0: if index > 0:
self.asm("iny") self.asm("iny")
cycleCount += 2 cycle_count += 2
# Optimization # Optimization
if mask == "01111111": if mask == "01111111":
optimizationCount += 1 optimization_count += 1
self.comment_line("byte %d: skipping! unchanged byte (mask = %s)" % (index, mask)) self.comment_line("byte %d: skipping! unchanged byte (mask = %s)" % (index, mask))
skip_iny += 1 skip_iny += 1
else: else:
@ -390,40 +390,40 @@ class Sprite(Listing):
skip_iny = 0 skip_iny = 0
# Store byte into video memory # Store byte into video memory
if self.xdraw: if self.xdraw:
self.asm("lda (SCRATCH0),y") self.asm("lda (scratch_addr),y")
self.asm("eor %s" % value) self.asm("eor %s" % value)
self.asm("sta (SCRATCH0),y"); self.asm("sta (scratch_addr),y");
cycleCount += 5 + 2 + 6 cycle_count += 5 + 2 + 6
elif self.use_mask: elif self.use_mask:
if mask == "00000000": if mask == "00000000":
# replacing all the bytes; no need for and/or! # replacing all the bytes; no need for and/or!
self.asm("lda %s" % value) self.asm("lda %s" % value)
self.asm("sta (SCRATCH0),y"); self.asm("sta (scratch_addr),y");
cycleCount += 2 + 5 cycle_count += 2 + 5
else: else:
mask = self.binary_constant(mask) mask = self.binary_constant(mask)
self.asm("lda (SCRATCH0),y") self.asm("lda (scratch_addr),y")
self.asm("and %s" % mask) self.asm("and %s" % mask)
self.asm("ora %s" % value) self.asm("ora %s" % value)
self.asm("sta (SCRATCH0),y"); self.asm("sta (scratch_addr),y");
cycleCount += 5 + 2 + 2 + 6 cycle_count += 5 + 2 + 2 + 6
else: else:
self.asm("lda %s" % value) self.asm("lda %s" % value)
self.asm("sta (SCRATCH0),y"); self.asm("sta (scratch_addr),y");
cycleCount += 2 + 6 cycle_count += 2 + 6
while skip_iny > 0: while skip_iny > 0:
self.pop_asm("iny") self.pop_asm("iny")
skip_iny -= 1 skip_iny -= 1
cycleCount -= 2 cycle_count -= 2
return cycleCount, optimizationCount return cycle_count, optimization_count
def rowStartCalculatorCode(self, row, baselabel): def row_start_calculator_code(self, row, baselabel):
self.out() self.out()
self.comment_line("row %d" % row) self.comment_line("row %d" % row)
if row == 0: if row == 0:
self.asm("ldx PARAM1") self.asm("ldx param_y")
cycles = 3 cycles = 3
else: else:
cycles = 0 cycles = 0
@ -435,31 +435,31 @@ class Sprite(Listing):
# and 6th bit # and 6th bit
self.asm("eor HGRSELECT") self.asm("eor HGRSELECT")
cycles += 3 cycles += 3
self.asm("sta SCRATCH1") self.asm("sta scratch_addr+1")
self.asm("lda HGRROWS_L+%d,x" % row) self.asm("lda HGRROWS_L+%d,x" % row)
self.asm("sta SCRATCH0") self.asm("sta scratch_addr")
cycles += 3 + 4 + 3 cycles += 3 + 4 + 3
if row == 0: if row == 0:
self.asm("ldy PARAM0") self.asm("ldy param_x")
self.asm("lda DIV%d_%d,y" % (self.screen.numShifts, self.screen.bitsPerPixel)) self.asm("lda DIV%d_%d,y" % (self.screen.num_shifts, self.screen.bits_per_pixel))
self.asm("sta PARAM2") # save the mod lookup; it doesn't change self.asm("sta scratch_col") # save the mod lookup; it doesn't change
self.asm("tay") self.asm("tay")
cycles += 3 + 4 + 3 + 2 cycles += 3 + 4 + 3 + 2
else: else:
self.asm("ldy PARAM2") self.asm("ldy scratch_col")
cycles += 2 cycles += 2
return cycles; return cycles;
def shiftStringRight(string, shift, bitsPerPixel, fillerBit): def shift_string_right(string, shift, bits_per_pixel, filler_bit):
if shift==0: if shift==0:
return string return string
shift *= bitsPerPixel shift *= bits_per_pixel
result = "" result = ""
for i in range(shift): for i in range(shift):
result += fillerBit result += filler_bit
result += string result += string
return result return result
@ -467,49 +467,49 @@ def shiftStringRight(string, shift, bitsPerPixel, fillerBit):
class ScreenFormat(object): class ScreenFormat(object):
numShifts = 8 num_shifts = 8
bitsPerPixel = 1 bits_per_pixel = 1
screenWidth = 320 screen_width = 320
screenHeight = 192 screen_height = 192
def __init__(self): def __init__(self):
self.offsets = self.generate_row_offsets() self.offsets = self.generate_row_offsets()
self.numX = self.screenWidth / self.bitsPerPixel self.numX = self.screen_width / self.bits_per_pixel
def byteWidth(self, png_width): def byte_width(self, png_width):
return (png_width * self.bitsPerPixel + self.numShifts - 1) // self.numShifts + 1 return (png_width * self.bits_per_pixel + self.num_shifts - 1) // self.num_shifts + 1
def bitsForColor(self, pixel): def bits_for_color(self, pixel):
raise NotImplementedError raise NotImplementedError
def bitsForMask(self, pixel): def bits_for_mask(self, pixel):
raise NotImplementedError raise NotImplementedError
def pixelColor(self, pixelData, row, col): def pixel_color(self, pixel_data, row, col):
raise NotImplementedError raise NotImplementedError
def generate_row_offsets(self): def generate_row_offsets(self):
offsets = [40 * y for y in range(self.screenHeight)] offsets = [40 * y for y in range(self.screen_height)]
return offsets return offsets
def generate_row_addresses(self, baseAddr): def generate_row_addresses(self, base_addr):
addrs = [baseAddr + offset for offset in self.offsets] addrs = [base_addr + offset for offset in self.offsets]
return addrs return addrs
class HGR(ScreenFormat): class HGR(ScreenFormat):
numShifts = 7 num_shifts = 7
bitsPerPixel = 2 bits_per_pixel = 2
screenWidth = 280 screen_width = 280
black,magenta,green,orange,blue,white,key = range(7) black,magenta,green,orange,blue,white,key = range(7)
def bitsForColor(self, pixel): def bits_for_color(self, pixel):
if pixel == self.black or pixel == self.key: if pixel == self.black or pixel == self.key:
return "00" return "00"
else: else:
@ -522,27 +522,27 @@ class HGR(ScreenFormat):
# blue or magenta # blue or magenta
return "10" return "10"
def bitsForMask(self, pixel): def bits_for_mask(self, pixel):
if pixel == self.key: if pixel == self.key:
return "11" return "11"
return "00" return "00"
def highBitForColor(self, pixel): def high_bit_for_color(self, pixel):
# Note that we prefer high-bit white because blue fringe is less noticeable than magenta. # Note that we prefer high-bit white because blue fringe is less noticeable than magenta.
highBit = "0" high_bit = "0"
if pixel == self.orange or pixel == self.blue or pixel == self.white: if pixel == self.orange or pixel == self.blue or pixel == self.white:
highBit = "1" high_bit = "1"
return highBit return high_bit
def highBitForMask(self, pixel): def high_bit_for_mask(self, pixel):
return "0" return "0"
def pixelColor(self, pixelData, row, col): def pixel_color(self, pixel_data, row, col):
r = pixelData[row][col*3] r = pixel_data[row][col*3]
g = pixelData[row][col*3+1] g = pixel_data[row][col*3+1]
b = pixelData[row][col*3+2] b = pixel_data[row][col*3+2]
rhi = r == 255 rhi = r == 255
rlo = r == 0 rlo = r == 0
@ -568,68 +568,68 @@ class HGR(ScreenFormat):
color = self.key color = self.key
return color return color
def byteStreamsFromPixels(self, shift, source, mask=False): def byte_streams_from_pixels(self, shift, source, mask=False):
byteStreams = ["" for x in range(source.height)] byte_streams = ["" for x in range(source.height)]
byteWidth = self.byteWidth(source.width) byte_width = self.byte_width(source.width)
if mask: if mask:
bitDelegate = self.bitsForMask bit_delegate = self.bits_for_mask
highBitDelegate = self.highBitForMask high_bit_delegate = self.high_bit_for_mask
fillerBit = "1" filler_bit = "1"
else: else:
bitDelegate = self.bitsForColor bit_delegate = self.bits_for_color
highBitDelegate = self.highBitForColor high_bit_delegate = self.high_bit_for_color
fillerBit = "0" filler_bit = "0"
for row in range(source.height): for row in range(source.height):
bitStream = "" bit_stream = ""
highBit = "0" high_bit = "0"
highBitFound = False high_bit_found = False
# Compute raw bitstream for row from PNG pixels # Compute raw bitstream for row from PNG pixels
for pixelIndex in range(source.width): for pixel_index in range(source.width):
pixel = self.pixelColor(source.pixelData,row,pixelIndex) pixel = self.pixel_color(source.pixel_data,row,pixel_index)
bitStream += bitDelegate(pixel) bit_stream += bit_delegate(pixel)
# Determine palette bit from first non-black pixel on each row # Determine palette bit from first non-black pixel on each row
if not highBitFound and pixel != self.black and pixel != self.key: if not high_bit_found and pixel != self.black and pixel != self.key:
highBit = highBitDelegate(pixel) high_bit = high_bit_delegate(pixel)
highBitFound = True high_bit_found = True
# Shift bit stream as needed # Shift bit stream as needed
bitStream = shiftStringRight(bitStream, shift, self.bitsPerPixel, fillerBit) bit_stream = shift_string_right(bit_stream, shift, self.bits_per_pixel, filler_bit)
bitStream = bitStream[:byteWidth*8] bit_stream = bit_stream[:byte_width*8]
# Split bitstream into bytes # Split bitstream into bytes
bitPos = 0 bit_pos = 0
byteSplits = [0 for x in range(byteWidth)] byte_splits = [0 for x in range(byte_width)]
for byteIndex in range(byteWidth): for byte_index in range(byte_width):
remainingBits = len(bitStream) - bitPos remaining_bits = len(bit_stream) - bit_pos
bitChunk = "" bit_chunk = ""
if remainingBits < 0: if remaining_bits < 0:
bitChunk = fillerBit * 7 bit_chunk = filler_bit * 7
else: else:
if remainingBits < 7: if remaining_bits < 7:
bitChunk = bitStream[bitPos:] bit_chunk = bit_stream[bit_pos:]
bitChunk += fillerBit * (7-remainingBits) bit_chunk += filler_bit * (7-remaining_bits)
else: else:
bitChunk = bitStream[bitPos:bitPos+7] bit_chunk = bit_stream[bit_pos:bit_pos+7]
bitChunk = bitChunk[::-1] bit_chunk = bit_chunk[::-1]
byteSplits[byteIndex] = highBit + bitChunk byte_splits[byte_index] = high_bit + bit_chunk
bitPos += 7 bit_pos += 7
byteStreams[row] = byteSplits; byte_streams[row] = byte_splits;
return byteStreams return byte_streams
def generate_row_offsets(self): def generate_row_offsets(self):
offsets = [] offsets = []
for y in range(self.screenHeight): for y in range(self.screen_height):
# From Apple Graphics and Arcade Game Design # From Apple Graphics and Arcade Game Design
a = y // 64 a = y // 64
d = y - (64 * a) d = y - (64 * a)
@ -640,23 +640,23 @@ class HGR(ScreenFormat):
class HGRBW(HGR): class HGRBW(HGR):
bitsPerPixel = 1 bits_per_pixel = 1
def bitsForColor(self, pixel): def bits_for_color(self, pixel):
if pixel == self.white: if pixel == self.white:
return "1" return "1"
else: else:
return "0" return "0"
def bitsForMask(self, pixel): def bits_for_mask(self, pixel):
if pixel == self.key: if pixel == self.key:
return "1" return "1"
return "0" return "0"
def pixelColor(self, pixelData, row, col): def pixel_color(self, pixel_data, row, col):
r = pixelData[row][col*3] r = pixel_data[row][col*3]
g = pixelData[row][col*3+1] g = pixel_data[row][col*3+1]
b = pixelData[row][col*3+2] b = pixel_data[row][col*3+2]
color = self.black color = self.black
if abs(r - g) < 16 and abs(g - b) < 16 and r!=0 and r!=255: # Any grayish color is chroma key if abs(r - g) < 16 and abs(g - b) < 16 and r!=0 and r!=255: # Any grayish color is chroma key
@ -693,21 +693,21 @@ 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.slug = "hgrcols-%dx%d" % (screen.num_shifts, screen.bits_per_pixel)
self.generate_x(screen) self.generate_x(screen)
def generate_x(self, screen): def generate_x(self, screen):
self.out("\n") self.out("\n")
self.label("DIV%d_%d" % (screen.numShifts, screen.bitsPerPixel)) self.label("DIV%d_%d" % (screen.num_shifts, screen.bits_per_pixel))
for pixel in range(screen.numX): for pixel in range(screen.numX):
self.byte("$%02x" % ((pixel / screen.numShifts) * screen.bitsPerPixel), screen.numShifts) self.byte("$%02x" % ((pixel / screen.num_shifts) * screen.bits_per_pixel), screen.num_shifts)
self.out("\n") self.out("\n")
self.label("MOD%d_%d" % (screen.numShifts, screen.bitsPerPixel)) self.label("MOD%d_%d" % (screen.num_shifts, screen.bits_per_pixel))
for pixel in range(screen.numX): for pixel in range(screen.numX):
# This is the index into the jump table, so it's always multiplied # This is the index into the jump table, so it's always multiplied
# by 2 # by 2
self.byte("$%02x" % ((pixel % screen.numShifts) * 2), screen.numShifts) self.byte("$%02x" % ((pixel % screen.num_shifts) * 2), screen.num_shifts)
class BackingStore(Listing): class BackingStore(Listing):
@ -752,22 +752,22 @@ class BackingStore(Listing):
self.asm("lda #>%s" % self.restore_label) self.asm("lda #>%s" % self.restore_label)
self.asm("sta (bgstore),y") self.asm("sta (bgstore),y")
self.asm("iny") self.asm("iny")
self.asm("lda PARAM0") self.asm("lda param_x")
self.asm("sta (bgstore),y") self.asm("sta (bgstore),y")
self.asm("iny") self.asm("iny")
self.asm("lda PARAM1") self.asm("lda param_y")
# Note that we can't clobber PARAM1 like the restore routine can # Note that we can't clobber param_y like the restore routine can
# because this is called in the sprite drawing routine and these # because this is called in the sprite drawing routine and these
# values must be retained to draw the sprite in the right place! # values must be retained to draw the sprite in the right place!
self.asm("sta SCRATCH0") self.asm("sta scratch_addr")
self.asm("sta (bgstore),y") self.asm("sta (bgstore),y")
self.asm("iny") self.asm("iny")
# The unrolled code is taken from Quinn's row sweep backing store # The unrolled code is taken from Quinn's row sweep backing store
# code in a previous version of HiSprite # code in a previous version of HiSprite
loop_label, col_label = self.smc_row_col(self.save_label, "SCRATCH0") loop_label, col_label = self.smc_row_col(self.save_label, "scratch_addr")
for c in range(self.byte_width): for c in range(self.byte_width):
self.label(col_label % c) self.label(col_label % c)
@ -778,7 +778,7 @@ class BackingStore(Listing):
# last loop doesn't need this # last loop doesn't need this
self.asm("inx") self.asm("inx")
self.asm("inc SCRATCH0") self.asm("inc scratch_addr")
self.asm("cpy #%d" % self.space_needed) self.asm("cpy #%d" % self.space_needed)
self.asm("bcc %s" % loop_label) self.asm("bcc %s" % loop_label)
@ -788,7 +788,7 @@ class BackingStore(Listing):
def smc_row_col(self, label, row_var): def smc_row_col(self, label, row_var):
# set up smc for hires column, because the starting column doesn't # set up smc for hires column, because the starting column doesn't
# change when moving to the next row # change when moving to the next row
self.asm("ldx PARAM0") self.asm("ldx param_x")
self.asm("lda DIV7_1,x") self.asm("lda DIV7_1,x")
smc_label = "%s_smc1" % label smc_label = "%s_smc1" % label
self.asm("sta %s+1" % smc_label) self.asm("sta %s+1" % smc_label)
@ -815,16 +815,16 @@ class BackingStore(Listing):
# screen, which is 4 bytes into the bgstore array. Everything before # 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 # 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, # 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. # and param_x and param_y will be filled with the x & y values.
# #
# also, no need to save registers because this is being called from a # also, no need to save registers because this is being called from a
# driver that will do all of that. # driver that will do all of that.
self.label(self.restore_label) self.label(self.restore_label)
# we can clobber the heck out of PARAM1 because we're being called from # we can clobber the heck out of param_y because we're being called from
# the restore driver and when we return we are just going to load it up # the restore driver and when we return we are just going to load it up
# with the next value anyway. # with the next value anyway.
loop_label, col_label = self.smc_row_col(self.restore_label, "PARAM1") loop_label, col_label = self.smc_row_col(self.restore_label, "param_y")
for c in range(self.byte_width): for c in range(self.byte_width):
self.asm("lda (bgstore),y") self.asm("lda (bgstore),y")
@ -835,7 +835,7 @@ class BackingStore(Listing):
# last loop doesn't need this # last loop doesn't need this
self.asm("inx") self.asm("inx")
self.asm("inc PARAM1") self.asm("inc param_y")
self.asm("cpy #%d" % self.space_needed) self.asm("cpy #%d" % self.space_needed)
self.asm("bcc %s" % loop_label) self.asm("bcc %s" % loop_label)
@ -850,8 +850,8 @@ class BackingStoreDriver(Listing):
# variables used: # variables used:
# bgstore: (lo byte, hi byte) 1 + the first byte of free memory. # bgstore: (lo byte, hi byte) 1 + the first byte of free memory.
# I.e. points just beyond the last byte # I.e. points just beyond the last byte
# PARAM0: (byte) x coord # param_x: (byte) x coord
# PARAM1: (byte) y coord # param_y: (byte) y coord
# #
# everything else is known because the sizes of each erase/restore # everything else is known because the sizes of each erase/restore
# routine are hardcoded because this is a sprite *compiler*. # routine are hardcoded because this is a sprite *compiler*.
@ -900,10 +900,10 @@ class BackingStoreDriver(Listing):
self.asm("sta restorebg_jsr_smc+2") self.asm("sta restorebg_jsr_smc+2")
self.asm("iny") self.asm("iny")
self.asm("lda (bgstore),y") self.asm("lda (bgstore),y")
self.asm("sta PARAM0") self.asm("sta param_x")
self.asm("iny ") self.asm("iny ")
self.asm("lda (bgstore),y") self.asm("lda (bgstore),y")
self.asm("sta PARAM1") self.asm("sta param_y")
self.asm("iny") self.asm("iny")
self.label("restorebg_jsr_smc") self.label("restorebg_jsr_smc")
self.asm("jsr $ffff") self.asm("jsr $ffff")
@ -942,7 +942,7 @@ class FastFont(Listing):
self.asm("sta %s_JMP+2" % label) self.asm("sta %s_JMP+2" % label)
self.asm("lda %s_JMP_LO,y" % label) self.asm("lda %s_JMP_LO,y" % label)
self.asm("sta %s_JMP+1" % label) self.asm("sta %s_JMP+1" % label)
self.asm("sty FASTFONT_SCRATCH0") self.asm("sty scratch_0")
self.asm("pla") self.asm("pla")
self.asm("tay") self.asm("tay")
self.label("%s_JMP" % label) self.label("%s_JMP" % label)
@ -962,9 +962,9 @@ class FastFont(Listing):
for r in range(24): for r in range(24):
self.label("%s_%d" % (label, r)) self.label("%s_%d" % (label, r))
for i in range(8): for i in range(8):
self.asm("lda TRANSPOSED_FONT_ROW%d,y" % i) self.asm("lda TransposedFontRow%d,y" % i)
self.asm("sta $%04x,x" % (hgr1[r*8 + i])) self.asm("sta $%04x,x" % (hgr1[r*8 + i]))
self.asm("ldy FASTFONT_SCRATCH0") self.asm("ldy scratch_0")
self.asm("rts") self.asm("rts")
self.out() self.out()
@ -974,7 +974,7 @@ class FastFont(Listing):
num_bytes = len(data) num_bytes = len(data)
num_chars = num_bytes / 8 num_chars = num_bytes / 8
for r in range(8): for r in range(8):
self.label("TRANSPOSED_FONT_ROW%d" % r) self.label("TransposedFontRow%d" % r)
for i in range(num_chars): for i in range(num_chars):
index = i * 8 + r index = i * 8 + r
self.byte("$%02x" % ord(data[index]), 16) self.byte("$%02x" % ord(data[index]), 16)

193
cpbg.s
View File

@ -12,35 +12,52 @@ SETHIRES = $c057
COUT = $fded COUT = $fded
ROMWAIT = $fca8 ROMWAIT = $fca8
; Zero page locations we use (unused by Monitor, Applesoft, or ProDOS) ; Zero page locations. Using the whole thing because we aren't using any
PARAM0 = $06 ; ROM routines
PARAM1 = $07
PARAM2 = $08 *= $0006
PARAM3 = $09 ; parameters: these should not be changed by child subroutines
SCRATCH0 = $19 param_x .ds 1
SCRATCH1 = $1a param_y .ds 1
SPRITEPTR_L = $1b param_col .ds 1
SPRITEPTR_H = $1c param_row .ds 1
RENDERCOUNT = $ce param_index .ds 1
DRAWPAGE = $d7 ; pos = page1, neg = page2 param_count .ds 1
BGSTORE = $fa
TEMPADDR = $fc *= $0010
COUNTER1 = $80 ; scratch areas: these may be modified by child subroutines
HGRHI = $82 ; either $20 or $40, the base of each hgr screen scratch_addr .ds 2
HGRSELECT = $83 ; either $00 or $60, used as xor mask to turn HGRROWS_H1 into address of either page scratch_ptr .ds 2
TEXTPTR = $84 scratch_0 .ds 1
HGRPTR = $86 scratch_1 .ds 1
TEMPROW = $88 scratch_index .ds 1
TEMPCOL = $89 scratch_col .ds 1
DAMAGE_W = $8a
DAMAGE_H = $8b *= $0020
DAMAGEPTR = $8c ; required variables for HiSprite
DAMAGEPTR1 = $8e bgstore .ds 2
DAMAGEINDEX1 = $91 damage_w .ds 1
DAMAGEPTR2 = $92 damage_h .ds 1
DAMAGEINDEX2 = $94 damageptr .ds 2
DAMAGEINDEX = $95 damageindex .ds 1
FASTFONT_SCRATCH0 = $96 damageptr1 .ds 2
damageindex1 .ds 1
damageptr2 .ds 2
damageindex2 .ds 1
hgrhi .ds 1 ; either $20 or $40, the base of each hgr screen
hgrselect .ds 1 ; either $00 or $60, used as xor mask for HGRROWS_H1
*= $0030
; global variables for this program
rendercount .ds 1
drawpage .ds 1 ; pos = page1, neg = page2
tempaddr .ds 2
counter1 .ds 1
textptr .ds 2
hgrptr .ds 2
temprow .ds 1
tempcol .ds 1
DAMAGEPAGE1 = $bf ; page number of first byte beyond top of backing store stack DAMAGEPAGE1 = $bf ; page number of first byte beyond top of backing store stack
DAMAGEPAGE2 = $be DAMAGEPAGE2 = $be
@ -80,16 +97,16 @@ fasttoggle
initonce initonce
lda #0 lda #0
sta DRAWPAGE sta drawpage
sta DAMAGEINDEX1 sta damageindex1
sta DAMAGEINDEX2 sta damageindex2
sta DAMAGEPTR sta damageptr
sta DAMAGEPTR1 sta damageptr1
sta DAMAGEPTR2 sta damageptr2
lda #DAMAGEPAGE1 lda #damagepage1
sta DAMAGEPTR+1 sta damageptr+1
sta DAMAGEPTR1+1 sta damageptr1+1
sta DAMAGEPTR2+1 sta damageptr2+1
rts rts
@ -200,38 +217,38 @@ copytexthgrslow
pageflip pageflip
lda DRAWPAGE lda drawpage
eor #$80 eor #$80
sta DRAWPAGE sta drawpage
bpl pageflip1 ; pos = show 1, draw 2; neg = show 1, draw 1 bpl pageflip1 ; pos = show 1, draw 2; neg = show 1, draw 1
bit TXTPAGE2 ; show page 2, work on page 1 bit TXTPAGE2 ; show page 2, work on page 1
lda #$00 lda #$00
sta HGRSELECT sta hgrselect
lda #$20 lda #$20
sta HGRHI sta hgrhi
lda DAMAGEPTR ; save other page's damage pointer lda damageptr ; save other page's damage pointer
sta DAMAGEPTR2 sta damageptr2
lda DAMAGEPTR1 lda damageptr1
sta DAMAGEPTR sta damageptr
lda DAMAGEPTR1+1 lda damageptr1+1
sta DAMAGEPTR+1 sta damageptr+1
lda DAMAGEINDEX1 lda damageindex1
sta DAMAGEINDEX sta damageindex
rts rts
pageflip1 pageflip1
bit TXTPAGE1 ; show page 1, work on page 2 bit TXTPAGE1 ; show page 1, work on page 2
lda #$60 lda #$60
sta HGRSELECT sta hgrselect
lda #$40 lda #$40
sta HGRHI sta hgrhi
lda DAMAGEPTR ; save other page's damage pointer lda damageptr ; save other page's damage pointer
sta DAMAGEPTR1 sta damageptr1
lda DAMAGEPTR2 lda damageptr2
sta DAMAGEPTR sta damageptr
lda DAMAGEPTR2+1 lda damageptr2+1
sta DAMAGEPTR+1 sta damageptr+1
lda DAMAGEINDEX2 lda damageindex2
sta DAMAGEINDEX sta damageindex
rts rts
@ -247,15 +264,15 @@ restorebg_driver
; Draw sprites by looping through the list of sprites ; Draw sprites by looping through the list of sprites
renderstart renderstart
lda #sprite_l - sprite_active lda #sprite_l - sprite_active
sta RENDERCOUNT sta param_count
inc renderroundrobin_smc+1 inc renderroundrobin_smc+1
renderroundrobin_smc renderroundrobin_smc
ldy #0 ldy #0
sty PARAM3 sty param_index
renderloop renderloop
lda PARAM3 lda param_index
and #sprite_l - sprite_active - 1 and #sprite_l - sprite_active - 1
tay tay
lda sprite_active,y lda sprite_active,y
@ -265,42 +282,42 @@ renderloop
lda sprite_h,y lda sprite_h,y
sta jsrsprite_smc+2 sta jsrsprite_smc+2
lda sprite_x,y lda sprite_x,y
sta PARAM0 sta param_x
lda sprite_y,y lda sprite_y,y
sta PARAM1 sta param_y
jmp jsrsprite_smc jmp jsrsprite_smc
jsrsprite_smc jsrsprite_smc
jsr $ffff ; wish you could JSR ($nnnn) jsr $ffff ; wish you could JSR ($nnnn)
ldy DAMAGEINDEX ldy damageindex
lda PARAM2 ; contains the byte index into the line lda scratch_col ; contains the byte index into the line
sta (DAMAGEPTR),y sta (damageptr),y
iny iny
clc clc
adc DAMAGE_W adc damage_w
sta (DAMAGEPTR),y sta (damageptr),y
iny iny
; need to convert HGR y values to char rows ; need to convert hgr y values to char rows
lda PARAM1 lda param_y
lsr a lsr a
lsr a lsr a
lsr a lsr a
sta (DAMAGEPTR),y sta (damageptr),y
iny iny
lda PARAM1 lda param_y
clc clc
adc DAMAGE_H adc damage_h
lsr a lsr a
lsr a lsr a
lsr a lsr a
sta (DAMAGEPTR),y sta (damageptr),y
iny iny
sty DAMAGEINDEX sty damageindex
renderskip renderskip
inc PARAM3 inc param_index
dec RENDERCOUNT dec param_count
bne renderloop bne renderloop
renderend renderend
@ -309,7 +326,7 @@ renderend
movestart movestart
lda #sprite_l - sprite_active lda #sprite_l - sprite_active
sta RENDERCOUNT sta param_count
ldy #0 ldy #0
moveloop moveloop
@ -377,7 +394,7 @@ movey_end
movenext movenext
iny iny
dec RENDERCOUNT dec param_count
bne moveloop bne moveloop
moveend moveend
@ -434,19 +451,19 @@ clrouter
ldx #0 ldx #0
clrloop clrloop
lda HGRROWS_H1,x lda HGRROWS_H1,x
sta SCRATCH1 sta scratch_addr+1
lda HGRROWS_H2,x lda HGRROWS_H2,x
sta TEMPADDR+1 sta scratch_ptr+1
lda HGRROWS_L,x lda HGRROWS_L,x
sta SCRATCH0 sta scratch_addr
sta TEMPADDR sta scratch_ptr
lda tophalf,y lda tophalf,y
cpx #96 cpx #96
bcc clrwrite bcc clrwrite
lda bothalf,y lda bothalf,y
clrwrite clrwrite
sta (SCRATCH0),y sta (scratch_addr),y
sta (TEMPADDR),y sta (scratch_ptr),y
inx inx
cpx #192 cpx #192
bcc clrloop bcc clrloop

View File

@ -58,7 +58,7 @@ DrawCharCol ; A=%PQRstuvw
; ORG $034C ; Listing 4a ; ORG $034C ; Listing 4a
_DrawChar1 _DrawChar1
LDX hgrptr+1 LDX hgrptr+1
STX scratch0 STX scratch_0
; ORG $0350 ; Listing 1 ; ORG $0350 ; Listing 1
_DrawChar _DrawChar
LDX #7 LDX #7
@ -74,7 +74,7 @@ _LoadFont ; A = font[ offset ]
; ORG $0363 ; Listing 4a ; ORG $0363 ; Listing 4a
IncCursorCol IncCursorCol
INY INY
LDX scratch0 ; Move cursor back to top of scanline LDX scratch_0 ; Move cursor back to top of scanline
STX hgrptr+1 STX hgrptr+1
RTS RTS
; ORG $0369 ; Listing 10 ; ORG $0369 ; Listing 10