In: Electrical Engineering
Design and write a verilog code and testbench for a 16-bit RISC MIPS Processor on vivado and show waveform.
Verilog code for Data memory:
module data_memory ( input clk, // address input, shared by read and write port input [15:0] mem_access_addr, // write port input [15:0] mem_write_data, input mem_write_en, input mem_read, // read port output [15:0] mem_read_data ); integer i; reg [15:0] ram [255:0]; wire [7 : 0] ram_addr = mem_access_addr[8 : 1]; initial begin for(i=0;i<256;i=i+1) ram[i] <= 16'd0; end always @(posedge clk) begin if (mem_write_en) ram[ram_addr] <= mem_write_data; end assign mem_read_data = (mem_read==1'b1) ? ram[ram_addr]: 16'd0; endmodule
Verilog code for ALU control unit:
module ALUControl( ALU_Control, ALUOp, Function); output reg[2:0] ALU_Control; input [1:0] ALUOp; input [3:0] Function; wire [5:0] ALUControlIn; assign ALUControlIn = {ALUOp,Function}; always @(ALUControlIn) casex (ALUControlIn) 6'b11xxxx: ALU_Control=3'b000; 6'b10xxxx: ALU_Control=3'b100; 6'b01xxxx: ALU_Control=3'b001; 6'b000000: ALU_Control=3'b000; 6'b000001: ALU_Control=3'b001; 6'b000010: ALU_Control=3'b010; 6'b000011: ALU_Control=3'b011; 6'b000100: ALU_Control=3'b100; default: ALU_Control=3'b000; endcase endmodule // Verilog code for JR control unit module JR_Control( input[1:0] alu_op, input [3:0] funct, output JRControl ); assign JRControl = ({alu_op,funct}==6'b001000) ? 1'b1 : 1'b0; endmodule
Verilog code for control unit:
module control( input[2:0] opcode, input reset, output reg[1:0] reg_dst,mem_to_reg,alu_op, output reg jump,branch,mem_read,mem_write,alu_src,reg_write,sign_or_zero ); always @(*) begin if(reset == 1'b1) begin reg_dst = 2'b00; mem_to_reg = 2'b00; alu_op = 2'b00; jump = 1'b0; branch = 1'b0; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b0; reg_write = 1'b0; sign_or_zero = 1'b1; end else begin case(opcode) 3'b000: begin // add reg_dst = 2'b01; mem_to_reg = 2'b00; alu_op = 2'b00; jump = 1'b0; branch = 1'b0; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b0; reg_write = 1'b1; sign_or_zero = 1'b1; end 3'b001: begin // sli reg_dst = 2'b00; mem_to_reg = 2'b00; alu_op = 2'b10; jump = 1'b0; branch = 1'b0; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b1; reg_write = 1'b1; sign_or_zero = 1'b0; end 3'b010: begin // j reg_dst = 2'b00; mem_to_reg = 2'b00; alu_op = 2'b00; jump = 1'b1; branch = 1'b0; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b0; reg_write = 1'b0; sign_or_zero = 1'b1; end 3'b011: begin // jal reg_dst = 2'b10; mem_to_reg = 2'b10; alu_op = 2'b00; jump = 1'b1; branch = 1'b0; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b0; reg_write = 1'b1; sign_or_zero = 1'b1; end 3'b100: begin // lw reg_dst = 2'b00; mem_to_reg = 2'b01; alu_op = 2'b11; jump = 1'b0; branch = 1'b0; mem_read = 1'b1; mem_write = 1'b0; alu_src = 1'b1; reg_write = 1'b1; sign_or_zero = 1'b1; end 3'b101: begin // sw reg_dst = 2'b00; mem_to_reg = 2'b00; alu_op = 2'b11; jump = 1'b0; branch = 1'b0; mem_read = 1'b0; mem_write = 1'b1; alu_src = 1'b1; reg_write = 1'b0; sign_or_zero = 1'b1; end 3'b110: begin // beq reg_dst = 2'b00; mem_to_reg = 2'b00; alu_op = 2'b01; jump = 1'b0; branch = 1'b1; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b0; reg_write = 1'b0; sign_or_zero = 1'b1; end 3'b111: begin // addi reg_dst = 2'b00; mem_to_reg = 2'b00; alu_op = 2'b11; jump = 1'b0; branch = 1'b0; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b1; reg_write = 1'b1; sign_or_zero = 1'b1; end default: begin reg_dst = 2'b01; mem_to_reg = 2'b00; alu_op = 2'b00; jump = 1'b0; branch = 1'b0; mem_read = 1'b0; mem_write = 1'b0; alu_src = 1'b0; reg_write = 1'b1; sign_or_zero = 1'b1; end endcase end end endmodule
Verilog code for Single cycle MIPS processor:
module mips_16( input clk,reset, output[15:0] pc_out, alu_result //,reg3,reg4 ); reg[15:0] pc_current; wire signed[15:0] pc_next,pc2; wire [15:0] instr; wire[1:0] reg_dst,mem_to_reg,alu_op; wire jump,branch,mem_read,mem_write,alu_src,reg_write ; wire [2:0] reg_write_dest; wire [15:0] reg_write_data; wire [2:0] reg_read_addr_1; wire [15:0] reg_read_data_1; wire [2:0] reg_read_addr_2; wire [15:0] reg_read_data_2; wire [15:0] sign_ext_im,read_data2,zero_ext_im,imm_ext; wire JRControl; wire [2:0] ALU_Control; wire [15:0] ALU_out; wire zero_flag; wire signed[15:0] im_shift_1, PC_j, PC_beq, PC_4beq,PC_4beqj,PC_jr; wire beq_control; wire [14:0] jump_shift_1; wire [15:0]mem_read_data; wire [15:0] no_sign_ext; wire sign_or_zero; // PC always @(posedge clk or posedge reset) begin if(reset) pc_current <= 16'd0; else pc_current <= pc_next; end // PC + 2 assign pc2 = pc_current + 16'd2; // instruction memory instr_mem instrucion_memory(.pc(pc_current),.instruction(instr)); // jump shift left 1 assign jump_shift_1 = {instr[13:0],1'b0}; // control unit control control_unit(.reset(reset),.opcode(instr[15:13]),.reg_dst(reg_dst) ,.mem_to_reg(mem_to_reg),.alu_op(alu_op),.jump(jump),.branch(branch),.mem_read(mem_read), .mem_write(mem_write),.alu_src(alu_src),.reg_write(reg_write),.sign_or_zero(sign_or_zero)); // multiplexer regdest assign reg_write_dest = (reg_dst==2'b10) ? 3'b111: ((reg_dst==2'b01) ? instr[6:4] :instr[9:7]); // register file assign reg_read_addr_1 = instr[12:10]; assign reg_read_addr_2 = instr[9:7]; register_file reg_file(.clk(clk),.rst(reset),.reg_write_en(reg_write), .reg_write_dest(reg_write_dest), .reg_write_data(reg_write_data), .reg_read_addr_1(reg_read_addr_1), .reg_read_data_1(reg_read_data_1), .reg_read_addr_2(reg_read_addr_2), .reg_read_data_2(reg_read_data_2)); //.reg3(reg3), //.reg4(reg4)); // sign extend assign sign_ext_im = {{9{instr[6]}},instr[6:0]}; assign zero_ext_im = {{9{1'b0}},instr[6:0]}; assign imm_ext = (sign_or_zero==1'b1) ? sign_ext_im : zero_ext_im; // JR control JR_Control JRControl_unit(.alu_op(alu_op),.funct(instr[3:0]),.JRControl(JRControl)); // ALU control unit ALUControl ALU_Control_unit(.ALUOp(alu_op),.Function(instr[3:0]),.ALU_Control(ALU_Control)); // multiplexer alu_src assign read_data2 = (alu_src==1'b1) ? imm_ext : reg_read_data_2; // ALU alu alu_unit(.a(reg_read_data_1),.b(read_data2),.alu_control(ALU_Control),.result(ALU_out),.zero(zero_flag)); // immediate shift 1 assign im_shift_1 = {imm_ext[14:0],1'b0}; // assign no_sign_ext = ~(im_shift_1) + 1'b1; // PC beq add assign PC_beq = (im_shift_1[15] == 1'b1) ? (pc2 - no_sign_ext): (pc2 +im_shift_1); // beq control assign beq_control = branch & zero_flag; // PC_beq assign PC_4beq = (beq_control==1'b1) ? PC_beq : pc2; // PC_j assign PC_j = {pc2[15],jump_shift_1}; // PC_4beqj assign PC_4beqj = (jump == 1'b1) ? PC_j : PC_4beq; // PC_jr assign PC_jr = reg_read_data_1; // PC_next assign pc_next = (JRControl==1'b1) ? PC_jr : PC_4beqj; // data memory data_memory datamem(.clk(clk),.mem_access_addr(ALU_out), .mem_write_data(reg_read_data_2),.mem_write_en(mem_write),.mem_read(mem_read), .mem_read_data(mem_read_data)); // write back assign reg_write_data = (mem_to_reg == 2'b10) ? pc2:((mem_to_reg == 2'b01)? mem_read_data: ALU_out); // output assign pc_out = pc_current; assign alu_result = ALU_out; endmodule
Verilog testbench code for the single-cycle MIPS processor:
module tb_mips16; // Inputs reg clk; reg reset; // Outputs wire [15:0] pc_out; wire [15:0] alu_result;//,reg3,reg4; // Instantiate the Unit Under Test (UUT) mips_16 uut ( .clk(clk), .reset(reset), .pc_out(pc_out), .alu_result(alu_result) //.reg3(reg3), // .reg4(reg4) ); initial begin clk = 0; forever #10 clk = ~clk; end initial begin // Initialize Inputs //$monitor ("register 3=%d, register 4=%d", reg3,reg4); reset = 1; // Wait 100 ns for global reset to finish #100; reset = 0; // Add stimulus here end endmodule