Status bits

F1
At least one of the bits 14..0 of the ALU output is 1
M1
The most significant bit of the ALU output is 1
EQ
The input operands of the ALU are equal
CY
The carry-out of the ALU is 1.
This bit should be set only when the M-bit to the ALU is 1
OA
The is a overflow from the ALU (check overflow computation for 2's complement addition in an earlier assignment)
This should be set only when the ALU is used for arithmetic operations
OM
The is a overflow as a result of the multiplication (with respect to a 16-bit result)

Required status conditions may be computed from these status bits, for example:

Condition codes (CC)

The condition codes are a function of the status bits

ZERO
Result of ALU is zero
POSU
Result of ALU is positive if treated as an unsigned number
POS2
Result of ALU is positive if treated as a 2's complement number
COUT
The carry out of the ALU is 1
EQUL
Both the operands of the ALU are equal
OVRA
The is an overflow from the ALU
OVRM
The is an overflow from the multiplier
MSB1
The MSB of the ALU is 1

General behaviour of CPU for signals at some pins

RST - asynchronous reset
Causes PC to be cleared (all 0's) and the SyR line to be asserted
SyR - system reset
Asserted when RST is asserted
HLD - Hold
When HLD is found to be asserted, CPU responds by tristating MAB and MDB and asserting HLA
HLA - Hold acknowledge
Asserted in response to HLD being asserted
IO/M'
Indicates whether address on MAB is for memory or IO device
INT - Interrupt
For this CPU, RSB is set to all 0's, and when INT is asserted, IV is set 001

Machine instructions

The generic m/c instruction formats are given below. There are eight GPRs each of 16 bits. Note the presence of a number of organisational registers in the data path which are not visible to the programmer and so are not architectural registers. The memory address space is restricted to 216 addresses. I/O mapped input/output is used. The i/o address space is restricted to 25 addresses.

The most significant seven bits of each instruction serve as the opcode. However, not all instructions use all the seven bits, leaving some of the bits as don't cares. It is not even always necessary to examine all the bits of the opcode that are used to decode the instruction, e.g. the ADD and ADI and similar instructions.

This ISA does not conform to the load-store architecture because access to the memory is not restricted to load and store instructions. In general, the instructions require multiple clock cycles to execute.

Execution of all instructions start with fetching the instruction and updating the PC to point to the next instruction, as detailed below, in terms of the micro operations needed to realise the same.

Instruction fetching
State IFetch:
  • MAB ← PC [xMAB←10, wMAB←1]
  • MDB ← MEM [wMDB←1]
  • IR ← MDB [wIR←1]
  • PC ← PC+2 [P/M'←1, xPC←11, wPC←1]

Instruction decoding
State IDecode
  • Examine bits of the opcode (colour highlighted most significant bits of the instruction)
  • Perform multiway branching to one of the following cases depending on the opcode that is matched
ADD Ra Rb Rc (and similar instructions with two register operands)
00aaaaaRaRbRc
aaaaa: 5-bit ALU operation; Ra, Rb, Rc: register index (3-bits each)
Ra ← Rb + Rc
State IExRR:
  • ALU.left ← RegFile.D3
  • ALU.right ← RegFile.D2 [tbR←1]
  • RegFile.D1 ← ALU.out [tbA←1, wR←1]
ADI Ra Rb Imm (and similar instructions with register and immediate operands)
01aaaaaRaRb   
Imm
Imm: 16-bit immediate operand
Ra ← Rb + Imm (in the following word)
State IExRI:
  • ALU.left ← RegFile.D3
  • {* ALU.R ← Imm *}
  • PC ← PC+2 [P/M'←1, xPC←11, wPC←1]
  • MAB ← PC [xMAB←10, wMAB←1]
  • MDB ← MEM [wMDB←1]
  • ALU.right ← MDB [tbD←1]
  • RegFile.D1 ← ALU.out [tbA←1, wR←1]
MUL Ra Rb Rc
10011  RaRbRc
Ra ← Rb × Rc
State IExM:
  • MUL.left ← RegFile.D3
  • MUL.right ← RegFile.D2 [tbR←1]
  • RegFile.D1 ← MUL.out [tbM←1, wR←1]
BRU M
10111            
M
Branch unconditionally to memory address stored in following word
State IExBU:
  • MAB ← PC [xMAB←10, wMAB←1]
  • MDB ← MEM [wMDB←1]
  • PC ← MDB [xPC←10, wPC←1]
BRC CC M
10110  CC       
M
Branch conditionally, if CC is satisfied
State IExBC:
  • MAB ← PC [xMAB←10, wMAB←1]
  • MDB ← MEM [wMDB←1]
  • PC ← MDB if CC else PC ← PC+2
    [wPC←1, P/M'←1, xPC← if (brFn(SBVec, CC)) 10 else 11]
BSR M
10001   spR    spR
M
Branch to subroutine at memory address stored in following word. Use one of the CPU registers as the stack pointer (SPReg).
State IExJS1: {* get and save subroutine address in T *}
  • MAB ← PC [xMAB←10, wMAB←1]
  • T ← MDB ← MEM {* via ALU *}
    [wMDB←1, tbD←1, IR.aaaaa←?ALU.R, tbA←1, wT←1]

State IExJS2:
  • PC ← T [xPC← 01, wPC←1] {* PC←subAddr *}
  • {* Push return address to stack *}
  • MDB ← PC+2 [P/M'←1, xMDB←01, tbE←11, wMDB←1]
  • MAB ← SPReg ← SPReg+2 {* IR.Ra=IR.Rc=SPReg *}
    [IR.aaaaa←?INC2, tbA←1, xMAB←00 wMAB←1, wR←1]
RET
10000   spR    spR
Return from subroutine
State IExRS1:
  • {* Pop return address from stack (through ALU) *}
  • MAB ← SPReg; {* IR.Ra=IR.Rc=SPReg *}
    [IR.aaaaa←?ALU.R, tbA←1, xMAB←00 wMAB←1]
  • PC ← MDB ← MEM [wMDB←1, xPC←10, wPC←1]

State IExRS2: {* Can this separate step be avoided? *}
  • SPReg ← SPReg-2 [IR.aaaaa←?DEC2, tbA←1, wR←1]
    {* IR.Ra=IR.Rc=SPReg *}
TRP
10101   spR  I VXspR
TRAP - generate a software interrupt. RSB is set to all 0's, and when INT is asserted, IVX is set to the bits from the instruction marked as IVX
State IExTR1:
  • {* Push return address to stack *}
  • MDB ← PC+2 [P/M'←1, xMDB←01, tbE←11, wMDB←1]
  • MAB ← SPReg ← SPReg+2 {* IR.Ra=IR.Rc=SPReg *}
    [IR.aaaaa←?INC2, tbA←1, xMAB←00 wMAB←1, wR←1]

State IExTR2:
  • {* Save resolved trap address in PC *}
  • IV ←? IR(2..0) {* RSB ← 0 *}
  • PC ← INTVecAddr [xPC←00, wPC←1]
  • {* Push SBVec to stack *}
  • MDB ← SBVec [xMDB ← 11 tbE←11, wMDB←1]
  • MAB ← SPReg ← SPReg+2 {* IR.Ra=IR.Rc=SPReg *}
    [IR.aaaaa←?INC2, tbA←1, xMAB←00 wMAB←1, wR←1]
  • intMask←?1; privFlag←?1
RTI
10100   spR    spR
Return from interrupt
State IExRT1:
  • {* Pop SBVec from stack *}
  • MAB ← SPReg; {* from SPReg, through ALU, IR.Ra=IR.Rc=SPReg *}
    [IR.aaaaa←?ALU.L, tbA←1, xMAB←00 wMAB←1]
  • SBVec ← MDB ← MEM [wMDB←1, tbD←1]
  • intMask←?0; privFlag←?0

State IExRT2:
  • {* Pop return address from stack (through ALU) *}
  • MAB ← SPReg ← SPReg-2 wMAB←1]
    [IR.aaaaa←?DEC2, tbA←1, xMAB←00 {* IR.Ra=IR.Rc=SPReg *}
  • PC ← MDB ← MEM [wMDB←1, xPC←10, wPC←1]

State IExRT3: {* Can this separate step be avoided? *}
  • SPReg ← SPReg-2 [IR.aaaaa←?DEC2, tbA←1, wR←1]
    {* IR.Ra=IR.Rc=SPReg *}
HLT
10010            
HALT - suspend CPU execution until receipt of interrupt
State IExHLT:
  • {* If intMask flag is set or INT is clear, Controller NextState←HLT *}
INP P
110 00ppRa ppp   
Input from address P in IO space
Ra ← IO[P]
State IExI:
  • MAB ← IO::P [xMAB←01, wMAB←1]
  • Ra ← MDB ← MEM {* via ALU *}
    [wMDB←1, tbD←1, IR.aaaaa←?ALU.R, tbA←1, wR←1, IO/M;←1]
OUT P
110 00pp    pppRc
Output to address P in IO space
IO[P] ← Rc
State IExO:
  • MAB ← IO::P [xMAB←01, wMAB←1]
  • MEM ← MDB ← Rc {* via ALU *}
    [IR.aaaaa←?ALU.L, tbA←1, xMDB←10, tbE←1, wMDB←1, IO/M;←1]
LDM Ra, M
11100   Ra      
M
Ra ← MEM[M]
State IExLM1:
  • PC ← PC+2 [P/M'←1, xPC←11, wPC←1]
  • MAB ← PC [xMAB←10, wMAB←1]
  • T ← MDB ← MEM {* via ALU *}
    [tbD←1, IR.aaaaa←?ALU.R, wMDB←1, wT←1]

State IExLM2:
  • MAB ← T [xMAB←11]
  • ALU.right ← MDB [tbD←1]
  • {* IR.aaaaa ←? ALU.R *}
  • RegFile.D1 ← ALU.out [tbA←1, wR←1]
STM Rc, M
11101         Rc
M
MEM[M] ← Ra
State IExSM1:
  • PC ← PC+2 [P/M'←1, xPC←11, wPC←1]
  • MAB ← PC [xMAB←10, wMAB←1]
  • T ← MDB ← MEM {* via ALU *}
    [tbD←1, IR.aaaaa←?ALU.R, wMDB←1, wT←1]

State IExSM2:
  • MAB ← T [xMAB←11]
  • MDB ← RegFile.D3
    [IR.aaaaa ←? ALU.L, tbA←1, xMDB←10, tbE←1]
LDX Ra, M, Rb
11110   RaRb   
M
Ra ← MEM[M+Rb]
State IExLX1:
  • PC ← PC+2 [P/M'←1, xPC←11, wPC←1]
  • MAB ← PC [xMAB←10, wMAB←1]
  • MDB ← MEM [wMDB←1]
  • T ← MDB + Rb; [IR.aaaaa←? PLUS, tbD←1, wT←1]

State IExLX2:
  • MAB ← T [xMAB←11]
  • ALU.right ← MDB [tbD←1]
  • {* IR.aaaaa ←? ALU.R *}
  • RegFile.D1 ← ALU.out [tbA←1, wR←1]
STX Rc, M, Rb
111 11      RbRc
M
MEM[M+Rb] ← Rc
State IExSX1:
  • PC ← PC+2 [P/M'←1, xPC←11, wPC←1]
  • MAB ← PC [xMAB←10, wMAB←1]
  • MDB ← MEM [wMDB←1]
  • T ← MDB + Rb; [IR.aaaaa←? PLUS, tbD←1, wT←1]

State IExSX2:
  • MAB ← T [xMAB←11]
  • MDB ← RegFile.D3
    [IR.aaaaa ←? ALU.L, tbA←1, xMDB←10, tbE←1]
External interrupt handling
{* if intMask flag is set or INT is clear, Controller NextState←IFetch *}

State cpuINT1:
  • {* Stamp TRP instruction to IR with IVX bits from external source *}

State cpuINT2:
  • {* Push return address (current PC value) to stack *}
  • MDB ← PC [xMDB←00, tbE←11, wMDB←1]
  • MAB ← SPReg ← SPReg+2 {* IR.Ra=IR.Rc=SPReg *}
    [IR.aaaaa←?INC2, tbA←1, xMAB←00 wMAB←1, wR←1]
  • {* Controller NextState←IExTR2 *}
HLD signal handling
State cpuHLD:
  • {* if HLD is set, Controller NextState←cpuHLD
    else Controller NextState←IFetch *}
  • {* Busy waiting by CPU, how can this be made productive? *}
  • {* Useful for DMA operation *}

Critique

Deviations from load/store architecture
A direct deviation is observed in the BSR, RET, TRP and RTI instructions where accesses to the memory are required in course of executing the instructions.
A more subtle deviation occurs in the multi-word instructions entailing a second memory reference after the basic instruction fetch step.
This is caused by the fact that only 16 bits are available per word and not enough bits are available for encoding all instrucions within a single word; the situation is remedied when 32 bits are available per word.
Deviations from RISC architecture
Instructions that are complex in nature are: BSR, RET, TRP, RTI; these can be split into simpler instructions

Design organisation

The datapath should be in pure in structural form, just as it would be if components were to be wired on to a bread board.

The controller should be in behavioural form, so that its behaviour can be ascertained by inspecting the given behaviour.

Do not use delays anywhere in your design as those are not synthesisable. The verilog for your datapath and controller should be fully synthesisable. It is expected that it will be possible to map your design onto an FPGA and execute small programs stored in an EPROM.

Your design should be in two files as follows:

  1. Single verilog file for datapath including components not explicitly specified, but required to complete the design
  2. Single verilog file for controller
  3. Test bench