Ответ 1
Кажется, есть еще одна глава, которая более точно определяет процессор Hack. В нем говорится:
Процессор Hack состоит из ALU, указанного в главе 2 и трех регистры, называемые регистром данных (D), адресным регистром (A) и программой счетчик (ПК). D и A - 16-разрядные регистры общего назначения, которые могут быть управляются арифметическими и логическими инструкциями, такими как A = D-1, D = D | A, и т.д., следуя за машинным языком Hack, указанным в главе 4. Хотя D-регистр используется исключительно для хранения данных, содержимое A-регистра можно интерпретировать тремя различными способами, в зависимости от контекста команд: как значение данных, как ОЗУ адрес или адрес ROM
Таким образом, по-видимому, "M" обращаются к ячейкам RAM, контролируемым A. Там косвенная адресация, которую я отсутствовал. Теперь все нажимает.
С устранением этой путаницы, теперь мы можем справиться с вопросом OP (намного проще).
Давайте начнем с выполнения вызовов подпрограмм со стеком.
; subroutine calling sequence
@returnaddress ; sets the A register
D=A
@subroutine
0 ; jmp
returnaddress:
...
subroutine: ; D contains return address
; all parameters must be passed in memory locations, e.g, R1-R15
; ***** subroutine entry code *****
@STK
AM=M+1 ; bump stack pointer; also set A to new SP value
M=D ; write the return address into the stack
; **** subroutine entry code end ***
<do subroutine work using any or all registers>
; **** subroutine exit code ****
@STK
AM=M-1 ; move stack pointer back
A=M ; fetch entry from stack
0; jmp ; jmp to return address
; **** subroutine exit code end ****
Команда "push constant" может быть легко переведена для хранения в динамическое место в стеке:
@<constant> ; sets A register
D=A ; save the constant someplace safe
@STK
AM=M+1 ; bump stack pointer; also set A to new SP value
M=D ; write the constant into the stack
Если мы хотим сделать подпрограмму для нажатия констант:
pushR2: ; value to push in R2
@R15 ; save return address in R15
M=D ; we can't really use the stack,...
@R2 ; because we are pushing on it
D=M
@STK
AM=M+1 ; bump stack pointer; also set A to new SP value
M=D ; write the return address into the stack
@R15
A=M
0 ; jmp
И для вызова подпрограммы "push constant":
@<constant>
D=A
@R2
M=D
@returnaddress ; sets the A register
D=A
@pushR2
0 ; jmp
returnaddress:
Чтобы нажать значение переменной X:
@X
D=M
@R2
M=D
@returnaddress ; sets the A register
D=A
@pushR2
0 ; jmp
returnaddress:
Подпрограмма, чтобы вывести значение из стека в регистр D:
popD:
@R15 ; save return address in R15
M=D ; we can't really use the stack,...
@STK
AM=M-1 ; decrement stack pointer; also set A to new SP value
D=M ; fetch the popped value
@R15
A=M
0 ; jmp
Теперь, чтобы выполнить вычисление "EQ", которое было исходным запросом OP:
EQ: ; compare values on top of stack, return boolean in D
@R15 ; save return address
M=D
@EQReturn1
D=A
@PopD
0; jmp
@EQReturn1:
@R2
M=D ; save first popped value
@EQReturn2
D=A
@PopD
0; jmp
@EQReturn2:
; here D has 2nd popped value, R2 has first
@R2
D=D-M
@EQDone
equal; jmp
@AddressOfXFFFF
D=M
EQDone: ; D contains 0 or FFFF here
@R15
A=M ; fetch return address
0; jmp
Объединяя все это:
@5 ; push constant 5
D=A
@R2
M=D
@returnaddress1
D=A
@pushR2
0 ; jmp
returnaddress1:
@X ; now push X
D=M
@R2
M=D
@returnaddress2
D=A
@pushR2
0 ; jmp
returnaddress2:
@returnaddress3 ; pop and compare the values
D=A
@EQ
0 ; jmp
returnaddress3:
В этот момент OP может генерировать код, чтобы нажимать D на стек:
@R2 ; push D onto stack
M=D
@returnaddress4
D=A
@pushR2
0 ; jmp
returnaddress4:
или он может сгенерировать код для ветвления по значению D:
@jmptarget
EQ ; jmp