Сложите два 32-битных числа, используя 8-битные регистры.

Цель здесь состоит в том, чтобы сложить два 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, 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

Вопрос: мне интересно, есть ли способ реализовать это с помощью цикла и уменьшить количество повторяющихся инструкций?

Например, в этом примере используются банки регистров при использовании 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)


person HTF    schedule 28.12.2020    source источник
comment
Да, использовать петлю вполне можно, и делать это нужно с ее помощью. Посмотрите на свой код, какие инструкции похожи или равны, и изучите набор инструкций, какие инструкции могут быть полезны.   -  person the busybee    schedule 28.12.2020
comment
@thebusybee, можно поконкретнее? Как я могу ссылаться на 2-байтовый адрес памяти, используя 8-битные регистры?   -  person HTF    schedule 29.12.2020
comment
Один за другим... Или, если вы имеете в виду, как получить доступ к DPTR: в DPH и DPL есть обе половинки.   -  person the busybee    schedule 29.12.2020
comment
@thebusybee хм, не уверен, что ты имеешь в виду. Чтобы использовать циклы, я должен хранить адрес памяти в регистрах, чтобы извлекать отдельные байты, увеличивать их и т. д., но я не могу хранить 2-байтовый адрес памяти, например 0x3000, в 8-битных регистрах (R0, R1…)   -  person HTF    schedule 29.12.2020
comment
Ну, еще раз, пожалуйста, прочитайте документацию. DPTR — 16-битный регистр.   -  person the busybee    schedule 29.12.2020
comment
@thebusybee Я знаю, что DPTR - это 16-битный регистр, но это все еще не объясняет, как я могу использовать его в цикле.   -  person HTF    schedule 29.12.2020
comment
Давайте продолжим это обсуждение в чате.   -  person the busybee    schedule 29.12.2020


Ответы (1)


Зная, что младшие байты адресов внешней памяти идентичны (00h), можно упростить код. Это означает, что мы можем сохранять младший байт указателя данных DPTR (регистр специальной функции DPL по адресу 82h) фиксированным на протяжении всей итерации цикла.
Чтобы переключиться между тремя внешними двойными словами, нам нужно просто измените старший байт DPTR (регистр специальной функции DPH по адресу 83h).

Чтобы перейти к следующему более высокому байту во всех задействованных двойных словах, я использовал инструкцию 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
person Sep Roland    schedule 31.12.2020