News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_SerErris

Struggeling with SBC A

Started by SerErris, 19:35, 06 April 24

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

SerErris

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?
Proud owner of 2 Schneider CPC 464, 1 Schneider CPC 6128, GT65 and lots of books
Still learning all the details on how things work.

Jean-Marie

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!

Jean-Marie

Also you can discard the RET instruction here :

JP  #bb5a
RET

andycadley

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.

Powered by SMFPacks Menu Editor Mod