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