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

193
cpbg.s
View File

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

View File

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