MIPS is a RISC (Reduced Instruction Set Computer) based architecture which is used in MIPS based processors. Let us design a simple ALU in Verilog using few example instructions from the MIPS Instruction Set.
For details on MIPS instruction set, I have referred this Programmer's guide: MIPS Programmer's Guide
MIPS Instructions are classified into three types: R, I and J. They have the following specified formats:
R-Type:
op - Opcode
rs, rt - Source Registers 1 and 2
rd - Destination Register
shamt - Shift Amount
funct - Function Code
I-Type:
J-Type:
Step 1: Decide the various instructions that your ALU must support.
From the MIPS Instruction Set, let us have our ALU to support the following instructions:
AND, OR, ADD, SUB, SLT, NOR, LW, SW, BEQ.
Step 2: ALU Control Signal Generation
For I-Type Instructions, we can find out the type of operation to be performed by looking at the opcode.
However for R-Type Instructions, the type of operation is determined by the function field (opcode field will remain as all zeroes).
So we need a control signal for the ALU which determines the type of operation to be performed by looking at either the opcode for I-Type or function field for R-Type instructions.
In our case, it is as simple as: if the opcode field is all zeroes, then look at the function field.
For BEQ, subtraction has to be performed. If the operands are equal, then the subtraction result will be 0 and the branching condition will be true. Our ALU will have a separate zero output signal to indicate output zero condition.
This ALU can be later added to a processor design.
Verilog Module: ALU_Controller
Inputs: opcode (6 bits), func_field (6 bits)
Outputs: alu_control (3 bits)
Verilog Code for ALU Control:
module Alu_Control( opcode, func_field, alu_control ); input [5:0] opcode; input [5:0] func_field; output reg [2:0] alu_control; reg [2:0] func_code; always @ (*) begin case (func_field) 6'h20: func_code = 3'h0; 6'h22: func_code = 3'h1; 6'h24: func_code = 3'h2; 6'h25: func_code = 3'h3; 6'h27: func_code = 3'h4; 6'h2A: func_code = 3'h5; default: func_code = 3'h0; endcase case (opcode) 6'h00: alu_control = func_code; 6'h04: alu_control = 3'h1; 6'h23: alu_control = 3'h0; 6'h2B: alu_control = 3'h0; default: alu_control = 3'h0; endcase end endmodule
Now that the control signal tells us the type of operation to be performed, the desired operation can be performed in the ALU core module. Let the input operands be A and B. The computed output is sent out as result.
Verilog module: ALU_Core
Inputs: alu_control (3 bits), A (32 bits), B (32 bits)
Outputs: result (32 bits), zero (1 bit)
Verilog Code for ALU Core:
module Alu_Core( A, B, alu_control, result, zero ); input [31:0] A; input [31:0] B; input [2:0] alu_control; output reg [31:0] result; output wire zero; assign zero = !(|result); always @ (*) begin case(alu_control) 3'h0: result = A + B; 3'h1: result = A - B; 3'h2: result = A & B; 3'h3: result = A | B; 3'h4: result = ~(A | B); 3'h5: result = (A < B); default: result = A + B; endcase end endmodule
Step 4: Create the ALU top module.
The top module instantiates and connects both the above modules.
Verilog Module: ALU_Top
Inputs: opcode (6 bits), func_field (6 bits), A (32 bits), B (32 bits)
Outputs: result (32 bits), zero (1 bit)
Verilog Code for ALU Top:
module Alu_Top( opcode, func_field, A, B, result, zero ); input [5:0] opcode; input [5:0] func_field; input [31:0] A; input [31:0] B; output [31:0] result; output zero; wire [2:0] alu_control; Alu_Control alu_ctrlr_inst ( .opcode (opcode), .func_field (func_field), .alu_control (alu_control) ); Alu_Core alu_core_inst ( .A (A), .B (B), .alu_control (alu_control), .result (result), .zero (zero) ); endmodule
The above verilog code implements an ALU using certain instructions from the MIPS Instruction set.
module Alu_Top_tb; // Inputs reg [5:0] opcode; reg [5:0] func_field; reg [31:0] A; reg [31:0] B; // Outputs wire [31:0] result; wire zero; // Instantiate the Unit Under Test (UUT) Alu_Top uut ( .opcode(opcode), .func_field(func_field), .A(A), .B(B), .result(result), .zero(zero) ); initial begin // Initialize Inputs opcode = 0; func_field = 0; A = 0; B = 0; #30; A=32'h2222; B=32'h1111; opcode=6'h00;func_field=6'h20; #30; opcode=6'h00;func_field=6'h24; #30; opcode=6'h23;func_field=6'h00; #30; A=31'h5555; B=32'h5555; opcode=6'h04;func_field=6'h00; #30; A=32'h1111; B=32'h2222; opcode=6'h00;func_field=6'h2A; #30; $finish; end endmodule
Simulation Result:
No comments:
Post a Comment