All registers shown here are 8-bit (1-byte) registers. The memory is a 256-byte memory and is byte-addressible, so that a memory address is also 8 bits and the range of memory addresses (the "address space") is 0-255.
Here, Source and Target identify the two registers (any of r0 - r3) that contain the two operands to be added, subtracted, etc. and Target identifies also the register where the result will be stored. The assembly language mirrors this instruction layout. Thus, when writing an assembly language instruction like
add r1,r2
the interpretation is that r2 is the Target of the operation and gets the sum of its contents and the contents of Source register r1. Below is a summary of the one-byte instructions:
Symbol Op Meaning ------ ---- ------- halt 0000 Halt execution add 0001 Integer addition (8-bit) Target <- [Source] + [Target] sub 0010 " subtraction " - mul 0011 " multiplication " * div 0100 " division " / and 0101 Logical AND (8-bit) " && or 0110 " OR (8-bit) " || cmp 0111 Compare registers; set LT GT EQ and CO accordinglyNote that the Op code for these instructions always 0 as its first bit, so this group is easy to distinguish from the 2-byte instructions. According to his table, the complete machine coding for the add r1,r2 instruction is given as follows (its hex version is shown on the right):
0001 01 10 (16)If the instruction is a load, store, or branching instruction, it will require two bytes in memory, the second of which is the IROffset field for computing an address or an immediate value. These instructions have the following layout:
Because these instructions occupy two bytes, their instruction fetch cycles will require 6 steps rather than 3 in order to fetch the second byte and load it into the IROffset register. The 4-bit op codes for these instructions and their meanings are summarized as follows (notice that their first bit is always 1):
Symbol Op Meaning ------ ---- ------- lbz 1000 Load from memory to register Target <- [[Source] + IROffset] la 1001 Load an address to a register Target <- [Source] + IROffset li 1010 Load immediate to register Target <- IROffset stb 1011 Store to memory from register [Target] + IROffset <- [Source] b<cc> 1100 Branch conditionally (the four bits of Source and Target define the branch condition <cc>): b = 0000, blt = 1000, beq = 0010, ble = 1010, bgt = 0101, bne = 1101, BOV (branch on overflow) = 0001. If the values of LT GT EQ SO match the condition <cc>, then PC <- [Source] + IROffset bl 1101 Branch and link (procedure call): LR <- [PC], PC <- [PC] + IROffset blr 1110 Return from procedure PC <- [LR] nop 1111 Continue to the next instructuction (do nothing)For example, the instruction
lbz 12(r3), r2loads register r2 with the byte at the memory address which is 12 bytes beyond the address stored in register r3. This instruction has the following binary coding (its hex version is shown on the right):
1000 11 10 0000 1100 (8E0C)The instruction
li -1, r2loads the constant -1 into register r2. Its binary coding (hex on the right) is:
1001 00 10 1111 1111 (92FF)The branch instruction
bne *+7branches to the instruction that is 7 bytes after it, but only if the EQ condition code <cc> is not set to 1. Its binary representation (hex on the right) is:
1100 11 01 0000 0111 (CD07)
String Msg = "Hello"; for (int i=0; i<Msg.length(); i++) Msg[i] = Msg[i] && '%11011111';The Assembly language code for this example looks like what you've been writing for the PowerPC assembler, except that each instruction has two operands rather than 3. Another main difference is that instructions are byte operations and integer and character data values are stored in single bytes of memory (numbers are in 2's complement notation):
Addr Instruction ---- ---------------------------- 00 la Msg, R0 ; R0 <- address of 1st character in Msg 02 li 1, R1 ; R1 <- constant 1 04 la 4(R0), R3 ; R3 <- address of last character in Msg 06 Loop: cmp R0, R3 ; see if done 07 bgt Done ; this operand could be written *+12 09 lbz 0(R0), R2 ; R2 <- a character in Msg 0B li %11011111, R1 ; put the mask into R1 0D and R1, R2 ; convert it to upper case 0E stb R2, 0(R0) ; put it back in Msg 10 li 1, R1 ; put constant 1 back into R1 12 add R1, R0 ; increment to address next character 13 b Loop ; this operand could be written *-15 15 Done: halt 16-1A Msg: dc 'Hello'Note that the hex addresses 'Addr' shown on the left are for this program's machine instructions, once it is assembled (by hand!). The machine code for this program is given below:
Machine Instruction Addr Hex Op Source Target IROffset Notes ---- ---- --------------------------- ------------------------------- 00 9010 1001 00 00 00010000 ; R0 <- address of 1st character 02 A101 1010 00 01 00000001 ; R1 <- constant 1 04 9304 1001 00 11 00000100 ; R3 <- address of last char 06 73 0111 00 11 ; see if done 07 C30C 1100 01 01 00001100 ; this operand could be *+12 09 8200 1000 00 10 00000000 ; R2 <- that character from Msg 0B A1DF 1010 00 01 11011111 ; put the mask into R1 0D 56 0101 01 10 ; convert it to upper case 0E B800 1011 10 00 00000000 ; put it back into Msg 10 A101 1010 00 01 00000001 ; put constant 1 back into R1 12 14 0001 01 00 ; increment to address next char 13 C0F1 1100 00 00 11110001 ; this operand could be *-15 15 00 0000 16-1A 48656C6C6F 0100 1000 0110 0101 0110 1100 0110 1100 0110 1111 ; 'Hello'
int [] List = {2, 3, -1, 9, 4, 6, 7};
Sum = 0;
for (int i=0; i<List.length; i++)
Sum = Sum + List[i];
The assembly code for this program might look like this:
Addr Instruction ---- -------------------------- 00 la List, R0 ; R0 <- address of an integer 02 li 1, R1 ; R1 <- constant 1 04 li 0, R2 ; R2 <- temporary Sum 06 la 6(R0), R3 ; R3 <- address of last integer 08 Loop: cmp R0, R3 ; see if sum is complete 09 bgt Done 0B lbz 0(R0), R1 ; if not, load next integer 0D add R1, R2 ; R2 <- [R2] + [[R0]] 0E li 1, R1 ; put 1 back into R1 10 add R1, R0 ; address of next integer 11 b Loop 13 Done: stb R2, Sum ; store the result 15 halt 16 List: DC 2, 3, -1, 9, 4, 6, 7 1D Sum: DC 0Note that R1 serves double-duty here (for the constant 1 and for an integer to be added to the sum. This is due to the small number of registers we have in this machine. Try hand-coding this program into machine code:
Machine Instruction Addr Hex Op Source Target IROffset Notes ---- ---- --------------------------- ------------------------------- 00 ; R0 <- address of an integer 02 ; R1 <- constant 1 04 ; R2 <- temporary Sum 06 ; R3 <- address of last integer 08 ; see if sum is complete 09 0B ; if not, load next integer 0D ; R2 <- [R2] + [[R0]] 0E ; put 1 back into R1 10 ; address of next integer 11 13 ; store the result 15 16 0203FF09040607 00000010 00000011 11111111 00001001 00000100 00000110 00000111 1D 00