As I've started doing a refresh on my recent C02Monitor code, I've started crunching the size down on some routines and the results are more than expected. Some of it is the result of reuse in the monitor and other the result of leveraging some of the newer opcodes in the CMOS version. Some of the routines recently rewritten include memory fill, move and compare routines. The result is over 100 bytes saved. As the 6502 has been around a long time, memory fill, move and compare routines have been around and almost standardized on for decades now. The usual method is to handle full pages of 256 bytes first, then handle the remaining page of less than 256 bytes. This method results in two complete routine loops to accomplish the function.
Doing it differently in a single loop, I ended up being able to reuse a core routine that updates source, target and length pointers commonly used to move memory (non-overlapping), fill memory and compare memory. I can use the new routines for the monitor functions which fill memory, compare memory, write to the EEPROM insitu (basically a move/compare) and half of the memory move function. Here's some snippets of the core code:
Code:
USERFILL TAX ;Save fill byte
FILL_LP LDA LENL ;Get length low byte
ORA LENH ;OR in length high byte
BEQ DONEFILL ;Exit if zero
TXA ;Get fill byte
STA (TGTL) ;Store in target location
JSR UPD_TL ;Update Target/Length pointers
BRA FILL_LP ;Loop back until done
DONEFILL RTS ;Return to caller
Code:
;Move memory block first byte to last byte, no overwrite condition, do the move
MVNO_LP LDA LENL ;Get length low byte
ORA LENH ;OR in length high byte
BEQ QUITMV ;Exit if zero bytes to move
LDA (SRCL) ;Load source data
STA (TGTL) ;Store as target data
JSR UPD_STL ;Update Source/Target/Length variables
BRA MVNO_LP ;Branch back until length is zero
;
Code:
COMPLP LDA LENL ;Get low byte of length
ORA LENH ;OR in High byte of length
BEQ QUITMV ;If zero, nothing to write
LDA (SRCL) ;Get the source data
CMP (TGTL) ;Compare to target data
BEQ CMP_OK ;If equal, continue compare
JSR COMPERR ;Print failed compare address
CMP_OK JSR UPD_STL ;Update Source/Target/Length variables
BRA COMPLP ;Branch back until done
QUITMV RTS ;Return to caller
;
COMPERR JSR SPC2 ;Send 2 spaces
JSR DOLLAR ;Print $ sign
LDA TGTH ;Get high byte of address
LDY TGTL ;Get Low byte of address
JSR PRWORD ;Print word
JMP SPC ;Add 1 space for formatting and return
Code:
PROG_LP LDA LENL ;Get low byte of length
ORA LENH ;OR in High byte of length
BEQ QUITPRG ;If zero, nothing to write
;
JSR BURN_BYTE ;Write a byte to EEPROM
LDA (SRCL) ;Get the source data
CMP (TGTL) ;Compare to target data
BEQ PRG_OK ;If equal, continue writing
;
LDA #$FF ;Get flag setting
STA TEMP2 ;Set flag for error
JSR COMPERR ;Print compare fail address
;
PRG_OK JSR UPD_STL ;Update Source/Target/Length variables
BRA PROG_LP ;Branch back until done
;
QUITPRG LDA TEMP2 ;Get Prog error flag
BEQ PRG_GOOD ;Branch to good program exit
LDA #$26 ;Get Prog failed message
BRA BRA_PRMPT ;Branch to Prompt routine
;
PRG_GOOD LDA #$25 ;Get completed message
JSR PROMPT ;Send to console and exit
LDA #$27 ;Get warning message for RTC and Reset
BRA_PRMPT JMP PROMPT ;Send to console and exit
Code:
;UPD_STL subroutine: Increments Source and Target pointers
;UPD_TL subroutine: Increments Target pointers only
; then drops into decrement length pointer. Used by multiple commands
UPD_STL INC SRCL ;Increment source low byte
BNE UPD_TL ;Check for rollover
INC SRCH ;Increment source high byte
UPD_TL INC TGTL ;Increment target low byte
BNE DECLEN ;Check for rollover
INC TGTH ;Increment target high byte
;
;DECLEN subroutine: decrement 16-bit variable LENL/LENH
DECLEN SEC ;Set carry for subtract
LDA LENL ;Get length low byte
SBC #$01 ;Subtract one
STA LENL ;Save it back
LDA LENH ;Get length high byte
SBC #$00 ;Subtract carry
STA LENH ;Save it back
RTS ;Return to caller
;
So far I've reduced ROM size in excess of hundred bytes but have rewritten multiple routines and made a few minor changes to help as well. Just thought I'd share the above routines for anyone looking for shorter code. I have more routines I'm looking at but the above are a good start. Granted, execution time is going to be longer, but when you're typing commands into the monitor, it's still blazingly quick.