The goal here is two add two 32-bit numbers stored in little-endian notation. The numbers are stored in the following memory cells:
The following is my implementation, that is not very efficient in terms of DRY principle:
ARG1 EQU 3000H
ARG2 EQU 4000H
RESULT EQU 5000H
ORG 0000H
MOV DPTR, #ARG1 + 0
MOV A, #12H
MOVX @DPTR, A
MOV DPTR, #ARG1 + 1
MOV A, #34H
MOVX @DPTR, A
MOV DPTR, #ARG1 + 2
MOV A, #00H
MOVX @DPTR, A
MOV DPTR, #ARG1 + 3
MOV A, #00H
MOVX @DPTR, A
MOV DPTR, #ARG2 + 0
MOV A, #00H
MOVX @DPTR, A
MOV DPTR, #ARG2 + 1
MOV A, #00H
MOVX @DPTR, A
MOV DPTR, #ARG2 + 2
MOV A, #56H
MOVX @DPTR, A
MOV DPTR, #ARG2 + 3
MOV A, #78H
MOVX @DPTR, A
MOV DPTR, #ARG1 + 0
MOVX A, @DPTR
MOV R0, A
MOV DPTR, #ARG2 + 0
MOVX A, @DPTR
ADDC A, R0
MOV DPTR, #RESULT + 0
MOVX @DPTR, A
MOV DPTR, #ARG1 + 1
MOVX A, @DPTR
MOV R0, A
MOV DPTR, #ARG2 + 1
MOVX A, @DPTR
ADDC A, R0
MOV DPTR, #RESULT + 1
MOVX @DPTR, A
MOV DPTR, #ARG1 + 2
MOVX A, @DPTR
MOV R0, A
MOV DPTR, #ARG2 + 2
MOVX A, @DPTR
ADDC A, R0
MOV DPTR, #RESULT + 2
MOVX @DPTR, A
MOV DPTR, #ARG1 + 3
MOVX A, @DPTR
MOV R0, A
MOV DPTR, #ARG2 + 3
MOVX A, @DPTR
ADDC A, R0
MOV DPTR, #RESULT + 3
MOVX @DPTR, A
JNC EXIT
INC A
MOVX @DPTR, A
EXIT:
NOP
SJMP $
END
Question: I was wondering if there is a way to implement this using loop and reduce the repetitive instructions?
For instance this example is using register banks when using 8-bit memory addresses in direct addressing mode:
ORG 0H
MOV 30H, #12H
MOV 31H, #34H
MOV 32H, #00H
MOV 33H, #00H
MOV 40H, #00H
MOV 41H, #00H
MOV 42H, #56H
MOV 43H, #78H
MOV R0, #30H ;pointer of bank 0
MOV R1, #50H ;result storage bank 0
MOV R2, #4 ;counter
SETB RS0
MOV R1, #40H ;pointer bank 1
CLR RS0
CLR C
LOOP:
MOV A, @R0
SETB RS0
ADDC A, @R1
INC R1
CLR RS0
MOV @R1, A
INC R0
INC R1
DJNZ R2, LOOP
JNC EXIT
INC @R1
EXIT:
NOP
SJMP $
END
(I'm using µVision IDE)
Knowing that the low bytes of the external memory addresses are identical (00h), can simplify the code. It means we can keep the low byte of the data pointer DPTR (special function register DPL
at address 82h) fixed throughout an iteration of the loop.
To switch between the 3 external dwords we need just change the high byte of the DPTR (special function register DPH
at address 83h).
To move on to the next higher byte in all the dwords involved, I have used the INC 82h
instruction at the bottom of the loop. It is important to use INC
(and not ADD
) because INC
does not change the carry flag C that we want propagating through the loop.
MOV 82h, #00h ; DPL = 00h
MOV R1, #4 ; Each dword has 4 bytes
CLR C ; Clear carry so 1st ADDC works fine
LOOP:
MOV 83h, #30h ; DPH = 30h --> DPTR == [3000h,3003h]
MOVX A, @DPTR ; Load byte from 1st dword
MOV R0, A ; Free the accumulator (MOVX needs A)
MOV 83h, #40h ; DPH = 40h --> DPTR == [4000h,4003h]
MOVX A, @DPTR ; Load byte from 2nd dword
ADDC A, R0 ; Addition defines carry
MOV 83h, #50h ; DPH = 50h --> DPTR == [5000h,5003h]
MOVX @DPTR, A ; Store byte in 3rd dword
INC 82h ; DPL++
DJNZ R1, LOOP ; Decrement counter and loop back if not zero
; Process the final carry as needed