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.
|