Some Assembly (Part 2) https://schweigi.github.io/assembler-simulator/ https://schweigi.github.io/assembler-simulator/instruction- set.html
Before CALL print 38 18 (38 opcode for CALL) (18 the address corresponding to the label “print”) Calling a subroutine involves changing the value of the IP (jumping to the subroutine’s code) as well as storing the IP’s value in the stack so that we can return. Recall that subroutine calling uses the stack because returning from subroutines using the same LIFO protocol as the stack.
(after) CALL print The return location (17, the location of the instruction after the CALL) has been pushed onto the stack. And the stack pointer updated. The location corresponding to the print label (the start of the print subroutine) is placed in the IP.
Before PUSH A 32 00 (32 opcode for CALL) (00 corresponds to Register A) We are going to put the value that’s in Register A onto the stack and update the SP (stack pointer). Why? 1) Because we can and it’s a demo program. 2) We are going to use Register A and perhaps we want to return it to its state when we are done using it.
(after) PUSH A The value of Register A (00) was pushed onto the stack. The stack pointer was updated. The IP moves to the next instruction.
Before PUSH B 32 00 (32 opcode for CALL) (01 corresponds to Register B) We are going to put the value that’s in Register B onto the stack and update the SP (stack pointer). Why? 1) Because we can and it’s a demo program. 2) We are going to use Register B and perhaps we want to return it to its state when we are done using it.
(after) PUSH B The value of Register B (00) was pushed onto the stack. The stack pointer was updated. The IP moves to the next instruction.
Before MOV B 0 06 01 00 (06 opcode for MOV) (01 corresponds to Register B) 00 data places there We are going to put a 0 into Register B. Why? Recall that we used a 0 as the string terminating character. We will loop through the characters in the string and will stop when the character in memory matches the character in Register B
(after) MOV B 0 The value of 00 was placed in Register B. The IP moves to the next instruction.
Before MOV A [C] 03 00 02 03 opcode for MOV – there’s more than one kind of MOV 00 Register A 02 Register C The square brackets indicate that we are taking the value from memory indicated by the address in Register C and placing it in Register A. Update IP
(after) MOV A [C] Take the value (48) at the address found in Register C (02) and copy it into Register A. The IP moves to the next instruction.
Before MOV [D] A 05 03 00 05 opcode for MOV – yet another version of MOV 03 Register D 00 Register A The square brackets around D indicate that we are writing the value from Register A to the memory location indicated by the address in Register D. Update IP
(after) MOV [D] A Take the value of Register A (48) and copy it into the location held by Register D (E8) – the first memory-mapped output location. The IP moves to the next instruction.
Before INC C 12 02 12 opcode for INC – increment 02 Register C Update IP Why? Register C was pointing to the ASCII for the ‘H’ in “Hello World!” and by incrementing the Register will now point to the ‘e’
(after) INC C Register C was incremented from 02 to 03 so now it is pointing to the letter ‘e’ in Hello.
Before INC D 12 03 12 opcode for INC – increment 03 Register D Update IP Why? Register D was pointing to the first memory-mapped output location (where we displayed the ‘H’). Now it will point to the next output location to display the ‘e’
(after) INC D Register D was incremented from E8 to E9 so now it is pointing to the second memory-mapped output location.
Before CMP B, [C] 15 01 02 15 opcode for Compare 01 Register B 02 Register C Update IP Why? We are comparing (seeing if they are equal) the contents of Register B and the contents of memory pointed to by Register C. The true or false result will be put in the Z (zero) FLAG. We are looping over the characters in a string and we are testing for the end of string character.
(after) CMP B, [C] Register B has the string termination character 00, Register C pointed to the letter ‘e’ (65). Thus the Z flag was set to false.
Before JNZ .loop 27 1F 27 opcode for Jump-If-Not-Zero 1F the value of the loop label, i.e. the top of the loop Update IP (because it’s a jump-if command, this may or may not be a simple increment). We’re branching here. Can’t you see we’re branching here. Why? We previously determined if we were at the end of the string. If we are not at the end of the string we jump to the top of the loop to process another character, otherwise we would fall out of the loop.
(after) JNZ .loop The Z flag was false, so we jumped to the loop label – in other words the IP was set to 1F
LOOPING We are looping through the characters of “Hello World!”. It is very repetitive until we get up to displaying the ‘!’ (that 21 in the first row of RAM) and then increment so that we are pointing to the 00 next to it – which is the string termination character. We will pick it back up at that point.
Before CMP B, [C] 15 01 02 15 opcode for Compare 01 Register B 02 Register C Update IP Why? We are comparing (seeing if they are equal) the contents of Register B and the contents of memory pointed to by Register C. The true or false result will be put in the Z (zero) FLAG. We are looping over the characters in a string and we are testing for the end of string character.
(after) CMP B, [C] Register B has the string termination character 00, Register C pointed to the string termination character (00) as well. Thus the Z flag was set to true.
Before JNZ .loop 27 1F 27 opcode for Jump-If-Not-Zero 1F the value of the loop label, i.e. the top of the loop Update IP (because it’s a jump-if command, this may or may not be a simple increment). Why? We previously determined if we were at the end of the string. This time we are at the end of the string and we will fall out of the loop.
(after) JNZ .loop The Z flag was true, so we did not jump – in other words the IP was just incremented as a normal instruction.
Before POP B 36 01 36 opcode for POP 01 Register B Update IP & SP Take the value off the top of the stack (00) and copy it into Register B.
(after) POP B Register B now has a 00 (well it also had a 00 previously). The SP and IP are adjusted. We are returning Register B to its state for starting the loop. (In principle it might have changed.)
Before POP A 36 00 36 opcode for POP 00 Register A Update IP & SP Take the value off the top of the stack (00) and copy it into Register A. Adjust the stack pointer location.
(after) POP A Register A now has a 00 (previously it had a 21). The SP and IP are adjusted. We are returning Register A to its state for starting the loop.
Before RET 39 39 opcode for RET (NO DATA) Take the value from the top of the Stack which now matches what was placed there on the Subroutine CALL and place it in the IP. Also adjust the SP
(after) RET The IP is now pointing to the line of code after the subroutine call. The SP is back to its original value. You might still see the 17. But it’s really no longer “on the stack” because of the rules of stack access (LIFO protocol) that 17 is not accessible.
Before HLT 00 00 opcode for HLT (NO DATA) The purpose of HLT is to let us know we are done. Otherwise we would continue interpreting data in the RAM as opcodes and operands. Do not adjust IP
(after) HLT NOTHING. Stay as you are.