//file mips multi processor.v:
module mips_multi(clk, reset);
input clk, reset;
// instruction bus wire [31:0] instr;
// break out important fields from instruction wire [5:0] opcode, funct;
wire [4:0] rs, rt, rd, shamt;
wire [15:0] immed;
wire [31:0] extend_immed, b_offset;
wire [25:0] j_offset;
wire [31:0] j_addr;
assign opcode = instr[31:26];
assign rs = instr[25:21];
assign rt = instr[20:16];
assign rd = instr[15:11];
assign shamt = instr[10:6];
assign funct = instr[5:0];
assign immed = instr[15:0];
assign j_offset = instr[25:0];
// sign-extender
assign extend_immed = { {16{immed[15]}}, immed };
// branch offset shifter
assign b_offset = extend_immed << 2;
// datapath signals wire [4:0] rfile_wn;
wire [31:0] pc, pc_next, mem_addr, mem_rd, mdr, rfile_wd, rfile_rd1, rfile_rd2, a, b, alu_a, alu_b, aluout_in, aluout;
// jump address
assign j_addr = { pc[31:28], j_offset, 2'b0 };
// control signals
wire PCWriteEnable, PCWriteBr, PCWrite, PCWriteCond, Zero, IRWrite, IorD,
MemRead, MemWrite, MemtoReg, RegWrite, RegDst, ALUSrcA;
wire [1:0] ALUOp, ALUSrcB, PCSource;
wire [2:0] Operation;
// module instantiations
reg32en PC(clk, reset, PCWriteEnable, pc_next, pc);
mux2 MEM_MUX(IorD, pc, aluout, mem_addr);
mem32 MEM(clk, MemRead, MemWrite, mem_addr, b, mem_rd);
reg32en IR(clk, reset, IRWrite, mem_rd, instr);
reg32 MDR(clk, reset, mem_rd, mdr);
reg_file RFILE(clk, RegWrite, rs, rt, rfile_wn, rfile_rd1, rfile_rd2, rfile_wd);
mux2 RFMUX(MemtoReg, aluout, mdr, rfile_wd);
mux2 #(5) RFWNMUX(RegDst, rt, rd, rfile_wn);
reg32 A(clk, reset, rfile_rd1, a);
reg32 B(clk, reset, rfile_rd2, b);
mux2 ALUMUXA(ALUSrcA, pc, a, alu_a);
mux4 ALUMUXB(ALUSrcB, b, 32'd4, extend_immed, b_offset, alu_b);
alu ALU(Operation, alu_a, alu_b, aluout_in, Zero);
reg32 ALUOUT(clk, reset, aluout_in, aluout);
mux3 PCMUX(PCSource, aluout_in, aluout, j_addr, pc_next);
and BR_AND(PCWriteBr, PCWriteCond, Zero);
or PC_OR(PCWriteEnable, PCWriteBr, PCWrite);
control_multi CTL(.clk(clk), .reset(reset), .Op(opcode), .PCWrite(PCWrite), .PCWriteCond(PCWriteCond), .IorD(IorD), .MemRead(MemRead), .MemWrite(MemWrite), .MemtoReg(MemtoReg), .IRWrite(IRWrite), .PCSource(PCSource), .ALUOp(ALUOp), .ALUSrcB(ALUSrcB), .ALUSrcA(ALUSrcA),
.RegWrite(RegWrite), .RegDst(RegDst));
alu_ctl ALUCTL(ALUOp, funct, Operation);
endmodule
//file control-multi.v
module control_multi( clk, reset, Op, PCWrite, PCWriteCond, IorD, MemRead, MemWrite,
MemtoReg, IRWrite, PCSource, ALUOp, ALUSrcB, ALUSrcA, RegWrite, RegDst );
input clk;
input reset;
input [5:0] Op;
output PCWrite;
output PCWriteCond;
output IorD;
output MemRead;
output MemWrite;
output MemtoReg;
output IRWrite;
output [1:0] PCSource;
output [1:0] ALUOp;
output ALUSrcA;
output [1:0] ALUSrcB;
output RegWrite;
output RegDst;
reg PCWrite;
reg PCWriteCond;
reg IorD;
reg MemRead;
reg MemWrite;
reg MemtoReg;
reg IRWrite;
reg [1:0] PCSource;
reg [1:0] ALUOp;
reg ALUSrcA;
reg [1:0] ALUSrcB;
reg RegWrite;
reg RegDst;
// Symbolic constants for Opcodes parameter R_FORMAT = 6'd0;
parameter LW = 6'd35;
parameter SW = 6'd43;
parameter BEQ = 6'd4;
parameter ADDI = 6'd8;
parameter J = 6'd2;
reg [3:0] current_state, next_state;
// State Codes for FSM
parameter S0=4'd0, S1=4'd1, S2=4'd2, S3=4'd3, S4=4'd4,
S5=4'd5, S6=4'd6, S7=4'D7, S8=4'd8, S9=4'd9, ERROR=4'bxxxx;
// State Register
always @(posedge clk)
if (reset) current_state <= S0;
else current_state <= next_state;
// Next-State & Output Logic
always @(current_state or Op or reset) begin
// default values PCWrite = 1'b0;
PCWriteCond = 1'b0;
IorD = 1'bx;
MemRead = 1'b0;
MemWrite = 1'b0;
MemtoReg = 1'bx;
IRWrite = 1'b0;
PCSource = 2'bxx;
ALUOp = 2'bxx;
ALUSrcA = 1'bx;
ALUSrcB = 2'bxx;
RegWrite = 1'b0;
RegDst = 1'bx;
if (reset) next_state = S0;
else case (current_state) S0: begin
MemRead = 1'b1;
ALUSrcA = 1'b0;
IorD = 1'b0;
IRWrite = 1'b1;
ALUSrcB = 2'b01;
ALUOp = 2'b00;
PCWrite = 1'b1;
PCSource = 2'b00;
next_state = S1;
end S1: begin
ALUSrcA = 1'b0;
ALUSrcB = 2'b11;
ALUOp = 2'b00;
case (Op)
LW, SW: next_state = S2;
R_FORMAT: next_state = S6;
BEQ: next_state = S8;
J: next_state = S9;
default: next_state = ERROR;
endcase end S2: begin
ALUSrcA = 1'b1;
ALUSrcB = 2'b10;
ALUOp = 2'b00;
case (Op)
LW: next_state = S3;
SW: next_state = S5;
default: next_state = ERROR;
endcase end S3: begin
MemRead = 1'b1;
IorD = 1'b1;
next_state = S4;
end S4: begin
RegDst = 1'b0;
RegWrite = 1'b1;
MemtoReg = 1'b1;
next_state = S0;
end S5: begin
MemWrite = 1'b1;
IorD = 1'b1;
next_state = S0;
end S6: begin
ALUSrcA = 1'b1;
ALUSrcB = 2'b00;
ALUOp = 2'b10;
next_state = S7;
end S7: begin
RegDst = 1'b1;
RegWrite = 1'b1;
MemtoReg = 1'b0;
next_state = S0;
end S8: begin
ALUSrcA = 1'b1;
ALUSrcB = 2'b00;
ALUOp = 2'b01;
PCWriteCond = 1'b1;
PCSource = 2'b01;
next_state = S0;
end S9: begin
PCWrite = 1'b1;
PCSource = 2'b10;
next_state = S0;
end
default: next_state = S0;
endcase end // always endmodule
//file ALU.v
module alu(ctl, a, b, result, zero);
input [2:0] ctl;
input [31:0] a, b;
output [31:0] result;
output zero;
reg [31:0] result;
reg zero;
always @(a or b or ctl) begin
case (ctl)
3'b000 : result = a & b; // AND 3'b001 : result = a | b; // OR 3'b010 : result = a + b; // ADD
3'b110 : result = a - b; // SUBTRACT 3'b111 : if (a < b) result = 32'd1;
else result = 32'd0; //SLT default : result = 32'hxxxxxxxx;
endcase
if (result == 32'd0) zero = 1;
else zero = 0;
end
endmodule
//file ALU control unit.v
module alu_ctl(ALUOp, Funct, ALUOperation);
input [1:0] ALUOp;
input [5:0] Funct;
output [2:0] ALUOperation;
reg [2:0] ALUOperation;
// symbolic constants for instruction function code parameter F_add = 6'd32;
parameter F_sub = 6'd34;
parameter F_and = 6'd36;
parameter F_or = 6'd37;
parameter F_slt = 6'd42;
// symbolic constants for ALU Operations parameter ALU_add = 3'b010;
parameter ALU_sub = 3'b110;
parameter ALU_and = 3'b000;
parameter ALU_or = 3'b001;
parameter ALU_slt = 3'b111;
always @(ALUOp or Funct) begin
case (ALUOp)
2'b00 : ALUOperation = ALU_add;
2'b01 : ALUOperation = ALU_sub;
2'b10 : case (Funct)
F_add : ALUOperation = ALU_add;
F_sub : ALUOperation = ALU_sub;
F_and : ALUOperation = ALU_and;
F_or : ALUOperation = ALU_or;
F_slt : ALUOperation = ALU_slt;
default ALUOperation = 3'bxxx;
endcase
default ALUOperation = 3'bxxx;
endcase end
endmodule //file mem32.v
module mem32(clk, mem_read, mem_write, address, data_in, data_out);
input clk, mem_read, mem_write;
input [31:0] address, data_in;
output [31:0] data_out;
reg [31:0] data_out;
parameter BASE_ADDRESS = 25'd0; // address that applies to this memory - change if desired
reg [31:0] mem_array [0:31];
wire [4:0] mem_offset;
wire address_select;
assign mem_offset = address[6:2]; // drop 2 LSBs to get word offset
assign address_select = (address[31:7] == BASE_ADDRESS); // address decoding always @(mem_read or address_select or mem_offset or mem_array[mem_offset]) begin
if (mem_read == 1'b1 && address_select == 1'b1) begin
if ((address % 4) != 0)
$display($time, " rom32 error: unaligned address %d", address);
data_out = mem_array[mem_offset];
$display($time, " reading data: Mem[%h] => %h", address, data_out);
end
else data_out = 32'hxxxxxxxx;
end
// for WRITE operations always @(posedge clk) begin
if (mem_write == 1'b1 && address_select == 1'b1) begin
$display($time, " writing data: Mem[%h] <= %h", address,data_in);
mem_array[mem_offset] <= data_in;
end end
// initialize with some arbitrary values integer i;
initial begin
mem_array[0] = { 6'd35, 5'd0, 5'd2, 16'd36 }; // x00 l2 $2, 36($0) r2=1 mem_array[1] = { 6'd35, 5'd0, 5'd3, 16'd40 }; // x04 lw $3, 40($0) r3=2 mem_array[2] = { 6'd35, 5'd0, 5'd4, 16'd52 }; // x08 lw $4, 52($0) r4=5 mem_array[3] = { 6'd0, 5'd0, 5'd0, 5'd5, 5'd0, 6'd32 }; // x0C add $5, $0, $0 r5=0 mem_array[4] = { 6'd0, 5'd5, 5'd2, 5'd5, 5'd0, 6'd32 }; // x10 add $5, $5, $1 r5 = r5 + 1
mem_array[5] = { 6'd0, 5'd4, 5'd5, 5'd6, 5'd0, 6'd42 }; // x14 slt $6, $4, $5 is $5 >
54?
mem_array[6] = { 6'd4, 5'd6, 5'd0, -16'd3 }; // x18 beq $6, $zero, -3 if not, go back 2
mem_array[7] = { 6'd43, 5'd0, 5'd5, 16'd64 }; // x1C sw $5, 0($0) MEM[64] = $5
mem_array[8] = { 6'd2, 26'd0 }; // x20 j 0 goto 0
for (i=1; i<7; i=i+1) mem_array[i+8] = i; // MEM[x24]=1; MEM[x28]=2; , etc.
end endmodule //file reg-file.v
module reg_file(clk, RegWrite, RN1, RN2, WN, RD1, RD2, WD);
input clk;
input RegWrite;
input [4:0] RN1, RN2, WN;
input [31:0] WD;
output [31:0] RD1, RD2;
reg [31:0] RD1, RD2;
reg [31:0] file_array [31:1];
always @(RN1 or file_array[RN1]) begin
if (RN1 == 0) RD1 = 32'd0;
else RD1 = file_array[RN1];
$display($time, " reg_file[%d] => %d (Port 1)", RN1, RD1);
end
always @(RN2 or file_array[RN2]) begin
if (RN2 == 0) RD2 = 32'd0;
else RD2 = file_array[RN2];
$display($time, " reg_file[%d] => %d (Port 2)", RN2, RD2);
end
always @(posedge clk)
if (RegWrite && (WN != 0)) begin
file_array[WN] <= WD;
$display($time, " reg_file[%d] <= %d (Write)", WN, WD);
end endmodule //file reg32.v
module reg32 (clk, reset, d_in, d_out);
input clk, reset;
input [31:0] d_in;
output [31:0] d_out;
reg [31:0] d_out;
always @(posedge clk)
begin
if (reset) d_out <= 0;
else d_out <= d_in;
end endmodule //file reg32en.v
module reg32en (clk, reset, enable, d_in, d_out);
input clk, reset, enable;
input [31:0] d_in;
output [31:0] d_out;
reg [31:0] d_out;
always @(posedge clk) begin
if (reset) d_out <= 0;
else if (enable) d_out <= d_in;
end endmodule //file mux2.v
module mux2( sel, a, b, y );
parameter bitwidth=32;
input sel;
input [bitwidth-1:0] a, b;
output [bitwidth-1:0] y;
assign y = sel ? b : a;
endmodule //file mux3.v
module mux3(s, d0, d1, d2, y);
parameter bitwidth=32;
input [1:0] s;
input [bitwidth-1:0] d0, d1, d2;
output [bitwidth-1:0] y;
reg [bitwidth-1:0] y;
always @(d0 or d1 or d2 or s) case ( s)
2'd0 : y = d0;
2'd1 : y = d1;
2'd2 : y = d2;
default : y = {bitwidth{1'bx}};
endcase endmodule //file mux4.v
module mux4(s, d0, d1, d2, d3, y);
parameter bitwidth=32;
input [1:0] s;
input [bitwidth-1:0] d0, d1, d2, d3;
output [bitwidth-1:0] y;
reg [bitwidth-1:0] y;
always @(d0 or d1 or d2 or d3 or s) case ( s)
2'd0 : y = d0;
2'd1 : y = d1;
2'd2 : y = d2;
2'd3 : y = d3;
default : y = {bitwidth{1'bx}};
endcase endmodule
PHỤ LỤC 2: