Hi,
I am analyzing a specific checksum code from the Compute mit magazine (never heard of it before, but working on a typein).
Here is the assembler code for 464 (do not use on any other machine as it makes direct jumps to BASIC rom). There is a basic programm, that loads it and patches the addresses according to the CPC you run it on.
;The checksummer is patched to the EDIT LOW_JUMP routine
;#BD3A, so that instead of the original routine
;the checksummer is called.
org #a000
LD A, #ff ;FF into A
LD (#ac00), A ;save in buffer
CALL .low_jump_EDIT ;call original EDIT
;and put return address on Stack (A008)
org #a008
;this routine is run automatically after a line is entered,
;because the address is on the stack and a RET instruction
;is starting it.
PUSH AF ;save all registers
PUSH BC
PUSH DE
PUSH HL
LD HL, (#bf20) ;load line buffer start into HL
CALL #dd61 ;find next non whitespace char.
OR A ;check if A=0
JR Z, end_la069 ;if A=0, then end of line, jmp end
PUSH HL ;save current line buffer position
LD HL, (#bf20) ;load line buffer start
CALL .sub_insert_line
POP HL ;restore line buffer position
JR NC, end_la069 ;If error (sub_insert_line Carry=0), end
CALL #ee04 ;else parse number
CALL #e7a3 ;
CALL #e163
LD HL, (#bf20)
LD B, #ff
XOR A
.loop_a02e
LD C, A
LD A, (HL)
CP #00
JR Z, cont_la039
ADD C
XOR B
INC HL
DJNZ loop_la02e
.cont_la039
ADD C
XOR B
LD C, A
LD A, #0d
CALL #bb5a
LD A, #0a
CALL #bb5a
LD A, #7b
CALL #bb5a
LD A, C
AND #f0
RRA
RRA
RRA
RRA
ADD #41
CALL #bb5a
LD A, C
AND #0f
ADD #41
CALL #bb5a
POP HL
POP DE
POP BC
POP AF
LD A, #7d
JP #bb5a
RET
.end_la069
POP HL
POP DE
POP BC
POP AF
RET
.sub_insert_line
;IN: HL, pointer to line-buffer
;OUT: CY=0, if okay
;CY=1, if error
;Z=1, Line empty (nothing in it)
;Z=0, Line has errors (could not get inserted)
CALL #dd61 ;Search for first byte in buffer
;ignore SPACE,TAB,LF
OR A ;Check if byte is = 0 (end of line)
SCF ;Set Carry
RET Z ;if end of line, return with CY=1
CALL #ee04 ;else convert Line-Number
RET NC ;if error (CY=0), return
;HL points to byte after line number
;DE containes the line number
LD A, (HL) ;else read next byte
CP #20 ;check if it is SPACE
JR NZ, cont_la07e ;IF !SPACE continue
INC HL ;else increment buffer-pointer (next byte)
.cont_la07e
CALL #e6d2 ;parse line and insert into program
SCF ;set carry
SBC A ;???
RET ;return (CY=1)
org #BF20
;this is the original address to EDIT saved from BD3A,
;This is patched via the loader and BD3A is replaced with JMP &A000
DW #ACA4 ;buffer address
.low_jump_EDIT
RST #08 ;LOW_JUMP
DW #AA98 ;HIGH ROM DISABLED, LOW ROM ENABLED
;Address #2A98 (EDIT)
What I do not understand is specifically this part in the .sub_instert_line routine.
CALL #e6d2 ;parse line and insert into program
SCF ;set carry
SBC A ;???
RET ;return (CY=1)
So it calls a ROM routine (E6D2) which actually inserts the text into the program. It does not return anything meaningful in A or in any flag. It does not even care if it was successful or not, maybe it cannot fail, as we know we do have a correct line number.
Then we set Carry Flag (to signal everything was okay in the subroutine), and then we subtract A from A with Carry ...
The result is always FF and the flags are always:
Z=0
C=1
However in the calling function, in the code does never check the result of Z, but only of C.
For me the SBC A instruction does just not add anything to the code, so why is it there?
All comments are from myself, so they are not part of the original code, which was a basic listing with DATA instructions as a loader for the code.
Any idea on why the SBC A is there? To make a clear result in case of error, what the error is and then never use it anyhow?
SBC A is a useful instruction which copies the content of the carry flag to the A register. It also modifies the Zero flag accordingly, as you noted.
If neither the A register or the zero flag are tested eventually, then I guess it has no purposes.
It is not unusual to find some wonky code in type-in programs, or even commercial ones (you wouldn't believe all the horrors I've seen lately!).
Try to remove it, and check if everything runs as before.
Also :
There is an error in your comment :
;OUT: CY=0, if okay
;CY=1, if error
I guess it's the opposite?
LD A, (HL)
CP #00
We can replace this with or a, and a, cp a. Unless it is self-modified code!
Also you can discard the RET instruction here :
JP #bb5a
RET
It's entirely possible the coder borrowed this code from elsewhere and the idea was you could use either the carry flag or value in A to work with the result (being in a flag is advantageous for immediate branching, but a register held value is easier to store).
Replace it with a NOP and if nothing breaks, it's probably safe to remove.