Getting code size even smaller

Programming the 6502 microprocessor and its relatives in assembly and other languages.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Getting code size even smaller

Post by barrym95838 »

theGSman wrote:
... I'm sure that much greater optimizations can be achieved but that would take a lot of further research and I already have something that works a treat ...
I stewed for many hours cooking the UM/MOD and UD/MOD further down in that thread. I don't have a 6502 Forth handy to do the speed comparison, but I'm willing to bet you a soda pop that mine will beat yours slightly for speed and significantly for size.

Mike B.
teamtempest
Posts: 443
Joined: 08 Nov 2009
Location: Minnesota
Contact:

Re: Getting code size even smaller

Post by teamtempest »

Since you don't use the X or Y registers in the main loops, you might consider saving the length value in them. Updating is quicker and shorter; you can also do it before updating the pointers so as not to waste time doing that if it's not necessary (not a big deal overall, more of a neatness thing). You'll have to put the length values in those registers, which is an opportunity to check if the initial value is zero:

Code: Select all

; initialize length
; - Z-flag set if no length, clear if at least one byte

INI_LEN:
    ldx lenl
    ldy lenh
    bne +
    txa
+   rts

; update length, source and target pointers
; - Z-flag set if done, clear if not done

UPD_STL:
    txa        ; update length
    bne +
    tya
    beq done   ; no more to do
    dey
 +  dex
    inc srcl   ; update source pointer
    bne +
    inc srch
 +  inc tgtl   ; update target pointer
    bne done
    inc tgth   ; warning: sets Z-flag if rollover from $FFFF to $0000
done:
    rts
If you didn't want to disturb the A register in these routines, you could replace all the "t-a" instructions with "cp- #$00". Adds three bytes overall but no time.
theGSman
Posts: 85
Joined: 26 Jan 2015

Re: Getting code size even smaller

Post by theGSman »

barrym95838 wrote:
I stewed for many hours cooking the UM/MOD and UD/MOD further down in that thread. I don't have a 6502 Forth handy to do the speed comparison, but I'm willing to bet you a soda pop that mine will beat yours slightly for speed and significantly for size.
You'd win that bet hands down. At the time I dreamed up the algorithm and method of achieving it, I'd never heard of the concept of gradually shifting the dividend out and the quotient/remainder in.

I will definitely have to examine your code in more detail some time.
User avatar
floobydust
Posts: 1394
Joined: 05 Mar 2013

Re: Getting code size even smaller

Post by floobydust »

I've updated the UPD_STL routine and it's now 21 bytes in size, a savings of 5 bytes.

Code: Select all

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	LDA	LENL	;Get length low byte
			BNE	SKP_LENH	;Test for LENL = zero
			DEC	LENH	;Else decrement length high byte
SKP_LENH	DEC	LENL	;Decrement length low byte
			RTS	;Return to caller
The memory move and memory fill routines have the stayed the same at 15 bytes each. I rewrote the compare routine so it handles the EEPROM writing based on a flag setting. It no longer requires the JSR/RTS to the error routine which prints the failed address. This resulted in the compare routine being 9 bytes larger.

Code: Select all

COMPLP	LDA	LENL	;Get low byte of length
			ORA	LENH	;OR in High byte of length
			BEQ	QUITMV	;If zero, nothing to write
			BIT	TEMP2	;Check for EEPROM programming
			BPL	SKP_BURN	;If bit 7 not set, skip it
			JSR	BURN_BYTE	;Else Burn a byte to EEPROM
SKP_BURN	LDA	(SRCL)	;Else load source
			CMP	(TGTL)	;Compare to source
			BEQ	CMP_OK	;If compare is good, continue
;
			LDA	TEMP2	;Get EEPROM flag
			ORA	#$40 ;Get bit 6 mask for error
			STA	TEMP2	;Store to flag to show error in EEPROM write
			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
			JSR	SPC	;Add 1 space for formatting
;
CMP_OK		JSR	UPD_STL	;Update pointers
			BRA	COMPLP	;Loop back until done
The EEPROM write routine was rewritten to simply set the flag, call the compare routine and check the flag for an error on return to print the appropriate message before exiting. This saved 20 bytes of code.

Code: Select all

PROG	LDA	#$80	;Get EEPROM write active mask
			STA	TEMP2	;Set flag for COMPLP routine
			JSR	COMPLP	;Call routine to write/compare
;
			BIT	TEMP2	;Check for error bit in flag
			BVC	PRG_GOOD	;Branch if no errors
;
			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
Since starting this thread, between the core routines here plus two others which increment and decrement another 16-bit pointer, I've reduced code by 27 bytes. I'm still looking at some other options and can likely save a few more bytes by putting the length check for zero in the UPD_STL routine, but it needs to check on entry and confirm on exit to work with the existing routines.
Post Reply