Skip to content

Control Unit

The ControlUnit module generates control signals for the CPU pipeline based on instruction opcodes. It determines which functional units should be active and how data should flow through the pipeline for each instruction type.

Module Declaration

module ControlUnit(
    input wire [3:0]    instrOP,        // Main instruction opcode
    input wire [3:0]    aluOP,          // ALU operation code

    // ALU control signals
    output reg          alu_use_const,  // Use constant instead of register B
    output reg          alu_use_constu, // Use unsigned constant

    // Stack control signals
    output reg          push,           // Push operation
    output reg          pop,            // Pop operation

    // Register control signals
    output reg          dreg_we,        // Destination register write enable

    // Memory control signals
    output reg          mem_write,      // Memory write enable
    output reg          mem_read,       // Memory read enable

    // Multi-cycle operation control
    output reg          arithm,         // Multi-cycle arithmetic operation

    // Control flow signals
    output reg          jumpc,          // Jump with constant
    output reg          jumpr,          // Jump with register
    output reg          branch,         // Branch operation
    output reg          halt,           // Halt processor
    output reg          reti,           // Return from interrupt

    // Special operation signals
    output reg          getIntID,       // Get interrupt ID
    output reg          getPC,          // Get program counter
    output reg          clearCache      // Clear cache
);

Instruction Decoding

The control unit uses a combinational always block with a case statement:

always @(*) begin
    // Default all outputs to inactive
    alu_use_const  = 1'b0;
    alu_use_constu = 1'b0;
    push           = 1'b0;
    pop            = 1'b0;
    dreg_we        = 1'b0;
    mem_write      = 1'b0;
    mem_read       = 1'b0;
    arithm         = 1'b0;
    jumpc          = 1'b0;
    jumpr          = 1'b0;
    branch         = 1'b0;
    halt           = 1'b0;
    reti           = 1'b0;
    getIntID       = 1'b0;
    getPC          = 1'b0;
    clearCache     = 1'b0;

    case (instrOP)
        // Instruction-specific control signal generation
        ...
    endcase
end

Control Signals by Instruction

Instruction Key Control Signals
HALT halt=1
READ mem_read=1, dreg_we=1
WRITE mem_write=1
INTID getIntID=1, dreg_we=1
PUSH push=1
POP pop=1, dreg_we=1
JUMP jumpc=1
JUMPR jumpr=1
CCACHE clearCache=1
BRANCH branch=1
SAVPC getPC=1, dreg_we=1
RETI reti=1
ARITH dreg_we=1
ARITHC alu_use_const=1, dreg_we=1
ARITHM arithm=1, dreg_we=1
ARITHMC arithm=1, alu_use_const=1, dreg_we=1

Special Cases

Unsigned Constant Selection

For ARITHC and ARITHMC instructions, the control unit checks the ALU opcode to determine if unsigned constants should be used:

// LOAD and LOADHI use unsigned constants
if (aluOP[3:1] == 3'b110) begin
    alu_use_constu = 1'b1;
end

This corresponds to LOAD (opcode 1100) and LOADHI (opcode 1101) operations which use unsigned 16-bit immediates.

Register Write Enable

The dreg_we signal enables writing to the destination register. It's set for:

  • ALU operations (ARITH, ARITHC, ARITHM, ARITHMC)
  • Memory reads (READ)
  • Stack pops (POP)
  • Special registers (INTID, SAVPC)

Multi-cycle Operations

The arithm signal indicates that the instruction requires the MultiCycleALU (multiplication, division, modulo). The pipeline stalls until the operation completes.