使用 8 位寄存器将两个 32 位数字相加

问题描述

这里的目标是将两个以小端表示法存储的 32 位数字相加。这些数字存储在以下存储单元中:

  • 一个数字:0x3000-0x3003
  • 秒数:0x4000-0x4003
  • 结果应该是:0x5000-0x5003

以下是我的实现,就 DRY 原则而言,效率不是很高:

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,#ARG1 + 2
MOV A,#00H
MOVX @DPTR,#ARG1 + 3
MOV A,A

MOV DPTR,#ARG2 + 0
MOV A,#ARG2 + 1
MOV A,#ARG2 + 2
MOV A,#56H
MOVX @DPTR,#ARG2 + 3
MOV A,#78H
MOVX @DPTR,#ARG1 + 0
MOVX A,@DPTR
MOV R0,#ARG2 + 0
MOVX A,@DPTR
ADDC A,R0
MOV DPTR,#RESULT + 0
MOVX @DPTR,#ARG1 + 1
MOVX A,#ARG2 + 1
MOVX A,#RESULT + 1
MOVX @DPTR,#ARG1 + 2
MOVX A,#ARG2 + 2
MOVX A,#RESULT + 2
MOVX @DPTR,#ARG1 + 3
MOVX A,#ARG2 + 3
MOVX A,#RESULT + 3
MOVX @DPTR,A

JNC EXIT
INC A
MOVX @DPTR,A

EXIT:
  nop
  SJMP $

END

问题:我想知道是否有办法使用循环来实现这一点并减少重复指令?

例如这个例子是在直接寻址模式下使用 8 位内存地址时使用寄存器组:

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

(我使用的是 µVision IDE)

解决方法

知道外部存储器地址的低字节是相同的(00h),可以简化代码。这意味着我们可以在循环的整个迭代过程中保持数据指针 DPTR(地址 82h 处的特殊功能寄存器 DPL)的低字节固定。
要在 3 个外部双字之间切换,我们只需更改 DPTR(地址 83h 处的特殊功能寄存器 DPH)的高字节。

为了移动到所有涉及的双字中的下一个更高字节,我在循环底部使用了 INC 82h 指令。使用 INC(而不是 ADD)很重要,因为 INC 不会改变我们想要通过循环传播的进位标志 C。

  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