├── sign_extend.v ├── control_table.csv ├── branch_control.v ├── tb ├── sign_extend_tb.v ├── mux2_tb.v ├── adder_tb.v ├── branch_control_tb.v ├── mux3_tb.v ├── pc_tb.v ├── JumpAddr_tb.v ├── Control_tb.v ├── Alu_control_tb.v ├── Decoder_tb.v ├── Memory_tb.v ├── mipscpu_tb.v ├── Alu_tb.v ├── Regfile_tb.v ├── AluRegfile_tb.v └── cpu_tb.v ├── JumpAddr.v ├── .gitignore ├── adder.v ├── mux2.v ├── pc.v ├── sandbox.v ├── mux3.v ├── License.txt ├── Memory.v ├── AluRegfile.v ├── Decoder.v ├── Regfile.v ├── Alu_control.v ├── mipscpu.v ├── Alu.v ├── readme.md ├── Control.v └── cpu.v /sign_extend.v: -------------------------------------------------------------------------------- 1 | module sign_extend_32( 2 | input wire [15:0] input_16, 3 | output reg [31:0] result_32 4 | ); 5 | 6 | always @(*) begin 7 | result_32[15:0] <= input_16; 8 | case (input_16[15]) 9 | 1'b0: result_32 [31:16] <= '0; 10 | 1'b1: result_32 [31:16] <= '1; 11 | endcase 12 | end 13 | endmodule 14 | -------------------------------------------------------------------------------- /control_table.csv: -------------------------------------------------------------------------------- 1 | Opcode, ALUop, mem_toreg, mem_read, branch, alu_src, reg_dst, reg_write, jump, error 2 | LW,0,1,1,0,1,0,1,0,0 3 | SW,0,3,0,0,1,3,0,0,0 4 | BEQ,1,3,0,10,0,3,0,0,0 5 | BNE,1,3,0,11,0,3,0,0,0 6 | ADDI,0,0,0,0,1,3,1,0,0 7 | J,11,3,0,0,0,3,0,1,0 8 | JAL,11,2,0,0,0,2,1,1,0 9 | JR,10,0,0,00,0,1,1,2,0 10 | R-type,10,0,0,00,0,1,1,0,0 11 | -------------------------------------------------------------------------------- /branch_control.v: -------------------------------------------------------------------------------- 1 | // Rui Tu 2 | module branch_control( 3 | branch_op, 4 | zero, 5 | do_branch 6 | ); 7 | 8 | input wire [1:0] branch_op; 9 | input wire zero; 10 | output reg do_branch; 11 | 12 | always@(*) begin 13 | // do_branch will be 1 if we are going to use a branch 14 | do_branch <= (branch_op[0] ^ zero) & branch_op[1]; 15 | end 16 | 17 | endmodule 18 | -------------------------------------------------------------------------------- /tb/sign_extend_tb.v: -------------------------------------------------------------------------------- 1 | 2 | 3 | module sign_extend_test; 4 | reg [15:0] in; 5 | wire [31:0] out; 6 | sign_extend_32 dut (in, out); 7 | 8 | initial 9 | begin 10 | $monitor("input: %b, output: %b", in, out); 11 | in = 16'hFFFF; 12 | #5; 13 | in = 16'h0000; 14 | #5; 15 | in = 16'h8000; 16 | #5; 17 | in = 16'h4000; 18 | #5; 19 | in = 16'h7FFF; 20 | #5; 21 | end 22 | endmodule 23 | -------------------------------------------------------------------------------- /JumpAddr.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // jump_addr Module 3 | // 4 | 5 | module jump_addr ( 6 | jump_relative_addr, 7 | pc_upper, 8 | jump_addr 9 | ); 10 | 11 | input wire [25:0] jump_relative_addr; 12 | input wire [3:0] pc_upper; 13 | output reg [31:0] jump_addr; 14 | 15 | always @(*) 16 | begin 17 | jump_addr[27:0] <= jump_relative_addr << 2; 18 | jump_addr[31:28] <= pc_upper; 19 | end 20 | 21 | endmodule 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ws.vim 2 | .*.swp 3 | .*.swo 4 | 5 | # ignore ModelSim generated files and directories (temp files and so on) 6 | [_@]* 7 | 8 | # ignore compilation output of ModelSim 9 | *.mti 10 | *.dat 11 | *.dbs 12 | *.psm 13 | *.bak 14 | *.cmp 15 | *.jpg 16 | *.html 17 | *.bsf 18 | 19 | # ignore simulation output of ModelSim 20 | wlf* 21 | *.wlf 22 | *.vstf 23 | *.ucdb 24 | cov*/ 25 | transcript* 26 | sc_dpiheader.h 27 | vsim.dbg 28 | -------------------------------------------------------------------------------- /adder.v: -------------------------------------------------------------------------------- 1 | // 2016 Rui Tu 2 | // adder Module 3 | // we don't handle overflows in anyform 4 | 5 | module adder ( 6 | input_a, 7 | input_b, 8 | result 9 | ); 10 | parameter width = 32; 11 | 12 | input wire [width - 1: 0] input_a; 13 | input wire [width - 1: 0] input_b; 14 | 15 | output reg [width - 1: 0] result; 16 | 17 | 18 | always@(*) begin 19 | result <= input_a + input_b; 20 | end 21 | 22 | 23 | endmodule 24 | -------------------------------------------------------------------------------- /tb/mux2_tb.v: -------------------------------------------------------------------------------- 1 | 2 | // 2016 Rui Tu 3 | // mux2_tb Module 4 | 5 | 6 | module mux2_tb; 7 | reg [31:0]input_a; 8 | reg [31:0]input_b; 9 | reg choose; 10 | 11 | wire [31:0]result; 12 | 13 | mux2 dut( 14 | input_a, 15 | input_b, 16 | choose, 17 | result 18 | ); 19 | 20 | initial begin 21 | $monitor("A: %h B: %h, CHOOSE: %b, result %h", input_a, input_b, choose, result); 22 | input_a = 32'hA; input_b = 32'hB; 23 | choose = 2'd0;#5; 24 | choose = 2'd1;#5; 25 | end 26 | endmodule 27 | 28 | -------------------------------------------------------------------------------- /mux2.v: -------------------------------------------------------------------------------- 1 | 2 | // 2016 Rui Tu 3 | // mux2 Module 4 | module mux2 ( 5 | input_a, 6 | input_b, 7 | 8 | choose, 9 | result 10 | ); 11 | parameter width = 32; 12 | 13 | input wire [width - 1: 0] input_a; 14 | input wire [width - 1: 0] input_b; 15 | input wire choose; 16 | 17 | output reg [width - 1: 0] result; 18 | 19 | localparam CHOOSE_A = 1'b0, 20 | CHOOSE_B = 1'b1; 21 | 22 | always@(*) begin 23 | case(choose) 24 | CHOOSE_A: result <= input_a; 25 | CHOOSE_B: result <= input_b; 26 | endcase 27 | end 28 | endmodule 29 | -------------------------------------------------------------------------------- /pc.v: -------------------------------------------------------------------------------- 1 | // Rui Tu 2 | module pc( 3 | clock, 4 | reset, 5 | pc_in, 6 | pc_out 7 | ); 8 | 9 | 10 | reg [31:0] pc_reg; 11 | 12 | input wire clock; 13 | input wire reset; 14 | input wire [31:0] pc_in; 15 | output reg [31:0] pc_out; 16 | 17 | 18 | // we assume the output of the jumpmux will be 19 | // stable until the start of the posedge of the next 20 | // clock cycle 21 | always@(posedge clock) begin 22 | if (reset) 23 | begin 24 | pc_reg = 32'h0; 25 | end 26 | else 27 | begin 28 | pc_reg = pc_in; 29 | end 30 | 31 | pc_out = pc_reg; 32 | end 33 | 34 | endmodule 35 | -------------------------------------------------------------------------------- /tb/adder_tb.v: -------------------------------------------------------------------------------- 1 | // 2016 Rui Tu 2 | // adder_tb Module 3 | // we don't handle overflows in anyform 4 | 5 | 6 | module adder_tb; 7 | reg [31:0]input_a; 8 | reg [31:0]input_b; 9 | 10 | wire [31:0]result; 11 | 12 | localparam width = 32; 13 | adder #(.width(width)) dut( 14 | input_a, 15 | input_b, 16 | result 17 | ); 18 | 19 | initial begin 20 | $monitor("%d + %d = %d", input_a, input_b, result); 21 | input_a = 32'd0; input_b = 32'h0; #5; 22 | input_a = 32'd1000000; input_b = 32'd99999999; #5; 23 | input_a = 32'd4; input_b = 32'd10000000; #5; 24 | end 25 | 26 | 27 | 28 | 29 | endmodule 30 | -------------------------------------------------------------------------------- /tb/branch_control_tb.v: -------------------------------------------------------------------------------- 1 | // Rui Tu 2 | 3 | 4 | module branch_control_tb; 5 | reg [1:0] branchop; 6 | reg zero; 7 | 8 | wire out; 9 | branch_control dut (branchop, zero, out); 10 | 11 | initial 12 | begin 13 | $monitor("branchop: %b, zero: %b, out: %b", branchop, zero, out); 14 | branchop = 2'b00; zero = 1'b0; #5; 15 | branchop = 2'b10; zero = 1'b0; #5; 16 | branchop = 2'b01; zero = 1'b0; #5; 17 | branchop = 2'b00; zero = 1'b1; #5; 18 | branchop = 2'b11; zero = 1'b0; #5; 19 | branchop = 2'b01; zero = 1'b1; #5; 20 | branchop = 2'b10; zero = 1'b1; #5; 21 | branchop = 2'b11; zero = 1'b1; #5; 22 | end 23 | endmodule 24 | -------------------------------------------------------------------------------- /tb/mux3_tb.v: -------------------------------------------------------------------------------- 1 | // 2016 Rui Tu 2 | // mux3_tb Module 3 | 4 | 5 | module mux3_tb; 6 | reg [31:0]input_a; 7 | reg [31:0]input_b; 8 | reg [31:0]input_c; 9 | reg [1:0]choose; 10 | 11 | wire [31:0]result; 12 | 13 | mux3 dut( 14 | input_a, 15 | input_b, 16 | input_c, 17 | choose, 18 | result 19 | ); 20 | 21 | initial begin 22 | $monitor("A: %h B: %h C: %h, CHOOSE: %b, result %h", input_a, input_b, input_c, choose, result); 23 | input_a = 32'hA; input_b = 32'hB; input_c = 32'hC; 24 | choose = 2'd0;#5; 25 | choose = 2'd1;#5; 26 | choose = 2'd2;#5; 27 | choose = 2'd3;#5; 28 | end 29 | 30 | 31 | 32 | 33 | endmodule 34 | 35 | -------------------------------------------------------------------------------- /tb/pc_tb.v: -------------------------------------------------------------------------------- 1 | // Rui Tu 2 | module pc_test; 3 | reg reset; 4 | reg clk; 5 | reg [31:0] pc_in; 6 | wire [31:0] pc_out; 7 | 8 | pc dut (clk, reset, pc_in, pc_out); 9 | 10 | initial begin 11 | clk = 0; 12 | reset = 0; 13 | end 14 | 15 | always 16 | #5 clk = !clk; 17 | 18 | initial 19 | begin 20 | 21 | 22 | $monitor("clk: %b, reset: %b, pc_in: %h, pc_out: %h", clk, reset, pc_in, pc_out); 23 | reset = 1; #10; 24 | reset = 0; #10; 25 | pc_in = 32'haaaaaaaa; #10; 26 | pc_in = 32'hbbbbbbbb; #10; 27 | pc_in = 32'hcccccccc; #10; 28 | pc_in = 32'hdddddddd; #10; 29 | pc_in = 32'heeeeeeee; #10; 30 | pc_in = 32'hffffffff; #10; 31 | end 32 | endmodule 33 | -------------------------------------------------------------------------------- /sandbox.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // Sandbox Module 3 | 4 | `timescale 1ns / 1ns 5 | module sandbox(); 6 | 7 | reg [7:0] a, b; 8 | wire [7:0] res; 9 | wire carry; 10 | 11 | reg [7:0] c, d; 12 | wire [7:0] res2; 13 | wire carry2; 14 | wire x, y; 15 | 16 | assign {carry, res} = a + b; 17 | 18 | assign {carry2, res2} = c - d; 19 | 20 | assign {x, y} = 2'b10; 21 | 22 | initial 23 | begin 24 | a=0; b=0; 25 | #10 a=8; b=8; 26 | #10 a=100; b=100; 27 | #10 a=255; b=1; 28 | #10 a=255; b=255; 29 | c=0; d=0; 30 | #10 c=8; d=8; 31 | #10 c=100; d=100; 32 | #10 c=255; d=1; 33 | #10 c=-10; d=255; 34 | $display("{x,y} = 2'b10 -- x(%d), y(%d)", x, y); 35 | end 36 | 37 | initial 38 | begin 39 | $monitor("%d, %d + %d = %d (%d)", $time, a, b, res, carry); 40 | $monitor("%d, %d - %d = %d (%d)", $time, c, d, res2, carry2); 41 | end 42 | 43 | 44 | 45 | endmodule 46 | -------------------------------------------------------------------------------- /tb/JumpAddr_tb.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // jump_addr Module Testbench 3 | // 4 | 5 | module jump_addr_test; 6 | reg [25:0] jump_relative_addr; 7 | reg [3:0] pc_upper; 8 | wire [31:0] jump_addr; 9 | 10 | jump_addr dut(jump_relative_addr, pc_upper, jump_addr); 11 | 12 | initial 13 | begin // BEG Test stimulus 14 | $monitor("relativeaddr: %h, pcupper: %h || jumpaddr: %h", jump_relative_addr, pc_upper, jump_addr); 15 | jump_relative_addr = 26'h1; 16 | pc_upper = 'h0; 17 | #10; 18 | 19 | jump_relative_addr = 26'h0; 20 | pc_upper = 4'hF; 21 | #10; 22 | 23 | jump_relative_addr = 26'h1; 24 | pc_upper = 4'hF; 25 | #10; 26 | 27 | jump_relative_addr = 26'h2AAAAAA; 28 | pc_upper = 4'hF; 29 | #10; 30 | jump_relative_addr = 26'h0CCCCCC; 31 | pc_upper = 4'hF; 32 | #10; 33 | 34 | jump_relative_addr = 26'h3FFFFFF; 35 | pc_upper = 4'hF; 36 | #10; 37 | 38 | end 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /mux3.v: -------------------------------------------------------------------------------- 1 | // 2016 Rui Tu 2 | // adder Module 3 | // we don't handle overflows in anyform 4 | // THe default will return the most recent choice 5 | module mux3 ( 6 | input_a, 7 | input_b, 8 | input_c, 9 | 10 | choose, 11 | result 12 | ); 13 | parameter width = 32; 14 | 15 | input wire [width - 1: 0] input_a; 16 | input wire [width - 1: 0] input_b; 17 | input wire [width - 1: 0] input_c; 18 | input wire [1:0] choose; 19 | 20 | output reg [width - 1: 0] result; 21 | 22 | localparam CHOOSE_A = 2'b00, 23 | CHOOSE_B = 2'b01, 24 | CHOOSE_C = 2'b10; 25 | 26 | always@(*) begin 27 | case(choose) 28 | CHOOSE_A: result <= input_a; 29 | CHOOSE_B: result <= input_b; 30 | CHOOSE_C: result <= input_c; 31 | // default gets the result from the most recent value 32 | // $display("UNknown choose for mux3"); 33 | endcase 34 | end 35 | endmodule 36 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright 2017 Ryan Leonard 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Memory.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // Memory Module 3 | // 4 | // Read/write happenning at same time is unexpected behavior. 5 | // 6 | // Read enabled is no longer used 7 | module memory ( 8 | clock, 9 | write_enabled, 10 | read_enabled, 11 | input_address, 12 | input_data, 13 | output_data, 14 | err_invalid_address 15 | ); 16 | 17 | // Parametrs to change the size of our system's basic 18 | parameter 19 | ON = 1'b1, 20 | OFF = 1'b0, 21 | MEMORY_SIZE = 1024, 22 | WORD_SIZE = 32; // 32 --> 32bit system, 64 --> 64bit system 23 | 24 | input wire clock; 25 | input wire write_enabled; 26 | input wire read_enabled; 27 | input wire [WORD_SIZE-1:0] input_address; 28 | input wire [WORD_SIZE-1:0] input_data; 29 | output wire [WORD_SIZE-1:0] output_data; 30 | output reg err_invalid_address; 31 | 32 | // A data structure 33 | reg [WORD_SIZE:0] data[MEMORY_SIZE:0]; 34 | 35 | // Begin computing on positive edge 36 | always @ (negedge clock) 37 | begin 38 | err_invalid_address <= (input_address > MEMORY_SIZE-1) || (input_address < 0) ? ON : OFF; 39 | 40 | if (write_enabled) 41 | data[input_address] <= input_data; 42 | end 43 | 44 | assign output_data = data[input_address]; 45 | 46 | endmodule 47 | -------------------------------------------------------------------------------- /AluRegfile.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // ALU + RF Module 3 | 4 | `timescale 1ns / 1ns 5 | module alu_rf_32( 6 | input wire clock, 7 | // Register File Knobs 8 | input wire write_enabled, 9 | input wire [4:0] read_addr_s, 10 | input wire [4:0] read_addr_t, 11 | input wire [4:0] write_addr, 12 | // ALU Knob 13 | input wire [3:0] control, 14 | // ALU Outputs 15 | output wire cout, 16 | output wire zero, 17 | output wire err_overflow, 18 | output wire err_invalid_control 19 | ); 20 | 21 | // The nets interconnecting our alu and rf 22 | wire [31:0] regfile_to_alu_s; 23 | wire [31:0] regfile_to_alu_t; 24 | wire [31:0] alu_result_write_data; // It is a register for laziness 25 | 26 | // Connect our ALU to our Register File (rf) 27 | alu_32 alu( 28 | .clock (clock), 29 | .input_a (regfile_to_alu_s), 30 | .input_b (regfile_to_alu_t), 31 | .result (alu_result_write_data), 32 | .control (control), 33 | .cout (cout), 34 | .zero (zero), 35 | .err_overflow (err_overflow), 36 | .err_invalid_control (err_invalid_control) 37 | ); 38 | 39 | rf_32 regfile( 40 | .clock (clock), 41 | .write_data (alu_result_write_data), 42 | .outA (regfile_to_alu_s), 43 | .outB (regfile_to_alu_t), 44 | .read_addr_s (read_addr_s), 45 | .read_addr_t (read_addr_t), 46 | .write_addr (write_addr), 47 | .write_enabled (write_enabled) 48 | ); 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /Decoder.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // Decoder Module 3 | // 4 | // R-type 5 | // opcode rs rt rd shamt alu_function 6 | // ______ ______ ______ ______ ______ ______ 7 | // |______|______|______|______|______|______| 8 | // 6bit 5bit 5bit 5bit 5bit 6bit 9 | // 10 | // 11 | // I-type 12 | // opcode rs rt immediate 13 | // ______ ______ ______ ____________________ 14 | // |______|______|______|____________________| 15 | // 6bit 5bit 5bit 16bit 16 | // 17 | // J-type 18 | // opcode jump_target 19 | // ______ __________________________________ 20 | // |______|__________________________________| 21 | // 6bit 26bit 22 | // 23 | 24 | module decoder_32( 25 | instruction, 26 | opcode, 27 | rs, 28 | rt, 29 | rd, 30 | shamt, 31 | funct, 32 | immediate, 33 | jump_target 34 | ); 35 | 36 | input wire [31:0] instruction; 37 | output wire [5:0] opcode; 38 | output wire [4:0] rs; 39 | output wire [4:0] rt; 40 | output wire [4:0] rd; 41 | output wire [4:0] shamt; 42 | output wire [5:0] funct; 43 | output wire [15:0] immediate; 44 | output wire [25:0] jump_target; 45 | 46 | assign opcode = instruction[31:26]; 47 | assign rs = instruction[25:21]; 48 | assign rt = instruction[20:16]; 49 | assign rd = instruction[15:11]; 50 | assign shamt = instruction[10:06]; 51 | assign funct = instruction[05:00]; 52 | assign immediate = instruction[15:00]; 53 | assign jump_target = instruction[25:00]; 54 | 55 | endmodule 56 | -------------------------------------------------------------------------------- /Regfile.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // RegisterFile (RF) Module 3 | // 4 | // The internal data structure is a collection of 5 | // 32 registeread_addr_s each 32 bits in size. This is represented 6 | // using the 'memories' data structure as discussed in: 7 | // http://www.verilogtutorial.info/chapter_3.htm 8 | // 9 | // Notice that on the positive edge of each clock cycle, we 10 | // are performing data write. On the negative edge of each clock 11 | // cycle, we are performing data read. 12 | 13 | // TODO: How do we make the finish bit work as expected? 14 | 15 | module rf_32( 16 | clock, 17 | read_enabled, 18 | read_addr_s, 19 | read_addr_t, 20 | write_enabled, 21 | write_addr, 22 | write_data, 23 | outA, 24 | outB 25 | ); 26 | 27 | localparam 28 | REG_SIZE = 32, 29 | REGFILE_SIZE = 32, 30 | INDEX_SIZE = 5, 31 | ZERO = 32'b0; 32 | 33 | input wire clock; 34 | input wire read_enabled; 35 | input wire [INDEX_SIZE-1:0] read_addr_s; 36 | input wire [INDEX_SIZE-1:0] read_addr_t; 37 | input wire write_enabled; 38 | input wire [INDEX_SIZE-1:0] write_addr; 39 | input wire [REG_SIZE-1:0] write_data; 40 | output wire [REG_SIZE-1:0] outA; 41 | output wire [REG_SIZE-1:0] outB; 42 | 43 | // A 'memories' data structure representing: 44 | // 32 registeread_addr_s each 32 bits 45 | reg [REG_SIZE-1:0] register_file[REGFILE_SIZE-1:0]; 46 | 47 | // write logic 48 | always @ (negedge clock) 49 | begin 50 | if (write_enabled) 51 | register_file[write_addr] <= write_data; 52 | register_file[0] <= ZERO; 53 | end 54 | 55 | // Read logic is combinational 56 | assign outA = register_file[read_addr_s]; 57 | assign outB = register_file[read_addr_t]; 58 | 59 | endmodule 60 | -------------------------------------------------------------------------------- /tb/Control_tb.v: -------------------------------------------------------------------------------- 1 | module control_test; 2 | reg [5:0] opcode; 3 | reg [5:0] funct; 4 | 5 | wire [1:0] alu_op; 6 | wire [1:0] mem_toreg; 7 | wire mem_write; 8 | wire mem_read; 9 | wire [1:0] branch; 10 | wire alu_src; 11 | wire [1:0] reg_dst; 12 | wire reg_write; 13 | wire [1:0] jump; 14 | wire error; 15 | 16 | control_32 dut ( 17 | .opcode(opcode), 18 | .funct(funct), 19 | .alu_op(alu_op), 20 | .mem_toreg(mem_toreg), 21 | .mem_write(mem_write), 22 | .mem_read(mem_read), 23 | .branch(branch), 24 | .alu_src(alu_src), 25 | .reg_dst(reg_dst), 26 | .reg_write(reg_write), 27 | .jump(jump), 28 | .err_illegal_opcode(error) 29 | ); 30 | 31 | initial begin 32 | funct <= 0; 33 | $dumpfile("control_test.vcd"); 34 | $dumpvars(0, control_test); 35 | 36 | $display("Opcode, ALUop, mem_toreg, mem_read, branch, alu_src, reg_dst, reg_write, jump, error"); 37 | $monitor("%b,%b,%d,%b,%b,%b,%d,%b,%d,%b", opcode, alu_op, mem_toreg, mem_read, branch, alu_src, reg_dst, reg_write, jump, error); 38 | opcode <= 6'b0000_00; #5; // r_type 39 | 40 | $display("LW"); 41 | opcode = dut.lw; #5;// lw 42 | $display("SW"); 43 | opcode = dut.sw; #5;// sw 44 | $display("BEQ"); 45 | opcode = dut.beq; #5;// beq 46 | $display("BNE"); 47 | opcode = dut.bne; #5;// bne 48 | $display("R-type"); 49 | opcode = dut.r_type; #5;// r-type 50 | $display("ADDI"); 51 | opcode = dut.addi; #5;// addi 52 | $display("J"); 53 | opcode = dut.j; #5;// jump 54 | $display("JAL"); 55 | opcode = dut.jal; 56 | #5;// jal 57 | $display("JR"); 58 | opcode = dut.r_type; funct = dut.jr_func; 59 | #5;// jr 60 | 61 | $display("\nError codes\n\n"); 62 | opcode <= 6'b0011_10; #5;// r_type 63 | opcode <= 6'b1111_11; #5;// lw 64 | opcode <= 6'b1110_11; #5;// sw 65 | opcode <= 6'b0111_10; #5;// beq 66 | opcode <= 6'b1110_10; #5;// addi 67 | opcode <= 6'b1001_11; #5;// jump 68 | end 69 | endmodule 70 | -------------------------------------------------------------------------------- /tb/Alu_control_tb.v: -------------------------------------------------------------------------------- 1 | module alu_control_test; 2 | reg [5:0] func; 3 | 4 | reg [1:0] alu_op; 5 | wire [3:0] alu_control; 6 | wire alu_op_error; 7 | wire func_error; 8 | alu_control_32 dut( 9 | .func(func), 10 | .alu_op(alu_op), 11 | .alu_control(alu_control), 12 | .err_illegal_func_code(func_error), 13 | .err_illegal_alu_op(alu_op_error) 14 | ); 15 | 16 | initial begin 17 | 18 | $dumpfile("alu_control_32_test.vcd"); 19 | $dumpvars(0, dut); 20 | 21 | $monitor(" function code: %b, ALUop: %b, alu_control: %b, func_error: %b, , alu_op_error: %b", func, alu_op, alu_control, func_error, alu_op_error); 22 | 23 | $display("\n=======Mem type\n"); 24 | func <= 6'b10_0000; alu_op = 2'b00; #5; // add 25 | func <= 6'b10_0010; alu_op = 2'b00; #5; // sub 26 | func <= 6'b10_0100; alu_op = 2'b00; #5; // or 27 | func <= 6'b10_0101; alu_op = 2'b00; #5; // and 28 | func <= 6'b101_010; alu_op = 2'b00; #5; // slt 29 | 30 | $display("\n======= branch type\n"); 31 | func <= 6'b10_0000; alu_op = 2'b01; #5; // r_type 32 | func <= 6'b10_0010; alu_op = 2'b01; #5; // lw 33 | func <= 6'b10_0100; alu_op = 2'b01; #5; // sw 34 | func <= 6'b10_0101; alu_op = 2'b01; #5; // beq 35 | func <= 6'b101_010; alu_op = 2'b01; #5; // addi 36 | 37 | $display("\n======= r type\n"); 38 | func <= 6'b10_0000; alu_op = 2'b10; #5; // r_type 39 | func <= 6'b10_0010; alu_op = 2'b10; #5; // lw 40 | func <= 6'b10_0100; alu_op = 2'b10; #5; // sw 41 | func <= 6'b10_0101; alu_op = 2'b10; #5; // beq 42 | func <= 6'b101_010; alu_op = 2'b10; #5; // addi 43 | func <= dut.jr_func; alu_op = dut.arith_aluop; #5; // jr 44 | 45 | $display("\n======= Error function code\n"); 46 | func <= 6'b11_1010; alu_op = 2'b10; #5; // r_type 47 | func <= 6'b11_1111; alu_op = 2'b10; #5; // lw 48 | func <= 6'b11_0110; alu_op = 2'b10; #5; // sw 49 | func <= 6'b11_0101; alu_op = 2'b10; #5; // beq 50 | func <= 6'b101_011; alu_op = 2'b10; #5; // addi 51 | 52 | $display("\n======= ALUop code\n"); 53 | func <= 6'b11_1010; alu_op = 2'b11; #5; // r_type 54 | func <= 6'b11_1111; alu_op = 2'b11; #5; // lw 55 | func <= 6'b11_0110; alu_op = 2'b11; #5; // sw 56 | func <= 6'b11_0101; alu_op = 2'b11; #5; // beq 57 | func <= 6'b101_011; alu_op = 2'b11; #5; // addi 58 | end 59 | endmodule 60 | -------------------------------------------------------------------------------- /tb/Decoder_tb.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // Decoder Module Testbench 3 | // 4 | module decoder_32_test; 5 | 6 | reg [31:0] instruction; 7 | wire [5:0] opcode; 8 | wire [4:0] rs; 9 | wire [4:0] rt; 10 | wire [4:0] rd; 11 | wire [4:0] shamt; 12 | wire [5:0] alu_function; 13 | wire [15:0] immediate; 14 | wire [25:0] jump_target; 15 | 16 | decoder_32 dut ( 17 | .instruction (instruction), 18 | .opcode (opcode), 19 | .rs (rs), 20 | .rt (rt), 21 | .rd (rd), 22 | .shamt (shamt), 23 | .funct (alu_function), 24 | .immediate (immediate), 25 | .jump_target (jump_target) 26 | ); 27 | 28 | // Test stimulus 29 | initial 30 | begin // BEG test 31 | 32 | $display("==========\nCheck misc instructions R-type\n"); 33 | instruction = 32'hffffffff; 34 | #10; 35 | instruction = 32'h00000000; 36 | #10; 37 | instruction = 32'b000001_00001_00001_00001_00001_000001; 38 | #10; 39 | instruction = 32'b100000_10000_01000_00100_00010_000001; 40 | #10; 41 | instruction = 32'b100000_10000_01000_00100_00010_000000; 42 | #10; 43 | 44 | $display("==========\nCheck misc instructions I-type\n"); 45 | instruction = 32'b000001_00001_00001_0000000000000000; 46 | #10; 47 | instruction = 32'b000001_00001_00001_1000000000000000; 48 | #10; 49 | instruction = 32'b000001_00001_00001_1111111111111111; 50 | #10; 51 | 52 | $display("==========\nCheck misc instructions J-type (max is jump is 3ffffff)\n"); 53 | instruction = {6'b000001, 26'h00000000}; 54 | #10; 55 | instruction = {7'b000001_1, 25'h00000000}; 56 | #10; 57 | instruction = {6'b000001, 26'hffffffff}; 58 | #10; 59 | 60 | $display("==========\nIm slow testing functions... !TODO!\n"); 61 | instruction = 32'h20100000; #10; 62 | instruction = 32'h20090003; #10; 63 | instruction = 32'h00000020; #10; 64 | instruction = 32'h00000020; #10; 65 | instruction = 32'h01295020; #10; 66 | instruction = 32'hAE090000; #10; 67 | instruction = 32'h00000020; #10; 68 | instruction = 32'hAE0A0004; #10; 69 | instruction = 32'h8E0B0000; #10; 70 | instruction = 32'h8E0C0004; #10; 71 | instruction = 32'h00000020; #10; 72 | instruction = 32'h00000020; #10; 73 | instruction = 32'h016C402A; #10; 74 | end // END testing 75 | 76 | // Basic console output 77 | initial 78 | begin 79 | $display("opcode, rs, rt, rd, shamt, alu_function || immediate || jump_target"); 80 | $monitor("%d, %d, %d, %d, %d, %d, %h, %h", 81 | opcode, rs, rt, rd, shamt, alu_function, immediate, jump_target); 82 | end 83 | 84 | endmodule 85 | 86 | -------------------------------------------------------------------------------- /Alu_control.v: -------------------------------------------------------------------------------- 1 | module alu_control_32 ( 2 | input wire[5:0] func, 3 | input wire[1:0] alu_op, 4 | 5 | output reg [3:0] alu_control, 6 | output reg err_illegal_func_code, 7 | output reg err_illegal_alu_op 8 | ); 9 | 10 | reg [3:0] temp_op; 11 | 12 | parameter add_func = 6'b10_0000, 13 | sub_func = 6'b10_0010, 14 | or_func = 6'b10_0101, 15 | and_func = 6'b10_0100, 16 | slt_func = 6'b101_010, 17 | // This function code is also hardcoded in Control module 18 | jr_func = 6'b001_000, 19 | mem_aluop = 2'b00, 20 | beq_aluop = 2'b01, 21 | arith_aluop = 2'b10, 22 | default_aluop = 2'b00, 23 | 24 | add_op = 4'b0010, 25 | sub_op = 4'b0110, 26 | and_op = 4'b0000, 27 | or_op = 4'b0001, 28 | slt_op = 4'b0111, 29 | default_op = 4'b0000; 30 | 31 | 32 | always @(*) begin 33 | case(func) 34 | add_func: begin 35 | temp_op <= add_op; 36 | err_illegal_func_code <= 0; 37 | end 38 | sub_func: begin 39 | temp_op <= sub_op; 40 | err_illegal_func_code <= 0; 41 | end 42 | or_func: begin 43 | temp_op <= or_op; 44 | err_illegal_func_code <= 0; 45 | end 46 | and_func: begin 47 | temp_op <= and_op; 48 | err_illegal_func_code <= 0; 49 | end 50 | slt_func: begin 51 | temp_op <= slt_op; 52 | err_illegal_func_code <= 0; 53 | end 54 | jr_func: begin 55 | // JR we don't care what the ALU does, so we use 'and_op' because it 56 | // is cheaper. 57 | temp_op <= and_op; 58 | err_illegal_func_code <= 0; 59 | end 60 | default: begin 61 | temp_op <= default_op; 62 | err_illegal_func_code <= 1; 63 | // $display("unimplement function code: %b\n", func); 64 | end 65 | endcase 66 | 67 | case(alu_op) 68 | mem_aluop: begin 69 | alu_control <= add_op; 70 | err_illegal_alu_op <= 0; 71 | end 72 | beq_aluop: begin 73 | alu_control <= sub_op; 74 | err_illegal_alu_op <= 0; 75 | end 76 | arith_aluop: begin 77 | alu_control <= temp_op; 78 | err_illegal_alu_op <= 0; 79 | end 80 | default: begin 81 | alu_control <= default_op; 82 | err_illegal_alu_op <= 1; 83 | // $display("unsupported ALUop: %b\n", alu_op); 84 | end 85 | endcase 86 | end 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /tb/Memory_tb.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // Memory Module Testbench 3 | // 4 | // 5 | module memory_32_test(); 6 | 7 | // setup our memory parameters 8 | localparam WORD_SIZE = 32; 9 | localparam MEMORY_SIZE = 1000; 10 | localparam ON = 1'b1; 11 | localparam OFF = 1'b0; 12 | 13 | // The reg/nets we will maniupulate/monitor for testing 14 | reg clock; 15 | reg read_enabled; 16 | reg write_enabled; 17 | reg [WORD_SIZE-1:0] address; 18 | reg [WORD_SIZE-1:0] input_data; 19 | wire error; 20 | wire [WORD_SIZE-1:0] output_data; 21 | 22 | // build a version of the Design Under Test (dut) 23 | // Instead of hand controlling the 'start' signal, we will 24 | // hook it up to the clock so that every clock cycle we will 25 | // attempt to perform either a read or a write to memory. 26 | memory 27 | #( 28 | .WORD_SIZE (WORD_SIZE), 29 | .MEMORY_SIZE (MEMORY_SIZE) 30 | ) dut( 31 | .clock (clock), 32 | .read_enabled (read_enabled), 33 | .write_enabled (write_enabled), 34 | .input_address (address), 35 | .input_data (input_data), 36 | .output_data (output_data), 37 | .err_invalid_address (error) 38 | ); 39 | 40 | task reset(); 41 | begin 42 | read_enabled = OFF; 43 | write_enabled = OFF; 44 | address = OFF; 45 | input_data = OFF; 46 | end 47 | endtask 48 | 49 | // Clock Generator (#10 period) 50 | initial 51 | begin 52 | clock = 1; 53 | #5; 54 | forever 55 | begin 56 | clock = ~clock; 57 | #5; 58 | end 59 | end 60 | 61 | integer i; 62 | initial 63 | begin // BEG Test stimulus 64 | 65 | $display("==========\n Write Values (offset 200) \n"); 66 | for (i=0; i> 2; 74 | pc pc( 75 | .clock(clock), 76 | .reset(reset), 77 | .pc_in(jumpmux_pc), 78 | .pc_out(pc_imem_addr) 79 | ); 80 | 81 | memory instruction_memory ( 82 | .clock(clock), 83 | .write_enabled(), // this will be wired up with a loader module 84 | .read_enabled(), // not now 85 | .input_address(pc_imem_addrshifted), // input data comes from pc 86 | .input_data(), // this will be wired up with a loader module 87 | .output_data(imem_dec_instr), // the output is instructions 88 | .err_invalid_address() // we don't care 89 | ); 90 | 91 | decoder_32 decode( 92 | .instruction(imem_dec_instr), 93 | .opcode(dec_opcode), 94 | .rs(dec_rf_readaddrs), 95 | .rt(dec_rf_readaddrt), 96 | .rd(dec_rfwritemux_b), 97 | .shamt(), 98 | .funct(dec_funct), 99 | .immediate(dec_immediate), 100 | .jump_target(dec_jumptarg) 101 | ); 102 | 103 | control_32 control ( 104 | .opcode(dec_opcode), 105 | .funct(dec_funct), 106 | .alu_op(control_aluopraw), 107 | .mem_toreg(control_wbmux), 108 | .mem_write(control_memwrite), 109 | .mem_read(control_memread), 110 | .branch(control_branch), 111 | .alu_src(control_alusrcmux), 112 | .reg_dst(control_rfwritemux), 113 | .reg_write(control_regwrite), 114 | .jump(control_jumpmux), 115 | .err_illegal_opcode() 116 | ); 117 | 118 | mux3 #(.width(5)) rfwrite_mux ( 119 | .input_a(dec_rfwritemux_a), 120 | .input_b(dec_rfwritemux_b), 121 | .input_c(rfwritemux_c), 122 | .choose(control_rfwritemux), 123 | .result(rfwritemux_rf_writeaddr) 124 | ); 125 | 126 | rf_32 regfile ( 127 | .clock(clock), 128 | .read_addr_s(dec_rf_readaddrs), 129 | .read_addr_t(dec_rf_readaddrt), 130 | .write_addr(rfwritemux_rf_writeaddr), 131 | .write_data(wbmux_rf_data), 132 | .write_enabled(control_regwrite), 133 | .read_enabled(), 134 | .outA(rf_alu_a), 135 | .outB(rf_alusrcmux_a) 136 | ); 137 | 138 | 139 | sign_extend_32 sign_ext( 140 | .input_16(dec_immediate), 141 | .result_32(sext_alusrcmux_b) 142 | ); 143 | 144 | mux2 alusrc_mux( 145 | .input_a(rf_alusrcmux_a), 146 | .input_b(sext_alusrcmux_b), 147 | .choose(control_alusrcmux), 148 | .result(alusrcmux_alu_b) 149 | ); 150 | 151 | alu_control_32 alu_control( 152 | .func(dec_funct), 153 | .alu_op(control_aluopraw), 154 | .alu_control(alucontrol_control), 155 | .err_illegal_alu_op(), 156 | .err_illegal_func_code() 157 | ); 158 | 159 | alu_32 alu ( 160 | .input_a(rf_alu_a), 161 | .input_b(alusrcmux_alu_b), 162 | .control(alucontrol_control), 163 | .result(alu_mem_addr), 164 | .zero(alu_branchcontrol_zero), 165 | .cout(), 166 | .err_overflow(), 167 | .err_invalid_control() 168 | ); 169 | 170 | // data memory is also 32 bit addressed -- same logic as instruction memory: 171 | // we drop the bottom two bits, essentially dividing by 4. 172 | wire [31:0] alu_mem_addrshifted = alu_mem_addr >> 2; 173 | memory data_memory ( 174 | .clock(clock), 175 | .input_address(alu_mem_addrshifted), 176 | .input_data(rf_mem_data), 177 | .read_enabled(control_memread), 178 | .write_enabled(control_memwrite), 179 | .output_data(mem_wbmux_b), 180 | .err_invalid_address() 181 | ); 182 | 183 | mux3 wb_mux( 184 | .input_a(alu_wbmux_a), 185 | .input_b(mem_wbmux_b), 186 | .input_c(pcincadder_wbmux_pcp4), 187 | .choose(control_wbmux), 188 | .result(wbmux_rf_data) 189 | ); 190 | 191 | adder pc_inc_adder( 192 | .input_a(pc_pcincadder), 193 | .input_b(pc_inc_advance), 194 | .result(pcincadder_branchmux_a) 195 | ); 196 | 197 | jump_addr jumpaddr( 198 | .jump_relative_addr(dec_jumptarg), 199 | .pc_upper(pcincadder_jumpaddr), 200 | .jump_addr(ja_jumpmux_b) 201 | ); 202 | 203 | adder branch_adder( 204 | .input_a(pcincadder_branchadder), 205 | .input_b(sext_branchadder), 206 | .result(branchadder_branchmux_b) 207 | ); 208 | 209 | branch_control branch_control( 210 | .branch_op(control_branch), 211 | .zero(alu_branchcontrol_zero), 212 | .do_branch(branchcontrol_branchmux) 213 | ); 214 | 215 | mux2 branch_mux( 216 | .input_a(pcincadder_branchmux_a), 217 | .input_b(branchadder_branchmux_b), 218 | .choose(branchcontrol_branchmux), 219 | .result(branchmux_jumpmux_a) 220 | ); 221 | 222 | // TODO: Does this account for when reading from instruction memory addresses 223 | // such that we actually use the pc_upper bits? 224 | // wire [31:0] ja_jumpmux_bshift = ja_jumpmux_b >> 2; // Divide by 4 after calculating jump address 225 | mux3 jump_mux( 226 | .input_a(branchmux_jumpmux_a), 227 | .input_b(ja_jumpmux_b), 228 | .input_c(rf_jumpmux_c), 229 | .choose(control_jumpmux), 230 | .result(jumpmux_pc) 231 | ); 232 | 233 | endmodule 234 | -------------------------------------------------------------------------------- /tb/AluRegfile_tb.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan Leonard 2 | // ALU + RF Module Testbench 3 | 4 | `timescale 1ns / 1ns 5 | module test_alu_rf_32; 6 | 7 | // The reg/nets we will maniupulate/monitor for testing 8 | // Essentially we are controlling which instruction is being 9 | // executed directly instead of the instruction decoder and 10 | // resultant instruction register telling us what to do. 11 | reg clock; //clock 12 | reg [4:0] rs; //input 13 | reg [4:0] rt; //input 14 | reg [4:0] rd; //input 15 | reg [3:0] control; //input 16 | reg we; //input 17 | wire cout; //out 18 | wire zero; //out 19 | wire overflow; //out 20 | wire err_invalid_control; //out 21 | 22 | // Connect our ALU to our Register File (rf) 23 | alu_rf_32 dut( 24 | .clock (clock), 25 | .read_addr_s (rs), // knob 26 | .read_addr_t (rt), // knob 27 | .write_addr (rd), // knob 28 | .write_enabled (we), // knob 29 | .control (control),// knob 30 | .cout (cout), // monitor 31 | .zero (zero), // monitor 32 | .err_overflow (overflow),// monitor 33 | .err_invalid_control (err_invalid_control)// monitor 34 | ); 35 | 36 | 37 | // Clock Generator 38 | initial 39 | begin 40 | clock = 1; 41 | forever 42 | #5 clock = !clock; 43 | end 44 | 45 | task no_operation(); 46 | begin 47 | rs=5'd0; 48 | rt=5'd0; 49 | we=1'b0; 50 | control=dut.alu.CONTROL_AND; 51 | rd=5'd0; 52 | end 53 | endtask 54 | 55 | // Test stimulus 56 | // Our test stimulus is broken down into three sections: 57 | // 1: Register Initialization 58 | // 2: Testing basic operations of ALU (uses RegisterFile[20-30]) 59 | // 3: Testing a toy program 60 | // 4: Testing a toy program filling the pipeline 61 | // 62 | // Nuances: 63 | // First detail we run into is that we are using a pipelined 64 | // structure and as a result to perform ONE computation we need 65 | // to perform Register Read, ALU Execution, and Register Write 66 | // each on their own clock cycle. This looks like the following: 67 | // (1) Register Read CC -- set Write Enabled to false, select rs 68 | // and rt values. 69 | // (2) ALU Execution CC -- set the control signal 70 | // (3) Register WriteBack CC -- set the writeback (rd) value and 71 | // enable write (set Write Enabled to true) 72 | // 73 | // Need to make sure that write enabled is turned off unless 74 | // we are writing to the register file (i.e. in the "Register 75 | // Write" Clock cycle). 76 | // To actually fill the pipeline we will have to do some strange 77 | // magic -- most notably, we will still have to abide by the three 78 | // clock cycle layout of above, 79 | // Performing a NOOP is simple enough by just adding r0 and r0 to 80 | // r0. 81 | // 82 | initial 83 | begin 84 | // Start with NOOP 85 | no_operation(); 86 | 87 | //////////////////////////////////////////////////////////// 88 | /// Register Initialization 89 | //////////////////////////////////////////////////////////// 90 | $display("==========\nSetup our Register File by hand\n"); 91 | dut.regfile.register_file[1] = 32'd1; 92 | dut.regfile.register_file[2] = 32'd16; 93 | dut.regfile.register_file[3] = 32'd4; 94 | dut.regfile.register_file[4] = 32'd0; 95 | dut.regfile.register_file[5] = 32'd0; 96 | dut.regfile.register_file[10] = 32'd0; 97 | #10; 98 | 99 | //////////////////////////////////////////////////////////// 100 | /// Testing basic addition 101 | //////////////////////////////////////////////////////////// 102 | no_operation(); 103 | #50; 104 | 105 | $display("==========\nRun our super basic program: adding together \n"); 106 | 107 | // add $r20, $r0, $r0 108 | rs=5'd0; 109 | rt=5'd0; 110 | we=1'b0; 111 | #10; // Register Read CC 112 | control=dut.alu.CONTROL_ADD; 113 | #10; // ALU Execution CC 114 | rd=5'd20; 115 | we=1'b1; 116 | #10; // Writeback CC 117 | 118 | // add $r20, $r20, $r2 119 | rs=5'd20; 120 | rt=5'd2; 121 | we=1'b0; 122 | #10; // Register Read CC 123 | control=dut.alu.CONTROL_ADD; 124 | #10; // ALU Execution CC 125 | rd=5'd20; 126 | we=1'b1; 127 | #10; // Writeback CC 128 | 129 | // add $r21, $r20, $r2 130 | rs=5'd20; 131 | rt=5'd2; 132 | we=1'b0; 133 | #10; // Register Read CC 134 | control=dut.alu.CONTROL_ADD; 135 | #10; // ALU Execution CC 136 | rd=5'd21; 137 | we=1'b1; 138 | #10; // Writeback CC 139 | 140 | //////////////////////////////////////////////////////////// 141 | /// Testing basic subtraction 142 | //////////////////////////////////////////////////////////// 143 | 144 | $display("==========\nRun our super basic program: subtracting \n"); 145 | 146 | // sub $r22, $r10, $r1 147 | rs=5'd20; 148 | rt=5'd1; 149 | we=1'b0; 150 | #10; // Register Read CC 151 | control=dut.alu.CONTROL_SUB; 152 | #10; // ALU Execution CC 153 | rd=5'd22; 154 | we=1'b1; 155 | #10; // Writeback CC 156 | 157 | // sub $r22, $r22, $r1 158 | rs=5'd22; 159 | rt=5'd1; 160 | we=1'b0; 161 | #10; // Register Read CC 162 | control=dut.alu.CONTROL_SUB; 163 | #10; // ALU Execution CC 164 | rd=5'd22; 165 | we=1'b1; 166 | #10; // Writeback CC 167 | 168 | //////////////////////////////////////////////////////////// 169 | /// Testing Toy Program 170 | //////////////////////////////////////////////////////////// 171 | no_operation(); 172 | #50; 173 | 174 | $display("==========\nRun our super toy program \n"); 175 | // Check if our decrementer is less than zero 176 | // slt $r5, $r3, $r0 177 | rs=5'd3; 178 | rt=5'd0; 179 | we=1'b0; 180 | #10; // Register Read CC 181 | control=dut.alu.CONTROL_SLT; 182 | #10; // ALU Execution CC 183 | rd=5'd5; 184 | we=1'b1; 185 | #10; // Writeback CC 186 | 187 | // Do the branching in verilog logic... 188 | while (dut.regfile.register_file[5] == 0) 189 | begin 190 | // add $r4, $r4, $r2 191 | rs=5'd4; 192 | rt=5'd2; 193 | we=1'b0; 194 | #10; // Register Read CC 195 | control=dut.alu.CONTROL_ADD; 196 | #10; // ALU Execution CC 197 | rd=5'd4; 198 | we=1'b1; 199 | #10; // Writeback CC 200 | 201 | // sub $r3, $r3, $r1 202 | rs=5'd3; 203 | rt=5'd1; 204 | we=1'b0; 205 | #10; // Register Read CC 206 | control=dut.alu.CONTROL_SUB; 207 | #10; // ALU Execution CC 208 | rd=5'd3; 209 | we=1'b1; 210 | #10; // Writeback CC 211 | 212 | // slt $r5, $r3, $r1 213 | rs=5'd3; 214 | rt=5'd1; 215 | we=1'b0; 216 | #10; // Register Read CC 217 | control=dut.alu.CONTROL_SLT; 218 | #10; // ALU Execution CC 219 | rd=5'd5; 220 | we=1'b1; 221 | #10; // Writeback CC 222 | end 223 | $display("R4\n Expected: %d\n Observed: %d", 224 | 32'h40, dut.regfile.register_file[4]); 225 | 226 | //////////////////////////////////////////////////////////// 227 | /// Testing basic pipelining 228 | //////////////////////////////////////////////////////////// 229 | $display("==========\nRunning a basic pipelined set of Ops\n"); 230 | no_operation(); 231 | #50; 232 | 233 | // add $r9, $r0, $r0 234 | // or $r10, $r2, $r1 235 | // and $r11, $r2, $r1 236 | // slt $r30, $r0, $r9 237 | rs=5'd0; rt=5'd0; we=1'b0; #10; // CC 1 238 | rs=5'd2; rt=5'd1; control=dut.alu.CONTROL_ADD; we=1'b0; #10; // CC 2 239 | rs=5'd2; rt=5'd1; rd=5'd9; control=dut.alu.CONTROL_OR; we=1'b1; #10; // CC 3 240 | rs=5'd9; rt=5'd10; rd=5'd10; control=dut.alu.CONTROL_AND; we=1'b1; #10; // CC 3 241 | rd=5'd11; control=dut.alu.CONTROL_SLT; we=1'b1; #10; // CC 4 242 | rd=5'd30; we=1'b1; #10; // CC 5 243 | 244 | $display("R30\n Expected: %d\n Observed: %d", 245 | 32'h01, dut.regfile.register_file[30]); 246 | 247 | //////////////////////////////////////////////////////////// 248 | /// End with NOOPs 249 | //////////////////////////////////////////////////////////// 250 | no_operation(); 251 | end 252 | 253 | // Basic console output 254 | initial 255 | $monitor("%d, %b(cout), %b(zero), %b(overflow), %b(control_err)", 256 | $time, cout, zero, overflow, err_invalid_control); 257 | 258 | endmodule 259 | -------------------------------------------------------------------------------- /tb/cpu_tb.v: -------------------------------------------------------------------------------- 1 | // 2016 Ryan and Rui 2 | 3 | // We got rid of the shift right 2 in the jump mux for JAL 4 | 5 | module cpu_test; 6 | 7 | reg clock; 8 | reg reset; 9 | cpu dut(clock, reset); 10 | 11 | localparam [31:0] fib_instr [0:43] = '{ 12 | 32'h201d0100, 13 | 32'h2010000c, 14 | 32'hafb00000, 15 | 32'h23bdfffc, 16 | 32'h0c000009, 17 | 32'h23bd0004, 18 | 32'h8fb10000, 19 | 32'hac110024, 20 | 32'h0800002b, 21 | 32'hafbf0000, 22 | 32'h23bdfffc, 23 | 32'hafbe0000, 24 | 32'h23bdfffc, 25 | 32'h23be000c, 26 | 32'h8fc80000, 27 | 32'h20090002, 28 | 32'h00005820, 29 | 32'h0128582a, 30 | 32'h15600002, 31 | 32'h20080001, 32 | 32'h08000023, 33 | 32'h2108ffff, 34 | 32'hafa80000, 35 | 32'h23bdfffc, 36 | 32'h0c000009, 37 | 32'h8fc80000, 38 | 32'h2108fffe, 39 | 32'hafa80000, 40 | 32'h23bdfffc, 41 | 32'h0c000009, 42 | 32'h23bd0004, 43 | 32'h8fa80000, 44 | 32'h23bd0004, 45 | 32'h8fa90000, 46 | 32'h01094020, 47 | 32'h23bd0004, 48 | 32'h8fbe0000, 49 | 32'h23bd0004, 50 | 32'h8fbf0000, 51 | 32'h23bd0004, 52 | 32'hafa80000, 53 | 32'h23bdfffc, 54 | 32'h03e00008, 55 | 32'h20000000 }; 56 | // Test input instructions 57 | localparam 58 | t0 = 8, 59 | t1 = 9, 60 | t2 = 10, 61 | addi_t0_zero_6 = 32'h20080006, 62 | addi_t1_zero_11 = 32'h2009000B, 63 | addi_t0_t0_10 = 32'h2108000A, 64 | addi_t2_t1_240 = 32'h212A00F0, 65 | add_t2_t0_t1 = 32'h01095020, 66 | 67 | addi_t0_zero_5 = 32'h20080005, 68 | addi_t1_zero_9 = 32'h20090009, 69 | sw_t0_zero_0 = 32'hAC080000, 70 | sw_t1_zero_4 = 32'hAC090004, 71 | lw_t0_zero_4 = 32'h8C080004, 72 | 73 | 74 | // Begin branch assm: 75 | // https://github.com/jmahler/mips-cpu/blob/master/test/t0005-branch.asm 76 | addi_t0_zero_1 = 32'h2008_0001, 77 | addi_t1_zero_2 = 32'h2009_0002, 78 | addi_t0_t0_1 = 32'h2108_0001, 79 | beq_t0_t1_skip1 = 32'h1109_0002, // jump forward 2 80 | addi_t0_t0_255 = 32'h2108_00FF, 81 | addi_t1_t1_255 = 32'h2129_00FF, 82 | add_t0_t0_t1 = 32'h0109_4020, 83 | add_t1_t0_t1 = 32'h0109_4820, 84 | bne_t0_t1_skip2 = 32'h1509_0002, // jump forward 2 85 | addi_t0_t0_4095 = 32'h2108_0FFF, 86 | addi_t1_t1_4095 = 32'h2129_0FFF, 87 | 88 | // jump Testing 89 | // 90 | // 0: addi t0, 0, 255 91 | // 4: j 36 92 | // ... 93 | // 36: addi t1, 0, 255 94 | // 40: jal 80 95 | // 44: addi t0, 0, 4095 96 | // 48: j 88 97 | // ... 98 | // 80: add t2, t1, t0 99 | // 84: jr $31 100 | // 88: DONE 101 | addi_t0_zero_255 = 32'h2008_00FF, 102 | j_36 = 32'h0800_0024, 103 | addi_t1_zero_255 = 32'h2009_00FF, 104 | jal_80 = 32'h0C00_0050, 105 | addi_t0_zero_4095 = 32'h2008_0FFF, 106 | j_88 = 32'h0800_0058, 107 | //add_t2_t0_t1 = 32'h01095020, 108 | jr_ra = 32'h03E0_0008; 109 | 110 | 111 | // Clock Generator (#10 period) 112 | initial 113 | begin 114 | clock = 1; 115 | #5; 116 | forever 117 | begin 118 | clock = ~clock; 119 | #5; 120 | end 121 | end 122 | 123 | task assert_equal( 124 | input [31:0] expected, 125 | input [31:0] observed); 126 | begin 127 | if (expected === observed) 128 | $display("(%d)SUCCESS: %p == %p", $time, expected, observed); 129 | else 130 | $display("(%d)ASSERTION EQUAL FAIL: %p != %p", $time, expected, observed); 131 | end 132 | endtask 133 | 134 | task load_instr ( 135 | input [31:0] addr, 136 | input [31:0] instruction 137 | ); 138 | dut.instruction_memory.data[addr >> 2] = instruction; 139 | endtask 140 | 141 | // Test logic 142 | integer i; 143 | initial begin 144 | /* 145 | $display("TEST SUITE 1: "); 146 | $display("Initializing instruction memory"); 147 | load_instr(0, addi_t0_zero_6); 148 | load_instr(4, addi_t1_zero_11); 149 | load_instr(8, addi_t0_t0_10); 150 | load_instr(12, addi_t2_t1_240); 151 | load_instr(16, add_t2_t0_t1); 152 | load_instr(20, addi_t0_zero_5); 153 | load_instr(24, addi_t1_zero_9); 154 | load_instr(28, sw_t0_zero_0); 155 | load_instr(32, sw_t1_zero_4); 156 | load_instr(36, lw_t0_zero_4); 157 | // Don't need these since we are adding to the zero register 158 | //dut.regfile.register_file[8] = 2; 159 | //dut.regfile.register_file[9] = 3; 160 | 161 | $display("Resetting the program counter to 0th instruction"); 162 | reset = 1; 163 | #20 164 | 165 | $display("Running instructions!"); 166 | reset = 0; 167 | 168 | assert_equal(dut.regfile.register_file[t0], 6); 169 | #10; 170 | $display("PC: "); 171 | assert_equal(dut.pc.pc_reg, 4); 172 | 173 | assert_equal(dut.regfile.register_file[t1], 11); 174 | #10; 175 | assert_equal(dut.regfile.register_file[t0], 16); 176 | #10; 177 | assert_equal(dut.regfile.register_file[t2], 251); 178 | #10; 179 | assert_equal(dut.regfile.register_file[t2], 27); 180 | #10; 181 | 182 | $display("We started the second iteration"); 183 | assert_equal(dut.regfile.register_file[t0], 5); 184 | #10; 185 | assert_equal(dut.regfile.register_file[t1], 9); 186 | #10; 187 | assert_equal(dut.data_memory.data[0], 5); 188 | #10; 189 | assert_equal(dut.data_memory.data[1], 9); // Store into the '4th' byte address which is our 1st word address 190 | #10; 191 | assert_equal(dut.regfile.register_file[t0], 9); 192 | #10; 193 | 194 | 195 | 196 | #100; 197 | $display("Initializing instruction memory"); 198 | load_instr(0, addi_t0_zero_1); 199 | load_instr(4, addi_t1_zero_2); 200 | load_instr(8, addi_t0_t0_1); 201 | load_instr(12,beq_t0_t1_skip1); 202 | load_instr(16,addi_t0_t0_255); 203 | load_instr(20,addi_t1_t1_255); 204 | load_instr(24,add_t0_t0_t1); 205 | load_instr(28,add_t1_t0_t1); 206 | load_instr(32,bne_t0_t1_skip2); 207 | load_instr(36,addi_t0_t0_4095); 208 | load_instr(40,addi_t1_t1_4095); 209 | 210 | $display("Resetting the program counter to 0th instruction"); 211 | reset = 1; 212 | #20 213 | 214 | $display("Running instructions!"); 215 | reset = 0; 216 | #200; 217 | assert_equal(dut.regfile.register_file[t0], 4); 218 | assert_equal(dut.regfile.register_file[t1], 6); 219 | 220 | #100; 221 | */ 222 | /* 223 | $display("Initializing instruction memory"); 224 | load_instr(0, addi_t0_zero_255 ); 225 | load_instr(4, j_36 ); 226 | load_instr(36, addi_t1_zero_255); 227 | load_instr(40,jal_80 ); 228 | load_instr(44,addi_t0_zero_4095); 229 | load_instr(48,j_88 ); 230 | load_instr(80,add_t2_t0_t1 ); 231 | load_instr(84,jr_ra ); 232 | $display("Resetting the program counter to 0th instruction"); 233 | reset = 1; 234 | #20 235 | 236 | $display("Running instructions!"); 237 | reset = 0; 238 | #200; 239 | assert_equal(dut.regfile.register_file[t0], 4095); 240 | assert_equal(dut.regfile.register_file[t1], 255); 241 | assert_equal(dut.regfile.register_file[t2], 510); 242 | */ 243 | 244 | 245 | $display("Running Fibbonacci! Fib(4)"); 246 | for (i = 0; i < 44; i = i + 1) begin 247 | load_instr(i*4, fib_instr[i]); 248 | end 249 | 250 | // 2 reset the CPU 251 | $display("Resetting the program counter to 0th instruction"); 252 | reset = 1; 253 | #20 254 | 255 | $display("Running instructions!"); 256 | reset = 0; 257 | #1000000; // 1000 clock cycles 258 | 259 | // 3 Make assertions 260 | assert_equal(dut.regfile.register_file[t0], 144); 261 | 262 | end 263 | endmodule 264 | --------------------------------------------------------------------------------