В вашей программе есть две ошибки.
Чтение из неправильного регистра после возврата
Давайте посмотрим на эту подпрограмму SQUARE:
SQUARE
ADD R4,R5,#0 ;R4 <- multiplier
AND R6,R6,#0 ;R3 <- 0, sq
;inner loop
AGAIN
ADD R6,R6,R4
ADD R5,R5,#-1 ;decerement counter
BRp AGAIN ;check end of calculation
RET
Вы не делаете здесь есть какие-либо комментарии о том, как должна быть вызвана подпрограмма или что она возвращает. Это затрудняет понимание того, что не так. Вот что вы должны написать выше этой подпрограммы:
; SQUARE subroutine
; Squares an integer value
;
; Parameters:
; R5: Value to be squared
; Return value:
; R6: Squared value
; Notes:
; This subroutine tramples R4
Почему? Если вы пытаетесь отладить вызывающий код, сделать это гораздо проще, если вы знаете, как должна вызываться подпрограмма, и какие предположения вы сделали при ее написании. Например, вы можете внести изменения во внешнюю l oop, чтобы использовать R4 в качестве временной переменной, и не понять, почему это значение перезаписывается. (Если вы действительно хотите go лишнюю милю, также запишите, поддерживает ли подпрограмма нулевые или отрицательные значения в качестве аргумента.)
Теперь, когда у нас есть этот комментарий, проблема в основном коде ясна:
LDR R4,R1,#0 ;element ->R4
LDR R5,R1,#0 ;counter
JSR SQUARE
ADD R2,R2,R4 ;ans = ans + element
Загружаем значение в квадрат в R5 и вызываем SQUARE. Затем SQUARE записывает квадратное значение в R6, и мы ... загружаем значение из R4. Это не правильно. Он должен загружаться из R6, а не из R4.
(В качестве дополнительной проблемы здесь LDR R4,R1,#0
не требуется, поскольку подпрограмма SQUARE игнорирует значение в R4. Еще одно преимущество комментирования вашего кода!)
Таким образом, мы можем исправить этот код следующим образом:
LDR R5,R1,#0 ;counter
JSR SQUARE
ADD R2,R2,R6 ;ans = ans + element
DONE не сохраняет до ANS
Давайте посмотрим на внешнее условие l oop:
LOOP LDR R4,R1,#0 ;element -> R4
ADD R4,R4,-1
BRn DONE ;if R1 < 0, condition fails
Таким образом, мы загружаемся с адреса, на который указывает R1, и проверяем, является ли значение меньше или равно нулю. (Кстати, комментарий неверный.)
Так что же такое DONE?
DONE HALT ;halt
Он немедленно останавливается, не сохраняя R2 для вашего результата!
Итак исправление состоит в том, чтобы переместить строку, которая хранится в R2, чтобы она запускалась после перехода в DONE.
DONE
ST R2, ans
HALT ;halt
Вот полный список кодов фиксированной программы:
; Program to calculate Euclidian sum of numbers stored at location x4000
;
.ORIG x3000
LD R1,a ;first element address
LD R2,zero ;ans -> R2 initialized to 0
;while (R1 isn't zero)
LOOP
LDR R4,R1,#0 ;element -> R4
ADD R4,R4,-1
BRn DONE ;if R1 < 0, condition fails
;loop body
LDR R5,R1,#0 ;counter
JSR SQUARE
ADD R2,R2,R6 ;ans = ans + element
ADD R1,R1,#1 ;prepare for next element
BR LOOP ;another iteration
; SQUARE subroutine
; Squares an integer value
;
; Parameters:
; R5: Value to be squared
; Return value:
; R6: Squared value
; Notes:
; This subroutine tramples R4
SQUARE
ADD R4,R5,#0 ;R4 <- multiplier
AND R6,R6,#0 ;R3 <- 0, sq
;inner loop
AGAIN
ADD R6,R6,R4
ADD R5,R5,#-1 ;decerement counter
BRp AGAIN ;check end of calculation
RET
;
zero .FILL 0
a .FILL x4000 ;a has the address of first location
ans .BLKW 1 ;reserve location for ans
DONE
ST R2, ans
HALT ;halt
.END
Вот как я тестировал фиксированную программу:
$ lc3sim -quiet prog_fixed.obj
x0289 x0FFB BRNZP TRAP_LOOP
Loaded "prog_fixed.obj" and set PC to x3000
(lc3sim) memory x4000 3
Wrote x0003 to address x4000.
(lc3sim) continue
x0289 x0FFB BRNZP TRAP_LOOP
(lc3sim) translate ans
Address ans has value x0009.