5. IJVM Micro-program Notes

These notes elaborate figure 4-17 "The micro-program for the Mic-1" on pages 262-264.


In this 3 page table:

  • Each opcode has a micro-function associated with it. For example, IJVM instruction SWAP has micro-instructions swap1 through swap6
  • The ROM address of the first micro-instruction for an opcode is located at the opcode's hex number. For example, SWAP's opcode is 0x5F, so its first micro-instructions, swap1, will be located at address 0x5F in the ROM. That's where they got the funky opcode numbering... cool, huh.
  • Recall that each micro-instruction has a "next address" field. This is the next micro-instruction in the table, unless a goto is specified. For example, the "next address" field of  swap1 is the address of swap2 (usually the next address in the ROM). The "next address" field of swap6 is the address of the Main1 micro-instruction because of the goto Main1 statement in swap6.
  • Most micro-functions end with goto Main1 signifying the end of the execution of the current opcode. The Main1 micro-instruction increments the Program Counter (PC) and fetches the next opcode.

The main interpreter loop

The micro-program starts at Main1 (it may actually start with at nop1 which just jumps right to Main1) and has three parts (all executed in 1 cycle):

PC = PC + 1; fetch; goto (MBR)

The operations within this micro-instruction:

  • increment the program counter
  • fetch the next byte in the program, placing the byte in MBR
  • jump to the opcode in MBR

The control and datapath details are:

B Bus: Read PC onto B
ALU: Disable A input making it 0; enable B; add with increment (1 on the carry-in bit) resulting in B+1
C Bus: Write ALU result in PC register
Memory: Fetch 1 byte from memory at (new) location in PC register and store it in lower 8 bits of MBR
Next instruction: JMPC = 1, jump to micro-instruction at address in lower 8 bits of MBR

Please note that Main1 fetches the byte at PC address in memory before you really know that you need it. In the case of a branch/jump, this byte would be disregarded. There is no inefficiency here, however, as all this happens while the current instruction is being executed.

Micro-instruction encoding

So, what would the micro-instruction for Main1 look like?

Field Bit value Description
Next Addr 000000000 Next address is 0 because this value will be OR'd with the address in MBR. Remember, MBR OR 0 will equal MBR.
JMPC 1 MPC = MBR, use MBR as next micro-instruction ROM address
JAMN 0 Unused
JAMZ 0 Unused
SLL8 0 No shift
SRA1 0 No shift
F0 0 See next
F1 1 ALU function 01 is "A or B", but A is 0, so the ALU output is B
ENA 0 Use 0 for A input to ALU
ENB 1 Use B bus for B input to ALU
INVA 0 Don't invert A, use 0
INC 1 Increment PC
H 0  
OPC 0  
TOS 0  
CPP 0  
LV 0  
SP 0  
PC 1 PC = ALU result
MDR 0  
MAR 0  
WRITE 0 No memory write
READ 0 No memory read
FETCH 1 Fetch next byte from memory
B bus 0001 Place PC register value on B bus

So, here we go, the micro-instruction at Main1 is:

Addr Jam ALU C bus Mem B bus
000000000 100 00010101 000000100 001 0001

Or, the 36 bits in order are:

000000000 100 00010101 000000100 001 0001

Or (last one, I promise), in hex:

0 0415 0211

Example instruction: ADD

The ADD instruction in IJVM pops the top two integers off the stack, adds them and pushes their sum onto the stack. It has no operands. It has 3 micro-instructions: iadd1, iadd2, iadd3. Each of these micro-instructions is executed in one cycle, so ADD takes 3 cycles to complete.

iadd1

MAR = SP = SP - 1; rd

Decrement the stack pointer (effectively popping the first value off the stack) and initiate a read of the second value on the stack.

Detailed operation:

B Bus: Read SP onto B
ALU: Disable A input making it 0; invert A making it all 1's which is -1 in 2's complement; add resulting in B-1
C Bus: Write ALU result to SP setting new stack pointer; write to MAR as well, making future read/writes use the stack top.
Memory: Read into MDR the value at address MAR, remember we've already decremented SP so this read will get the 2nd value on the stack from memory.
Next instruction: JMPC = 0, jump to iadd2

In this micro-instruction, we're popping the first element off the stack and issuing a command to read the 2nd element on the stack from memory. Well, wait a second what happened to the first integer on the stack? Read on...

iadd2

H = TOS

Aha! The first element on the stack is assumed to be in the TOS register. While H is being set to this value (so we can use it in the ALU in the next micro-instruction), the memory read issued above also has time to complete.

Details:

B Bus: Read TOS onto B
ALU: Disable A input making it 0; add resulting in B
C Bus: Write ALU result to H register
Memory: None
Next instruction: JMPC = 0, jump to iadd3

iadd3

MDR = TOS = MDR + H; wr; goto Main1

In the final micro-instruction, we perform the add and save it off to memory. The sum is stored in memory at the SP address; remember that we set MAR to SP in the iadd1 micro-instruction.

B Bus: Read MDR onto B
ALU: Enable A and B, add resulting in A+B
C Bus: Write ALU result to TOS reflecting the new value at the top of the stack, and write to MDR so that we can also write the new value to the top of the stack in memory 
Memory: Write MDR to memory
Next instruction: JMPC = 0, jump to Main1

Done. Phew.


Author: William Krieger, Nov 2005 CSC 220