diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5b79766 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +*.out +*.vvp +*.vcd +vivado* diff --git a/Block_Diagram.jpg b/Block_Diagram.jpg new file mode 100644 index 0000000..d13e177 Binary files /dev/null and b/Block_Diagram.jpg differ diff --git a/CPUcontroller.v b/CPUcontroller.v new file mode 100644 index 0000000..99d5ed5 --- /dev/null +++ b/CPUcontroller.v @@ -0,0 +1,164 @@ + +/* + +add: 000000 100000 +addi: 001000 +sub: 000000 100011 +j 000010 +jal: 000011 +jr: 000000 001000 +bne: 000101 +xori: 001110 +sw: 101011 +lw: 100011 +slt: 000000 101010 + +*/ + +`include "alu.v" + +`define arith 6'b000000 +`define addi 6'b001000 +`define j 6'b000010 +`define jal 6'b000011 +`define bne 6'b000101 +`define xori 6'b001110 +`define sw 6'b101011 +`define lw 6'b100011 + +`define add 6'b100000 +`define sub 6'b100010 +`define jr 6'b001000 +`define slt 6'b101010 + + +module CPUcontroller ( + input [5:0] opcode, funct, + output reg [2:0] ALU3, + output reg dataWriteMuxSlt, writeback, notBNE, // writeback chooses where the output goes + output reg [1:0] operand2MuxSlt, regWriteAddrSlt, PCmux, + output reg reg_we, dm_we +); + + //for adders + // ALU0 <= `opADD; + // ALU1 <= `opADD; + // ALU2 <= `opADD; + + always @ (*) begin + + casex(opcode) + `addi: begin + dataWriteMuxSlt <= 1'd1; + operand2MuxSlt <= 2'd2; + regWriteAddrSlt <= 2'd0; + PCmux <= 2'd2; + notBNE<=1'd1; + reg_we <= 1'd1; + dm_we<= 1'd0; + writeback <= 1'd0; + ALU3 <= `opADD; + end + `j: begin + PCmux <= 2'd1; + notBNE<=1'd1; + reg_we <= 1'd0; + dm_we<= 1'd0; + end + `jal: begin + dataWriteMuxSlt <= 1'd0; + regWriteAddrSlt <= 2'd2; + PCmux <= 2'd1; + notBNE<=1'd1; + reg_we <= 1'd1; + dm_we<= 1'd0; + end + `bne: begin + PCmux <= 2'd2; + notBNE<=1'd0; + reg_we <= 1'd0; + dm_we<= 1'd0; + ALU3 <= `opSUB; + end + `xori: begin + dataWriteMuxSlt <= 1'd1; + operand2MuxSlt <= 2'd1; + regWriteAddrSlt <= 2'd0; + PCmux <= 2'd2; + notBNE<=1'd1; + reg_we <= 1'd1; + dm_we<= 1'd0; + writeback <= 1'd0; + ALU3 <= `opXOR; + end + `sw: begin + operand2MuxSlt <= 2'd2; + PCmux <= 2'd2; + notBNE<=1'd1; + reg_we <= 1'd0; + dm_we<= 1'd1; + ALU3 <= `opADD; + end + `lw: begin + dataWriteMuxSlt <= 1'd1; + operand2MuxSlt <= 2'd2; + regWriteAddrSlt <= 2'd0; + PCmux <= 2'd2; + notBNE<=1'd1; + reg_we <= 1'd1; + dm_we<= 1'd0; + writeback <= 1'd1; + ALU3 <= `opADD; + end + `arith: begin + case(funct) + `add: begin + dataWriteMuxSlt <= 1'd1; + operand2MuxSlt <= 2'd0; + regWriteAddrSlt <= 2'd1; + PCmux <= 2'd2; + notBNE<=1'd1; + reg_we <= 1'd1; + dm_we<= 1'd0; + writeback <= 1'd0; + ALU3 <= `opADD; + end + `sub: begin + dataWriteMuxSlt <= 1'd1; + operand2MuxSlt <= 2'd0; + regWriteAddrSlt <= 2'd1; + PCmux <= 2'd2; + notBNE<=1'd1; + reg_we <= 1'd1; + dm_we<= 1'd0; + writeback <= 1'd0; + ALU3 <= `opSUB; + end + `jr: begin + PCmux <= 2'd0; + notBNE<=1'd1; + reg_we <= 1'd0; + dm_we<= 1'd0; + end + `slt: begin + dataWriteMuxSlt <= 1'd1; + operand2MuxSlt <= 2'd0; + regWriteAddrSlt <= 2'd1; + PCmux <= 2'd2; + notBNE<=1'd1; + reg_we <= 1'd1; + dm_we<= 1'd0; + writeback <= 1'd0; + ALU3 <= `opSLT; + end + endcase + + end + default: begin + reg_we <= 1'd0; + dm_we<= 1'd0; + end + endcase + end + +endmodule \ No newline at end of file diff --git a/adder.v b/adder.v new file mode 100644 index 0000000..9109f2c --- /dev/null +++ b/adder.v @@ -0,0 +1,58 @@ +// Adder circuit + +module structuralFullAdder +( + output sum, + output carryout, + input a, + input b, + input carryin +); + + wire ab; + xor aXORb(ab, a, b); + xor abXORc(sum, ab, carryin); + + wire aAndb, oneAndC; + and aANDb(aAndb, a, b); + and aXORbANDc(oneAndC, ab, carryin); + or aorborc(carryout, aAndb, oneAndC); + +endmodule + +module FullAdder32bit +( + output[31:0] sum, + output carryout, + output overflow, + input[31:0] a, + input[31:0] b +); + wire[31:0] carry; + wire[31:0] over; + assign carry[0] = 1'b0; + genvar i; + generate + for (i=0; i<31; i=i+1)begin : add_block + structuralFullAdder add0 (sum[i], carry[i+1], a[i], b[i], carry[i]); + end + endgenerate + structuralFullAdder add0 (sum[31], carryout, a[31], b[31], carry[31]); + xor overflowCheck(overflow, carry[31], carryout); +endmodule + +module Subtractor32bit +( + input[31:0] a, b, + output[31:0] sum, + output carryout, overflow +); + + wire[31:0] notb, b2comp; + wire unusedCarryout, invertingOverflow, totalOverflow; + + not32 notbgate (notb, b); + FullAdder32bit add1tob(b2comp, unusedCarryout, invertingOverflow, notb, 32'd1); + FullAdder32bit getsum(sum, carryout, totalOverflow, a, b2comp); + or overflowgate(overflow, totalOverflow, invertingOverflow); +endmodule \ No newline at end of file diff --git a/alu.t.v b/alu.t.v new file mode 100644 index 0000000..65d9ffa --- /dev/null +++ b/alu.t.v @@ -0,0 +1,524 @@ +`include "alu.v" +// TODO: investigate, uncommenting this makes everything break. +// `timescale 1 ns / 1 ps + +`define ADD 3'd0 +`define SUB 3'd1 +`define XOR 3'd2 +`define SLT 3'd3 +`define AND 3'd4 +`define NAND 3'd5 +`define NOR 3'd6 +`define OR 3'd7 + +module testALU (); + // Your test code here + reg[2:0] address; + reg signed [31:0] a,b; + wire carryout, overflow, zero; + wire signed [31:0] out; + + ALU alu(out, carryout, zero, overflow, a, b, address); + + initial begin + + $dumpfile("alu.vcd"); + $dumpvars(0,alu); + + address = `SUB; a = 32'd10; b = 32'd10; #5000 + + if ((out !== 32'd0) || (carryout !== 1) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `ADD; a = 32'd10; b = 32'd10; #5000 + + if ((out !== 32'd20) || (carryout !== 0) || (overflow !== 0)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `XOR; a = 32'd10; b = 32'd10; #5000 + + if ((out !== 32'd0) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SLT; a = 32'd15; b = 32'd10; #5000 + + if ((out !== 32'd0) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `AND; a = 32'd10; b = 32'd10; #5000 + + if ((out !== 32'd10) || (carryout !== 0) || (overflow !== 0)) begin + $display("AND %d %d ", a, b); + $display("*** AND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NAND; a = 32'd10; b = 32'd10; #5000 + + if ((out !== 32'hfffffff5) || (carryout !== 0) || (overflow !== 0)) begin + $display("NAND%d %d ", a, b); + $display("*** NAND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NOR; a = 32'd10; b = 32'd10; #5000 + + if ((out !== 32'hfffffff5) || (carryout !== 0) || (overflow !== 0)) begin + $display("NOR %d %d ", a, b); + $display("*** NOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `OR; a = 32'd10; b = 32'd10; #5000 + + if ((out !== 32'd10) || (carryout !== 0) || (overflow !== 0)) begin + $display("OR %d %d ", a, b); + $display("*** OR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + + + // 10 - 0 + address = `SUB; a = 32'd10; b = 32'd0; #5000 + + if ((out !== 32'd10) || (carryout !== 0) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + // 0 - 10, has problems: + address = `SUB; a = 32'd0; b = 32'd10; #5000 + + if ((out !== -32'd10) || (carryout !== 0) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + // 15 - 10 + address = `SUB; a = 32'd15; b = 32'd10; #5000 + + if ((out !== 32'd5) || (carryout !== 1) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + // 10 + 0 + address = `ADD; a = 32'd10; b = 32'd0; #5000 + + if ((out !== 32'd10) || (carryout !== 0) || (overflow !== 0)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + // -1 + 0, has problems: + address = `ADD; a = 32'b1111; b = 32'd0; #5000 + + if ((out !== 32'b1111) || (carryout !== 0) || (overflow !== 0)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + // 10 + 20 + address = `ADD; a = 32'd10; b = 32'd20; #5000 + + if ((out !== 32'd30) || (carryout !== 0) || (overflow !== 0)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + // 0 XOR 1 + address = `XOR; a = 32'd0; b = 32'd1; #5000 + + if ((out !== 32'd1) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + // b'10000 XOR b'10101 + address = `XOR; a = 32'b10000; b = 32'b10101; #5000 + + if ((out !== 32'b00101) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + // b'00000 XOR b'11111 + address = `XOR; a = 32'b00000; b = 32'b11111; #5000 + + if ((out !== 32'b11111) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + // SLT 1 1 + address = `SLT; a = 32'd1; b = 32'd1; #5000 + + if ((out !== 32'd0) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + // SLT 5 10 + address = `SLT; a = 32'd5; b = 32'd10; #5000 + + if ((out !== 32'd1) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + // SLT b'001 d'1 + address = `SLT; a = 32'b001; b = 32'd1; #5000 + + if ((out !== 32'b0) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + + /*** serena's test cases ***/ + + address = `ADD; a = 32'hffffffff; b = 32'h1; #5000 + + if ((out !== 32'h0) || (carryout !== 1) || (overflow !== 0)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `ADD; a = 32'h7fffffff; b = 32'h1; #5000 + + if ((out !== 32'h80000000) || (carryout !== 0) || (overflow !== 1)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `ADD; a = 32'h1; b = 32'h7fffffff; #5000 + + if ((out !== 32'h80000000) || (carryout !== 0) || (overflow !== 1)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SUB; a = 32'h0; b = 32'h0; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SUB; a = 32'h1; b = 32'h7fffffff; #5000 + + if ((out !== 32'h80000002) || (carryout !== 0) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SUB; a = 32'h0; b = 32'h7fffffff; #5000 + + if ((out !== 32'h80000001) || (carryout !== 0) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SUB; a = 32'h0; b = 32'h80000000; #5000 + + if ((out !== 32'h80000000) || (carryout !== 0) || (overflow !== 1)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `XOR; a = 32'h1; b = 32'hffffffff; #5000 + + if ((out !== 32'hfffffffe) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `XOR; a = 32'haaaaaaaa; b = 32'h55555555; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `XOR; a = 32'h0; b = 32'hffffffff; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SLT; a = 32'h0; b = 32'h7fffffff; #5000 + + if ((out !== 32'h1) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SLT; a = 32'h0; b = 32'h80000000; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SLT; a = 32'h7fffffff; b = 32'h7fffffff; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `AND; a = 32'hffffffff; b = 32'hffffffff; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("AND %d %d ", a, b); + $display("*** AND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `AND; a = 32'hffffffff; b = 32'h1; #5000 + + if ((out !== 32'h1) || (carryout !== 0) || (overflow !== 0)) begin + $display("AND %d %d ", a, b); + $display("*** AND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `AND; a = 32'h7fffffff; b = 32'h80000000; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("AND %d %d ", a, b); + $display("*** AND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NAND; a = 32'hffffffff; b = 32'hffffffff; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("NAND%d %d ", a, b); + $display("*** NAND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NAND; a = 32'h7fffffff; b = 32'h80000000; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("NAND%d %d ", a, b); + $display("*** NAND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NAND; a = 32'h0; b = 32'h1; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("NAND%d %d ", a, b); + $display("*** NAND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NOR; a = 32'hffffffff; b = 32'hffffffff; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("NOR %d %d ", a, b); + $display("*** NOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NOR; a = 32'haaaaaaaa; b = 32'h1; #5000 + + if ((out !== 32'h55555554) || (carryout !== 0) || (overflow !== 0)) begin + $display("NOR %d %d ", a, b); + $display("*** NOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NOR; a = 32'h7fffffff; b = 32'h80000000; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("NOR %d %d ", a, b); + $display("*** NOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `OR; a = 32'hffffffff; b = 32'hffffffff; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("OR %d %d ", a, b); + $display("*** OR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `OR; a = 32'h7fffffff; b = 32'h80000000; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("OR %d %d ", a, b); + $display("*** OR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `OR; a = 32'haaaaaaaa; b = 32'h55555554; #5000 + + if ((out !== 32'hfffffffe) || (carryout !== 0) || (overflow !== 0)) begin + $display("OR %d %d ", a, b); + $display("*** OR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + + /*** kaitlyn's test cases ***/ + + address = `ADD; a = 32'h7fffffff; b = 32'h7fffffff; #5000 + + if ((out !== 32'hfffffffe) || (carryout !== 0) || (overflow !== 1)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `ADD; a = -32'd10; b = 32'd10; #5000 + + if ((out !== 32'd0) || (carryout !== 1) || (overflow !== 0)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `ADD; a = 32'h0000ffff; b = 32'hffff0000; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("ADD %d %d ", a, b); + $display("*** ADD %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SUB; a = 32'h0000ffff; b = -32'h0000ffff; #5000 + + if ((out !== 32'h0001fffe) || (carryout !== 0) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SUB; a = -32'h7fffffff; b = -32'h7fffffff; #5000 + + if ((out !== 32'h0) || (carryout !== 1) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SUB; a = 32'hffffffff; b = 32'h7fffffff; #5000 + + if ((out !== 32'h80000000) || (carryout !== 1) || (overflow !== 0)) begin + $display("SUB %d %d ", a, b); + $display("*** SUB %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `XOR; a = 32'hffffffff; b = 32'hffffffff; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `XOR; a = 32'hffff0000; b = 32'hffffffff; #5000 + + if ((out !== 32'h0000ffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `XOR; a = 32'h11111111; b = 32'h0e0e0e0e; #5000 + + if ((out !== 32'h1f1f1f1f) || (carryout !== 0) || (overflow !== 0)) begin + $display("XOR %d %d ", a, b); + $display("*** XOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SLT; a = 32'h7fffffff; b = 32'h0; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SLT; a = 32'd0; b = 32'd5; #5000 + + if ((out !== 32'h1) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `SLT; a = 32'd0; b = 32'd0; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("SLT %d %d ", a, b); + $display("*** SLT %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `AND; a = 32'h0f0f0f0f; b = 32'hf0f0f0f0; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("AND %d %d ", a, b); + $display("*** AND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `AND; a = 32'h11111111; b = 32'hffffffff; #5000 + + if ((out !== 32'h11111111) || (carryout !== 0) || (overflow !== 0)) begin + $display("AND %d %d ", a, b); + $display("*** AND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `AND; a = 32'heeeeeeee; b = 32'h77777777; #5000 + + if ((out !== 32'h66666666) || (carryout !== 0) || (overflow !== 0)) begin + $display("AND %d %d ", a, b); + $display("*** AND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NAND; a = 32'heeeeeeee; b = 32'h77777777; #5000 + + if ((out !== 32'h99999999) || (carryout !== 0) || (overflow !== 0)) begin + $display("NAND%d %d ", a, b); + $display("*** NAND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NAND; a = 32'h11111111; b = 32'h10101010; #5000 + + if ((out !== 32'hefefefef) || (carryout !== 0) || (overflow !== 0)) begin + $display("NAND%d %d ", a, b); + $display("*** NAND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NAND; a = 32'h77777777; b = 32'h88888888; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("NAND%d %d ", a, b); + $display("*** NAND %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NOR; a = 32'heeeeeeee; b = 32'h77777777; #5000 + + if ((out !== 32'h0) || (carryout !== 0) || (overflow !== 0)) begin + $display("NOR %d %d ", a, b); + $display("*** NOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NOR; a = 32'h0; b = 32'h77777777; #5000 + + if ((out !== 32'h88888888) || (carryout !== 0) || (overflow !== 0)) begin + $display("NOR %d %d ", a, b); + $display("*** NOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `NOR; a = 32'heeeeeeee; b = 32'h00000001; #5000 + + if ((out !== 32'h11111110) || (carryout !== 0) || (overflow !== 0)) begin + $display("NOR %d %d ", a, b); + $display("*** NOR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `OR; a = 32'heeeeeeee; b = 32'h77777777; #5000 + + if ((out !== 32'hffffffff) || (carryout !== 0) || (overflow !== 0)) begin + $display("OR %d %d ", a, b); + $display("*** OR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `OR; a = 32'h0; b = 32'h77777777; #5000 + + if ((out !== 32'h77777777) || (carryout !== 0) || (overflow !== 0)) begin + $display("OR %d %d ", a, b); + $display("*** OR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + address = `OR; a = 32'heeeeeeee; b = 32'h00000001; #5000 + + if ((out !== 32'heeeeeeef) || (carryout !== 0) || (overflow !== 0)) begin + $display("OR %d %d ", a, b); + $display("*** OR %d %d failed. out: %d carryout: %d overflow: %d", a, b, out, carryout, overflow); + end + + end +endmodule \ No newline at end of file diff --git a/alu.v b/alu.v new file mode 100644 index 0000000..8315676 --- /dev/null +++ b/alu.v @@ -0,0 +1,107 @@ +`include "logic32bits.v" +`include "adder.v" + +`define opADD 3'd0 +`define opSUB 3'd1 +`define opXOR 3'd2 +`define opSLT 3'd3 +`define opAND 3'd4 +`define opNAND 3'd5 +`define opNOR 3'd6 +`define opOR 3'd7 + +module SLT +( + input[31:0] a, b, + output[31:0] result +); +wire overflow, carryout, less_than; +wire[31:0] subtractoroutput; +Subtractor32bit compare(a, b, subtractoroutput, carryout, overflow); +xor getsign(less_than, subtractoroutput[31], overflow); +assign result = {30'b0, less_than}; + +endmodule + +module ALU +( +output reg [31:0] result, +output reg carryout, +output reg zero, +output reg overflow, +input [31:0] operandA, +input [31:0] operandB, +input[2:0] command +); + + +wire[31:0] add_out, sub_out, xor_out, slt_out, and_out, nand_out, nor_out, or_out; +wire add_carryout, add_overflow, sub_carryout, sub_overflow, add_zero, sub_zero; + +FullAdder32bit get_add_out(add_out, add_carryout, add_overflow, operandA, operandB); +Subtractor32bit get_sub_out(operandA, operandB, sub_out, sub_carryout, sub_overflow); +xor32 get_xor( xor_out, operandA, operandB); +SLT get_slt_out(operandA, operandB, slt_out); +and32 get_and(and_out, operandA, operandB); +nand32 get_nand(nand_out, operandA, operandB); +nor32 get_nor(nor_out, operandA, operandB); +or32 get_or(or_out, operandA, operandB); +zero_check zcheck_add(add_zero, add_out); +zero_check zcheck_sub(sub_zero, sub_out); + + +always @(command or operandA or operandB) begin +#5 + case(command) + `opADD: begin + result = add_out; + carryout = add_carryout; + overflow = add_overflow; + zero = add_zero; + end + `opSUB: begin + result = sub_out; + carryout = sub_carryout; + overflow = sub_overflow; + zero = sub_zero; + end + `opXOR: begin + result = xor_out; + carryout = 1'b0; + overflow = 1'b0; + zero = 1'b0; + end + `opSLT: begin + result = slt_out; + carryout = 1'b0; + overflow = 1'b0; + zero = 1'b0; + end + `opAND: begin + result = and_out; + carryout = 1'b0; + overflow = 1'b0; + zero = 1'b0; + end + `opNAND: begin + result = nand_out; + carryout = 1'b0; + overflow = 1'b0; + zero = 1'b0; + end + `opNOR: begin + result = nor_out; + carryout = 1'b0; + overflow = 1'b0; + zero = 1'b0; + end + `opOR: begin + result = or_out; + carryout = 1'b0; + overflow = 1'b0; + zero = 1'b0; + end + endcase +end + +endmodule \ No newline at end of file diff --git a/asmtest/readme.md b/asmtest/readme.md new file mode 100644 index 0000000..a7486f8 --- /dev/null +++ b/asmtest/readme.md @@ -0,0 +1,7 @@ +# Assembly Tests + +## Recursive Fib + +Finds the nth fibonacci number, where n is given in the first line of the file (stored in a0). When n=1, the program outputs 1; when n=2, the program outputs 2. For the value 7, the expected output is 13. + + diff --git a/asmtest/recursivefib.asm b/asmtest/recursivefib.asm new file mode 100644 index 0000000..7973385 --- /dev/null +++ b/asmtest/recursivefib.asm @@ -0,0 +1,41 @@ +addi $a0, $zero, 7 + +jal fib +add $s0, $zero, $v0 + +addi $v0, $zero, 10 +syscall + +fib: + ble $a0, 2, base # if base case + + # push current a0 and ra + addi $sp, $sp, -8 + sw $a0, 4($sp) + sw $ra, 0($sp) + # recurse a0-1 + addi $a0, $a0, -1 + jal fib + + # push additional result to stack + addi $sp, $sp, -4 + sw $v0, 0($sp) + # recurse a0-2 + addi $a0, $a0, -1 + jal fib + + # load from stack + lw $t0, 0($sp) # previous result + lw $ra, 4($sp) # current ra + lw $a0, 8($sp) # current a0 + addi $sp, $sp, 12 + + # get result + add $v0, $v0, $t0 + + j end +base: + addi $v0, $zero, 1 + +end: + jr $ra \ No newline at end of file diff --git a/cpu.t.v b/cpu.t.v new file mode 100644 index 0000000..c38a444 --- /dev/null +++ b/cpu.t.v @@ -0,0 +1,35 @@ +`include "cpu.v" + +module cputest(); + +reg clk; +wire[1023:0] registers; + +CPU dut(.clk(clk), .registers(registers)); + +initial clk=0; +always #10 clk=!clk; + +wire[31:0] registers2d[31:0]; + +genvar i; +generate for (i=0; i<32; i=i+1) begin : unpack_reg + assign registers2d[i][31:0] = registers[((32)*i+(31)):((32)*i)]; +end +endgenerate + +integer j, k; +initial begin + $dumpfile("cpu.vcd"); + $dumpvars(0,dut); + + #(800*20) + + $display("end:",); + for (j=0; j<32; j=j+1) begin + $display("reg %d : %h", j, registers2d[j]); + end + + $finish; +end +endmodule \ No newline at end of file diff --git a/cpu.v b/cpu.v new file mode 100644 index 0000000..2903f1e --- /dev/null +++ b/cpu.v @@ -0,0 +1,180 @@ +`include "dff.v" +`include "instruction_memory.v" +`include "instructiondecoder.v" +`include "CPUcontroller.v" +`include "datamemory.v" +`include "signextend.v" +`include "regfile.v" + + +module CPU ( + input clk, + output [1023:0] registers +); +reg we_on = 1'b1; +reg we_off = 1'b0; + +wire[31:0] pc_next, pc_curr; +wire[31:0] instruction; + +wire[5:0] opcode; +wire[4:0] rs; +wire[4:0] rt; +wire[4:0] rd; +wire[15:0] imm; +wire[25:0] addr; +wire[5:0] funct; + +PCReg #(32) pc ( + .clk(clk), + .ce(we_on), + .dataIn(pc_next), + .dataOut(pc_curr)); + +wire [31:0] pcPlus4; +assign pcPlus4 = pc_curr + 4; + +instruction_memory instrMem ( + .clk(clk), + .regWE(we_off), + .Addr(pc_curr), + .DataIn(32'b0), + .DataOut(instruction)); + +InstructionDecoder instrDecoder ( + .instruction(instruction), + .opcode(opcode), + .rs(rs), + .rt(rt), + .rd(rd), + .imm(imm), + .addr(addr), + .funct(funct)); + +wire [2:0] mainAluop; +wire dataWriteMuxSlt, writeback, notBNE; +wire [1:0] operand2MuxSlt, regWriteAddrSlt, PCmux; +wire reg_we, dm_we; + +CPUcontroller controller ( + .opcode(opcode), + .funct(funct), + .ALU3(mainAluop), + .PCmux(PCmux), + .notBNE(notBNE), + .dataWriteMuxSlt(dataWriteMuxSlt), + .operand2MuxSlt(operand2MuxSlt), + .regWriteAddrSlt(regWriteAddrSlt), + .writeback(writeback), + .reg_we(reg_we), + .dm_we(dm_we)); + +wire[31:0] dataA; +wire[31:0] dataB; +wire[31:0] dataWrite; +wire[31:0] writebackData; +wire[4:0] writeRegister; +wire[4:0] throwaway; + +fourToOneMux #(.DATA_WIDTH(5)) dwRegIn( + .out(writeRegister), + .in1(rt), + .in2(rd), + .in3(5'd31), //for jal + .in4(throwaway), + .slt(regWriteAddrSlt)); + +regfile registerFile ( + .ReadData1(dataA), + .ReadData2(dataB), + .AllOutputs(registers), + .WriteData(dataWrite), + .ReadRegister1(rs), + .ReadRegister2(rt), + .WriteRegister(writeRegister), + .RegWrite(reg_we), + .Clk(clk)); + +wire [31:0] thirtyTwoBitThrowaway; +wire [31:0] signExtendImmediate; +wire [31:0] zeroExtendImmediate; +assign zeroExtendImmediate = {16'b0, imm}; +wire [31:0] operandB; + +signextend signExtender ( + .a(imm), + .result(signExtendImmediate)); + +fourToOneMux operand2Mux ( + .out(operandB), + .in1(dataB), + .in2(zeroExtendImmediate), + .in3(signExtendImmediate), + .in4(32'd10), + .slt(operand2MuxSlt)); + +wire oneBitThrowaway; +wire [2:0] alu3SLT; +wire [31:0] mainAluOut; +wire [31:0] dmOut; +wire offsetMuxSelect; + +ALU mainAlu ( + .result(mainAluOut), + .carryout(oneBitThrowaway), + .zero(offsetMuxSelect), + .overflow(oneBitThrowaway), + .operandA(dataA), + .operandB(operandB), + .command(mainAluop)); + +datamemory #(.addresswidth(32), + .depth(600000), + .width(32)) dm( + .clk(clk), + .dataOut(dmOut), + .address(mainAluOut), + .writeEnable(dm_we), + .dataIn(dataB)); + +twoToOneMux opMultiplexer ( + .out(writebackData), + .in1(mainAluOut), + .in2(dmOut), + .slt(writeback)); + +twoToOneMux dataWriteMux( + .out(dataWrite), + .in1(pcPlus4), + .in2(writebackData), + .slt(dataWriteMuxSlt)); + + +wire [31:0] concatSignExtend; +assign concatSignExtend = {signExtendImmediate[29:0], 2'b00}; + +wire [31:0] instrOffset; + +twoToOneMux instrOffsetMux ( + .out(instrOffset), + .in1(concatSignExtend), + .in2(32'b0), + .slt(offsetMuxSelect || notBNE)); + +wire [31:0] alu0Out; + +wire [31:0] jumpAddr; +assign jumpAddr = {pcPlus4[31:28], instruction[25:0], 2'b0}; + +fourToOneMux pcMux ( + .out(pc_next), + .in1(dataA), + .in2(jumpAddr), + .in3(pcPlus4 + instrOffset), + .in4(32'd00), + .slt(PCmux)); + +wire [31:0] pcPlus8; +assign pcPlus8 = pcPlus4 + 4; + +endmodule \ No newline at end of file diff --git a/datamemory.t.v b/datamemory.t.v new file mode 100644 index 0000000..a4c8067 --- /dev/null +++ b/datamemory.t.v @@ -0,0 +1,36 @@ +`include "datamemory.v" + +module datamemory_test(); + reg clk; + wire [31:0] dataOut; + reg [31:0] address; + reg writeEnable; + reg [31:0] dataIn; + + datamemory datamem(.clk(clk), .dataOut(dataOut), + .address(address), .writeEnable(writeEnable), + .dataIn(dataIn)); + + + // Clock generation + initial clk=1; + always #10 clk = !clk; + + // Test sequence - try writing 2 different values an reading to make sure they were written properly + // and then inputing a value while writeEnable is low to make sure writeEnable is working properly + initial begin + + address = 32'd0; dataIn = 32'd1234; writeEnable = 1'b1; #40 //give it enough time for 1 clock cycle + if (dataOut != 32'd1234) $display("Test 1 failed"); + + address = 32'd1234; dataIn = 32'd4321; writeEnable = 1'b1; #40 + if (dataOut != 32'd4321) $display("Test 2 failed"); + + address = 32'd1234; dataIn = 32'd5678; writeEnable = 1'b0; #40 + if (dataOut != 32'd4321) $display("Test 3 failed"); + + // End execution so that it doesn't got on forever + #1000 $finish(); + end + +endmodule \ No newline at end of file diff --git a/datamemory.v b/datamemory.v new file mode 100644 index 0000000..b39dc5a --- /dev/null +++ b/datamemory.v @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------ +// Data Memory +// Positive edge triggered +// dataOut always has the value mem[address] +// If writeEnable is true, writes dataIn to mem[address] +//------------------------------------------------------------------------ + +module datamemory +#( + parameter addresswidth = 7, + parameter depth = 2**addresswidth, + parameter width = 32 +) +( + input clk, + output reg [width-1:0] dataOut, + input [addresswidth-1:0] address, + input writeEnable, + input [width-1:0] dataIn +); + + + reg [width-1:0] memory [depth-1:0]; + + always @(address or dataIn or clk) begin : proc_ + dataOut = memory[address]; + end + + always @(posedge clk) begin + if(writeEnable) begin + memory[address] = dataIn; + end + end + +endmodule diff --git a/decoders.v b/decoders.v new file mode 100644 index 0000000..dd467c2 --- /dev/null +++ b/decoders.v @@ -0,0 +1,14 @@ +// 32 bit decoder with enable signal +// enable=0: all output bits are 0 +// enable=1: out[address] is 1, all other outputs are 0 +module decoder1to32 +( +output[31:0] out, +input enable, +input[4:0] address +); + + assign out = enable<
>2]; +endmodule \ No newline at end of file diff --git a/instructiondecoder.t.v b/instructiondecoder.t.v new file mode 100644 index 0000000..3cffa2a --- /dev/null +++ b/instructiondecoder.t.v @@ -0,0 +1,31 @@ +`include "instructiondecoder.v" + +module DecoderTester(); + +reg[31:0] instruction; +wire[5:0] opcode; +wire[4:0] rs; +wire[4:0] rt; +wire[4:0] rd; +wire[15:0] imm; +wire[25:0] addr; +wire[5:0] funct; + +InstructionDecoder dut(instruction, opcode, rs, rt, rd, imm, addr, funct); + +initial begin +instruction = 32'b00000010101001111110100000100000; #100 +if ((opcode != 6'b000000) || (rs != 5'b10101) || (rt != 5'b00111) || (rd != 5'b11101) || (funct != 6'b100000)) + $display("test 1 failed"); + +instruction = 32'b00100010101001111110101100100011; #100 +if ((opcode != 6'b001000) || (rs != 5'b10101) || (rt != 5'b00111) || (imm != 16'b1110101100100011)) + $display("test 2 failed"); + +instruction = 32'b00001010101001111110101100100011; #100 +if ((opcode != 6'b000010) || (addr != 35'b10101001111110101100100011)) + $display("test 3 failed"); + +end + +endmodule \ No newline at end of file diff --git a/instructiondecoder.v b/instructiondecoder.v new file mode 100644 index 0000000..beb40c7 --- /dev/null +++ b/instructiondecoder.v @@ -0,0 +1,42 @@ +`define rtype 6'd0 +`define jtype 6'b00001z + +// 001000 addi +// 000101 bne +// 100011 lw +// 101011 sw +// 001110 xori + +module InstructionDecoder ( + input[31:0] instruction, + output reg[5:0] opcode, + output reg[4:0] rs, + output reg[4:0] rt, + output reg[4:0] rd, + output reg[15:0] imm, + output reg[25:0] addr, + output reg[5:0] funct +); + +always @(instruction) begin + opcode = instruction[31:26]; + + casex(opcode) + `rtype: begin + rs = instruction[25:21]; + rt = instruction[20:16]; + rd = instruction[15:11]; + funct = instruction[5:0]; + end + `jtype: begin + addr = instruction[25:0]; + end + default: begin + rs = instruction[25:21]; + rt = instruction[20:16]; + imm = instruction[15:0]; + end + endcase +end + +endmodule \ No newline at end of file diff --git a/lab-3.pdf b/lab-3.pdf new file mode 100644 index 0000000..2cf0ad4 Binary files /dev/null and b/lab-3.pdf differ diff --git a/logic32bits.v b/logic32bits.v new file mode 100644 index 0000000..0053e95 --- /dev/null +++ b/logic32bits.v @@ -0,0 +1,99 @@ +// define gates with delays + + +module nand32( + output[31:0] out, + input[31:0] a,b +); + + genvar i; + generate + for (i=0; i<32; i=i+1)begin : nand_block + nand bit_nand(out[i],a[i],b[i]); + end + endgenerate + +endmodule + +module nor32( + output[31:0] out, + input[31:0] a,b +); + + genvar i; + generate + for (i=0; i<32; i=i+1)begin : nor_block + nor bit_nor(out[i],a[i],b[i]); + end + endgenerate + +endmodule + + + +module not32( + + output[31:0] out, + input[31:0] a +); + + genvar i; + generate + for (i=0; i<32; i=i+1)begin : not_block + not bit_not(out[i],a[i]); + end + endgenerate + +endmodule + +module and32 ( + output[31:0] out, + input[31:0] a,b +); + wire[31:0] nand_out; + nand32 nandgate (nand_out, a, b); + not32 notgate (out, nand_out); + +endmodule + +module or32 ( + output[31:0] out, + input[31:0] a,b +); + wire[31:0] nor_out; + nor32 norgate (nor_out, a, b); + not32 notgate (out, nor_out); + +endmodule + +module xor32( + output[31:0] out, + input[31:0] a,b +); + genvar i; + generate + for (i=0; i<32; i=i+1)begin : xor_block + xor bit_xor(out[i],a[i],b[i]); + end + endgenerate + +endmodule + +module zero_check( + output out, + input[31:0] check +); + wire[30:0] carry_out; + + or or0(carry_out[0], check[0], check[1]); + + genvar i; + generate + for (i=0; i<30; i=i+1)begin : or_block + or bit_or(carry_out[i+1], check[i+2], carry_out[i]); + end + endgenerate + + not invert(out, carry_out[30]); + +endmodule \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 0000000..30ff34f --- /dev/null +++ b/makefile @@ -0,0 +1,12 @@ +cpu: cpu.t.v + iverilog -o cpu.t.o cpu.t.v + +test: alu.t.v instructiondecoder.t.v regfile.t.v signextend.t.v datamemory.t.v + iverilog -o alu.t.o alu.t.v + iverilog -o instructiondecoder.t.o instructiondecoder.t.v + iverilog -o regfile.t.o regfile.t.v + iverilog -o signextend.t.o signextend.t.v + iverilog -o datamemory.t.o datamemory.t.v + +clean: + rm *.o diff --git a/mem.dat b/mem.dat new file mode 100644 index 0000000..b67d08a --- /dev/null +++ b/mem.dat @@ -0,0 +1,26 @@ +20040007 +0c000005 +00028020 +2002000a +08000004 +2089ffff +200a0002 +012a482a +1520000f +23bdfff8 +afa40004 +afbf0000 +2084ffff +0c000005 +23bdfffc +afa20000 +2084ffff +0c000005 +8fa80000 +8fbf0004 +8fa40008 +23bd000c +00481020 +08000019 +20020001 +03e00008 \ No newline at end of file diff --git a/multiplexer.v b/multiplexer.v new file mode 100644 index 0000000..2c0cfa7 --- /dev/null +++ b/multiplexer.v @@ -0,0 +1,86 @@ +module fourToOneMux #(parameter DATA_WIDTH = 32) (out,in1,in2,in3,in4,slt); + output [DATA_WIDTH-1:0] out; + input [DATA_WIDTH-1:0] in1,in2,in3,in4; + input [1:0] slt; + + reg [DATA_WIDTH-1:0] out; + + always @ (*) begin + case(slt) + 2'b00:out = in1; + 2'b01:out = in2; + 2'b10:out = in3; + 2'b11:out = in4; + endcase + end +endmodule + +module twoToOneMux #(parameter DATA_WIDTH = 32) (out,in1,in2,slt); + output [DATA_WIDTH-1:0] out; + input [DATA_WIDTH-1:0] in1,in2; + input slt; + + assign out = slt ? in2 : in1; +endmodule + +module mux32to1by1 +( +output out, +input[4:0] address, +input[31:0] inputs +); + assign out = inputs[address]; +endmodule + +module mux32to1by32 +( +output reg[31:0] out, +input[4:0] address, +input[31:0] input0, input1, input2, input3, + input4, input5, input6, input7, + input8, input9, input10, input11, + input12, input13, input14, input15, + input16, input17, input18, input19, + input20, input21, input22, input23, + input24, input25, input26, input27, + input28, input29, input30, input31 +); + + wire[31:0] mux[31:0]; // Create a 2D array of wires + assign mux[0] = input0; // Connect the sources of the array + assign mux[1] = input1; + assign mux[2] = input2; + assign mux[3] = input3; + assign mux[4] = input4; + assign mux[5] = input5; + assign mux[6] = input6; + assign mux[7] = input7; + assign mux[8] = input8; + assign mux[9] = input9; + assign mux[10] = input10; + assign mux[11] = input11; + assign mux[12] = input12; + assign mux[13] = input13; + assign mux[14] = input14; + assign mux[15] = input15; + assign mux[16] = input16; + assign mux[17] = input17; + assign mux[18] = input18; + assign mux[19] = input19; + assign mux[20] = input20; + assign mux[21] = input21; + assign mux[22] = input22; + assign mux[23] = input23; + assign mux[24] = input24; + assign mux[25] = input25; + assign mux[26] = input26; + assign mux[27] = input27; + assign mux[28] = input28; + assign mux[29] = input29; + assign mux[30] = input30; + assign mux[31] = input31; + + always @(*) begin + out = mux[address]; + end +endmodule \ No newline at end of file diff --git a/regfile.t.v b/regfile.t.v new file mode 100644 index 0000000..6025dd9 --- /dev/null +++ b/regfile.t.v @@ -0,0 +1,190 @@ +//------------------------------------------------------------------------------ +// Test harness validates hw4testbench by connecting it to various functional +// or broken register files, and verifying that it correctly identifies each +//------------------------------------------------------------------------------ +`include "regfile.v" + +module hw4testbenchharness(); + + wire[31:0] ReadData1; // Data from first register read + wire[31:0] ReadData2; // Data from second register read + wire[31:0] WriteData; // Data to write to register + wire[1023:0] AllOutputs; + wire[4:0] ReadRegister1; // Address of first register to read + wire[4:0] ReadRegister2; // Address of second register to read + wire[4:0] WriteRegister; // Address of register to write + wire RegWrite; // Enable writing of register when High + wire Clk; // Clock (Positive Edge Triggered) + + reg begintest; // Set High to begin testing register file + wire dutpassed; // Indicates whether register file passed tests + + // Instantiate the register file being tested. DUT = Device Under Test + regfile DUT + ( + .ReadData1(ReadData1), + .ReadData2(ReadData2), + .WriteData(WriteData), + .AllOutputs(AllOutputs), + .ReadRegister1(ReadRegister1), + .ReadRegister2(ReadRegister2), + .WriteRegister(WriteRegister), + .RegWrite(RegWrite), + .Clk(Clk) + ); + + // Instantiate test bench to test the DUT + hw4testbench tester + ( + .begintest(begintest), + .endtest(endtest), + .dutpassed(dutpassed), + .ReadData1(ReadData1), + .ReadData2(ReadData2), + .WriteData(WriteData), + .ReadRegister1(ReadRegister1), + .ReadRegister2(ReadRegister2), + .WriteRegister(WriteRegister), + .RegWrite(RegWrite), + .Clk(Clk) + ); + + // Test harness asserts 'begintest' for 1000 time steps, starting at time 10 + initial begin + begintest=0; + #10; + begintest=1; + #1000; + end + + // Display test results ('dutpassed' signal) once 'endtest' goes high + always @(posedge endtest) begin + $display("DUT passed?: %b", dutpassed); + end + +endmodule + + +//------------------------------------------------------------------------------ +// Your HW4 test bench +// Generates signals to drive register file and passes them back up one +// layer to the test harness. This lets us plug in various working and +// broken register files to test. +// +// Once 'begintest' is asserted, begin testing the register file. +// Once your test is conclusive, set 'dutpassed' appropriately and then +// raise 'endtest'. +//------------------------------------------------------------------------------ + +module hw4testbench +( +// Test bench driver signal connections +input begintest, // Triggers start of testing +output reg endtest, // Raise once test completes +output reg dutpassed, // Signal test result + +// Register File DUT connections +input[31:0] ReadData1, +input[31:0] ReadData2, +output reg[31:0] WriteData, +output reg[4:0] ReadRegister1, +output reg[4:0] ReadRegister2, +output reg[4:0] WriteRegister, +output reg RegWrite, +output reg Clk +); + + // Initialize register driver signals + initial begin + WriteData=32'd0; + ReadRegister1=5'd0; + ReadRegister2=5'd0; + WriteRegister=5'd0; + RegWrite=0; + Clk=0; + end + + integer i, j; + // Once 'begintest' is asserted, start running test cases + always @(posedge begintest) begin + endtest = 0; + dutpassed = 1; + #10 + + // Test Case 1 + // Writing to registers + for (i = 0; i <= 'b11111; i = i + 1) begin + WriteRegister = i; + WriteData = i; + RegWrite = 1; + ReadRegister1 = i; + ReadRegister2 = i; + #5 Clk=1; #5 Clk=0; + + if((ReadData1 != i) || (ReadData2 != i)) begin + dutpassed = 0; + $display("Test Case 1 Failed : failed to write to register %d", i); + end + end + + // Test Case 2 + // write to 0 register + // should always return 0 + WriteRegister = 5'd0; + WriteData = 32'hffffffff; + RegWrite = 1; + ReadRegister1 = 5'd0; + ReadRegister2 = 5'd0; + #5 Clk=1; #5 Clk=0; + + if((ReadData1 != 0) || (ReadData2 != 0)) begin + dutpassed = 0; + $display("Test Case 2 Failed : wrote to zero port"); + end + + // Test Case 3 + // write enabled + // should return unchanged value from above + for (i = 0; i <= 'b11111; i = i + 1) begin + WriteRegister = i; + WriteData = 32'hffffffff; + RegWrite = 0; + ReadRegister1 = i; + ReadRegister2 = i; + #5 Clk=1; #5 Clk=0; + + if((ReadData1 != i) || (ReadData2 != i)) begin + dutpassed = 0; + $display("Test Case 3 Failed : register %d changed when wrenable is false", i); + end + end + + // Test Case 4 + // Broken decoder + // All registers should start with their address in their memory + for (i = 0; i <= 'b11111; i = i + 1) begin + WriteRegister = i; + WriteData = 32'hf0000000 + i; + RegWrite = 1; + #5 Clk=1; #5 Clk=0; + + for (j = 0; j <= 'b11111; j = j + 2) begin + RegWrite = 0; + ReadRegister1 = j; + ReadRegister2 = j + 1; + #5 Clk=1; #5 Clk=0; + + if((j != i && ReadData1 == WriteData) || (j+1 != i && ReadData2 == WriteData)) begin + dutpassed = 0; + $display("Test Case 4 Failed : value for register %d written to multiple registers", i); + end + end + end + + // All done! Wait a moment and signal test completion. + #5 + endtest = 1; + +end + +endmodule \ No newline at end of file diff --git a/regfile.v b/regfile.v new file mode 100644 index 0000000..f1ff544 --- /dev/null +++ b/regfile.v @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// MIPS register file +// width: 32 bits +// depth: 32 words (reg[0] is static zero register) +// 2 asynchronous read ports +// 1 synchronous, positive edge triggered write port +//------------------------------------------------------------------------------ + +`include "multiplexer.v" +`include "register.v" +`include "decoders.v" + +module regfile +( +output[31:0] ReadData1, // Contents of first register read +output[31:0] ReadData2, // Contents of second register read +output[1023:0] AllOutputs, +input[31:0] WriteData, // Contents to write to register +input[4:0] ReadRegister1, // Address of first register to read +input[4:0] ReadRegister2, // Address of second register to read +input[4:0] WriteRegister, // Address of register to write +input RegWrite, // Enable writing of register when High +input Clk // Clock (Positive Edge Triggered) +); + + +//outputs +wire[31:0] reg0out, reg1out, reg2out, reg3out, reg4out, + reg5out, reg6out, reg7out, reg8out, reg9out, + reg10out, reg11out, reg12out, reg13out, reg14out, + reg15out, reg16out, reg17out, reg18out, reg19out, + reg20out, reg21out, reg22out, reg23out, reg24out, + reg25out, reg26out, reg27out, reg28out, reg29out, + reg30out, reg31out; + +assign AllOutputs[1023:0] = { +reg31out, reg30out, reg29out, reg28out, +reg27out, reg26out, reg25out, reg24out, +reg23out, reg22out, reg21out, reg20out, +reg19out, reg18out, reg17out, reg16out, +reg15out, reg14out, reg13out, reg12out, +reg11out, reg10out, reg9out, reg8out, +reg7out, reg6out, reg5out, reg4out, +reg3out, reg2out, reg1out, reg0out }; + + +// enable writes +wire[31:0] regwrenable; +decoder1to32 wrdecoder (regwrenable, RegWrite, WriteRegister); + +// registers +register32zero reg0 (reg0out, WriteData, regwrenable[0], Clk); +register32 reg1 (reg1out, WriteData, regwrenable[1], Clk); +register32 reg2 (reg2out, WriteData, regwrenable[2], Clk); +register32 reg3 (reg3out, WriteData, regwrenable[3], Clk); +register32 reg4 (reg4out, WriteData, regwrenable[4], Clk); +register32 reg5 (reg5out, WriteData, regwrenable[5], Clk); +register32 reg6 (reg6out, WriteData, regwrenable[6], Clk); +register32 reg7 (reg7out, WriteData, regwrenable[7], Clk); +register32 reg8 (reg8out, WriteData, regwrenable[8], Clk); +register32 reg9 (reg9out, WriteData, regwrenable[9], Clk); +register32 reg10 (reg10out, WriteData, regwrenable[10], Clk); +register32 reg11 (reg11out, WriteData, regwrenable[11], Clk); +register32 reg12 (reg12out, WriteData, regwrenable[12], Clk); +register32 reg13 (reg13out, WriteData, regwrenable[13], Clk); +register32 reg14 (reg14out, WriteData, regwrenable[14], Clk); +register32 reg15 (reg15out, WriteData, regwrenable[15], Clk); +register32 reg16 (reg16out, WriteData, regwrenable[16], Clk); +register32 reg17 (reg17out, WriteData, regwrenable[17], Clk); +register32 reg18 (reg18out, WriteData, regwrenable[18], Clk); +register32 reg19 (reg19out, WriteData, regwrenable[19], Clk); +register32 reg20 (reg20out, WriteData, regwrenable[20], Clk); +register32 reg21 (reg21out, WriteData, regwrenable[21], Clk); +register32 reg22 (reg22out, WriteData, regwrenable[22], Clk); +register32 reg23 (reg23out, WriteData, regwrenable[23], Clk); +register32 reg24 (reg24out, WriteData, regwrenable[24], Clk); +register32 reg25 (reg25out, WriteData, regwrenable[25], Clk); +register32 reg26 (reg26out, WriteData, regwrenable[26], Clk); +register32 reg27 (reg27out, WriteData, regwrenable[27], Clk); +register32 #(.init(32'h1800)) reg28 (reg28out, WriteData, regwrenable[28], Clk); +register32 #(.init(32'h3ffc)) reg29 (reg29out, WriteData, regwrenable[29], Clk); +register32 reg30 (reg30out, WriteData, regwrenable[30], Clk); +register32 reg31 (reg31out, WriteData, regwrenable[31], Clk); + + +// reads +mux32to1by32 read1Mux (ReadData1, ReadRegister1, + reg0out, reg1out, reg2out, reg3out, reg4out, + reg5out, reg6out, reg7out, reg8out, reg9out, + reg10out, reg11out, reg12out, reg13out, reg14out, + reg15out, reg16out, reg17out, reg18out, reg19out, + reg20out, reg21out, reg22out, reg23out, reg24out, + reg25out, reg26out, reg27out, reg28out, reg29out, + reg30out, reg31out); + +mux32to1by32 read2Mux (ReadData2, ReadRegister2, + reg0out, reg1out, reg2out, reg3out, reg4out, + reg5out, reg6out, reg7out, reg8out, reg9out, + reg10out, reg11out, reg12out, reg13out, reg14out, + reg15out, reg16out, reg17out, reg18out, reg19out, + reg20out, reg21out, reg22out, reg23out, reg24out, + reg25out, reg26out, reg27out, reg28out, reg29out, + reg30out, reg31out); + +endmodule \ No newline at end of file diff --git a/register.v b/register.v new file mode 100644 index 0000000..84712d7 --- /dev/null +++ b/register.v @@ -0,0 +1,50 @@ +// Single-bit D Flip-Flop with enable +// Positive edge triggered +module register +( +output reg q, +input d, +input wrenable, +input clk +); + + always @(posedge clk) begin + if(wrenable) begin + q = d; + end + end + +endmodule + +module register32 #(parameter init = 32'b0) +( + + output reg[31:0] q, + input[31:0] d, + input wrenable, + input clk +); + + initial q = init; + always @(posedge clk) begin + if(wrenable) begin + q = d; + end + end + +endmodule + +module register32zero +( + output reg[31:0] q, + input[31:0] d, + input wrenable, + input clk +); + initial q = 32'b0; + + always @(posedge clk) begin + q = 32'b0; + end + +endmodule \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..08a3872 --- /dev/null +++ b/run.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +if [ $1 == "test" ]; then + make clean + make test + ./alu.t.o + ./instructiondecoder.t.o + ./regfile.t.o + ./signextend.t.o +elif [ $1 == "cpu" ]; then + make clean + make cpu + ./cpu.t.o +fi diff --git a/signextend.t.v b/signextend.t.v new file mode 100644 index 0000000..702aa5d --- /dev/null +++ b/signextend.t.v @@ -0,0 +1,26 @@ +`include "signextend.v" + +module signextendtest (); + + // Instantiate device/module under test + reg [15:0] A; // Primary test inputs + wire [31:0] result; + + signextend dut(A, result); // Module to be tested + + + // Run sequence of test stimuli + initial begin + A=16'b1010110011100010; #1 + if(result==32'b11111111111111111010110011100010) + $display("Test case 1 passed"); + else + $display("Test case 1 failed"); + + A=16'b0010110011100010; #1 + if(result==32'b00000000000000000010110011100010) + $display("Test case 1 passed"); + else + $display("Test case 1 failed"); + end +endmodule // End demorgan_test \ No newline at end of file diff --git a/signextend.v b/signextend.v new file mode 100644 index 0000000..aa26549 --- /dev/null +++ b/signextend.v @@ -0,0 +1,11 @@ +module signextend(a, result); + +parameter INPUT_SIZE = 16; +parameter OUTPUT_SIZE = 32; + +input [INPUT_SIZE-1:0] a; // 16-bit input +output [OUTPUT_SIZE-1:0] result; // 32-bit output + +assign result = {{OUTPUT_SIZE-INPUT_SIZE{a[INPUT_SIZE-1]}},a}; + +endmodule \ No newline at end of file diff --git a/workplan.txt b/workplan.txt new file mode 100644 index 0000000..cb5085d --- /dev/null +++ b/workplan.txt @@ -0,0 +1,19 @@ +Bryan Werth, Joseph Lee, Serena Chen + +Workplan - 1 hour - Today! +Verilog CPU design & test files + Single cycle - 3 hours - Done by Friday 11/10 + Single cycle tests - 2 hours - Done by Saturday 11/11 + Expand to pipelined - 1.5 hours - Done by Saturday 11/11 + Testing and debugging for hazards - Done by Wednesday 11/15 +Assembly tests - 1.5 hours - Done by Monday 11/13 +Vivado synthesis - .5 hours - Done by Thursday 11/16 +Readme for assembly tests - .5 hours - Done by Monday 11/13 + Expected results of the test + Any memory layout requirements (e.g. .data section) + Any instructions used outside the basic required subset (ok to use, but try to submit at least one test program everyone can run) +Report - 1 hour - Done by Thursday 11/16 + Written description and block diagram of your processor architecture. Consider including selected RTL to capture how instructions are implemented. + Description of your test plan and results + Some performance/area analysis of your design. This can be for the full processor, or a case study of choices made designing a single unit. It can be based on calculation, simulation, Vivado synthesis results, or a mix of all three. + Work plan reflection