The following is a design for a simple 16-bit central processing unit (CPU) which can be seen as an example of a microprogrammed programmable control unit. The implementation described is similar to the CPU shown here. The major difference is that this implementation has several addressing modes and a more flexible microprogramming scheme.
The CPU's instruction set architecture (instructions, addressing modes, programmer visible registers, and interrupt handling) is detailed in this section.
There are 16 register addresses but only 15 registers, and of these only 7 are available to the programmer. Each register is 16-bits wide. Register 0 is always read as zero and it cannot be loaded. Registers 1 to 7 are available to the programmer to use as he/she wishes. The registers 8 to 15 are used internally by the CPU and are not available to the programmer.
For each instruction the following is given:
The symbols used are as follows:
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Opcode | Mode | S | SRC | DST | |||||||||||
Data Word |
This class of instruction covers a group of instructions which have no common theme other than they take no operands.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | X | X | X | X |
This class of instruction covers the stack and shifter operations. If the mode is 000 or 001 then the data word is not present.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | X | X | X | X | Mode | S | SHA | DST | ||||||
Data Word |
This class of instruction covers the arithmetic and logic operations and data movement. If the mode is 000 or 001 then the data word is not present.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | X | X | X | X | Mode | S | SRC | DST | ||||||
Data Word |
This class of instructions covers branching and procedure call. If the mode is 000 or 001 then the data word is not present.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | X | X | X | X | Mode | DST | ||||||||
Data Word |
The table below enumerates all of the addressing modes. The three bit instruction field Mode is used as a selector, DST and SRC are three bit register addresses found in the instruction. The value W is the data word that follows the instruction in memory.
Two Operand | |||||
---|---|---|---|---|---|
Mode | Name | One Operand/Branch | S=0 | S=1 | |
000 | Register | PUSH REG[DST] |
ADD REG[DST], REG[SRC] |
ADD REG[DST], REG[SRC] |
|
001 | Register Indirect | PUSH MEMORY[REG[DST]] |
ADD REG[DST], MEMORY[REG[SRC]] |
ADD MEMORY[REG[DST]], REG[SRC] |
|
010 | Immediate | PUSH W |
ADD REG[DST], W |
ADD W, REG[SRC] |
|
011 | Direct | PUSH MEMORY[W] |
ADD REG[DST], MEMORY[W] |
ADD MEMORY[W], REG[SRC] |
|
100 | Indexed | PUSH MEMORY[REG[DST]+W] |
ADD REG[DST], MEMORY[REG[SRC]+W] |
ADD MEMORY[REG[DST]+W], REG[SRC] |
|
101 | Indexed Indirect | PUSH MEMORY[MEMORY[REG[DST]+W]] |
ADD REG[DST], MEMORY[MEMORY[REG[SRC]+W]] |
ADD MEMORY[MEMORY[REG[DST]+W]], REG[SRC] |
|
110 | Relative | PUSH MEMORY[PC+W]] |
ADD REG[DST], MEMORY[PC+W]] |
ADD MEMORY[PC+W]], REG[SRC] |
|
111 | Relative Indirect | PUSH MEMORY[MEMORY[PC+W]]] |
ADD REG[DST], MEMORY[MEMORY[PC+W]]] |
ADD MEMORY[MEMORY[PC+W]]], REG[SRC] |
The list of instructions is now given.
Addition.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 1 | 0 |
REG[DST] ⇐ REG[DST] + REG[SRC]
Flags: C, N, V, and Z.
Addition with carry.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 1 | 1 |
REG[DST] ⇐ REG[DST] + REG[SRC] + C
Flags: C, N, V, and Z.
Bitwise conjunction.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 0 | 0 | 1 |
REG[DST] ⇐ REG[DST] & REG[SRC]
Flags: N, and Z.
Arithmetic shift left.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 0 | 0 | 1 |
REG[DST] ⇐ REG[DST] << REG[SHA]
Flags: C, N, V, and Z.
Arithmetic shift right.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 0 | 0 | 0 |
REG[DST] ⇐ REG[DST] >> REG[SHA]
Flags: C, N, V, and Z.
Subroutine call.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 0 | 0 | 1 |
SP ⇐ SP - 1
MEMORY[SP] ⇐ PC
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Branch if carry.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 0 | 0 | 1 |
if(C == 1)
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Branch if negative.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 1 | 0 | 0 |
if(N == 1)
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Branch if not carry.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 0 | 1 | 1 |
if(C == 0)
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Branch if negative.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 1 | 0 | 1 |
if(N == 0)
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Branch if not overflow.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 1 | 1 | 1 |
if(V == 0)
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Branch if not zero.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 0 | 0 | 1 |
if(Z == 0)
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Branch if overflow.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 1 | 1 | 0 |
if(V == 1)
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Branch if zero.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 0 | 0 | 0 |
if(Z == 1)
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Compare. Two values are subtracted for their side effects on the PSR status bits only.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 0 | 0 | 0 |
REG[DST] - REG[SRC]
Flags: C, N, V, and Z.
Decrement.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 1 | 1 |
REG[DST] ⇐ REG[DST] - 1
Flags: C, N, V, and Z.
Increment.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 1 | 0 |
REG[DST] ⇐ REG[DST] + 1
Flags: C, N, V, and Z.
Unconditional branch.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 0 | 0 | 0 |
PC ⇐ MEMORY[REG[DST]]
Flags: None.
Move data.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0 | 0 |
REG[DST] ⇐ REG[SRC]
Flags: None.
Move a byte string of a given length from one location to another. The length is taken from REG[3] which is interpreted as a signed integer, the source address is taken from REG[1], and the destination address is taken from REG[2].
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 1 |
REG[8] ⇐ REG[1]
REG[9] ⇐ REG[2]
REG[10] ⇐ REG[3]
loop:
REG[10] ⇐ REG[10] - 1
if(REG[10] >= 0)
REG[11] ⇐ MEMORY[REG[8]]
MEMORY[REG[9]] ⇐ REG[11]
REG[8] ⇐ REG[8] + 1
REG[9] ⇐ REG[9] + 1
goto loop
Flags: None.
Negate.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 1 | 0 | 0 |
REG[DST] ⇐ -REG[DST]
Flags: C, N, V, and Z.
No operation.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 |
Flags: None.
Not (complement).
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 1 | 0 | 1 |
REG[DST] ⇐ ~REG[DST]
Flags: C, N, V, and Z.
Bitwise disjunction.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 0 | 1 | 0 |
REG[DST] ⇐ REG[DST] | REG[SRC]
Flags: N, and Z.
Pop the registers from the stack.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 0 |
REG[1] ⇐ MEMORY[SP]
SP ⇐ SP + 1
REG[2] ⇐ MEMORY[SP]
SP ⇐ SP + 1
REG[3] ⇐ MEMORY[SP]
SP ⇐ SP + 1
REG[4] ⇐ MEMORY[SP]
SP ⇐ SP + 1
REG[5] ⇐ MEMORY[SP]
SP ⇐ SP + 1
REG[6] ⇐ MEMORY[SP]
SP ⇐ SP + 1
REG[7] ⇐ MEMORY[SP]
SP ⇐ SP + 1
Flags: None.
Pop a value from the stack.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 1 |
REG[DST] ⇐ MEMORY[SP]
SP ⇐ SP + 1
Flags: None.
Push a value onto the stack.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 0 |
SP ⇐ SP - 1
MEMORY[SP] ⇐ REG[DST]
Flags: None.
Push the registers onto the stack.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 |
SP ⇐ SP - 1
MEMORY[SP] ⇐ REG[1]
SP ⇐ SP - 1
MEMORY[SP] ⇐ REG[2]
SP ⇐ SP - 1
MEMORY[SP] ⇐ REG[3]
SP ⇐ SP - 1
MEMORY[SP] ⇐ REG[4]
SP ⇐ SP - 1
MEMORY[SP] ⇐ REG[5]
SP ⇐ SP - 1
MEMORY[SP] ⇐ REG[6]
SP ⇐ SP - 1
MEMORY[SP] ⇐ REG[7]
Flags: None.
Return from subroutine.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 0 |
PC ⇐ MEMORY[SP]
SP ⇐ SP + 1
Flags: None.
Rotate left.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 0 | 1 | 1 |
REG[DST] ⇐ REG[DST] << REG[SHA]
Flags: C, and Z.
Rotate left through carry.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 0 | 1 |
REG[DST] ⇐ REG[DST] << REG[SHA]
Flags: C, and Z.
Rotate right.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 0 | 1 | 0 |
REG[DST] ⇐ REG[DST] >> REG[SHA]
Flags: C, and Z.
Rotate right through carry.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 0 | 0 |
REG[DST] ⇐ REG[DST] >> REG[SHA]
Flags: C, and Z.
Return from interrupt.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 1 |
PSR ⇐ MEMORY[SP]
SP ⇐ SP + 1
PC ⇐ MEMORY[SP]
SP ⇐ SP + 1
Flags: None.
Logical shift left.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 1 | 1 | 1 |
REG[DST] ⇐ REG[DST] << REG[SHA]
Flags: C, and Z.
Logical shift right.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 1 | 1 | 0 |
REG[DST] ⇐ REG[DST] >> REG[SHA]
Flags: C, and Z.
Subtraction.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 1 | 0 | 0 |
REG[DST] ⇐ REG[DST] - REG[SRC]
Flags: C, N, V, and Z.
Subtraction with borrow.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 1 | 0 | 1 |
REG[DST] ⇐ REG[DST] - REG[SRC] - C
Flags: C, N, V, and Z.
Move data
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0 | 1 |
REG[15] ⇐ REG[DST]
REG[DST] ⇐ REG[SRC]
REG[SRC] ⇐ REG[15]
Flags: None.
Bitwise exclusive disjunction.
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 0 | 1 | 1 |
REG[DST] ⇐ REG[DST] ^ REG[SRC]
Flags: N, and Z.
The INTS input line to the CPU is used to signal an interrupt (active high). The CPU will poll this input as the final stage of instruction execution. If the input is active then the CPU will branch to address zero. Before branching the current contents of the PC and PSR registers are pushed onto the stack. To resume execution the RTI instruction should be executed. Currently interrupts are not actually disabled via the EI status bit. This was omitted to save time.
The top-level module merely connects the control unit and the datapath.
module cpu (MEMA, MEMD, MWR, INTS, RESETn, CLK);
output [15:0] MEMA; // Memory Address.
output [15:0] MEMD; // Memory Data out.
output MWR; // Memory WRite.
input INTS; // INTerrupt Signal.
input RESETn; // System reset.
input CLK; // System clock.
wire [15:0] SHA; // SHift Amount.
wire [4:0] FS; // Function unit Selector.
wire [3:0] MO; // Misc. Operation.
wire [3:0] DST; // DST register address.
wire [4:0] DSA; // D and A register address.
wire [3:0] SRC; // SRC register address.
wire [4:0] SB; // B register address.
wire [1:0] MA; // Multipexer A selector.
wire [1:0] MB; // Multipexer B selector.
wire MD; // Multipexer D selector.
wire [15:0] PC; // Program Counter.
wire [15:0] SP; // Stack Pointer.
wire [15:0] DBUS; // Bus D.
wire RL; // Register file Load.
wire MSC; // MicroStatus Carry bit.
wire MSN; // MicroStatus Negative bit.
wire MSV; // MicroStatus oVerflow bit.
wire MSZ; // MicroStatus Zero bit.
wire C; // ISA Carry status bit.
wire N; // ISA Negative status bit.
wire V; // ISA oVerflow status bit.
wire Z; // ISA Zero status bit.
wire EI; // ISA Enable Interrupts status bit.
control_unit cu0(SHA, MWR, FS, MO, DST, DSA, SRC, SB, MA, MB, MD, PC, SP, RL, DBUS, INTS, MSC, MSN, MSV, MSZ, C, N, V, Z, EI, RESETn, CLK);
datapath d0(MEMA, MEMD, DBUS, EI, C, N, V, Z, MSC, MSN, MSV, MSZ, FS, MO, PC, SP, RL, DST, DSA, SRC, SB, MA, MB, MD, SHA, RESETn, CLK);
endmodule // cpu
The top-level datapath module is just a container for the register file, the function unit, and the status registers.
module datapath(MEMA, MEMD,
DBUS,
EI, Cout, Nout, Vout, Zout,
MCout, MNout, MVout, MZout,
Op,
MO,
PC, SP, RL, DST, DSA, SRC, SB, MAS, MBS, MDS, SHA, RESETn, CLK);
output [15:0] MEMA; // Memory Address.
inout [15:0] MEMD; // Memory Data.
output [15:0] DBUS; // D BUS.
output EI; // Processor Enable Interrupts status bit.
output Cout; // Processor Carry status bit.
output Nout; // Processor Minus status bit.
output Vout; // Processor oVerflow status bit.
output Zout; // Processor Zero status bit.
output MCout; // Microstatus Carry status bit.
output MNout; // Microstatus Negative status bit.
output MVout; // Microstatus oVerflow status bit.
output MZout; // Microstatus Zero status bit.
input [15:0] PC; // Program Counter contents.
input [15:0] SP; // Stack Pointer contents.
input [4:0] Op; // Function unit operation.
input [3:0] MO; // Misc. Operation.
input RL; // Register Load.
input [3:0] DST; // Address of D reg and A reg from instruction with prepended 0 bit.
input [4:0] DSA; // Address of D reg and A reg from microinstruction.
input [3:0] SRC; // Address of A reg from instruction with prepended 0 bit.
input [4:0] SB; // Address of B reg from microinstruction.
input [1:0] MAS; // Mux A select.
input [1:0] MBS; // Mux B select.
input MDS; // Mux D select.
input [15:0] SHA; // SHift Amount.
input RESETn; // System reset.
input CLK; // System clock.
wire [15:0] CST; // Constant from micro instruction via zero fill.
wire [15:0] PSR; // 16-bit version of PSR bits.
wire [15:0] RFA; // Connections to the register file for bus A.
wire [15:0] RFB; // Connections to the register file for bus B.
wire [15:0] A; // Bus A.
wire [15:0] B; // Bus B.
wire [15:0] Y; // ALU output.
assign MEMA = A; // Address bus (bus A).
assign MEMD = (MDS == 1'b0) ? B : 16'bz; // Bus D input or output.
zero_fill zf1(CST, SB); // CST goes into muxB.
zero_fill zf2(PSR, {EI, Cout, Nout, Vout, Zout}); // PSR goes into muxB.
register_file rf(RFA, RFB, DBUS, DST, DSA, SRC, SB, RL, CLK); // RFA goes into muxA, RFB goes into muxB.
multiplexer_4_1 muxA(A, RFA, PC, SP, RFB, MAS[1], MAS[0]); // Bus A. This goes to MEM/IO as MEMA and into fu.
multiplexer_4_1 muxB(B, RFB, PSR, CST, SHA, MBS[1], MBS[0]); // Bus B. This goes to MEM/IO as MEMD and into fu.
function_unit fu(Y, C, V, N, Z, A, B, Cout, Op, MO); // Y goes to muxD.
psr regPSR(EI, Cout, Nout, Vout, Zout, DBUS, C, N, V, Z, MO, RESETn, CLK); // Status bits go to the control unit, function unit, and into zf2.
msts regMSTS(MCout, MNout, MVout, MZout, C, N, V, Z, MO, RESETn, CLK); // Microstatus bits go to the control unit.
multiplexer_2_1 muxD(DBUS, Y, MEMD, MDS); // Bus D. This goes to the register file and the control unit.
endmodule // datapath
The PSR is the Processor Status Register. It contains the status bits from the ALU: C, N, V, and Z, along with the EI status bit which Enables Interrupts (currently unused). The MO (Misc. Operation) input determines which status bits are updated.
MO | Meaning |
---|---|
0000 | NOP |
0001 | INACK = 1 (Acknowledge interrupt) |
0010 | Memory write (prevent write to register file) |
0011 | Load PC (prevent write to register file) |
0100 | Load IR and increment PC (prevent write to register file) |
0101 | Increment PC |
0110 | Load PSR (prevent write to register file) |
0111 | Load SP (prevent write to register file) |
1000 | Decrement SP |
1001 | Decrement SP and memory write (prevent write to register file) |
1010 | Increment SP |
1011 | Select C as Cin for ALU and update PSR bits CNVZ as below |
1100 | Update PSR bits CNVZ |
1101 | Update PSR bits CZ |
1110 | Update PSR bits NZ |
1111 | Update MSTS bits CNVZ |
module psr(EI, Cout, Nout, Vout, Zout, D, C, N, V, Z, MO, RESETn, CLK);
output EI; // Enable Interrupt status bit output.
output Cout; // Carry status bit output.
output Nout; // Negative status bit output.
output Vout; // oVerflow status bit output.
output Zout; // Zero status bit output.
input [15:0] D; // Data from bus D.
input C; // Carry status bit from ALU.
input N; // Negative status bit from ALU.
input V; // oVerflow status bit from ALU.
input Z; // Zero status bit from ALU.
input [3:0] MO; // Misc. Operation.
input RESETn; // Reset active low.
input CLK; // System clock.
wire [15:0] Q;
wire [15:0] RD;
wire [15:0] RDMO;
wire [15:0] QCNVZ, QCZ, QNZ;
assign EI = Q[4];
assign Zout = Q[3];
assign Vout = Q[2];
assign Nout = Q[1];
assign Cout = Q[0];
assign QCNVZ = (Q & 16'hfff0) | {Z, V, N, C};
assign QCZ = (Q & 16'hfff6) | {Z, 1'b0, 1'b0, C};
assign QNZ = (Q & 16'hfff5) | {Z, 1'b0, N, 1'b0};
multiplexer_16_1 mRD0(RDMO, Q, Q, Q, Q, Q, Q, D, Q, Q, Q, Q, QCNVZ, QCNVZ, QCZ, QNZ, Q, MO);
multiplexer_2_1 mRD1(RD, 16'h0000, RDMO, RESETn); // Handle resets.
register_parallel_load r(Q, RD, 1'b1, CLK);
endmodule // psr
The MSTS register is the Microprogram STatuS. Essentially this register holds the C, N, V, and Z status bits from the ALU, and it is updated when the microcode executes ALU operations. With two registers, MSTS and PSR, we are free to use the ALU in our microprograms without interfering with the PSR. The MO (Misc. Operation) determines if the bits are to be updated or not.
MO | Meaning |
---|---|
0000 | NOP |
0001 | INACK = 1 (Acknowledge interrupt) |
0010 | Memory write (prevent write to register file) |
0011 | Load PC (prevent write to register file) |
0100 | Load IR and increment PC (prevent write to register file) |
0101 | Increment PC |
0110 | Load PSR (prevent write to register file) |
0111 | Load SP (prevent write to register file) |
1000 | Decrement SP |
1001 | Decrement SP and memory write (prevent write to register file) |
1010 | Increment SP |
1011 | Select C as Cin for ALU and update PSR bits CNVZ as below |
1100 | Update PSR bits CNVZ |
1101 | Update PSR bits CZ |
1110 | Update PSR bits NZ |
1111 | Update MSTS bits CNVZ |
module msts(Cout, Nout, Vout, Zout, C, N, V, Z, MO, RESETn, CLK);
output Cout; // Carry status bit output.
output Nout; // Negative status bit output.
output Vout; // oVerflow status bit output.
output Zout; // Zero status bit output.
input C; // Carry status bit from ALU.
input N; // Negative status bit from ALU.
input V; // oVerflow status bit from ALU.
input Z; // Zero status bit from ALU.
input [3:0] MO; // Misc. Operation.
input RESETn; // Reset active low.
input CLK; // System clock.
wire [15:0] Q;
wire [15:0] RD;
wire [15:0] RDMO;
wire [15:0] QCNVZ;
wire S;
assign Zout = Q[3];
assign Vout = Q[2];
assign Nout = Q[1];
assign Cout = Q[0];
assign QCNVZ = (Q & 16'hfff0) | {Z, V, N, C};
and(S, MO[3], MO[2], MO[1], MO[0]); // Update when MO = 4'b1111
multiplexer_2_1 mRD0(RDMO, Q, QCNVZ, S);
multiplexer_2_1 mRD1(RD, 16'h0000, RDMO, RESETn); // Handle resets.
register_parallel_load r(Q, RD, 1'b1, CLK);
endmodule // msts
The zero fill module is used to zero extend the immediate data constant from the control unit and the PSR register contents to 16 bits so that they can be injected into the datapath.
module zero_fill(Y, A);
output [15:0] Y; // Result value zero filled.
input [4:0] A; // Value to fill.
assign Y[0] = A[0];
assign Y[1] = A[1];
assign Y[2] = A[2];
assign Y[3] = A[3];
assign Y[4] = A[4];
assign Y[15:5] = 11'b00000000000;
endmodule // zero_fill
The register file comprises 16 registers. Register 0 is always zero so it isn't really a register. DST and SRC are fields in the instruction used to address registers. These fields are 3 bits wide so the instruction can address the first 8 registers. However, when passed to the register file, these addresses have a 0 bit prepended to them to make the address 4 bits. DSA and SB are fields of the microinstruction. Bit 4 of these fields select between the microinstruction register or the instruction register (see muxda and muxb). Only one of DSA or SB can have bit 4 set. The one that has bit 4 set uses bit 3 to make the instruction field DST or SRC the destination or source (see muxs and muxaddr). DAA is the A and D bus register addresses. BA is the B bus register address.
DSA[4] | DSA[3] | SB[4] | SB[3] | DAA | BA |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | DSA[3:0] | SB[3:0] |
0 | 0 | 0 | 1 | DSA[3:0] | SB[3:0] |
0 | 0 | 1 | 0 | DSA[3:0] | DST |
0 | 0 | 1 | 1 | DSA[3:0] | SRC |
0 | 1 | 0 | 0 | DSA[3:0] | SB[3:0] |
0 | 1 | 0 | 1 | DSA[3:0] | SB[3:0] |
0 | 1 | 1 | 0 | DSA[3:0] | DST |
0 | 1 | 1 | 1 | DSA[3:0] | SRC |
1 | 0 | 0 | 0 | DST | SB[3:0] |
1 | 0 | 0 | 1 | DST | SB[3:0] |
1 | 0 | 1 | 0 | XXX | XXX |
1 | 0 | 1 | 1 | XXX | XXX |
1 | 1 | 0 | 0 | SRC | SB[3:0] |
1 | 1 | 0 | 1 | SRC | SB[3:0] |
1 | 1 | 1 | 0 | XXX | XXX |
1 | 1 | 1 | 1 | XXX | XXX |
module register_file(A, B, D, DST, DSA, SRC, SB, Load, CLK);
output [15:0] A; // Data contents of A reg.
output [15:0] B; // Data contents of B reg.
input [15:0] D; // Data to load into D reg from bus D.
input [3:0] DST; // Address of D reg and A reg from instruction with prepended 0 bit.
input [4:0] DSA; // Address of D reg and A reg from microinstruction.
input [3:0] SRC; // Address of A reg from instruction with prepended 0 bit.
input [4:0] SB; // Address of B reg from microinstruction.
input Load; // Enable loading of D reg - active high.
input CLK; // Clock.
wire [3:0] DAA; // Address of A reg and D reg.
wire [3:0] BA; // Address of B reg.
wire [3:0] ADDR; // Address of either A reg and D reg, or of B reg.
wire SADDR; // Selector for muxaddr.
registers reggies(A, B, D, DAA, BA, DAA, Load, CLK);
multiplexer_2_1 #(1)muxS(SADDR, DSA[3], SB[3], SB[4]);
multiplexer_2_1 #(4)muxAddr(ADDR, DST, SRC, SADDR);
multiplexer_2_1 #(4)muxdA(DAA, DSA[3:0], ADDR, DSA[4]);
multiplexer_2_1 #(4)muxB(BA, SB[3:0], ADDR, SB[4]);
endmodule // register_file
/*
* 16 x 16-bit registers with register 0 always containing zero.
*/
module registers(A, B, D, AA, BA, DA, Load, CLK);
output [15:0] A; // Data contents of A reg.
output [15:0] B; // Data contents of B reg.
input [15:0] D; // Data to load into D reg.
input [3:0] AA; // Address of A reg.
input [3:0] BA; // Address of B reg.
input [3:0] DA; // Address of D reg.
input Load; // Enable loading of D reg - active high.
input CLK; // Clock.
wire [15:0] Q1, Q2, Q3, Q4, Q5, Q6, Q7;
wire [15:0] Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15;
wire dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7;
wire dr8, dr9, dr10, dr11, dr12, dr13, dr14, dr15;
wire load1, load2, load3, load4, load5, load6, load7;
wire load8, load9, load10, load11, load12, load13, load14, load15;
multiplexer_16_1 muxa(A, 16'h0000, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, AA);
multiplexer_16_1 muxb(B, 16'h0000, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, BA);
// Note: dr0 is unused.
hex_decoder decd(dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7, dr8, dr9, dr10, dr11, dr12, dr13, dr14, dr15, DA[3], DA[2], DA[1], DA[0], 1'b1);
and(load1, dr1, Load);
and(load2, dr2, Load);
and(load3, dr3, Load);
and(load4, dr4, Load);
and(load5, dr5, Load);
and(load6, dr6, Load);
and(load7, dr7, Load);
and(load8, dr8, Load);
and(load9, dr9, Load);
and(load10, dr10, Load);
and(load11, dr11, Load);
and(load12, dr12, Load);
and(load13, dr13, Load);
and(load14, dr14, Load);
and(load15, dr15, Load);
register_parallel_load r1(Q1, D, load1, CLK);
register_parallel_load r2(Q2, D, load2, CLK);
register_parallel_load r3(Q3, D, load3, CLK);
register_parallel_load r4(Q4, D, load4, CLK);
register_parallel_load r5(Q5, D, load5, CLK);
register_parallel_load r6(Q6, D, load6, CLK);
register_parallel_load r7(Q7, D, load7, CLK);
register_parallel_load r8(Q8, D, load8, CLK);
register_parallel_load r9(Q9, D, load9, CLK);
register_parallel_load r10(Q10, D, load10, CLK);
register_parallel_load r11(Q11, D, load11, CLK);
register_parallel_load r12(Q12, D, load12, CLK);
register_parallel_load r13(Q13, D, load13, CLK);
register_parallel_load r14(Q14, D, load14, CLK);
register_parallel_load r15(Q15, D, load15, CLK);
endmodule // registers
module register_parallel_load(Q, D, Load, CLK);
output [15:0] Q;
input [15:0] D;
input Load;
input CLK;
wire Loadn;
wire w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12; // Connecting wires.
wire w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24; // Connecting wires.
wire w25, w26, w27, w28, w29, w30, w31, w32, w33, w34, w35, w36; // Connecting wires.
wire w37, w38, w39, w40, w41, w42, w43, w44, w45, w46, w47, w48; // Connecting wires.
wire [15:0] Qn; // Unused.
not(Loadn, Load);
and(w1, Q[0], Loadn);
and(w2, D[0], Load);
or(w3, w2, w1);
and(w4, Q[1], Loadn);
and(w5, D[1], Load);
or(w6, w5, w4);
and(w7, Q[2], Loadn);
and(w8, D[2], Load);
or(w9, w8, w7);
and(w10, Q[3], Loadn);
and(w11, D[3], Load);
or(w12, w11, w10);
and(w13, Q[4], Loadn);
and(w14, D[4], Load);
or(w15, w14, w13);
and(w16, Q[5], Loadn);
and(w17, D[5], Load);
or(w18, w17, w16);
and(w19, Q[6], Loadn);
and(w20, D[6], Load);
or(w21, w20, w19);
and(w22, Q[7], Loadn);
and(w23, D[7], Load);
or(w24, w23, w22);
and(w25, Q[8], Loadn);
and(w26, D[8], Load);
or(w27, w26, w25);
and(w28, Q[9], Loadn);
and(w29, D[9], Load);
or(w30, w29, w28);
and(w31, Q[10], Loadn);
and(w32, D[10], Load);
or(w33, w32, w31);
and(w34, Q[11], Loadn);
and(w35, D[11], Load);
or(w36, w35, w34);
and(w37, Q[12], Loadn);
and(w38, D[12], Load);
or(w39, w38, w37);
and(w40, Q[13], Loadn);
and(w41, D[13], Load);
or(w42, w41, w40);
and(w43, Q[14], Loadn);
and(w44, D[14], Load);
or(w45, w44, w43);
and(w46, Q[15], Loadn);
and(w47, D[15], Load);
or(w48, w47, w46);
d_flip_flop_edge_triggered dff0(Q[0], Qn[0], CLK, w3);
d_flip_flop_edge_triggered dff1(Q[1], Qn[1], CLK, w6);
d_flip_flop_edge_triggered dff2(Q[2], Qn[2], CLK, w9);
d_flip_flop_edge_triggered dff3(Q[3], Qn[3], CLK, w12);
d_flip_flop_edge_triggered dff4(Q[4], Qn[4], CLK, w15);
d_flip_flop_edge_triggered dff5(Q[5], Qn[5], CLK, w18);
d_flip_flop_edge_triggered dff6(Q[6], Qn[6], CLK, w21);
d_flip_flop_edge_triggered dff7(Q[7], Qn[7], CLK, w24);
d_flip_flop_edge_triggered dff8(Q[8], Qn[8], CLK, w27);
d_flip_flop_edge_triggered dff9(Q[9], Qn[9], CLK, w30);
d_flip_flop_edge_triggered dff10(Q[10], Qn[10], CLK, w33);
d_flip_flop_edge_triggered dff11(Q[11], Qn[11], CLK, w36);
d_flip_flop_edge_triggered dff12(Q[12], Qn[12], CLK, w39);
d_flip_flop_edge_triggered dff13(Q[13], Qn[13], CLK, w42);
d_flip_flop_edge_triggered dff14(Q[14], Qn[14], CLK, w45);
d_flip_flop_edge_triggered dff15(Q[15], Qn[15], CLK, w48);
endmodule // register_parallel_load
module d_flip_flop_edge_triggered(Q, Qn, C, D);
output Q;
output Qn;
input C;
input D;
wire Cn; // Control input to the D latch.
wire Cnn; // Control input to the SR latch.
wire DQ; // Output from the D latch, inputs to the gated SR latch.
wire DQn; // Output from the D latch, inputs to the gated SR latch.
not(Cn, C);
not(Cnn, Cn);
d_latch dl(DQ, DQn, Cn, D);
sr_latch_gated sr(Q, Qn, Cnn, DQ, DQn);
endmodule // d_flip_flop_edge_triggered
module d_latch(Q, Qn, G, D);
output Q;
output Qn;
input G;
input D;
wire Dn;
wire D1;
wire Dn1;
not(Dn, D);
and(D1, G, D);
and(Dn1, G, Dn);
nor(Qn, D1, Q);
nor(Q, Dn1, Qn);
endmodule // d_latch
module sr_latch_gated(Q, Qn, G, S, R);
output Q;
output Qn;
input G;
input S;
input R;
wire S1;
wire R1;
and(S1, G, S);
and(R1, G, R);
nor(Qn, S1, Q);
nor(Q, R1, Qn);
endmodule // sr_latch_gated
module hex_decoder(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, A3, A2, A1, A0, E);
output X0; // Minterm 0
output X1; // Minterm 1
output X2; // Minterm 2
output X3; // Minterm 3
output X4; // Minterm 4
output X5; // Minterm 5
output X6; // Minterm 6
output X7; // Minterm 7
output X8; // Minterm 8
output X9; // Minterm 9
output X10; // Minterm 10
output X11; // Minterm 11
output X12; // Minterm 12
output X13; // Minterm 13
output X14; // Minterm 14
output X15; // Minterm 15
input A3; // Input binary code most significant bit
input A2;
input A1;
input A0; // Input binary code least significant bit
input E; // Enable signal
wire A3n; // A3 negated
wire A2n; // A2 negated
wire A1n; // A1 negated
wire A0n; // A0 negated
not(A3n, A3);
not(A2n, A2);
not(A1n, A1);
not(A0n, A0);
and(X0, A3n, A2n, A1n, A0n, E); // Minterm 0: 0000
and(X1, A3n, A2n, A1n, A0, E); // Minterm 1: 0001
and(X2, A3n, A2n, A1, A0n, E); // Minterm 2: 0010
and(X3, A3n, A2n, A1, A0, E); // Minterm 3: 0011
and(X4, A3n, A2, A1n, A0n, E); // Minterm 4: 0100
and(X5, A3n, A2, A1n, A0, E); // Minterm 5: 0101
and(X6, A3n, A2, A1, A0n, E); // Minterm 6: 0110
and(X7, A3n, A2, A1, A0, E); // Minterm 7: 0111
and(X8, A3, A2n, A1n, A0n, E); // Minterm 8: 1000
and(X9, A3, A2n, A1n, A0, E); // Minterm 9: 1001
and(X10, A3, A2n, A1, A0n, E); // Minterm 10: 1010
and(X11, A3, A2n, A1, A0, E); // Minterm 11: 1011
and(X12, A3, A2, A1n, A0n, E); // Minterm 12: 1100
and(X13, A3, A2, A1n, A0, E); // Minterm 13: 1101
and(X14, A3, A2, A1, A0n, E); // Minterm 14: 1110
and(X15, A3, A2, A1, A0, E); // Minterm 15: 1111
endmodule // octal_decoder
This unit is similar to the one described in the function unit notes. The table shows all of the operations where A and B are inputs and Y is the output.
Op | Function |
---|---|
00000 | Addition |
00001 | Subtraction |
00010 | Increment |
00011 | Decrement |
00100 | Bitwise AND |
00101 | Bitwise OR |
00110 | Bitwise XOR |
00111 | Bitwise NOT |
10000 | Y = A |
11000 | Logical shift left |
10100 | Logical shift right |
11001 | Arithmetic shift left |
10101 | Arithmetic shift right |
11010 | Rotate left |
10110 | Rotate right |
11011 | Rotate left with carry |
10111 | Rotate right with carry |
111XX | Y = B |
The MO (Misc. Operation) input determines if the Cin (Carry input) bit is to be used.
MO | Meaning |
---|---|
0000 | NOP |
0001 | INACK = 1 (Acknowledge interrupt) |
0010 | Memory write (prevent write to register file) |
0011 | Load PC (prevent write to register file) |
0100 | Load IR and increment PC (prevent write to register file) |
0101 | Increment PC |
0110 | Load PSR (prevent write to register file) |
0111 | Load SP (prevent write to register file) |
1000 | Decrement SP |
1001 | Decrement SP and memory write (prevent write to register file) |
1010 | Increment SP |
1011 | Select C as Cin for ALU and update PSR bits CNVZ as below |
1100 | Update PSR bits CNVZ |
1101 | Update PSR bits CZ |
1110 | Update PSR bits NZ |
1111 | Update MSTS bits CNVZ |
module function_unit(Y, C, V, N, Z, A, B, Cin, Op, MO);
output [15:0] Y; // Bus D result.
output C; // Carry output.
output N; // Negative.
output V; // Overflow.
output Z; // Zero.
input [15:0] A; // Bus A operand.
input [15:0] B; // Bus B operand.
input Cin; // Carry input.
input [4:0] Op; // Operation.
input [3:0] MO; // Misc. Operation.
wire [15:0] Ya; // ALU result output.
wire [15:0] Ys; // Shifter result output.
wire Ca; // Carry out from the ALU.
wire Cs; // Carry out from the shifter.
wire Va; // oVerflow out from the ALU.
wire Vs; // oVerflow out from the shifter.
// MO = 4'b1011 then select C status bit as Cin for ALU.
wire CB; // ALU carry/borrow input
wire MO2n; // not(MO[2])
not(MO2n, MO[2]);
and(CB, MO[3], MO2n, MO[1], MO[0], Cin);
alu aluf(Ya, Ca, Va, A, B, CB, {Op[2], Op[1], Op[0]});
shifter shifterf(Ys, Cs, Vs, A, {Op[3], Op[2], Op[1], Op[0]}, Cin, B);
multiplexer_2_1 muxf(Y, Ya, Ys, Op[4]);
multiplexer_2_1 #(1) muxc(C, Ca, Vs, Op[3]);
multiplexer_2_1 #(1) muxv(V, Ca, Vs, Op[3]);
assign N = Y[15]; // Most significant bit is the sign bit in 2's complement.
zero z(Z, Y); // Zero status bit.
endmodule // function_unit
module zero(Z, A);
output Z; // Result.
input [15:0] A; // Operand.
wire [15:0] Y; // Temp result.
xnor(Y[0], A[0], 1'b0);
xnor(Y[1], A[1], 1'b0);
xnor(Y[2], A[2], 1'b0);
xnor(Y[3], A[3], 1'b0);
xnor(Y[4], A[4], 1'b0);
xnor(Y[5], A[5], 1'b0);
xnor(Y[6], A[6], 1'b0);
xnor(Y[7], A[7], 1'b0);
xnor(Y[8], A[8], 1'b0);
xnor(Y[9], A[9], 1'b0);
xnor(Y[10], A[10], 1'b0);
xnor(Y[11], A[11], 1'b0);
xnor(Y[12], A[12], 1'b0);
xnor(Y[13], A[13], 1'b0);
xnor(Y[14], A[14], 1'b0);
xnor(Y[15], A[15], 1'b0);
and(Z, Y[0], Y[1], Y[2], Y[3], Y[4],
Y[5], Y[6], Y[7], Y[8],
Y[9], Y[10], Y[11], Y[12],
Y[13], Y[14], Y[15]);
endmodule // zero
This unit is similar to the one described in the ALU notes. The table shows all of the operations.
S | Operation |
---|---|
000 | Addition |
001 | Subtraction |
010 | Increment |
011 | Decrement |
100 | Bitwise AND |
101 | Bitwise OR |
110 | Bitwise XOR |
111 | Bitwise NOT |
module alu(Y, C, V, A, B, CB, Op);
output [15:0] Y; // Bus D result.
output C; // Carry.
output V; // oVerflow.
input [15:0] A; // Bus A operand.
input [15:0] B; // Bus B operand.
input CB; // Carry/borrow.
input [2:0] Op; // Operation.
wire [15:0] AS, Inc, Dec, And, Or, Xor, Not;
wire s;
wire Varith, Vas, Vinc, Vdec;
wire Carith, Cas, Cinc, Cdec;
// The operations
carry_select_adder_subtractor addsub(AS, Cas, Vas, A, B, CB, Op[0]); // Op == 3'b000, 3'b001
carry_select_adder_subtractor inc(Inc, Cinc, Vinc, A, 16'h0001, 1'b0, 1'b0); // Op == 3'b010
carry_select_adder_subtractor dec(Dec, Cdec, Vdec, A, 16'h0001, 1'b0, 1'b1); // Op == 3'b011
andop aluand(And, A, B); // Op == 3'b100
orop aluor(Or, A, B); // Op == 3'b101
xorop aluxor(Xor, A, B); // Op == 3'b110
notop alunot(Not, A); // Op == 3'b111
multiplexer_8_1 muxy(Y, AS, AS, Inc, Dec, And, Or, Xor, Not, Op); // Select the result.
multiplexer_4_1 #(1)muxc(C, Cas, Cas, Cinc, Cdec, Op[1], Op[0]); // Select the carry.
multiplexer_4_1 #(1)muxv(V, Vas, Vas, Vinc, Vdec, Op[1], Op[0]); // Select the carry.
endmodule // alu
module andop(Y, A, B);
output [15:0] Y; // Result.
input [15:0] A; // Operand.
input [15:0] B; // Operand.
and(Y[0], A[0], B[0]);
and(Y[1], A[1], B[1]);
and(Y[2], A[2], B[2]);
and(Y[3], A[3], B[3]);
and(Y[4], A[4], B[4]);
and(Y[5], A[5], B[5]);
and(Y[6], A[6], B[6]);
and(Y[7], A[7], B[7]);
and(Y[8], A[8], B[8]);
and(Y[9], A[9], B[9]);
and(Y[10], A[10], B[10]);
and(Y[11], A[11], B[11]);
and(Y[12], A[12], B[12]);
and(Y[13], A[13], B[13]);
and(Y[14], A[14], B[14]);
and(Y[15], A[15], B[15]);
endmodule // andop
module orop(Y, A, B);
output [15:0] Y; // Result.
input [15:0] A; // Operand.
input [15:0] B; // Operand.
or(Y[0], A[0], B[0]);
or(Y[1], A[1], B[1]);
or(Y[2], A[2], B[2]);
or(Y[3], A[3], B[3]);
or(Y[4], A[4], B[4]);
or(Y[5], A[5], B[5]);
or(Y[6], A[6], B[6]);
or(Y[7], A[7], B[7]);
or(Y[8], A[8], B[8]);
or(Y[9], A[9], B[9]);
or(Y[10], A[10], B[10]);
or(Y[11], A[11], B[11]);
or(Y[12], A[12], B[12]);
or(Y[13], A[13], B[13]);
or(Y[14], A[14], B[14]);
or(Y[15], A[15], B[15]);
endmodule // orop
module xorop(Y, A, B);
output [15:0] Y; // Result.
input [15:0] A; // Operand.
input [15:0] B; // Operand.
xor(Y[0], A[0], B[0]);
xor(Y[1], A[1], B[1]);
xor(Y[2], A[2], B[2]);
xor(Y[3], A[3], B[3]);
xor(Y[4], A[4], B[4]);
xor(Y[5], A[5], B[5]);
xor(Y[6], A[6], B[6]);
xor(Y[7], A[7], B[7]);
xor(Y[8], A[8], B[8]);
xor(Y[9], A[9], B[9]);
xor(Y[10], A[10], B[10]);
xor(Y[11], A[11], B[11]);
xor(Y[12], A[12], B[12]);
xor(Y[13], A[13], B[13]);
xor(Y[14], A[14], B[14]);
xor(Y[15], A[15], B[15]);
endmodule // xorop
module notop(Y, A);
output [15:0] Y; // Result.
input [15:0] A; // Operand.
not(Y[0], A[0]);
not(Y[1], A[1]);
not(Y[2], A[2]);
not(Y[3], A[3]);
not(Y[4], A[4]);
not(Y[5], A[5]);
not(Y[6], A[6]);
not(Y[7], A[7]);
not(Y[8], A[8]);
not(Y[9], A[9]);
not(Y[10], A[10]);
not(Y[11], A[11]);
not(Y[12], A[12]);
not(Y[13], A[13]);
not(Y[14], A[14]);
not(Y[15], A[15]);
endmodule // notop
module carry_select_adder_subtractor(S, C, V, A, B, CB, Op);
output [15:0] S; // The 16-bit sum/difference.
output C; // The 1-bit carry/borrow status.
output V; // The 1-bit overflow status.
input CB; // The carry/borrow input.
input [15:0] A; // The 16-bit augend/minuend.
input [15:0] B; // The 16-bit addend/subtrahend.
input Op; // The operation: 0 => Add, 1=>Subtract.
wire C15; // The carry out bit of adder/subtractor, used to generate final carry/borrrow.
wire [15:0] Bx;
wire CBx;
// Looking at the truth table for not we see that
// B xor 0 = B, and
// B xor 1 = not(B).
// So, if Op==1 means we are subtracting, then
// adding A and B xor Op alog with setting the first
// carry bit to Op, will give us a result of
// A+B when Op==0, and A+not(B)+1 when Op==1.
// Note that not(B)+1 is the 2's complement of B, so
// this gives us subtraction.
xor(Bx[0], B[0], Op);
xor(Bx[1], B[1], Op);
xor(Bx[2], B[2], Op);
xor(Bx[3], B[3], Op);
xor(Bx[4], B[4], Op);
xor(Bx[5], B[5], Op);
xor(Bx[6], B[6], Op);
xor(Bx[7], B[7], Op);
xor(Bx[8], B[8], Op);
xor(Bx[9], B[9], Op);
xor(Bx[10], B[10], Op);
xor(Bx[11], B[11], Op);
xor(Bx[12], B[12], Op);
xor(Bx[13], B[13], Op);
xor(Bx[14], B[14], Op);
xor(Bx[15], B[15], Op);
xor(C, C15, Op); // Carry = C15 for addition, Carry = not(C15) for subtraction.
xor(CBx, CB, Op);
carry_select_adder csa(S, C15, V, A, Bx, CBx);
endmodule // carry_select_adder_subtractor
module carry_select_adder(S, C, V, A, B, Cin);
output [15:0] S; // The 16-bit sum.
output C; // The 1-bit carry.
output V; // The 1-bit overflow status.
input [15:0] A; // The 16-bit augend.
input [15:0] B; // The 16-bit addend.
input Cin; // The initial carry in.
wire [3:0] S1_0; // Nibble 1 sum output with carry input 0.
wire [3:0] S1_1; // Nibble 1 sum output with carry input 1.
wire [3:0] S2_0; // Nibble 2 sum output with carry input 0.
wire [3:0] S2_1; // Nibble 2 sum output with carry input 1.
wire [3:0] S3_0; // Nibble 3 sum output with carry input 0.
wire [3:0] S3_1; // Nibble 3 sum output with carry input 1.
wire C1_0; // Nibble 1 carry output with carry input 0.
wire C1_1; // Nibble 1 carry output with carry input 1.
wire C2_0; // Nibble 2 carry output with carry input 0.
wire C2_1; // Nibble 2 carry output with carry input 1.
wire C3_0; // Nibble 3 carry output with carry input 0.
wire C3_1; // Nibble 3 carry output with carry input 1.
wire C0; // Nibble 0 carry output used to select multiplexer output.
wire C1; // Nibble 1 carry output used to select multiplexer output.
wire C2; // Nibble 2 carry output used to select multiplexer output.
wire V0; // Nibble 0 overflow output.
wire V1_0; // Nibble 1 overflow output with carry input 0.
wire V1_1; // Nibble 1 overflow output with carry input 1.
wire V2_0; // Nibble 2 overflow output with carry input 0.
wire V2_1; // Nibble 2 overflow output with carry input 1.
wire V3_0; // Nibble 3 overflow output with carry input 0.
wire V3_1; // Nibble 3 overflow output with carry input 1.
ripple_carry_adder rc_nibble_0(S[3:0], C0, V0, A[3:0], B[3:0], Cin); // Calculate S nibble 0.
ripple_carry_adder rc_nibble_1_carry_0(S1_0, C1_0, V1_0, A[7:4], B[7:4], 1'b0); // Calculate S nibble 1 with carry input 0.
ripple_carry_adder rc_nibble_1_carry_1(S1_1, C1_1, V1_1, A[7:4], B[7:4], 1'b1); // Calculate S nibble 1 with carry input 1.
ripple_carry_adder rc_nibble_2_carry_0(S2_0, C2_0, V2_0, A[11:8], B[11:8], 1'b0); // Calculate S nibble 2 with carry input 0.
ripple_carry_adder rc_nibble_2_carry_1(S2_1, C2_1, V2_1, A[11:8], B[11:8], 1'b1); // Calculate S nibble 2 with carry input 1.
ripple_carry_adder rc_nibble_3_carry_0(S3_0, C3_0, V3_0, A[15:12], B[15:12], 1'b0); // Calculate S nibble 3 with carry input 0.
ripple_carry_adder rc_nibble_3_carry_1(S3_1, C3_1, V3_1, A[15:12], B[15:12], 1'b1); // Calculate S nibble 3 with carry input 1.
multiplexer_2_1 #(1) muxc1(C1, C1_0, C1_1, C0); // C0 selects the carry output for nibble 1.
multiplexer_2_1 #(1) muxc2(C2, C2_0, C2_1, C1); // C1 selects the carry output for nibble 2.
multiplexer_2_1 #(1) muxc(C, C3_0, C3_1, C2); // C2 selects the carry output for nibble 3 which is the global carry output.
multiplexer_2_1 #(1) muxv(V, V3_0, V3_1, C2); // C2 selects the overflow output for nibble 3 which is the global overflow output.
multiplexer_2_1 #(4) muxs1(S[7:4], S1_0, S1_1, C0); // C0 selects the result for nibble 1.
multiplexer_2_1 #(4) muxs2(S[11:8], S2_0, S2_1, C1); // C1 selects the result for nibble 2.
multiplexer_2_1 #(4) muxs3(S[15:12], S3_0, S3_1, C2); // C2 selects the result for nibble 3.
endmodule // carry_select_adder
module ripple_carry_adder(S, C, V, A, B, Cin);
output [3:0] S; // The 4-bit sum.
output C; // The 1-bit carry.
output V; // The 1-bit overflow status.
input [3:0] A; // The 4-bit augend.
input [3:0] B; // The 4-bit addend.
input Cin; // The carry input.
wire C0; // The carry out bit of fa0, the carry in bit of fa1.
wire C1; // The carry out bit of fa1, the carry in bit of fa2.
wire C2; // The carry out bit of fa2, the carry in bit of fa3.
full_adder fa0(S[0], C0, A[0], B[0], Cin); // Least significant bit.
full_adder fa1(S[1], C1, A[1], B[1], C0);
full_adder fa2(S[2], C2, A[2], B[2], C1);
full_adder fa3(S[3], C, A[3], B[3], C2); // Most significant bit.
xor(V, C, C2); // Overflow
endmodule // ripple_carry_adder
module full_adder(S, Cout, A, B, Cin);
output S;
output Cout;
input A;
input B;
input Cin;
wire w1;
wire w2;
wire w3;
wire w4;
xor(w1, A, B);
xor(S, Cin, w1);
and(w2, A, B);
and(w3, A, Cin);
and(w4, B, Cin);
or(Cout, w2, w3, w4);
endmodule // full_adder
The shifter is a basic design which shifts/rotates only one place. The functions are given in the following table:
S | Function |
---|---|
0000 | Y = A |
1000 | logical shift left |
0100 | logical shift right |
1001 | arithmetic shift left |
0101 | arithmetic shift right |
1010 | rotate left |
0110 | rotate right |
1011 | rotate left with carry |
0111 | rotate right with carry |
11XX | Y = B |
module shifter(Y, Cout, V, A, S, Cin, B);
output [15:0] Y; // The bus D result.
output Cout; // The carry result.
output V; // The oVerflow result.
input [15:0] A; // The value to be shifted from bus A.
input [3:0] S; // The shift function.
input Cin; // The carry input.
input [15:0] B; // The input value from bus B. (passed through in a register to register move).
wire L; // The bit to shift in to the LSB when shifting left.
wire R; // The bit to shift in to the MSB when shifting right.
multiplexer_4_1 #(1) muxL(L, 1'b0, 1'b0, A[15], Cin, S[1], S[0]);
multiplexer_4_1 #(1) muxR(R, 1'b0, A[15], A[0], Cin, S[1], S[0]);
multiplexer_2_1 #(1) muxC(Cout, A[0], A[15], S[3]); // Chose the Cout bit depending on direction.
shifter_16 basic_shifter(Y, A, S[3:2], L, R, B);
xor(V, Y[15], A[15]); // oVerflow if the sign bits are different.
endmodule
module shifter_16(Y, A, S, L, R, B);
output [15:0] Y; // The shifted result.
input [15:0] A; // The value to be shifted.
input [1:0] S; // The direction of the shift.
input L; // The bit to shift in to the LSB when shifting left.
input R; // The bit to shift in to the MSB when shifting right.
input [15:0] B; // The input value from bus B. (passed through in a register to register move).
multiplexer_4_1 #(1) mux0(Y[0], A[0], A[1], L, B[0], S[1], S[0]);
multiplexer_4_1 #(1) mux1(Y[1], A[1], A[2], A[0], B[1], S[1], S[0]);
multiplexer_4_1 #(1) mux2(Y[2], A[2], A[3], A[1], B[2], S[1], S[0]);
multiplexer_4_1 #(1) mux3(Y[3], A[3], A[4], A[2], B[3], S[1], S[0]);
multiplexer_4_1 #(1) mux4(Y[4], A[4], A[5], A[3], B[4], S[1], S[0]);
multiplexer_4_1 #(1) mux5(Y[5], A[5], A[6], A[4], B[5], S[1], S[0]);
multiplexer_4_1 #(1) mux6(Y[6], A[6], A[7], A[5], B[6], S[1], S[0]);
multiplexer_4_1 #(1) mux7(Y[7], A[7], A[8], A[6], B[7], S[1], S[0]);
multiplexer_4_1 #(1) mux8(Y[8], A[8], A[9], A[7], B[8], S[1], S[0]);
multiplexer_4_1 #(1) mux9(Y[9], A[9], A[10], A[8], B[9], S[1], S[0]);
multiplexer_4_1 #(1) mux10(Y[10], A[10], A[11], A[9], B[10], S[1], S[0]);
multiplexer_4_1 #(1) mux11(Y[11], A[11], A[12], A[10], B[11], S[1], S[0]);
multiplexer_4_1 #(1) mux12(Y[12], A[12], A[13], A[11], B[12], S[1], S[0]);
multiplexer_4_1 #(1) mux13(Y[13], A[13], A[14], A[12], B[13], S[1], S[0]);
multiplexer_4_1 #(1) mux14(Y[14], A[14], A[15], A[13], B[14], S[1], S[0]);
multiplexer_4_1 #(1) mux15(Y[15], A[15], R, A[14], B[15], S[1], S[0]);
endmodule // shifter_16
The control unit is the most complicated part of the CPU. This particular control unit is microprogrammed and there is some decoding performed in this module. The microinstructions have the following format:
Microinstrucion | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MC | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
00,01,10 | MC | MM | MR | DSA | SB | MA | MB | MD | FS | MO | ||||||||||||||||||||||
11 | MC | LS | PS | MS | NA | MO |
The generation of the MWR (Memory WRite) and RL (Register Load) output signals depends upon the MO (Misc. Operation) field of the microinstruction.
MO | Meaning |
---|---|
0000 | NOP |
0001 | INACK = 1 (Acknowledge interrupt) |
0010 | Memory write (prevent write to register file) |
0011 | Load PC (prevent write to register file) |
0100 | Load IR and increment PC (prevent write to register file) |
0101 | Increment PC |
0110 | Load PSR (prevent write to register file) |
0111 | Load SP (prevent write to register file) |
1000 | Decrement SP |
1001 | Decrement SP and memory write (prevent write to register file) |
1010 | Increment SP |
1011 | Select C as Cin for ALU and update PSR bits CNVZ as below |
1100 | Update PSR bits CNVZ |
1101 | Update PSR bits CZ |
1110 | Update PSR bits NZ |
1111 | Update MSTS bits CNVZ |
Instructions are also decoded in the control unit. The instructions have the following format:
Instruction | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Type | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Generic format | Opcode | Mode | S | SRC | DST | |||||||||||
Zero operands | 0 | 0 | X | X | X | X | ||||||||||
One operand | 0 | 1 | X | X | X | X | Mode | S | SHA | DST | ||||||
Two operands | 1 | 0 | X | X | X | X | Mode | S | SRC | DST | ||||||
Branch | 1 | 1 | X | X | X | X | Mode | S | DST |
module control_unit(SHA, MWR, FS, MO, DST, DSA, SRC, SB, MA, MB, MD, PC, SP, RL, DBUS, INTS, MSC, MSN, MSV, MSZ, C, N, V, Z, EI, RESETn, CLK);
output [15:0] SHA; // SHift Amount.
output MWR; // Memory WRite.
output [4:0] FS; // Function unit Selector.
output [3:0] MO; // Misc. Operation.
output [3:0] DST; // DST register address.
output [4:0] DSA; // D and A register address.
output [3:0] SRC; // SRC register address.
output [4:0] SB; // B register address.
output [1:0] MA; // Multipexer A selector.
output [1:0] MB; // Multipexer B selector.
output MD; // Multipexer D selector.
output [15:0] PC; // Program Counter.
output [15:0] SP; // Stack Pointer.
output RL; // Register file Load.
input [15:0] DBUS; // Datapath D bus input.
input INTS; // INTerrupt Signal.
input MSC; // MicroStatus Carry bit.
input MSN; // MicroStatus Negative bit.
input MSV; // MicroStatus oVerflow bit.
input MSZ; // MicroStatus Zero bit.
input C; // ISA Carry status bit.
input N; // ISA Negative status bit.
input V; // ISA oVerflow status bit.
input Z; // ISA Zero status bit.
input EI; // ISA Enable Interrupts status bit.
input RESETn; // System reset.
input CLK; // System clock.
wire [7:0] MROMA; // Mapping ROM Address.
wire [7:0] CROMA; // Control ROM Address.
wire [15:0] Instruction;
wire [30:0] Microinstruction;
// Control unit specific microinstruction fields.
wire [1:0] MC;
wire [1:0] MM;
wire [2:0] MR;
wire LS;
wire PS;
wire [3:0] MS;
wire [7:0] NA;
// The microsequencer can disable loads for branching instructions.
wire MSRL;
pc pc0(PC, DBUS, MO, RESETn, CLK);
ir ir0(Instruction, DBUS, MO, RESETn, CLK);
sp sp0(SP, DBUS, MO, RESETn, CLK);
instruction_decoder id0(MROMA, MR, MM, Instruction);
microsequencer m0(CROMA, MSRL, INTS, MSC, MSN, MSV, MSZ, C, N, V, Z, EI, NA, MS, PS, LS, MC, MROMA, RESETn, CLK);
control_rom cr0(Microinstruction, CROMA);
assign MC = Microinstruction[30:29];
assign MM = Microinstruction[28:27];
assign MR = Microinstruction[26:24];
assign DSA = Microinstruction[23:19];
assign SB = Microinstruction[18:14];
assign MA = Microinstruction[13:12];
assign MB = Microinstruction[11:10];
assign MD = Microinstruction[9];
assign FS = Microinstruction[8:4];
assign MO = Microinstruction[3:0];
assign LS = Microinstruction[28];
assign PS = Microinstruction[27];
assign MS = Microinstruction[26:23];
assign NA = Microinstruction[11:4];
assign SRC = {1'b0, Instruction[5:3]}; // Prepend a 0 bit.
assign DST = {1'b0, Instruction[2:0]}; // Prepend a 0 bit.
assign SHA = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0,Instruction[5:3]}; // Prepend a 12 0-bits.
/*
* Generate the MWR and RL signals.
*/
assign MWR = (MO == 4'b0010) || (MO == 4'b1001);
assign RL = MSRL && (MO != 4'b0010) && (MO != 4'b0010) && (MO != 4'b0011) && (MO != 4'b0100) && (MO != 4'b0110) && (MO != 4'b0111) && (MO != 4'b1001);
endmodule // control_unit
The program counter (PC) holds the address of the next instruction to be fetched from memory. The MO (Misc. Operation) input determines if the PC is to be loaded or incremented.
MO | Meaning |
---|---|
0000 | NOP |
0001 | INACK = 1 (Acknowledge interrupt) |
0010 | Memory write (prevent write to register file) |
0011 | Load PC (prevent write to register file) |
0100 | Load IR and increment PC (prevent write to register file) |
0101 | Increment PC |
0110 | Load PSR (prevent write to register file) |
0111 | Load SP (prevent write to register file) |
1000 | Decrement SP |
1001 | Decrement SP and memory write (prevent write to register file) |
1010 | Increment SP |
1011 | Select C as Cin for ALU and update PSR bits CNVZ as below |
1100 | Update PSR bits CNVZ |
1101 | Update PSR bits CZ |
1110 | Update PSR bits NZ |
1111 | Update MSTS bits CNVZ |
module pc(Q, Din, MO, RESETn, CLK);
output [15:0] Q; // Contents of the PC
input [15:0] Din; // New contents upon loading.
input [3:0] MO; // Misc. Operation.
input RESETn; // System reset.
input CLK; // System clock.
wire [15:0] D0, D1;
wire [15:0] Dinc; // Incremented PC.
wire Cinc; // Carry for increment operation.
wire Vinc; // oVerflow for increment operation.
carry_select_adder_subtractor inc(Dinc, Cinc, Vinc, Q, 16'h0001, 1'b0, 1'b0);
multiplexer_16_1 mux0(D0, Q, 16'h0000, Q, Din, Dinc, Dinc, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, MO); // 16'h0000 is the interrupt vector
multiplexer_2_1 mux1(D1, 16'h0000, D0, RESETn); // Handle resets.
register_parallel_load r1(Q, D1, 1'b1, CLK);
endmodule // pc
The Instruction Register (IR) holds the instruction that is currently being executed. The MO (Misc. Operation) input determines when the IR is loaded.
MO | Meaning |
---|---|
0000 | NOP |
0001 | INACK = 1 (Acknowledge interrupt) |
0010 | Memory write (prevent write to register file) |
0011 | Load PC (prevent write to register file) |
0100 | Load IR and increment PC (prevent write to register file) |
0101 | Increment PC |
0110 | Load PSR (prevent write to register file) |
0111 | Load SP (prevent write to register file) |
1000 | Decrement SP |
1001 | Decrement SP and memory write (prevent write to register file) |
1010 | Increment SP |
1011 | Select C as Cin for ALU and update PSR bits CNVZ as below |
1100 | Update PSR bits CNVZ |
1101 | Update PSR bits CZ |
1110 | Update PSR bits NZ |
1111 | Update MSTS bits CNVZ |
module ir(Q, Din, MO, RESETn, CLK);
output [15:0] Q; // Contents of the IR
input [15:0] Din; // New contents upon loading.
input [3:0] MO; // Misc. Operation.
input RESETn; // System reset.
input CLK; // System clock.
wire [15:0] D0, D1;
wire Load;
wire M03n, MO1n, MO0n;
not(MO3n, MO[3]);
not(MO1n, MO[1]);
not(MO0n, MO[0]);
and(Load, MO3n, MO[2], MO1n, MO0n);
multiplexer_2_1 mux1(D0, Q, Din, Load);
multiplexer_2_1 mux2(D1, 16'h0000, D0, RESETn); // Handle resets.
register_parallel_load r1(Q, D1, 1'b1, CLK);
endmodule // ir
The Stack Pointer (SP) is a counter which holds the address of the top of the processor stack. The MO (Misc. Operation) input determines the stack operation.
MO | Meaning |
---|---|
0000 | NOP |
0001 | INACK = 1 (Acknowledge interrupt) |
0010 | Memory write (prevent write to register file) |
0011 | Load PC (prevent write to register file) |
0100 | Load IR and increment PC (prevent write to register file) |
0101 | Increment PC |
0110 | Load PSR (prevent write to register file) |
0111 | Load SP (prevent write to register file) |
1000 | Decrement SP |
1001 | Decrement SP and memory write (prevent write to register file) |
1010 | Increment SP |
1011 | Select C as Cin for ALU and update PSR bits CNVZ as below |
1100 | Update PSR bits CNVZ |
1101 | Update PSR bits CZ |
1110 | Update PSR bits NZ |
1111 | Update MSTS bits CNVZ |
module sp(Q, Din, MO, RESETn, CLK);
output [15:0] Q; // Contents of the SP
input [15:0] Din; // New contents upon loading from bus D.
input [3:0] MO; // Misc. Operation.
input RESETn; // System reset.
input CLK; // System clock.
wire [15:0] D0, D1;
wire [15:0] Dinc; // Incremented SP.
wire Cinc; // Carry for increment operation (ignored).
wire Vinc; // oVerflow for increment operation (ignored).
wire [15:0] Ddec; // Decremented SP.
wire Cdec; // Carry for decrement operation (ignored).
wire Vdec; // oVerflow for decrement operation (ignored).
carry_select_adder_subtractor inc(Dinc, Cinc, Vinc, Q, 16'h0001, 1'b0, 1'b0);
carry_select_adder_subtractor dec(Ddec, Cdec, Vdec, Q, 16'h0001, 1'b0, 1'b1);
multiplexer_16_1 mux0(D0, Q, Q, Q, Q, Q, Q, Q, Din, Ddec, Ddec, Dinc, Q, Q, Q, Q, Q, MO);
multiplexer_2_1 mux1(D1, 16'hffff, D0, RESETn); // Handle resets.
register_parallel_load r1(Q, D1, 1'b1, CLK);
endmodule // sp
The generic form of the instruction along with the four different types of instruction is given in the table below.
Instruction | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Type | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Generic format | Opcode | Mode | S | SRC | DST | |||||||||||
Zero operands | 0 | 0 | X | X | X | X | ||||||||||
One operand | 0 | 1 | X | X | X | X | Mode | S | SHA | DST | ||||||
Two operands | 1 | 0 | X | X | X | X | Mode | S | SRC | DST | ||||||
Branch | 1 | 1 | X | X | X | X | Mode | S | DST |
The most significant two bits of the opcode give us the number of operands/type.
OPCODE[5:4] | Type |
---|---|
00 | 0 operand |
01 | 1 operand |
10 | 2 operand |
11 | branch |
The opcodes are as follows:
OPCODE[5:0] | Mnemonic |
---|---|
000000 | NOP |
000001 | PSHR |
000010 | POPR |
000011 | MVS |
000100 | RET |
000101 | RTI |
... | ... |
010000 | PUSH |
010001 | POP |
010010 | INC |
010011 | DEC |
010100 | NEG |
010101 | NOT |
010110 | SHR |
010111 | SHL |
011000 | ASR |
011001 | ASL |
011010 | ROR |
011011 | ROL |
011100 | RORC |
011101 | ROLC |
... | ... |
100000 | MOV |
100001 | XCHG |
100010 | ADD |
100011 | ADDC |
100100 | SUB |
100101 | SUBB |
100110 | MUL |
100111 | DIV |
101000 | CMP |
101001 | AND |
101010 | OR |
101011 | XOR |
... | ... |
110000 | JMP |
110001 | CALL |
110010 | BC |
110011 | BNC |
110100 | BN |
110101 | BNN |
110110 | BV |
110111 | BNV |
111000 | BZ |
111001 | BNZ |
... | ... |
The MODE field is decoded as follows:
MODE | Addressing mode |
---|---|
000 | Register |
001 | Register indirect |
010 | Immediate |
011 | Direct |
100 | Indexed |
101 | Indexed Indirect |
110 | Relative |
111 | Relative indirect |
The S field determines which of the two fields, SRC or DST, are subject to the addressing mode determined by MODE.
S | Meaning |
---|---|
0 | SRC is subject to addressing mode. |
1 | DST is subject to addressing mode. |
module instruction_decoder(A, MR, MM, Instruction);
output [7:0] A; // ROM output.
input [2:0] MR; // ROM address bits.
input [1:0] MM; // The muxM selector.
input [15:0] Instruction; // The instruction to be decoded.
wire [3:0] M0; // The muxM output.
multiplexer_4_1 #(4) muxM(M0, {Instruction[15:14], 1'b0, 1'b0}, Instruction[13:10], Instruction[9:6], Instruction[9:6], MM[1], MM[0]);
mapping_rom rom0(A, {MM, MR, M0});
endmodule // instruction_decoder
The microsequencer is driven by the microinstruction fields, the CAR register, and the MSTS register. The MS field of the microinstruction is used when branching.
MS | Meaning |
---|---|
0000 | Unconditional branch. |
0001 | Branch if C status bit set. |
0010 | Branch if N status bit set. |
0011 | Branch if V status bit set. |
0100 | Branch if Z status bit set. |
0101 | Branch if EI status bit set. |
0110 | Branch if C microstatus bit set. |
0111 | Branch if N microstatus bit set. |
1000 | Branch if V microstatus bit set. |
1001 | Branch if Z microstatus bit set. |
1010 | Branch if interrupt. |
1011 | Unused. |
1100 | Unused. |
1101 | Unused. |
1110 | Unused. |
1111 | Unused. |
The PS field of the microinstruction determines how we check for a branch condition. If PS==0 then the status bit is passed unchanged, otherwise, when PS==1, the status bit is complemented. The wire ST has the following meaning where NA is a microinstruction field meaning Next Address.
ST | Meaning |
---|---|
0 | No branch so continue at A+1. |
1 | Branch to NA. |
The MC microinstruction field is interpreted as follows:
MC | Meaning |
---|---|
00 | Increment CAR. |
01 | Return from subroutine. |
10 | Map instruction into CAR. |
11 | Branch or call. |
module microsequencer(A, RL, INTS, MSC, MSN, MSV, MSZ, C, N, V, Z, EI, NA, MS, PS, LS, MC, MROMA, RESETn, CLK);
output [7:0] A; // Address of next microinstruction.
output RL; // Register Load signal for the register file.
input INTS; // Interrupt signal.
input MSC; // Microstatus Carry bit.
input MSN; // Microstatus Negative bit.
input MSV; // Microstatus oVerflow bit.
input MSZ; // Microstatus Zero bit.
input C; // ISA Carry bit.
input N; // ISA Negative bit.
input V; // ISA oVerflow bit.
input Z; // ISA Zero bit.
input EI; // ISA Enable Interrupts bit.
input [7:0] NA; // Next address.
input [3:0] MS; // MuxS selector.
input PS; // Pass Status bit. 0 => status bit unchanged, 1 => status bit complemented.
input LS; // Load SBR.
input [1:0] MC; // MuxC selector.
input [7:0] MROMA; // Mapping ROM Address.
input RESETn; // System clock.
input CLK; // System reset.
wire [7:0] C0; // Output from muxC.
wire [7:0] R0; // Output from muxR.
wire SO; // Output from muxS.
wire ST; // Processed status bit. This is the muxR selector.
wire [7:0] Ainc; // The incremented address output.
wire [7:0] SBR; // Output of the SRB register.
wire SBRLoad; // The load SBR signal.
multiplexer_16_1 #(1) muxS(S0, 1'b1, C, N, V, Z, EI, MSC, MSN, MSV, MSZ, INTS, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, MS);
/*
* Complement the status bit if necessary. ST == 1 => status condition met.
*/
xor(ST, S0, PS);
/*
* Increment the output address (A).
*/
incrementer_8 inc(Ainc, A);
multiplexer_2_1 #(8) muxR(R0, Ainc, NA, ST);
multiplexer_4_1 #(8) muxC(C0, Ainc, SBR, MROMA, R0, MC[1], MC[0]);
/*
* Save the incremented output address (A) in the SBR
* if we are calling a subroutine.
* We load the SBR when MC[1] & MC[0] & LS & ST
*/
sbr sbr0(SBR, Ainc, SBRLoad, CLK);
and(SBRLoad, MC[1], MC[0], LS, ST);
/*
* The CAR holds the output address.
*/
car car0(A, C0, RESETn, CLK);
/*
* We output the RL (Register Load) signal to the register
* file when not(MC[1] & MC[0]).
*/
nand(RL, MC[1], MC[0]);
endmodule // microsequencer
The Control Address Register (CAR) hold the address of the next microinstrcution.
module car(Q, D, RESETn, CLK);
output [7:0] Q; // Current contents of the CAR.
input [7:0] D; // New contents to load.
input RESETn; // System rest.
input CLK; // System clock.
wire [7:0] D1;
multiplexer_2_1 #(8) mux1(D1, 8'h00, D, RESETn); // Handle resets.
register_parallel_load_8 r1(Q, D1, 1'b1, CLK);
endmodule // car
The microcode SuBroutine Return address register (SBR) holds the address that the microcode can return to. This gives us the opportunity to write microsubroutines, however, there is only one such register so microsubroutines cannot be nested.
module sbr(Q, D, Load, CLK);
output [7:0] Q; // Contents of the SBR.
input [7:0] D; // New contents to load.
input Load; // Load the new contents of the SBR.
input CLK; // System clock.
register_parallel_load_8 r1(Q, D, Load, CLK);
endmodule // sbr
The mapping ROM is used to hold the addresses of microinstruction routines in the control ROM. Each mapping ROM address is a 9-bit value which comprises three fields:
8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
MM | MR | INSTR |
The fields MM and MR come from the microinstruction. The field INSTR is extracted from the instruction depending on the value of MM as seen in the table below.
MM | INSTR |
---|---|
00 | OPCODE[5:3] |
01 | OPCODE[3:0] |
10 | MODE|S |
11 | MODE|S |
This scheme gives us a sort of jump table. When MM==00 we can jump to a different routine for each type of instruction (zero operand, one operand, ...), when MM==01 we can jump to a different routine for each instruction (push, pop, ret, ....), and when MM==1X we can jump to a different routine for each addressing mode. The MR field gives us eight different addresses for each of these different routines.
module mapping_rom(D, A);
input [8:0] A;
output [7:0] D;
assign D = (A == 9'b00_000_0000) ? 8'h02 // 0EX
: (A == 9'b00_000_0001) ? 8'h02 // 0EX
: (A == 9'b00_000_0010) ? 8'h02 // 0EX
: (A == 9'b00_000_0011) ? 8'h02 // 0EX
: (A == 9'b00_000_0100) ? 8'h30 // 1OF
: (A == 9'b00_000_0101) ? 8'h30 // 1OF
: (A == 9'b00_000_0110) ? 8'hab // 2OF
: (A == 9'b00_000_0111) ? 8'hab // 2OF
: (A == 9'b00_000_1000) ? 8'hab // 2OF
: (A == 9'b00_000_1001) ? 8'hab // 2OF
: (A == 9'b00_000_1010) ? 8'hab // 2OF
: (A == 9'b00_000_1011) ? 8'h80 // BAF
: (A == 9'b00_000_1100) ? 8'h80 // BAF
: (A == 9'b00_001_0000) ? 8'h45 // 1EX
: (A == 9'b00_001_0001) ? 8'h45 // 1EX
: (A == 9'b00_001_0010) ? 8'h45 // 1EX
: (A == 9'b00_001_0011) ? 8'h45 // 1EX
: (A == 9'b00_001_0100) ? 8'h45 // 1EX
: (A == 9'b00_001_0101) ? 8'h45 // 1EX
: (A == 9'b00_001_0110) ? 8'h45 // 1EX
: (A == 9'b00_001_0111) ? 8'h45 // 1EX
: (A == 9'b00_001_1000) ? 8'h45 // 1EX
: (A == 9'b00_001_1001) ? 8'h45 // 1EX
: (A == 9'b00_001_1010) ? 8'h45 // 1EX
: (A == 9'b00_001_1011) ? 8'h45 // 1EX
: (A == 9'b00_001_1100) ? 8'h45 // 1EX
: (A == 9'b00_001_1101) ? 8'h45 // 1EX
: (A == 9'b00_001_1110) ? 8'h45 // 1EX
: (A == 9'b00_001_1111) ? 8'h45 // 1EX
: (A == 9'b00_010_0000) ? 8'he4 // 2EX
: (A == 9'b00_010_0001) ? 8'he4 // 2EX
: (A == 9'b00_010_0010) ? 8'he4 // 2EX
: (A == 9'b00_010_0011) ? 8'he4 // 2EX
: (A == 9'b00_010_0100) ? 8'he4 // 2EX
: (A == 9'b00_010_0101) ? 8'he4 // 2EX
: (A == 9'b00_010_0110) ? 8'h45 // 1EX
: (A == 9'b00_010_0111) ? 8'he4 // 2EX
: (A == 9'b00_010_1000) ? 8'he4 // 2EX
: (A == 9'b00_010_1001) ? 8'he4 // 2EX
: (A == 9'b00_010_1010) ? 8'he4 // 2EX
: (A == 9'b00_010_1011) ? 8'he4 // 2EX
: (A == 9'b00_010_1100) ? 8'he4 // 2EX
: (A == 9'b00_010_1101) ? 8'he4 // 2EX
: (A == 9'b00_010_1110) ? 8'he4 // 2EX
: (A == 9'b00_010_1111) ? 8'he4 // 2EX
: (A == 9'b00_011_0000) ? 8'h93 // BEX
: (A == 9'b00_011_0001) ? 8'h93 // BEX
: (A == 9'b00_011_0010) ? 8'h93 // BEX
: (A == 9'b00_011_0011) ? 8'h93 // BEX
: (A == 9'b00_011_0100) ? 8'h93 // BEX
: (A == 9'b00_011_0101) ? 8'h93 // BEX
: (A == 9'b00_011_0110) ? 8'h93 // BEX
: (A == 9'b00_011_0111) ? 8'h93 // BEX
: (A == 9'b00_011_1000) ? 8'h93 // BEX
: (A == 9'b00_011_1001) ? 8'h93 // BEX
: (A == 9'b00_011_1010) ? 8'h93 // BEX
: (A == 9'b00_011_1011) ? 8'h93 // BEX
: (A == 9'b00_011_1100) ? 8'h93 // BEX
: (A == 9'b00_011_1101) ? 8'h93 // BEX
: (A == 9'b00_011_1110) ? 8'h93 // BEX
: (A == 9'b00_011_1111) ? 8'h93 // BEX
: (A == 9'b01_000_0000) ? 8'h03 // NOP0
: (A == 9'b01_000_0001) ? 8'h04 // PSHR0
: (A == 9'b01_000_0010) ? 8'h0c // POPR0
: (A == 9'b01_000_0011) ? 8'h13 // MVS0
: (A == 9'b01_000_0100) ? 8'h1d // RET0
: (A == 9'b01_000_0101) ? 8'h1f // RTI0
: (A == 9'b01_001_0000) ? 8'h46 // PUSH0
: (A == 9'b01_001_0001) ? 8'h49 // POP
: (A == 9'b01_001_0010) ? 8'h4a // INC
: (A == 9'b01_001_0011) ? 8'h4b // DEC
: (A == 9'b01_001_0100) ? 8'h4c // NEG0
: (A == 9'b01_001_0101) ? 8'h4e // NOT
: (A == 9'b01_001_0110) ? 8'hff // INVALID
: (A == 9'b01_001_0111) ? 8'hff // INVALID
: (A == 9'b01_001_1000) ? 8'h4f // SHR0
: (A == 9'b01_001_1001) ? 8'h55 // SHL0
: (A == 9'b01_001_1010) ? 8'h5b // ASR0
: (A == 9'b01_001_1011) ? 8'h61 // ASL0
: (A == 9'b01_001_1100) ? 8'h67 // ROR0
: (A == 9'b01_001_1101) ? 8'h6d // ROL0
: (A == 9'b01_001_1110) ? 8'h73 // RORC0
: (A == 9'b01_001_1111) ? 8'h79 // ROLC0
: (A == 9'b01_010_0000) ? 8'he5 // MOV
: (A == 9'b01_010_0001) ? 8'he6 // XCHG0
: (A == 9'b01_010_0010) ? 8'heb // ADD
: (A == 9'b01_010_0011) ? 8'hec // ADDC
: (A == 9'b01_010_0100) ? 8'hed // SUB
: (A == 9'b01_010_0101) ? 8'hee // SUBB
: (A == 9'b01_010_0110) ? 8'hff // MUL
: (A == 9'b01_010_0111) ? 8'hff // DIV
: (A == 9'b01_010_1000) ? 8'hef // CMP
: (A == 9'b01_010_1001) ? 8'hf0 // AND
: (A == 9'b01_010_1010) ? 8'hf1 // OR
: (A == 9'b01_010_1011) ? 8'hf2 // XOR
: (A == 9'b01_010_1100) ? 8'hff // INVALID
: (A == 9'b01_010_1101) ? 8'hff // INVALID
: (A == 9'b01_010_1110) ? 8'hff // INVALID
: (A == 9'b01_010_1111) ? 8'hff // INVALID
: (A == 9'b01_011_0000) ? 8'h94 // JMP
: (A == 9'b01_011_0001) ? 8'h95 // CALL0
: (A == 9'b01_011_0010) ? 8'h99 // BC0
: (A == 9'b01_011_0011) ? 8'h9b // BNC0
: (A == 9'b01_011_0100) ? 8'h9d // BN0
: (A == 9'b01_011_0101) ? 8'h9f // BNN0
: (A == 9'b01_011_0110) ? 8'ha2 // BV0
: (A == 9'b01_011_0111) ? 8'ha4 // BNV0
: (A == 9'b01_011_1000) ? 8'ha6 // BZ0
: (A == 9'b01_011_1001) ? 8'ha8 // BNZ0
: (A == 9'b01_011_1010) ? 8'hff // INVALID
: (A == 9'b01_011_1011) ? 8'hff // INVALID
: (A == 9'b01_011_1100) ? 8'hff // INVALID
: (A == 9'b01_011_1101) ? 8'hff // INVALID
: (A == 9'b01_011_1110) ? 8'hff // INVALID
: (A == 9'b01_011_1111) ? 8'hff // INVALID
: (A == 9'b01_100_0000) ? 8'hf5 // WB0
: (A == 9'b01_100_0001) ? 8'hf5 // WB0
: (A == 9'b01_100_0010) ? 8'hf5 // WB0
: (A == 9'b01_100_0011) ? 8'hf5 // WB0
: (A == 9'b01_100_0100) ? 8'hf5 // WB0
: (A == 9'b01_100_0101) ? 8'hf5 // WB0
: (A == 9'b01_100_0110) ? 8'hf5 // WB0
: (A == 9'b01_100_0111) ? 8'hf5 // WB0
: (A == 9'b01_100_1000) ? 8'hf5 // WB0
: (A == 9'b01_100_1001) ? 8'hf5 // WB0
: (A == 9'b01_100_1010) ? 8'hf5 // WB0
: (A == 9'b01_100_1011) ? 8'hf5 // WB0
: (A == 9'b01_100_1100) ? 8'hf5 // WB0
: (A == 9'b01_100_1101) ? 8'hf5 // WB0
: (A == 9'b01_100_1110) ? 8'hf5 // WB0
: (A == 9'b01_100_1111) ? 8'hf5 // WB0
: (A == 9'b01_101_0000) ? 8'hf8 // INT0
: (A == 9'b01_101_0001) ? 8'hf8 // INT0
: (A == 9'b01_101_0010) ? 8'hf8 // INT0
: (A == 9'b01_101_0011) ? 8'hf8 // INT0
: (A == 9'b01_101_0100) ? 8'hf8 // INT0
: (A == 9'b01_101_0101) ? 8'hf8 // INT0
: (A == 9'b01_101_0110) ? 8'hf8 // INT0
: (A == 9'b01_101_0111) ? 8'hf8 // INT0
: (A == 9'b01_101_1000) ? 8'hf8 // INT0
: (A == 9'b01_101_1001) ? 8'hf8 // INT0
: (A == 9'b01_101_1010) ? 8'hf8 // INT0
: (A == 9'b01_101_1011) ? 8'hf8 // INT0
: (A == 9'b01_101_1100) ? 8'hf8 // INT0
: (A == 9'b01_101_1101) ? 8'hf8 // INT0
: (A == 9'b01_101_1110) ? 8'hf8 // INT0
: (A == 9'b01_101_1111) ? 8'hf8 // INT0
: (A == 9'b10_001_0000) ? 8'h31 // 1RG
: (A == 9'b10_001_0001) ? 8'h31 // 1RG
: (A == 9'b10_001_0010) ? 8'h32 // 1RGI0
: (A == 9'b10_001_0011) ? 8'h32 // 1RGI0
: (A == 9'b10_001_0100) ? 8'h34 // 1IM
: (A == 9'b10_001_0101) ? 8'h34 // 1IM
: (A == 9'b10_001_0110) ? 8'h35 // 1DR0
: (A == 9'b10_001_0111) ? 8'h35 // 1DR0
: (A == 9'b10_001_1000) ? 8'h37 // 1ID0
: (A == 9'b10_001_1001) ? 8'h37 // 1ID0
: (A == 9'b10_001_1010) ? 8'h3a // 1IDI0
: (A == 9'b10_001_1011) ? 8'h3a // 1IDI0
: (A == 9'b10_001_1100) ? 8'h3e // 1RL0
: (A == 9'b10_001_1101) ? 8'h3e // 1RL0
: (A == 9'b10_001_1110) ? 8'h41 // 1RLI0
: (A == 9'b10_001_1111) ? 8'h41 // 1RLI0
: (A == 9'b10_010_0000) ? 8'hac // 2RG0
: (A == 9'b10_010_0001) ? 8'hae // 2RGS0
: (A == 9'b10_010_0010) ? 8'hb0 // 2RGI00
: (A == 9'b10_010_0011) ? 8'hb3 // 2RGI0S0
: (A == 9'b10_010_0100) ? 8'hb6 // 2IM0
: (A == 9'b10_010_0101) ? 8'hb8 // 2IMS0
: (A == 9'b10_010_0110) ? 8'hba // 2DR00
: (A == 9'b10_010_0111) ? 8'hbd // 2DR0S0
: (A == 9'b10_010_1000) ? 8'hc0 // 2ID00
: (A == 9'b10_010_1001) ? 8'hc4 // 2ID0
: (A == 9'b10_010_1010) ? 8'hc8 // 2IDI00
: (A == 9'b10_010_1011) ? 8'hcd // 2IDIS0
: (A == 9'b10_010_1100) ? 8'hd2 // 2RL0
: (A == 9'b10_010_1101) ? 8'hd6 // 2RLS0
: (A == 9'b10_010_1110) ? 8'hda // 2RLI00
: (A == 9'b10_010_1111) ? 8'hdf // 2RLIS0
: (A == 9'b10_011_0000) ? 8'hff // INVALID
: (A == 9'b10_011_0001) ? 8'hff // INVALID
: (A == 9'b10_011_0010) ? 8'h81 // BRGI0
: (A == 9'b10_011_0011) ? 8'h81 // BRGI0
: (A == 9'b10_011_0100) ? 8'h83 // BIM
: (A == 9'b10_011_0101) ? 8'h83 // BIM
: (A == 9'b10_011_0110) ? 8'h84 // BDR0
: (A == 9'b10_011_0111) ? 8'h84 // BDR0
: (A == 9'b10_011_1000) ? 8'h85 // BID0
: (A == 9'b10_011_1001) ? 8'h85 // BID0
: (A == 9'b10_011_1010) ? 8'h88 // BIDI0
: (A == 9'b10_011_1011) ? 8'h88 // BIDI0
: (A == 9'b10_011_1100) ? 8'h8c // BRL0
: (A == 9'b10_011_1101) ? 8'h8c // BRL0
: (A == 9'b10_011_1110) ? 8'h8f // BRLI0
: (A == 9'b10_011_1111) ? 8'h8f // BRLI0
: (A == 9'b10_100_0000) ? 8'he9 // XCH3
: (A == 9'b10_100_0001) ? 8'he9 // XCH3
: (A == 9'b10_100_0010) ? 8'hea // XCH4
: (A == 9'b10_100_0011) ? 8'he9 // XCH3
: (A == 9'b10_100_0100) ? 8'hea // XCH4
: (A == 9'b10_100_0101) ? 8'he9 // XCH3
: (A == 9'b10_100_0110) ? 8'hea // XCH4
: (A == 9'b10_100_0111) ? 8'he9 // XCH3
: (A == 9'b10_100_1000) ? 8'hea // XCH4
: (A == 9'b10_100_1001) ? 8'he9 // XCH3
: (A == 9'b10_100_1010) ? 8'hea // XCH4
: (A == 9'b10_100_1011) ? 8'he9 // XCH3
: (A == 9'b10_100_1100) ? 8'hea // XCH4
: (A == 9'b10_100_1101) ? 8'he9 // XCH3
: (A == 9'b10_100_1110) ? 8'hea // XCH4
: (A == 9'b10_100_1111) ? 8'he9 // XCH3
: (A == 9'b11_000_0000) ? 8'hf6 // WB1
: (A == 9'b11_000_0001) ? 8'hf6 // WB1
: (A == 9'b11_000_0010) ? 8'hf6 // WB1
: (A == 9'b11_000_0011) ? 8'hf7 // WB2
: (A == 9'b11_000_0100) ? 8'hf6 // WB1
: (A == 9'b11_000_0101) ? 8'hf7 // WB2
: (A == 9'b11_000_0110) ? 8'hf6 // WB1
: (A == 9'b11_000_0111) ? 8'hf7 // WB2
: (A == 9'b11_000_1000) ? 8'hf6 // WB1
: (A == 9'b11_000_1001) ? 8'hf7 // WB2
: (A == 9'b11_000_1010) ? 8'hf6 // WB1
: (A == 9'b11_000_1011) ? 8'hf7 // WB2
: (A == 9'b11_000_1100) ? 8'hf6 // WB1
: (A == 9'b11_000_1101) ? 8'hf7 // WB2
: (A == 9'b11_000_1110) ? 8'hf6 // WB1
: (A == 9'b11_000_1111) ? 8'hf7 // WB2
: (A == 9'b11_001_0000) ? 8'hf8 // INT0
: (A == 9'b11_001_0001) ? 8'hf8 // INT0
: (A == 9'b11_001_0010) ? 8'hf8 // INT0
: (A == 9'b11_001_0011) ? 8'hf8 // INT0
: (A == 9'b11_001_0100) ? 8'hf8 // INT0
: (A == 9'b11_001_0101) ? 8'hf8 // INT0
: (A == 9'b11_001_0110) ? 8'hf8 // INT0
: (A == 9'b11_001_0111) ? 8'hf8 // INT0
: (A == 9'b11_001_1000) ? 8'hf8 // INT0
: (A == 9'b11_001_1001) ? 8'hf8 // INT0
: (A == 9'b11_001_1010) ? 8'hf8 // INT0
: (A == 9'b11_001_1011) ? 8'hf8 // INT0
: (A == 9'b11_001_1100) ? 8'hf8 // INT0
: (A == 9'b11_001_1101) ? 8'hf8 // INT0
: (A == 9'b11_001_1110) ? 8'hf8 // INT0
: (A == 9'b11_001_1111) ? 8'hf8 // INT0
: (A == 9'b11_010_0000) ? 8'h00 // IF0
: (A == 9'b11_010_0001) ? 8'h00 // IF0
: (A == 9'b11_010_0010) ? 8'h00 // IF0
: (A == 9'b11_010_0011) ? 8'h00 // IF0
: (A == 9'b11_010_0100) ? 8'h00 // IF0
: (A == 9'b11_010_0101) ? 8'h00 // IF0
: (A == 9'b11_010_0110) ? 8'h00 // IF0
: (A == 9'b11_010_0111) ? 8'h00 // IF0
: (A == 9'b11_010_1000) ? 8'h00 // IF0
: (A == 9'b11_010_1001) ? 8'h00 // IF0
: (A == 9'b11_010_1010) ? 8'h00 // IF0
: (A == 9'b11_010_1011) ? 8'h00 // IF0
: (A == 9'b11_010_1100) ? 8'h00 // IF0
: (A == 9'b11_010_1101) ? 8'h00 // IF0
: (A == 9'b11_010_1110) ? 8'h00 // IF0
: (A == 9'b11_010_1111) ? 8'h00 // IF0
: 8'hff;
endmodule // mapping_rom
The control ROM holds all of the microcode instructions. The microinstructions use the mapping ROM when branching, so both need to be designed at the same time. The format of a microinstruction is shown in the table below.
Microinstrucion | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MC | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
00,01,10 | MC | MM | MR | DSA | SB | MA | MB | MD | FS | MO | ||||||||||||||||||||||
11 | MC | LS | PS | MS | NA | MO |
Address zero is hard-coded to be the first address of the instruction fetch routine (IF0). Control is then passed to either the zero operand routine (0EX), the one operand routine (1EX), the two operand routine (2EX), or the branch routine (BEX). A branch is then made on addressing mode, followed by a branch to the instruction routine. When the instruction routine has executed, there is either a branch to the write-back routine (WB0) followed by a branch to the interrupt handling routine (INT0), or, if there are no values to write back to memory/registers, the write-back routine is skipped and there is a branch direct to the interrupt handling routine (INT0). The cycle then continues back at the instruction fetch routine (IF0).
module control_rom(D, A);
input [7:0] A;
output [30:0] D;
assign D = (A == 8'h00) ? 31'b00_00_000_00000_00000_01_00_1_00000_0100 // IF0: IR<=M[PC], PC<=PC+1
: (A == 8'h01) ? 31'b10_00_000_00000_00000_00_00_0_00000_0000 // IF1: CAR<=ROM[2'b00000||OPCODE[5:4]||2'b00]
: (A == 8'h02) ? 31'b10_01_000_00000_00000_00_00_0_00000_0000 // 0EX: CAR<=ROM[2'b10000||MODE||S]
: (A == 8'h03) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // NOP0: CAR<=INT0(ROM)
: (A == 8'h04) ? 31'b00_00_000_00000_00000_00_00_0_00000_1000 // PSHR0: SP<=SP-1
: (A == 8'h05) ? 31'b00_00_000_00000_00001_10_00_0_00000_1001 // PSHR1: M[SP]<=R1, SP<=SP-1
: (A == 8'h06) ? 31'b00_00_000_00000_00010_10_00_0_00000_1001 // PSHR2: M[SP]<=R2, SP<=SP-1
: (A == 8'h07) ? 31'b00_00_000_00000_00011_10_00_0_00000_1001 // PSHR3: M[SP]<=R3, SP<=SP-1
: (A == 8'h08) ? 31'b00_00_000_00000_00100_10_00_0_00000_1001 // PSHR4: M[SP]<=R4, SP<=SP-1
: (A == 8'h09) ? 31'b00_00_000_00000_00101_10_00_0_00000_1001 // PSHR5: M[SP]<=R5, SP<=SP-1
: (A == 8'h0a) ? 31'b00_00_000_00000_00110_10_00_0_00000_1001 // PSHR6: M[SP]<=R6, SP<=SP-1
: (A == 8'h0b) ? 31'b10_01_101_00000_00111_10_00_0_00000_0010 // PSHR7: M[SP]<=R7, CAR<=INT0(ROM)
: (A == 8'h0c) ? 31'b00_00_000_00111_00000_10_00_1_00000_1010 // POPR0: R7<=M[SP], SP<=SP+1
: (A == 8'h0d) ? 31'b00_00_000_00110_00000_10_00_1_00000_1010 // POPR1: R6<=M[SP], SP<=SP+1
: (A == 8'h0e) ? 31'b00_00_000_00101_00000_10_00_1_00000_1010 // POPR2: R5<=M[SP], SP<=SP+1
: (A == 8'h0f) ? 31'b00_00_000_00100_00000_10_00_1_00000_1010 // POPR3: R4<=M[SP], SP<=SP+1
: (A == 8'h10) ? 31'b00_00_000_00011_00000_10_00_1_00000_1010 // POPR4: R3<=M[SP], SP<=SP+1
: (A == 8'h11) ? 31'b00_00_000_00010_00000_10_00_1_00000_1010 // POPR5: R2<=M[SP], SP<=SP+1
: (A == 8'h12) ? 31'b10_01_101_00001_00000_10_00_1_00000_1010 // POPR6: R1<=M[SP], SP<=SP+1, CAR<=INT0(ROM)
: (A == 8'h13) ? 31'b00_00_000_01000_00001_00_00_0_11100_0000 // MVS0: R8<=R1
: (A == 8'h14) ? 31'b00_00_000_01001_00010_00_00_0_11100_0000 // MVS1: R9<=R2
: (A == 8'h15) ? 31'b00_00_000_01010_00011_00_00_0_11100_0000 // MVS2: R10<=R3
: (A == 8'h16) ? 31'b00_00_000_01010_00001_00_10_0_00001_1111 // MVS3: R10<=R10-1
: (A == 8'h17) ? 31'b11_0_0_0111_00000000000_00000000_0000 // MVS4: n:CAR<=IF0
: (A == 8'h18) ? 31'b00_00_000_01011_01000_11_00_1_00000_0000 // MVS5: R11<=M[R8]
: (A == 8'h19) ? 31'b00_00_000_01001_01011_00_00_0_00000_0010 // MVS6: M[R9]<=R11
: (A == 8'h1a) ? 31'b00_00_000_01000_00001_00_10_0_00000_0000 // MVS7: R8<=R8+1
: (A == 8'h1b) ? 31'b00_00_000_01001_00001_00_10_0_00000_0000 // MVS7: R9<=R9+1
: (A == 8'h1c) ? 31'b11_0_0_0000_00000000000_00010110_0000 // MVS4: CAR<=MVS3
: (A == 8'h1d) ? 31'b00_00_000_00000_00000_10_00_1_00000_0011 // RET0: PC<=M[SP]
: (A == 8'h1e) ? 31'b10_01_101_00000_00000_10_00_0_00000_1010 // RET1: SP<=SP+1, CAR<=INT0(ROM)
: (A == 8'h1f) ? 31'b00_00_000_00000_00000_10_00_1_00000_0110 // RTI0: PSR<=M[SP]
: (A == 8'h20) ? 31'b00_00_000_00010_00000_00_00_0_00000_1010 // RTI1: SP<=SP+1
: (A == 8'h21) ? 31'b00_00_000_00000_00000_10_00_1_00000_0011 // RTI2: PC<=M[SP]
: (A == 8'h21) ? 31'b10_01_101_00000_00000_10_00_0_00000_1010 // RTI1: SP<=SP+1, CAR<=INT0(ROM)
: (A == 8'h30) ? 31'b10_10_001_00000_00000_00_00_0_00000_0000 // 1OF: CAR<=ROM[2'b10001||MODE||S]
: (A == 8'h31) ? 31'b10_00_001_01111_10000_00_00_0_11100_0000 // 1RG: DD<=R[DST], CAR<=1EX(ROM)
: (A == 8'h32) ? 31'b00_00_000_01110_10000_00_00_0_11000_1000 // 1RGI0: DA<=R[DST]
: (A == 8'h33) ? 31'b10_00_001_01111_00000_00_00_1_00000_0000 // 1RGI1: DD<=M[DA], CAR<=1EX(ROM)
: (A == 8'h34) ? 31'b10_00_001_01111_00000_01_00_1_00000_0101 // 1IM: DD<=M[PC], PC<=PC+1, CAR<=1EX(ROM)
: (A == 8'h35) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 1DR0: DA<=M[PC], PC<=PC+1
: (A == 8'h36) ? 31'b10_00_001_01111_01110_00_00_1_00000_0000 // 1DR0: DD<=M[DA], CAR<=1EX(ROM)
: (A == 8'h37) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 1ID0: DA<=M[PC], PC<=PC+1
: (A == 8'h38) ? 31'b00_00_000_01110_10000_00_00_0_00000_0000 // 1ID1: DA<=DA+R[DST]
: (A == 8'h39) ? 31'b10_00_001_01111_01110_00_00_1_00000_0000 // 1ID2: DD<=M[DA], CAR<=1EX(ROM)
: (A == 8'h3a) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 1IDI0: DA<=M[PC], PC<=PC+1
: (A == 8'h3b) ? 31'b00_00_000_01110_10000_00_00_0_00000_0000 // 1IDI1: DA<=DA+R[DST]
: (A == 8'h3c) ? 31'b00_00_000_01111_00000_00_00_1_00000_0000 // 1IDI2: DA<=M[DA]
: (A == 8'h3d) ? 31'b10_00_001_01111_01110_00_00_1_00000_0000 // 1IDI3: DD<=M[DA], CAR<=1EX(ROM)
: (A == 8'h3e) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 1RL0: DA<=M[PC], PC<=PC+1
: (A == 8'h3f) ? 31'b00_00_000_01110_00000_01_00_0_00000_0000 // 1RL1: DA<=DA+PC
: (A == 8'h40) ? 31'b10_00_001_01111_01110_00_00_1_00000_0000 // 1RL2: DD<=M[DA]+PC, CAR<=1EX(ROM)
: (A == 8'h41) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 1RLI0: DA<=M[PC], PC<=PC+1
: (A == 8'h42) ? 31'b00_00_000_01110_00000_01_00_0_00000_0000 // 1RLI1: DA<=DA+PC
: (A == 8'h43) ? 31'b00_00_000_01111_00000_00_00_1_00000_0000 // 1RLI2: DA<=M[DA]
: (A == 8'h44) ? 31'b10_00_001_01111_01110_00_00_1_00000_0000 // 1RLI3: DD<=M[DA]+PC, CAR<=1EX(ROM)
: (A == 8'h45) ? 31'b10_01_001_00000_00000_00_00_0_00000_0000 // 1EX: CAR<=ROM[1'b01001||OPCODE[3:0]]
: (A == 8'h46) ? 31'b00_00_000_00000_00000_00_00_0_00000_1000 // PUSH0: SP<=SP-1
: (A == 8'h47) ? 31'b00_00_000_00000_01111_10_00_0_00000_0010 // PUSH1: M[SP]<=DD, SP<=SP-1
: (A == 8'h48) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // PUSH2: CAR<=WB0(ROM)
: (A == 8'h49) ? 31'b10_01_100_01111_00000_10_00_1_00000_1010 // POP: DD<=M[SP], SP<=SP+1, CAR<=WB0(ROM)
: (A == 8'h4a) ? 31'b10_01_100_01111_00001_00_10_0_00000_1100 // INC: DD<=DD+1, CAR<=WB0(ROM)
: (A == 8'h4b) ? 31'b10_01_100_01111_00001_00_10_0_00001_1100 // DEC: DD<=DD-1, CAR<=WB0(ROM)
: (A == 8'h4c) ? 31'b00_00_000_01111_00000_00_10_0_00111_0000 // NEG0: DD<=~DD
: (A == 8'h4d) ? 31'b10_01_100_01111_00001_00_10_0_00000_1100 // NEG1: DD<=DD+1, CAR<=WB0(ROM)
: (A == 8'h4e) ? 31'b10_01_100_01111_00001_00_10_0_00111_1110 // NOT: DD<=~DD, CAR<=WB0(ROM)
: (A == 8'h4f) ? 31'b00_00_000_01001_00000_00_11_0_11100_1111 // SHR0: R9<=SHA
: (A == 8'h50) ? 31'b11_0_0_1001_00000000000_11111000_0000 // SHR1: z:CAR<=INT0
: (A == 8'h51) ? 31'b00_00_000_01001_00001_00_10_0_00001_1111 // SHR2: R9<=R9-1
: (A == 8'h52) ? 31'b00_00_000_01111_00001_00_00_0_10100_1101 // SHR2: DD<=SHR(DD)
: (A == 8'h53) ? 31'b11_0_1_1001_00000000000_01010001_0000 // SHR3: ~z:CAR<=SHR2
: (A == 8'h54) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // SHR4: CAR<=WB0(ROM)
: (A == 8'h55) ? 31'b00_00_000_01001_00000_00_11_0_11100_1111 // SHL0: R9<=SHA
: (A == 8'h56) ? 31'b11_0_0_1001_00000000000_11111000_0000 // SHL1: z:CAR<=INT0
: (A == 8'h57) ? 31'b00_00_000_01001_00001_00_10_0_00001_1111 // SHL2: R9<=R9-1
: (A == 8'h58) ? 31'b00_00_000_01111_00001_00_00_0_11000_1101 // SHL2: DD<=SHL(DD)
: (A == 8'h59) ? 31'b11_0_1_1001_00000000000_01010111_0000 // SHL3: ~z:CAR<=SHL2
: (A == 8'h5a) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // SHL4: CAR<=WB0(ROM)
: (A == 8'h5b) ? 31'b00_00_000_01001_00000_00_11_0_11100_1111 // ASR0: R9<=SHA
: (A == 8'h5c) ? 31'b11_0_0_1001_00000000000_11111000_0000 // ASR1: z:CAR<=INT0
: (A == 8'h5d) ? 31'b00_00_000_01001_00001_00_10_0_00001_1111 // ASR2: R9<=R9-1
: (A == 8'h5e) ? 31'b00_00_000_01111_00001_00_00_0_10101_1100 // ASR2: DD<=ASR(DD)
: (A == 8'h5f) ? 31'b11_0_1_1001_00000000000_01011101_0000 // ASR3: ~z:CAR<=ASR2
: (A == 8'h60) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // ASR4: CAR<=WB0(ROM)
: (A == 8'h61) ? 31'b00_00_000_01001_00000_00_11_0_11100_1111 // ASL0: R9<=SHA
: (A == 8'h62) ? 31'b11_0_0_1001_00000000000_11111000_0000 // ASL1: z:CAR<=INT0
: (A == 8'h63) ? 31'b00_00_000_01001_00001_00_10_0_00001_1111 // ASL2: R9<=R9-1
: (A == 8'h64) ? 31'b00_00_000_01111_00001_00_00_0_11001_1100 // ASL2: DD<=ASL(DD)
: (A == 8'h65) ? 31'b11_0_1_1001_00000000000_01100011_0000 // ASL3: ~z:CAR<=ASL2
: (A == 8'h66) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // ASL4: CAR<=WB0(ROM)
: (A == 8'h67) ? 31'b00_00_000_01001_00000_00_11_0_11100_1111 // ROR0: R9<=SHA
: (A == 8'h68) ? 31'b11_0_0_1001_00000000000_11111000_0000 // ROR1: z:CAR<=INT0
: (A == 8'h69) ? 31'b00_00_000_01001_00001_00_10_0_00001_1111 // ROR2: R9<=R9-1
: (A == 8'h6a) ? 31'b00_00_000_01111_00001_00_00_0_10110_1101 // ROR2: DD<=ROR(DD)
: (A == 8'h6b) ? 31'b11_0_1_1001_00000000000_01101001_0000 // ROR3: ~z:CAR<=ROR2
: (A == 8'h6c) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // ROR4: CAR<=WB0(ROM)
: (A == 8'h6d) ? 31'b00_00_000_01001_00000_00_11_0_11100_1111 // ROL0: R9<=SHA
: (A == 8'h6e) ? 31'b11_0_0_1001_00000000000_11111000_0000 // ROL1: z:CAR<=INT0
: (A == 8'h6f) ? 31'b00_00_000_01001_00001_00_10_0_00001_1111 // ROL2: R9<=R9-1
: (A == 8'h70) ? 31'b00_00_000_01111_00001_00_00_0_11010_1101 // ROL2: DD<=ROL(DD)
: (A == 8'h71) ? 31'b11_0_1_1001_00000000000_01101111_0000 // ROL3: ~z:CAR<=ROL2
: (A == 8'h72) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // ROL4: CAR<=WB0(ROM)
: (A == 8'h73) ? 31'b00_00_000_01001_00000_00_11_0_11100_1111 // RORC0: R9<=SHA
: (A == 8'h74) ? 31'b11_0_0_1001_00000000000_11111000_0000 // RORC1: z:CAR<=INT0
: (A == 8'h75) ? 31'b00_00_000_01001_00001_00_10_0_00001_1111 // RORC2: R9<=R9-1
: (A == 8'h76) ? 31'b00_00_000_01111_00001_00_00_0_10111_1101 // RORC2: DD<=RORC(DD)
: (A == 8'h77) ? 31'b11_0_1_1001_00000000000_01110101_0000 // RORC3: ~z:CAR<=RORC2
: (A == 8'h78) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // RORC4: CAR<=WB0(ROM)
: (A == 8'h79) ? 31'b00_00_000_01001_00000_00_11_0_11100_1111 // ROLC0: R9<=SHA
: (A == 8'h7a) ? 31'b11_0_0_1001_00000000000_11111000_0000 // ROLC1: z:CAR<=INT0
: (A == 8'h7b) ? 31'b00_00_000_01001_00001_00_10_0_00001_1111 // ROLC2: R9<=R9-1
: (A == 8'h7c) ? 31'b00_00_000_01111_00001_00_00_0_11011_1101 // ROLC2: DD<=ROLC(DD)
: (A == 8'h7d) ? 31'b11_0_1_1001_00000000000_01111011_0000 // ROLC3: ~z:CAR<=ROLC2
: (A == 8'h7e) ? 31'b10_01_100_00000_00000_00_00_0_00000_0000 // ROLC4: CAR<=WB0(ROM)
: (A == 8'h80) ? 31'b10_10_011_00000_00000_00_00_0_00000_0000 // BAF: CAR<=ROM[2'b1011||MODE||S]
: (A == 8'h81) ? 31'b00_00_000_01110_10000_00_00_0_11000_1000 // BRGI0: DA<=R[DST]
: (A == 8'h82) ? 31'b10_00_011_01111_00000_00_00_1_00000_0000 // BRGI1: DD<=M[DA], CAR<=BEX(ROM)
: (A == 8'h83) ? 31'b10_00_011_01110_00000_01_00_1_00000_0101 // BIM: DA<=M[PC], PC<=PC+1, CAR<=BEX(ROM)
: (A == 8'h84) ? 31'b10_00_011_01110_00000_00_01_1_00000_0101 // BDR0: DA<=M[PC], PC<=PC+1, CAR<=BEX(ROM)
: (A == 8'h85) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // BID0: DA<=M[PC], PC<=PC+1
: (A == 8'h86) ? 31'b00_00_000_01110_10000_00_00_0_00000_0000 // BID1: DA<=DA+R[DST]
: (A == 8'h87) ? 31'b10_00_011_01110_01110_00_00_1_00000_0000 // BID2: DA<=M[DA], CAR<=BEX(ROM)
: (A == 8'h88) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // BIDI0: DA<=M[PC], PC<=PC+1
: (A == 8'h89) ? 31'b00_00_000_01110_10000_00_00_0_00000_0000 // BIDI1: DA<=DA+R[DST]
: (A == 8'h8a) ? 31'b00_00_000_01110_00000_00_00_1_00000_0000 // BIDI2: DA<=M[DA]
: (A == 8'h8b) ? 31'b10_00_011_01110_01110_00_00_1_00000_0000 // BIDI3: DA<=M[DA], CAR<=BEX(ROM)
: (A == 8'h8c) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // BRL0: DA<=M[PC], PC<=PC+1
: (A == 8'h8d) ? 31'b00_00_000_01110_01110_01_00_0_00000_0000 // BRL1: DA<=DA+PC
: (A == 8'h8e) ? 31'b10_00_011_01110_01110_00_00_1_00000_0000 // BRL2: DA<=M[DA], CAR<=BEX(ROM)
: (A == 8'h8f) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // BRLI0: DA<=M[PC], PC<=PC+1
: (A == 8'h90) ? 31'b00_00_000_01110_01110_01_00_0_00000_0000 // BRLI1: DA<=DA+PC
: (A == 8'h91) ? 31'b00_00_000_01110_00000_00_00_1_00000_0000 // BRLI2: DA<=M[DA]
: (A == 8'h92) ? 31'b10_00_011_01110_01110_00_00_1_00000_0000 // BRLI3: DA<=M[DA], CAR<=BEX(ROM)
: (A == 8'h93) ? 31'b10_01_011_00000_00000_00_00_0_00000_0000 // BEX: CAR<=ROM[2'b01011||OPCODE[3:0]]
: (A == 8'h94) ? 31'b10_01_101_01110_00000_00_00_0_00000_0011 // JMP: PC<=DA, CAR<=INT0(ROM)
: (A == 8'h95) ? 31'b00_00_000_01000_00000_01_00_0_10000_0000 // CALL0: R8<=PC
: (A == 8'h96) ? 31'b00_00_000_01000_00000_00_00_0_00000_1000 // CALL1: SP<=SP-1
: (A == 8'h97) ? 31'b00_00_000_00000_01000_10_00_0_00000_0010 // CALL2: M[SP]<=R8
: (A == 8'h98) ? 31'b10_01_101_01110_00000_00_00_0_00000_0011 // CALL3: PC<=DA, CAR<=INT0(ROM)
: (A == 8'h99) ? 31'b11_0_0_0001_00000000000_10101010_0000 // BC0: C:CAR<=BRA
: (A == 8'h9a) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // BC1: CAR<=INT0(ROM)
: (A == 8'h9b) ? 31'b11_0_1_0001_00000000000_10101010_0000 // BNC0: ~C:CAR<=BRA
: (A == 8'h9c) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // BNC1: CAR<=INT0(ROM)
: (A == 8'h9d) ? 31'b11_0_0_0010_00000000000_10101010_0000 // BN0: N:CAR<=BRA
: (A == 8'h9e) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // BN1: CAR<=INT0(ROM)
: (A == 8'h9f) ? 31'b11_0_1_0010_00000000000_10101010_0000 // BNN0: ~N:CAR<=BRA
: (A == 8'ha1) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // BNN1: CAR<=INT0(ROM)
: (A == 8'ha2) ? 31'b11_0_0_0011_00000000000_10101010_0000 // BV0: V:CAR<=BRA
: (A == 8'ha3) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // BV1: CAR<=INT0(ROM)
: (A == 8'ha4) ? 31'b11_0_1_0011_00000000000_10101010_0000 // BNV0: ~V:CAR<=BRA
: (A == 8'ha5) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // BNV1: CAR<=INT0(ROM)
: (A == 8'ha6) ? 31'b11_0_0_0100_00000000000_10101010_0000 // BZ0: Z:CAR<=BRA
: (A == 8'ha7) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // BZ1: CAR<=INT0(ROM)
: (A == 8'ha8) ? 31'b11_0_1_0100_00000000000_10101010_0000 // BNZ0: ~Z:CAR<=BRA
: (A == 8'ha9) ? 31'b10_01_101_00000_00000_00_00_0_00000_0000 // BNZ1: CAR<=INT0(ROM)
: (A == 8'haa) ? 31'b10_01_101_01110_00000_00_00_0_00000_0011 // BRA: PC<=DA, CAR<=INT0(ROM)
: (A == 8'hab) ? 31'b10_10_010_00000_00000_00_00_0_00000_0000 // 2OF: CAR<=ROM[2'b10010||MODE||S]
: (A == 8'hac) ? 31'b00_00_000_01101_11000_00_00_0_11100_0000 // 2RG0: SD<=R[SRC]
: (A == 8'had) ? 31'b10_00_010_01111_10000_00_00_0_11100_0000 // 2RG1: DD<=R[DST], CAR<=2EX(ROM)
: (A == 8'hae) ? 31'b00_00_000_01101_10000_00_00_0_11100_0000 // 2RGS0: SD<=R[DST]
: (A == 8'haf) ? 31'b10_00_010_01111_11000_00_00_0_11100_0000 // 2RGS1: DD<=R[SRC], CAR<=2EX(ROM)
: (A == 8'hb0) ? 31'b00_00_000_01100_11000_00_00_0_11100_0000 // 2RGI0: SA<=R[SRC]
: (A == 8'hb1) ? 31'b00_00_000_01101_01100_11_00_1_00000_0000 // 2RGI1: SD<=M[SA]
: (A == 8'hb2) ? 31'b10_00_010_01111_10000_00_00_0_11100_0000 // 2RGI2: DD<=R[DST], CAR<=2EX(ROM)
: (A == 8'hb3) ? 31'b00_00_000_01110_10000_00_00_0_11100_0000 // 2RGIS0: DA<=R[DST]
: (A == 8'hb4) ? 31'b00_00_000_01111_01110_11_00_1_00000_0000 // 2RGIS1: DD<=M[DA]
: (A == 8'hb5) ? 31'b10_00_010_01101_11000_00_00_0_11100_0000 // 2RGIS2: SD<=R[SRC], CAR<=2EX(ROM)
: (A == 8'hb6) ? 31'b00_00_000_01101_00000_01_00_1_00000_0101 // 2IM0: SD<=M[PC], PC<=PC+1
: (A == 8'hb7) ? 31'b10_00_010_01111_10000_00_00_0_11100_0000 // 2IM1: DD<=R[DST], CAR<=2EX(ROM)
: (A == 8'hb8) ? 31'b00_00_000_01101_00000_01_00_1_00000_0101 // 2IMS0: SD<=M[PC], PC<=PC+1
: (A == 8'hb9) ? 31'b10_00_010_01111_11000_00_00_0_11100_0000 // 2IMS1: DD<=R[SRC], CAR<=2EX(ROM)
: (A == 8'hba) ? 31'b00_00_000_01100_00000_01_00_1_00000_0101 // 2DR0: SA<=M[PC], PC<=PC+1
: (A == 8'hbb) ? 31'b00_00_000_01101_01100_11_00_1_00000_0000 // 2DR1: SD<=M[SA]
: (A == 8'hbc) ? 31'b10_00_010_01111_10000_00_00_0_11100_0000 // 2DR2: DD<=R[DST], CAR<=2EX(ROM)
: (A == 8'hbd) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 2DRS0: DA<=M[PC], PC<=PC+1
: (A == 8'hbe) ? 31'b00_00_000_01111_01110_11_00_1_00000_0000 // 2DRS1: DD<=M[DA]
: (A == 8'hbf) ? 31'b10_00_010_01101_11000_00_00_0_11100_0000 // 2DRS2: SD<=R[SRC], CAR<=2EX(ROM)
: (A == 8'hc0) ? 31'b00_00_000_01001_10000_00_00_0_11100_0000 // 2ID0: SD<=R[DST],
: (A == 8'hc1) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 2ID1: DA<=M[PC], PC<=PC+1
: (A == 8'hc2) ? 31'b00_00_000_01110_11000_00_00_0_00000_0000 // 2ID2: DA<=DA+R[SRC]
: (A == 8'hc3) ? 31'b10_00_010_01111_01110_00_00_1_00000_0000 // 2ID3: DD<=M[DA], CAR<=2EX(ROM)
: (A == 8'hc4) ? 31'b00_00_000_01101_11000_00_00_0_11100_0000 // 2IDS0: SD<=R[SRC],
: (A == 8'hc5) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 2IDS1: DA<=M[PC], PC<=PC+1
: (A == 8'hc6) ? 31'b00_00_000_01110_10000_00_00_0_00000_0000 // 2IDS2: DA<=DA+R[DST]
: (A == 8'hc7) ? 31'b10_00_010_01111_01110_00_00_1_00000_0000 // 2IDS3: DD<=M[DA], CAR<=2EX(ROM)
: (A == 8'hc8) ? 31'b00_00_000_01001_10000_00_00_0_11100_0000 // 2IDI0: SD<=R[DST],
: (A == 8'hc9) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 2IDI1: DA<=M[PC], PC<=PC+1
: (A == 8'hca) ? 31'b00_00_000_01110_11000_00_00_0_00000_0000 // 2IDI2: DA<=DA+R[SRC]
: (A == 8'hcb) ? 31'b00_00_000_01111_00000_00_00_1_00000_0000 // 2IDI3: DA<=M[DA]
: (A == 8'hcc) ? 31'b10_00_010_01111_01110_00_00_1_00000_0000 // 2IDI4: DD<=M[DA], CAR<=2EX(ROM)
: (A == 8'hcd) ? 31'b00_00_000_01001_11000_00_00_0_11100_0000 // 2IDIS0: SD<=R[SRC],
: (A == 8'hce) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 2IDIS1: DA<=M[PC], PC<=PC+1
: (A == 8'hcf) ? 31'b00_00_000_01110_10000_00_00_0_00000_0000 // 2IDIS2: DA<=DA+R[DST]
: (A == 8'hd0) ? 31'b00_00_000_01111_00000_00_00_1_00000_0000 // 2IDIS3: DA<=M[DA]
: (A == 8'hd1) ? 31'b10_00_010_01111_01110_00_00_1_00000_0000 // 2IDIS4: DD<=M[DA], CAR<=2EX(ROM)
: (A == 8'hd2) ? 31'b00_00_000_01101_10000_00_00_0_11100_0000 // 2RL0: SD<=R[DST],
: (A == 8'hd3) ? 31'b00_00_000_01100_00000_01_00_1_00000_0101 // 2RL1: SA<=M[PC], PC<=PC+1
: (A == 8'hd4) ? 31'b00_00_000_01100_01100_01_00_0_00000_0000 // 2RL2: SA<=SA+PC
: (A == 8'hd5) ? 31'b10_00_010_01101_01100_11_00_1_00000_0000 // 2RL3: SD<=M[SA], CAR<=2EX(ROM)
: (A == 8'hd6) ? 31'b00_00_000_01101_11000_00_00_0_11100_0000 // 2RLS0: SD<=R[SRC],
: (A == 8'hd7) ? 31'b00_00_000_01110_01110_01_00_1_00000_0101 // 2RLS1: DA<=M[PC], PC<=PC+1
: (A == 8'hd8) ? 31'b00_00_000_01110_01110_01_00_0_00000_0000 // 2RLS2: DA<=DA+PC
: (A == 8'hd9) ? 31'b10_00_010_01111_01110_11_00_1_00000_0000 // 2RLS3: DD<=M[DA], CAR<=2EX(ROM)
: (A == 8'hda) ? 31'b00_00_000_01101_10000_00_00_0_11100_0000 // 2RLI0: SD<=R[DST],
: (A == 8'hdb) ? 31'b00_00_000_01100_00000_01_00_1_00000_0101 // 2RLI1: SA<=M[PC], PC<=PC+1
: (A == 8'hdc) ? 31'b00_00_000_01100_01100_01_00_0_00000_0000 // 2RLI2: SA<=SA+PC
: (A == 8'hdd) ? 31'b00_00_000_01100_00000_00_00_1_00000_0000 // 2RLI3: SA<=M[SA]
: (A == 8'hde) ? 31'b10_00_010_01101_01100_11_00_1_00000_0000 // 2RLI4: SD<=M[SA], CAR<=2EX(ROM)
: (A == 8'hdf) ? 31'b00_00_000_01101_11000_00_00_0_11100_0000 // 2RLIS0: SD<=R[SRC],
: (A == 8'he0) ? 31'b00_00_000_01110_00000_01_00_1_00000_0101 // 2RLIS1: DA<=M[PC], PC<=PC+1
: (A == 8'he1) ? 31'b00_00_000_01110_01110_01_00_0_00000_0000 // 2RLIS2: DA<=DA+PC
: (A == 8'he2) ? 31'b00_00_000_01111_00000_00_00_1_00000_0000 // 2RLIS3: DA<=M[DA]
: (A == 8'he3) ? 31'b10_00_010_01101_01110_11_00_1_00000_0000 // 2RLIS4: SD<=M[DA], CAR<=2EX(ROM)
: (A == 8'he4) ? 31'b10_01_010_00000_00000_00_00_0_00000_0000 // 2EX: CAR<=ROM[2'b01010||OPCODE[3:0]]
: (A == 8'he5) ? 31'b10_01_100_01111_01101_00_00_0_11100_0000 // MOV: DD<=SD, CAR<=WB0(ROM)
: (A == 8'he6) ? 31'b00_00_000_01001_01101_00_00_0_11100_0000 // XCH0: R9<=SD
: (A == 8'he7) ? 31'b00_00_000_01101_01111_00_00_0_11100_0000 // XCH1: SD<=DD
: (A == 8'he8) ? 31'b10_10_100_01111_01001_00_00_0_11100_0000 // XCH2: DD<=R9, CAR<=ROM[2'b10100||MODE||S]
: (A == 8'he9) ? 31'b10_01_100_10000_01101_00_00_0_11100_0000 // XCH3: R[SRC]<=SD, CAR<=WB0(ROM)
: (A == 8'hea) ? 31'b10_01_100_11000_01101_00_00_0_00000_0010 // XCH4: M[SA]<=SD, CAR<=WB0(ROM)
: (A == 8'heb) ? 31'b10_01_100_01111_01101_00_00_0_00000_1100 // ADD: DD<=DD+SD, CAR<=WB0(ROM)
: (A == 8'hec) ? 31'b10_01_100_01111_01101_00_00_0_00000_1011 // ADDC: DD<=DD+SD+C, CAR<=WB0(ROM)
: (A == 8'hed) ? 31'b10_01_100_01111_01101_00_00_0_00001_1100 // SUB: DD<=DD-SD, CAR<=WB0(ROM)
: (A == 8'hee) ? 31'b10_01_100_01111_01101_00_00_0_00001_1011 // SUBB: DD<=DD-(SD+C), CAR<=WB0(ROM)
/*
* MUL & DIV MISSING. These are not implemented to save time.
*/
: (A == 8'hef) ? 31'b10_01_101_01111_01101_00_00_0_00001_1100 // CMP: DD<=DD-SD, CAR<=INT0(ROM)
: (A == 8'hf0) ? 31'b10_01_100_01111_01101_00_00_0_00010_1100 // AND: DD<=DD&SD, CAR<=WB0(ROM)
: (A == 8'hf1) ? 31'b10_01_100_01111_01101_00_00_0_00011_1100 // OR: DD<=DD|SD, CAR<=WB0(ROM)
: (A == 8'hf2) ? 31'b10_01_100_01111_01101_00_00_0_00100_1100 // XOR: DD<=DD^SD, CAR<=WB0(ROM)
: (A == 8'hf5) ? 31'b10_11_000_00000_00000_00_00_0_00000_0000 // WB0: CAR<=ROM[2'b11000||MODE||S]
: (A == 8'hf6) ? 31'b10_01_101_10000_01111_00_00_0_11100_0000 // WB1: R[DST]<=DD, CAR<=INT0(ROM)
: (A == 8'hf7) ? 31'b10_01_101_01110_01111_00_00_0_00000_0010 // WB2: M[DA]<=DD, CAR<=INT0(ROM)
: (A == 8'hf8) ? 31'b11_0_1_1010_00000000000000_00000_0000 // INT0: ~INTS:CAR<=IF0
: (A == 8'hf9) ? 31'b00_00_000_01000_00000_01_00_0_00000_0000 // INT1: R8<=PC
: (A == 8'hfa) ? 31'b00_00_000_00000_00000_00_00_0_00000_1000 // INT2: SP<=SP-1
: (A == 8'hfb) ? 31'b00_00_000_00000_01000_10_00_0_00000_1001 // INT3: M[SP]<=R8, SP<=SP-1
: (A == 8'hfc) ? 31'b00_00_000_00000_00000_10_01_0_00000_1001 // INT4: M[SP]<=PSR
: (A == 8'hfd) ? 31'b00_00_000_00000_00000_00_00_0_00000_0110 // INT5: PSR<=0
: (A == 8'hfe) ? 31'b00_00_000_00000_00000_00_00_0_00000_0001 // INT6: INACK<=1 (PC is loaded with 16'h0000)
: (A == 8'hff) ? 31'b10_11_010_00000_00000_00_00_1_00000_0000 // INT7: CAR<=IF0(ROM)
: 31'b00_00_000_00000_00000_00_00_0_00000_0000;
endmodule // control_rom
The eight-bit incrementer is used by the microsequencer to increment the contents of the CAR.
module incrementer_8(S, A);
output [7:0] S; // The 8-bit sum.
output C; // The 1-bit carry.
output V; // The 1-bit overflow status.
input [7:0] A; // The 8-bit augend.
input [7:0] B; // The 8-bit addend.
input Cin; // The initial carry in.
wire [3:0] S1_0; // Nibble 1 sum output with carry input 0.
wire [3:0] S1_1; // Nibble 1 sum output with carry input 1.
wire C1_0; // Nibble 1 carry output with carry input 0 (unused).
wire C1_1; // Nibble 1 carry output with carry input 1 (unused).
wire C0; // Nibble 0 carry output used to select multiplexer output.
wire V0; // Nibble 0 overflow output (unused).
wire V1_0; // Nibble 1 overflow output with carry input 0 (unused).
wire V1_1; // Nibble 1 overflow output with carry input 1 (unused).
ripple_carry_adder rc_nibble_0(S[3:0], C0, V0, A[3:0], 4'b0001, 1'b0); // Calculate S nibble 0.
ripple_carry_adder rc_nibble_1_carry_0(S1_0, C1_0, V1_0, A[7:4], 4'b0000, 1'b0); // Calculate S nibble 1 with carry input 0.
ripple_carry_adder rc_nibble_1_carry_1(S1_1, C1_1, V1_1, A[7:4], 4'b0000, 1'b1); // Calculate S nibble 1 with carry input 1.
multiplexer_2_1 #(4) muxs1(S[7:4], S1_0, S1_1, C0); // C0 selects the result for nibble 1.
endmodule
The eight-bit register is used to implement the CAR and the SBR.
module register_parallel_load_8(Q, D, Load, CLK);
output [7:0] Q; // Contents of the register.
input [7:0] D; // Data to load into the register.
input Load; // Signal to load contents.
input CLK; // System clock.
wire Loadn;
wire w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12; // Connecting wires.
wire w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24; // Connecting wires.
wire [7:0] Qn; // Unused.
not(Loadn, Load);
and(w1, Q[0], Loadn);
and(w2, D[0], Load);
or(w3, w2, w1);
and(w4, Q[1], Loadn);
and(w5, D[1], Load);
or(w6, w5, w4);
and(w7, Q[2], Loadn);
and(w8, D[2], Load);
or(w9, w8, w7);
and(w10, Q[3], Loadn);
and(w11, D[3], Load);
or(w12, w11, w10);
and(w13, Q[4], Loadn);
and(w14, D[4], Load);
or(w15, w14, w13);
and(w16, Q[5], Loadn);
and(w17, D[5], Load);
or(w18, w17, w16);
and(w19, Q[6], Loadn);
and(w20, D[6], Load);
or(w21, w20, w19);
and(w22, Q[7], Loadn);
and(w23, D[7], Load);
or(w24, w23, w22);
d_flip_flop_edge_triggered dff0(Q[0], Qn[0], CLK, w3);
d_flip_flop_edge_triggered dff1(Q[1], Qn[1], CLK, w6);
d_flip_flop_edge_triggered dff2(Q[2], Qn[2], CLK, w9);
d_flip_flop_edge_triggered dff3(Q[3], Qn[3], CLK, w12);
d_flip_flop_edge_triggered dff4(Q[4], Qn[4], CLK, w15);
d_flip_flop_edge_triggered dff5(Q[5], Qn[5], CLK, w18);
d_flip_flop_edge_triggered dff6(Q[6], Qn[6], CLK, w21);
d_flip_flop_edge_triggered dff7(Q[7], Qn[7], CLK, w24);
endmodule // register_parallel_load_8
Multiplexers are found almost everywhere in the CPU design. The code for all types are given below.
module multiplexer_2_1(X, A0, A1, S);
parameter WIDTH=16; // How many bits wide are the lines
output [WIDTH-1:0] X; // The output line
input [WIDTH-1:0] A1; // Input line with id 1'b1
input [WIDTH-1:0] A0; // Input line with id 1'b0
input S; // Selection bit
assign X = (S == 1'b0) ? A0 : A1;
endmodule // multiplexer_2_1
module multiplexer_4_1(X, A0, A1, A2, A3, S1, S0);
parameter WIDTH=16; // How many bits wide are the lines
output [WIDTH-1:0] X; // The output line
input [WIDTH-1:0] A3; // Input line with id 2'b11
input [WIDTH-1:0] A2; // Input line with id 2'b10
input [WIDTH-1:0] A1; // Input line with id 2'b01
input [WIDTH-1:0] A0; // Input line with id 2'b00
input S0; // Least significant selection bit
input S1; // Most significant selection bit
assign X = (S1 == 0
? (S0 == 0
? A0 // {S1,S0} = 2'b00
: A1) // {S1,S0} = 2'b01
: (S0 == 0
? A2 // {S1,S0} = 2'b10
: A3)); // {S1,S0} = 2'b11
endmodule // multiplexer_4_1
module multiplexer_8_1(X, A0, A1, A2, A3, A4, A5, A6, A7, S);
parameter WIDTH=16; // How many bits wide are the lines
output [WIDTH-1:0] X; // The output line
input [WIDTH-1:0] A7; // Input line with id 3'b111
input [WIDTH-1:0] A6; // Input line with id 3'b110
input [WIDTH-1:0] A5; // Input line with id 3'b101
input [WIDTH-1:0] A4; // Input line with id 3'b100
input [WIDTH-1:0] A3; // Input line with id 3'b011
input [WIDTH-1:0] A2; // Input line with id 3'b010
input [WIDTH-1:0] A1; // Input line with id 3'b001
input [WIDTH-1:0] A0; // Input line with id 3'b000
input [2:0] S;
assign X = (S[2] == 0
? (S[1] == 0
? (S[0] == 0
? A0 // {S2,S1,S0} = 3'b000
: A1) // {S2,S1,S0} = 3'b001
: (S[0] == 0
? A2 // {S2,S1,S0} = 3'b010
: A3)) // {S2,S1,S0} = 3'b011
: (S[1] == 0
? (S[0] == 0
? A4 // {S2,S1,S0} = 3'b100
: A5) // {S2,S1,S0} = 3'b101
: (S[0] == 0
? A6 // {S2,S1,S0} = 3'b110
: A7))); // {S2,S1,S0} = 3'b111
endmodule // multiplexer_8_1
module multiplexer_16_1(X, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, S);
parameter WIDTH=16; // How many bits wide are the lines
output [WIDTH-1:0] X; // The output line
input [WIDTH-1:0] A15; // Input line with id 4'b1111
input [WIDTH-1:0] A14; // Input line with id 4'b1110
input [WIDTH-1:0] A13; // Input line with id 4'b1101
input [WIDTH-1:0] A12; // Input line with id 4'b1100
input [WIDTH-1:0] A11; // Input line with id 4'b1011
input [WIDTH-1:0] A10; // Input line with id 4'b1010
input [WIDTH-1:0] A9; // Input line with id 4'b1001
input [WIDTH-1:0] A8; // Input line with id 4'b1000
input [WIDTH-1:0] A7; // Input line with id 4'b0111
input [WIDTH-1:0] A6; // Input line with id 4'b0110
input [WIDTH-1:0] A5; // Input line with id 4'b0101
input [WIDTH-1:0] A4; // Input line with id 4'b0100
input [WIDTH-1:0] A3; // Input line with id 4'b0011
input [WIDTH-1:0] A2; // Input line with id 4'b0010
input [WIDTH-1:0] A1; // Input line with id 4'b0001
input [WIDTH-1:0] A0; // Input line with id 4'b0000
input [3:0] S;
assign X = (S[3] == 0
? (S[2] == 0
? (S[1] == 0
? (S[0] == 0
? A0 // {S3, S2,S1,S0} = 4'b0000
: A1) // {S3, S2,S1,S0} = 4'b0001
: (S[0] == 0
? A2 // {S3, S2,S1,S0} = 4'b0010
: A3)) // {S3, S2,S1,S0} = 4'b0011
: (S[1] == 0
? (S[0] == 0
? A4 // {S3, S2,S1,S0} = 4'b0100
: A5) // {S3, S2,S1,S0} = 4'b0101
: (S[0] == 0
? A6 // {S3, S2,S1,S0} = 4'b0110
: A7))) // {S3, S2,S1,S0} = 4'b0111
: (S[2] == 0
? (S[1] == 0
? (S[0] == 0
? A8 // {S3, S2,S1,S0} = 4'b1000
: A9) // {S3, S2,S1,S0} = 4'b1001
: (S[0] == 0
? A10 // {S3, S2,S1,S0} = 4'b1010
: A11)) // {S3, S2,S1,S0} = 4'b1011
: (S[1] == 0
? (S[0] == 0
? A12 // {S3, S2,S1,S0} = 4'b1100
: A13) // {S3, S2,S1,S0} = 4'b1101
: (S[0] == 0
? A14 // {S3, S2,S1,S0} = 4'b1110
: A15)))); // {S3, S2,S1,S0} = 4'b1111
endmodule // multiplexer_16_1
Mano, M. Morris, and Kime, Charles R. Logic and Computer Design Fundamentals. 2nd Edition. Prentice Hall, 2000.
Copyright © 2014 Barry Watson. All rights reserved.