243 lines
7.1 KiB
Verilog
243 lines
7.1 KiB
Verilog
////////////////////////////////////////////////
|
|
// Purpose: Control unit for RISC_SPM
|
|
// Author: Mike Ciletti with heavy modification
|
|
//
|
|
// REVISION HISTORY:
|
|
// $Log: Control_Unit.v,v $
|
|
// Revision 1.1 2011/05/31 16:32:52 tumbush.tumbush
|
|
// Check into cloud repository.
|
|
//
|
|
// Revision 1.1 2011/03/20 20:43:01 Greg
|
|
// Initial check in
|
|
//
|
|
////////////////////////////////////////////////
|
|
`default_nettype none
|
|
module Control_Unit #(parameter Sel1_size = 3, Sel2_size = 2, word_size = 8)
|
|
(
|
|
// Load enables for the registers
|
|
output reg Load_R0, Load_R1, Load_R2, Load_R3, Load_PC,
|
|
output reg Inc_PC, Load_IR, Load_Add_R, Load_Reg_Y,
|
|
output reg Load_Reg_Z,
|
|
|
|
output reg write, // Flag indicating to write the memory unit
|
|
output wire [Sel1_size-1:0] Sel_Bus_1_Mux, // select for mux1
|
|
output wire [Sel2_size-1: 0] Sel_Bus_2_Mux, // select for mux2
|
|
input wire [word_size-1: 0] instruction, // Contains {opcode, src, dest}
|
|
input wire Zflag, // Zero flag
|
|
input wire clk,
|
|
input wire rst // Active low asynchronous reset
|
|
);
|
|
|
|
parameter op_size = 4; // Need 4-Bits for opcode
|
|
parameter state_size = 4; // Need 4-bits for current state and next_state
|
|
parameter src_size = 2, dest_size = 2; // Need 2-bits for the src and destination fields of the instruction
|
|
|
|
// State Codes
|
|
parameter S_idle = 0, S_fet1 = 1, S_fet2 = 2, S_dec = 3;
|
|
parameter S_ex1 = 4, S_rd1 = 5, S_rd2 = 6;
|
|
parameter S_wr1 = 7, S_wr2 = 8, S_br1 = 9, S_br2 = 10, S_halt = 11;
|
|
|
|
// Source and Destination Codes
|
|
parameter R0 = 0, R1 = 1, R2 = 2, R3 = 3;
|
|
|
|
`include "opcodes_include.v"
|
|
|
|
reg [state_size-1: 0] state, next_state;
|
|
reg Sel_ALU; // Select ALU for Mux_2
|
|
reg Sel_Mem; // Select Memory for Mux_2
|
|
reg Sel_Bus_1; // Select Bus_1 for Mux_2
|
|
reg Sel_R0, Sel_R1, Sel_R2, Sel_R3, Sel_PC;
|
|
reg err_flag;
|
|
|
|
wire [op_size-1:0] opcode = instruction [word_size-1: word_size - op_size];
|
|
wire [src_size-1: 0] src = instruction [src_size + dest_size -1: dest_size];
|
|
wire [dest_size-1:0] dest = instruction [dest_size -1:0];
|
|
|
|
// Mux selectors
|
|
assign Sel_Bus_1_Mux[Sel1_size-1:0] = Sel_R0 ? 0:
|
|
Sel_R1 ? 1:
|
|
Sel_R2 ? 2:
|
|
Sel_R3 ? 3:
|
|
Sel_PC ? 4: 0;
|
|
|
|
assign Sel_Bus_2_Mux[Sel2_size-1:0] = Sel_ALU ? 0:
|
|
Sel_Bus_1 ? 1:
|
|
Sel_Mem ? 2: 0;
|
|
|
|
always @ (posedge clk or negedge rst) begin
|
|
if (rst == 0)
|
|
state <= S_idle;
|
|
else
|
|
state <= next_state;
|
|
end
|
|
|
|
// Next state and output combinatorial logic
|
|
always @* begin
|
|
//always @ (state or opcode or Zflag) begin: Output_and_next_state
|
|
Sel_R0 = 0; Sel_R1 = 0; Sel_R2 = 0; Sel_R3 = 0; Sel_PC = 0;
|
|
Load_R0 = 0; Load_R1 = 0; Load_R2 = 0; Load_R3 = 0; Load_PC = 0;
|
|
Load_IR = 0; Load_Add_R = 0; Load_Reg_Y = 0; Load_Reg_Z = 0;
|
|
Inc_PC = 0;
|
|
Sel_Bus_1 = 0;
|
|
Sel_ALU = 0;
|
|
Sel_Mem = 0;
|
|
write = 0;
|
|
err_flag = 0; // Used for de-bug in simulation
|
|
next_state = state;
|
|
|
|
case (state)
|
|
S_idle: next_state = S_fet1;
|
|
|
|
// Load address register with PC
|
|
S_fet1: begin
|
|
next_state = S_fet2;
|
|
Sel_PC = 1;
|
|
Sel_Bus_1 = 1;
|
|
Load_Add_R = 1;
|
|
end
|
|
|
|
// Read instruction from memory into IR, increment PC
|
|
S_fet2: begin
|
|
next_state = S_dec;
|
|
Sel_Mem = 1;
|
|
Load_IR = 1;
|
|
Inc_PC = 1;
|
|
end
|
|
|
|
// Decode State
|
|
// Return to idle for NOP
|
|
// Load Reg_Y with src register for ADD/SUB/AND
|
|
// Load Address Register with PC for RD/WR/BR/BRZ
|
|
S_dec: case (opcode)
|
|
NOP: next_state = S_fet1;
|
|
|
|
ADD, SUB, AND: begin
|
|
next_state = S_ex1;
|
|
Sel_Bus_1 = 1;
|
|
Load_Reg_Y = 1;
|
|
do_select(src, Sel_R0, Sel_R1, Sel_R2, Sel_R3, err_flag);
|
|
end // ADD, SUB, AND
|
|
|
|
NOT: begin
|
|
next_state = S_fet1;
|
|
Load_Reg_Z = 1;
|
|
Sel_ALU = 1;
|
|
do_select(src, Sel_R0, Sel_R1, Sel_R2, Sel_R3, err_flag);
|
|
do_select(dest, Load_R0, Load_R1, Load_R2, Load_R3, err_flag);
|
|
end // NOT
|
|
|
|
RD, RDI: begin // New code for RDI
|
|
next_state = S_rd1;
|
|
Sel_PC = 1; Sel_Bus_1 = 1; Load_Add_R = 1;
|
|
end // RD
|
|
|
|
WR: begin
|
|
next_state = S_wr1;
|
|
Sel_PC = 1; Sel_Bus_1 = 1; Load_Add_R = 1;
|
|
end // WR
|
|
|
|
BR: begin
|
|
next_state = S_br1;
|
|
Sel_PC = 1; Sel_Bus_1 = 1; Load_Add_R = 1;
|
|
end // BR
|
|
|
|
BRZ: begin
|
|
if (Zflag == 1) begin
|
|
next_state = S_br1;
|
|
Sel_PC = 1; Sel_Bus_1 = 1; Load_Add_R = 1;
|
|
end
|
|
else begin
|
|
next_state = S_fet1;
|
|
Inc_PC = 1;
|
|
end
|
|
end // BRZ
|
|
|
|
default : next_state = S_halt;
|
|
endcase // (opcode)
|
|
|
|
// Execute state for ADD, SUB, AND
|
|
S_ex1: begin
|
|
next_state = S_fet1;
|
|
Load_Reg_Z = 1;
|
|
Sel_ALU = 1;
|
|
do_select(dest, Sel_R0, Sel_R1, Sel_R2, Sel_R3, err_flag);
|
|
do_select(dest, Load_R0, Load_R1, Load_R2, Load_R3, err_flag);
|
|
end
|
|
|
|
// Load address register with memory output for RD
|
|
// Load Register with memory output for RDI
|
|
S_rd1: begin
|
|
if (opcode == RD) begin
|
|
next_state = S_rd2;
|
|
Sel_Mem = 1;
|
|
Load_Add_R = 1;
|
|
Inc_PC = 1;
|
|
end
|
|
else begin // RDI instruction - New code for RDI
|
|
next_state = S_fet1;
|
|
Inc_PC = 1;
|
|
Sel_Mem = 1;
|
|
do_select(dest, Load_R0, Load_R1, Load_R2, Load_R3, err_flag);
|
|
end
|
|
end
|
|
|
|
// Load address register with memory output
|
|
S_wr1: begin
|
|
next_state = S_wr2;
|
|
Sel_Mem = 1;
|
|
Load_Add_R = 1;
|
|
Inc_PC = 1;
|
|
end
|
|
|
|
// Do read and steer memory output to correct register
|
|
S_rd2: begin
|
|
next_state = S_fet1;
|
|
Sel_Mem = 1;
|
|
do_select(dest, Load_R0, Load_R1, Load_R2, Load_R3, err_flag);
|
|
end
|
|
|
|
// Do write to memory of correct register
|
|
S_wr2: begin
|
|
next_state = S_fet1;
|
|
write = 1;
|
|
do_select(src, Sel_R0, Sel_R1, Sel_R2, Sel_R3, err_flag);
|
|
end
|
|
|
|
// Load address register with address containing branch location
|
|
S_br1: begin
|
|
next_state = S_br2;
|
|
Sel_Mem = 1;
|
|
Load_Add_R = 1;
|
|
end // S_br1
|
|
|
|
// Load PC with memory output
|
|
S_br2: begin
|
|
next_state = S_fet1;
|
|
Sel_Mem = 1;
|
|
Load_PC = 1;
|
|
end // S_br2
|
|
|
|
S_halt: next_state = S_halt;
|
|
default: next_state = S_idle;
|
|
endcase
|
|
end // always
|
|
|
|
// Build a decoder task
|
|
task do_select(input [src_size-1: 0] sel,
|
|
output reg set_R0, set_R1, set_R2, set_R3, err_flag
|
|
);
|
|
begin
|
|
{set_R0, set_R1, set_R2, set_R3} = 0;
|
|
err_flag = 0;
|
|
case (sel)
|
|
R0: set_R0 = 1;
|
|
R1: set_R1 = 1;
|
|
R2: set_R2 = 1;
|
|
R3: set_R3 = 1;
|
|
default : err_flag = 1;
|
|
endcase
|
|
end
|
|
endtask
|
|
|
|
endmodule
|