diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1ecedc --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Ignore compiled binaries +* +!/**/ +!*.* +!makefile +*.out + +# Ignore gtkwave files +*.vcd + +# Ignore temporary memory file +mem.dat diff --git a/AssemblyPrograms/bne_unit_test.asm b/AssemblyPrograms/bne_unit_test.asm new file mode 100644 index 0000000..4e8aab3 --- /dev/null +++ b/AssemblyPrograms/bne_unit_test.asm @@ -0,0 +1,17 @@ +main: +addi $t3, $zero, 0 +addi $t4, $zero, 4 + +whileloop: +bne $t3, $t4, branchtaken + +saveres: +addi $t5, $t3, 0 +j end + +branchtaken: +addi $t3, $t3, 1 +j whileloop + +end: +j end diff --git a/AssemblyPrograms/combined_unit_tests.asm b/AssemblyPrograms/combined_unit_tests.asm new file mode 100644 index 0000000..d01a84b --- /dev/null +++ b/AssemblyPrograms/combined_unit_tests.asm @@ -0,0 +1,96 @@ +# Test the addi command +additest: +addi $t0, $zero, 5 # $t0 = 5 +addi $t1, $t0, 125 # $t1 = 130 +addi $t0, $t0, 4 # $t0 = 9 + +# Test the xori command +xoritest: +# Reset the designated result register +addi $t0, $zero, 0 + +addi $t1, $zero, 2 +addi $t2, $zero, 11 + +xori $t0, $t1, 7 # $t0 = 5 +xori $t0, $t2, 11 # $t0 = 0 + +# Test the add command +addtest: +# Reset the designated result register +addi $t0, $zero, 0 + +# Two positive numbers +addi $t1, $zero, 6 +addi $t2, $zero, 57 + +# One positive and one negative number +addi $t3, $zero, -9 +addi $t4, $zero, 20 + +# Two negative numbers +addi $t5, $zero, -5 +addi $t6, $zero, -11 + +add $t0, $t1, $t2 # $t0 = 57 + 6 = 63 +add $t0, $t3, $t4 # $t0 = -9 + 20 = 11 +add $t0, $t5, $t6 # $t0 = -5 + -11 = -16 + +# Test the sub command +subtest: +# Reset the designated result register +addi $t0, $zero, 0 + +sub $t0, $t1, $t2 # $t0 = 6 - 57 = -51 +sub $t0, $t3, $t4 # $t0 = -9 - 20 = -29 +sub $t0, $t5, $t6 # $t0 = -5 - -11 = 6 + +# Test the slt command +slttest: +# Reset the designated result register +addi $t0, $zero, 0 + +slt $t0, $t1, $t2 # $t0 = 57 < 6 = 1 +slt $t0, $t3, $t4 # $t0 = -9 < 20 = 1 +slt $t0, $t5, $t6 # $t0 = -5 < 11 = 0 + +# Test the bne command +breginit: +addi $t3, $zero, 0 +addi $t4, $zero, 4 + +whileloop: +bne $t3, $t4, branchtaken + +saveres: +addi $t5, $t3, 0 # $t5 = 4 +j swtest + +branchtaken: +addi $t3, $t3, 1 +j whileloop + +swtest: +addi $sp, $zero, 64 +addi $t1, $zero, 2 +addi $t2, $zero, 169 + +sw $t1, 0($sp) +sw $t2, -4($sp) + +lwtest: +lw $t3, 0($sp) # $t3 = $t1 = 2 +lw $t4, -4($sp) # $t4 = $t2 = 169 + +jaltest: +addi $t1, $zero 100 # $t1 = 100 +jal jrtest +addi $t1, $t1, 1 # $t1 = 102 +j end + +jrtest: +addi $t1, $t1, 1 # $t1 = 101 +jr $ra + +end: +j end diff --git a/AssemblyPrograms/fibonacci.asm b/AssemblyPrograms/fibonacci.asm new file mode 100644 index 0000000..e810ebf --- /dev/null +++ b/AssemblyPrograms/fibonacci.asm @@ -0,0 +1,134 @@ + +# Function call example: recursive Fibonacci + +main: + +addi $sp, $zero, 64 +# Set up arguments for call to fib_test +addi $a0, $zero, 7 # arg0 = 4 +addi $a1, $zero, 3 # arg1 = 10 +jal fib_test + +# Print result +add $a0, $zero, $v0 # Copy result into argument register a0 + +# Jump to "exit", rather than falling through to subroutines +j program_end + +#------------------------------------------------------------------------------ +# Fibonacci test function. Equivalent C code: +# int fib_test(arg0, arg1) { +# return Fibonacci(arg0) + Fibonacci(arg1); +# } +# By MIPS calling convention, expects arguments in +# registers a0 and a1, and returns result in register v0. +fib_test: +# We will use s0 and s1 registers in this function, plus the ra register +# to return at the end. Save them to stack in case caller was using them. +addi $sp, $sp, -12 # Allocate three words on stack at once for three pushes +sw $ra, 8($sp) # Push ra on the stack (will be overwritten by Fib function calls) +sw $s0, 4($sp) # Push s0 onto stack +sw $s1, 0($sp) # Push s1 onto stack + +# a1 may be overwritten by called functions, so save it to s1 (saved temporary), +# which called function won't change, so we can use it later for the second fib call +add $s1, $zero, $a1 + +# Call Fib(arg0), save result in s0 +# arg0 is already in register a0, placed there by caller of fib_test +jal fib # Call fib(4), returns in register v0 +add $s0, $zero, $v0 # Move result to s0 so we can call fib again without overwriting + +# Call Fib(arg1), save result in s1 +add $a0, $zero, $s1 # Move original arg1 into register a0 for function call +jal fib +add $s1, $zero, $v0 # Move result to s1 + +# Add Fib(arg0) and Fib(arg1) into v0 (return value for fib_test) +add $v0, $s0, $s1 + +# Restore original values to s0 and s1 registers from stack before returning +lw $s1, 0($sp) # Pop s1 from stack +lw $s0, 4($sp) # Pop s0 from stack +lw $ra, 8($sp) # Pop ra from the stack so we can return to caller +addi $sp, $sp, 12 # Adjust stack pointer to reflect pops + +jr $ra # Return to caller + +#------------------------------------------------------------------------------ +# Recursive Fibonacci function. Equivalent C code: +# +# int Fibonacci(int n) { +# if (n == 0) return 0; // Base case +# if (n == 1) return 1; // Base case +# int fib_1 = Fibonacci(n - 1); +# int fib_2 = Fibonacci(n - 2); +# return fib_1+fib_2; +# } +fib: +# Test base cases. If we're in a base case, return directly (no need to use stack) +bne $a0, 0, testone +add $v0, $zero, $zero # a0 == 0 -> return 0 +jr $ra +testone: +bne $a0, 1, fib_body +add $v0, $zero, $a0 # a0 == 1 -> return 1 +jr $ra + +fib_body: +# Create stack frame for fib: push ra and s0 +addi $sp, $sp, -8 # Allocate two words on stack at once for two pushes +sw $ra, 4($sp) # Push ra on the stack (will be overwritten by recursive function calls) +sw $s0, 0($sp) # Push s0 onto stack + +# Call Fib(n-1), save result in s0 +add $s0, $zero, $a0 # Save a0 argument (n) in register s0 +addi $a0, $a0, -1 # a0 = n-1 +jal fib +add $a0, $s0, -2 # a0 = n-2 +add $s0, $zero, $v0 # s0 = Fib(n-1) + +# Call Fib(n-2), compute final result +jal fib +add $v0, $v0, $s0 # v0 = Fib(n-2) + Fib(n-1) + +# Restore registers and pop stack frame +lw $ra, 4($sp) +lw $s0, 0($sp) +addi $sp, $sp, 8 + +jr $ra # Return to caller + +#------------------------------------------------------------------------------ +# Utility function to print results +print_result: +# Create stack frame for ra and s0 +addi $sp, $sp, -8 +sw $ra, 4($sp) +sw $s0, 0($sp) + +add $s0, $zero, $a0 # Save argument (integer to print) to s0 + +addi $v0, $zero, 4 # Service code to print string +la $a0, result_str # Argument is memory address of string to print +syscall + +addi $v0, $zero, 1 # Service code to print integer +add $a0, $zero, $s0 # Argument is integer to print +syscall + +# Restore registers and pop stack frame +lw $ra, 4($sp) +lw $s0, 0($sp) +addi $sp, $sp, 8 + +#------------------------------------------------------------------------------ +# Jump loop to end execution, so we don't fall through to .data section +program_end: +j program_end + + +#------------------------------------------------------------------------------ +.data +# Null-terminated string to print as part of result +result_str: .asciiz "\nFib(4)+Fib(10) = " diff --git a/AssemblyPrograms/slt_unit_test.asm b/AssemblyPrograms/slt_unit_test.asm new file mode 100644 index 0000000..d063e18 --- /dev/null +++ b/AssemblyPrograms/slt_unit_test.asm @@ -0,0 +1,18 @@ +# Set Less Than unit tests +main: +addi $t1, $zero, 6 +addi $t2, $zero 57 + +addi $t3, $zero, -9 +addi $t4, $zero, 20 + +addi $t5, $zero, -5 +addi $t6, $zero, -11 + +slt $t0, $t1, $t2 +slt $t0, $t3, $t4 +slt $t0, $t5, $t6 +j end + +end: +j end \ No newline at end of file diff --git a/AssemblyPrograms/sub_unit_test.asm b/AssemblyPrograms/sub_unit_test.asm new file mode 100644 index 0000000..3dd85e3 --- /dev/null +++ b/AssemblyPrograms/sub_unit_test.asm @@ -0,0 +1,18 @@ +# Subtraction unit tests +main: +addi $t1, $zero, 6 +addi $t2, $zero 57 + +addi $t3, $zero, -9 +addi $t4, $zero, 20 + +addi $t5, $zero, -5 +addi $t6, $zero, -11 + +sub $t0, $t1, $t2 +sub $t0, $t3, $t4 +sub $t0, $t5, $t6 +j end + +end: +j end \ No newline at end of file diff --git a/AssemblyPrograms/testCPU.asm b/AssemblyPrograms/testCPU.asm new file mode 100644 index 0000000..774d6e8 --- /dev/null +++ b/AssemblyPrograms/testCPU.asm @@ -0,0 +1,17 @@ +main: +addi $t3, $zero, 0 +addi $t4, $zero, 4 + +whileloop: +bne $t3, $t4, branchtaken + +saveres: +addi $t5, $t3, 0 +j end + +branchtaken: +addi $t3, $t3, 1 +j whileloop + +end: +j end \ No newline at end of file diff --git a/CPU.v b/CPU.v new file mode 100644 index 0000000..0cf1343 --- /dev/null +++ b/CPU.v @@ -0,0 +1,56 @@ +// 32 Bit CPU +// Ariana Olson, Andrew Pan, Jonah Spear + +`include "Instruction_Parser/Instruction_Parser.v" +`include "Core/Core.v" +`include "PC_Calc/PC_Calc.v" +`include "DFF.v" + +module CPU +( + input CLK +); + // PC is the current program counter, new_PC is what it's next value will be. + wire[31:0] PC, new_PC; + reg en; + + initial begin + en = 0; #1000; + en = 1; + end + + DFF #(32) pc(.trigger(CLK), .enable(en), .out(PC), .in(new_PC)); + + wire[4:0] Rs, Rd, Rt; + wire[15:0] imm; + wire[25:0] addr; + wire[2:0] ALUCtrl; + wire[1:0] MemToReg, RegDst, PCSel; + wire MemWr, ALUSrc, RegWr, AddSel; + InstructionParser ip( + .PC(PC), + .Rs(Rs), .Rd(Rd), .Rt(Rt), + .imm(imm), .addr(addr), + .ALUCtrl(ALUCtrl), .MemToReg(MemToReg), + .MemWr(MemWr), .ALUSrc(ALUSrc), .PCSel(PCSel), + .RegDst(RegDst), .RegWr(RegWr), .AddSel(AddSel) + ); + + + wire[31:0] Da; + wire isZero; + wire[31:0] added_PC; + Core c( + .CLK(CLK), .Rd(Rd), .Rt(Rt), .Rs(Rs), .imm(imm), .addedPC(added_PC), + .RegDst(RegDst), .RegWr(RegWr), .MemWr(MemWr), + .ALUSrc(ALUSrc), .MemToReg(MemToReg), .ALUCntrl(ALUCtrl), + .Da(Da), .isZero(isZero) + ); + + PC_Calc pc_calc( + .old_PC(PC), .isZero(isZero), .PCSel(PCSel), .AddSel(AddSel), + .Da(Da), .addr(addr), .imm(imm), .added_PC(added_PC), .new_PC(new_PC) + ); + + +endmodule diff --git a/CPU_fib.t.v b/CPU_fib.t.v new file mode 100644 index 0000000..fc11d2c --- /dev/null +++ b/CPU_fib.t.v @@ -0,0 +1,29 @@ +`include "CPU.v" + +module testCPU (); + + reg CLK; + reg[31:0] mem [16:0]; + integer i; + + CPU dut (.CLK(CLK)); + + initial begin + $dumpfile("CPU_fib.vcd"); + $dumpvars(0, testCPU); + + repeat(600) begin + CLK = 1; #12000; CLK = 0; #12000; + end + if (dut.PC === 32'd228) begin + if (dut.c.regfile.register2out === 32'd15) begin + $display("Fibonnaci test passed!"); + end + + else begin + $display("Fibonnaci test failed. Expected value: %b Actual value: %b", 32'd15, dut.c.regfile.register2out); + end + end + end + +endmodule diff --git a/CPU_unit.t.v b/CPU_unit.t.v new file mode 100644 index 0000000..11b682d --- /dev/null +++ b/CPU_unit.t.v @@ -0,0 +1,254 @@ +// Test the full single cycle CPU + +`include "CPU.v" + +module testCPU (); + + reg CLK; + reg[31:0] mem [16:0]; + + CPU dut (.CLK(CLK)); + + initial begin + $dumpfile("CPU_unit.vcd"); + $dumpvars(0, testCPU); + + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd5) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd5, dut.c.regfile.register8out); + end + + // PC = 4 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register9out != 32'd130) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd130, dut.c.regfile.register9out); + end + + // PC = 8 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd9) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd9, dut.c.regfile.register8out); + end + + // xori test cases + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 24 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd5) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd5, dut.c.regfile.register8out); + end + + // PC = 28 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd0) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd0, dut.c.regfile.register8out); + end + + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 60 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd63) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd63, dut.c.regfile.register8out); + end + + // PC = 64 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd11) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd11, dut.c.regfile.register8out); + end + + // PC = 68 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != -32'd16) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", -32'd16, dut.c.regfile.register8out); + end + + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 76 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != -32'd51) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", -32'd51, dut.c.regfile.register8out); + end + + // PC = 80 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != -32'd29) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", -32'd29, dut.c.regfile.register8out); + end + + // PC = 84 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd6) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd6, dut.c.regfile.register8out); + end + + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 92 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd1) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd1, dut.c.regfile.register8out); + end + + // PC = 96 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd1) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd1, dut.c.regfile.register8out); + end + + // PC = 100 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register8out != 32'd0) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd0, dut.c.regfile.register8out); + end + + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 124 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register11out != 32'd1) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd1, dut.c.regfile.register11out); + end + + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 124 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register11out != 32'd2) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd2, dut.c.regfile.register11out); + end + + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 124 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register11out != 32'd3) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd3, dut.c.regfile.register11out); + end + + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 124 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register11out != 32'd4) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd4, dut.c.regfile.register11out); + end + + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 116 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register13out != 32'd4) begin + $display("Error at register $t0. Expected value: %h, actual value: %h", 32'd4, dut.c.regfile.register8out); + end + + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 132 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register29out != 32'd64) begin + $display("Error at register $sp. Expected value: %h, actual value: %h", 32'd16380, dut.c.regfile.register29out); + end + + // PC = 136 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register9out != 32'd2) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd2, dut.c.regfile.register9out); + end + + // PC = 140 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register10out != 32'd169) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd169, dut.c.regfile.register10out); + end + + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 152 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register11out != 32'd2) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd2, dut.c.regfile.register11out); + end + + // PC = 156 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register12out != 32'd169) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd169, dut.c.regfile.register12out); + end + + // PC = 160 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register9out != 32'd100) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd100, dut.c.regfile.register9out); + end + + // PC = 164 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register31out != 32'd168) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd168, dut.c.regfile.register31out); + end + + // PC = 176 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register9out != 32'd101) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd101, dut.c.regfile.register9out); + end + + CLK = 1; #12000; CLK = 0; #12000; + + // PC = 168 + CLK = 1; #12000; CLK = 0; #12000; + $display("Program counter: %h", dut.PC); + if (dut.c.regfile.register9out != 32'd102) begin + $display("Error at register $t1. Expected value: %h, actual value: %h", 32'd102, dut.c.regfile.register9out); + end + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + CLK = 1; #12000; CLK = 0; #12000; + end +endmodule diff --git a/CPU_while.t.v b/CPU_while.t.v new file mode 100644 index 0000000..dd2277d --- /dev/null +++ b/CPU_while.t.v @@ -0,0 +1,29 @@ +`include "CPU.v" + +module testCPU (); + + reg CLK; + reg[31:0] mem [16:0]; + integer i; + + CPU dut (.CLK(CLK)); + + initial begin + $dumpfile("CPU_fib.vcd"); + $dumpvars(0, testCPU); + + repeat(30) begin + CLK = 1; #12000; CLK = 0; #12000; + end + if (dut.PC === 32'd28) begin + if (dut.c.regfile.register11out === dut.c.regfile.register12out) begin + $display("While loop test passed!"); + end + + else begin + $display("While loop test failed. $t3 and $t4 are not equal at the end of the program."); + end + end + end + +endmodule \ No newline at end of file diff --git a/Core/ALU/adder.v b/Core/ALU/adder.v new file mode 100644 index 0000000..cc610e8 --- /dev/null +++ b/Core/ALU/adder.v @@ -0,0 +1,76 @@ +// Adder circuit + +module behavioralFullAdder +( + output sum, + output carryout, + input a, + input b, + input carryin +); + // Uses concatenation operator and built-in '+' + assign {carryout, sum}=a+b+carryin; +endmodule + +module structuralFullAdder +( + output sum, + output carryout, + input a, + input b, + input carryin +); + wire ab; //setting up wires + wire acarryin; + wire bcarryin; + wire orpairintermediate; + wire orsingleintermediate; + wire orall; + wire andsumintermediate; + wire andsingleintermediate; + wire andall; + wire invcarryout; + and #(50) andab(ab, a, b); // a and b + and #(50) andacarryin(acarryin, a, carryin); // a and carryin + and #(50) andbcarryin(bcarryin, b, carryin); // b and carryin + or #(50) orpair(orpairintermediate, ab, acarryin); // (a and b) or (a and carryin) + or #(50) orcarryout(carryout, orpairintermediate, bcarryin); // ((a and b) or (a and carryin)) or (b and carryin) + or #(50) orintermediate(orsingleintermediate, a, b); // a or b + or #(50) orallinputs(orall, orsingleintermediate, carryin); // (a or b) or carryin + not #(50) inv(invcarryout, carryout); // not carryout + and #(50) sumintermediate(andsumintermediate, invcarryout, orall); // (a or b or carryin) and not carryout + and #(50) andintermediate(andsingleintermediate, a, b); // a and b + and #(50) andallinputs(andall, andsingleintermediate, carryin); // (a and b) and carryin + or #(50) adder(sum, andsumintermediate, andall); // ((a or b or carryin) and not carryout) or (a and b and c) +endmodule + +module FullAdder4bit +( + output[3:0] sum, // 2's complement sum of a and b + output carryout, // Carry out of the summation of a and b + output overflow, // True if the calculation resulted in an overflow + input[3:0] a, // First operand in 2's complement format + input[3:0] b, // Second operand in 2's complement format + input carryin +); + wire carryout1; // wire setup for carryouts from each adder + wire carryout2; + wire carryout3; + wire aandb; + wire anorb; + wire bandsum; + wire bnorsum; + wire abandnoror; + wire bsumandnornor; + structuralFullAdder #50 adder1(sum[0], carryout1, a[0], b[0], carryin); // first adder to handle the first added bits + structuralFullAdder #50 adder2(sum[1], carryout2, a[1], b[1], carryout1); // second adder to take the carryout from the first adder and the next added bits + structuralFullAdder #50 adder3(sum[2], carryout3, a[2], b[2], carryout2); // third adder to take the second carryout and the third added bits + structuralFullAdder #50 adder4(sum[3], carryout, a[3], b[3], carryout3); // fourth adder to take the third carryout and the fourth bits + and #50 andinputs(aandb, a[3], b[3]); // logic to determine overflow (overflow occurs when two positives result in a negative or two negatives result in a positive, the larges bit in both inputs are equal and the largest bit in the output is not the same) + nor #50 norinputs(anorb, a[3], b[3]); + and #50 andsum(bandsum, b[3], sum[3]); + nor #50 norsum(bnorsum, b[3], sum[3]); + or #50 orinputcombs(abandnoror, aandb, anorb); + nor #50 norsumcombs(bsumandnornor, bandsum, bnorsum); + and #50 finaland(overflow, abandnoror, bsumandnornor); +endmodule \ No newline at end of file diff --git a/Core/ALU/adder_subtracter.t.v b/Core/ALU/adder_subtracter.t.v new file mode 100644 index 0000000..b8593b6 --- /dev/null +++ b/Core/ALU/adder_subtracter.t.v @@ -0,0 +1,60 @@ +// Adder_subtacter testbench + +`timescale 1 ns / 1 ps +`include "Core/ALU/adder_subtracter.v" + +module test32bitAdder(); + reg[31:0] a; + reg[31:0] b; + reg[2:0] carryin; + wire[31:0] ans; + wire carryout, overflow, zero; + + adder_subtracter adder0(ans[31:0], carryout, overflow, zero, a[31:0], b[31:0], carryin[2:0]); + + initial begin + $display("Input A Input B Command | Output Flag Carryout"); + + // Addition tests + a=32'b00000000000000000000000000000001; + b=32'b00000000000000000000000000000001; + carryin=3'b100; #5000 + $display("%b %b %b | %b %b %b", a[31:0],b[31:0],carryin,ans[31:0],carryout, overflow); + + a=32'b10000000000000000000000000000001; + b=32'b10000000000000000000000000000001; + carryin=3'b000; #5000 + $display("%b %b %b | %b %b %b", a[31:0],b[31:0],carryin,ans[31:0],carryout, overflow); + + // Subtraction Tests + a=32'b00000000000000000000000000000001; + b=32'b00000000000000000000000000000001; + carryin=3'b001; #5000 + $display("%b %b %b | %b %b %b", a[31:0],b[31:0],carryin,ans[31:0],carryout, overflow); + + a=32'b00000000001000000000000000000000; + b=32'b00000000000000000000000010000000; + carryin=3'b001; #5000 + $display("%b %b %b | %b %b %b", a[31:0],b[31:0],carryin,ans[31:0],carryout, overflow); + + a=32'b10000000001000010000000000000000; + b=32'b10000000000000010000000010000000; + carryin=3'b001; #5000 + $display("%b %b %b | %b %b %b", a[31:0],b[31:0],carryin,ans[31:0],carryout, overflow); + + a=32'b10000000000000000000000000000001; + b=32'b10000000000000000000000000000001; + carryin=3'b001; #5000 + $display("%b %b %b | %b %b %b", a[31:0],b[31:0],carryin,ans[31:0],carryout, overflow); + + a=32'b00000000000000000000000000000000; + b=32'b10000000000000000000000000000001; + carryin=3'b001; #5000 + $display("%b %b %b | %b %b %b", a[31:0],b[31:0],carryin,ans[31:0],carryout, overflow); + + a=32'b10000000000000000000000000000001; + b=32'b10000000000000000000000000000001; + carryin=3'b000; #5000 + $display("%b %b %b | %b %b %b", a[31:0],b[31:0],carryin,ans[31:0],carryout, overflow); + end +endmodule \ No newline at end of file diff --git a/Core/ALU/adder_subtracter.v b/Core/ALU/adder_subtracter.v new file mode 100644 index 0000000..87bd13c --- /dev/null +++ b/Core/ALU/adder_subtracter.v @@ -0,0 +1,266 @@ +`include "Core/ALU/adder.v" + +// 32 bit mux +module mux + ( + output[31:0] out, + input address, + input[31:0] in0, + input[31:0] in1 + ); + wire invaddr; + wire in00addr; // input 0 bit 0 andded with address + wire in01addr; + wire in02addr; + wire in03addr; + wire in04addr; + wire in05addr; + wire in06addr; + wire in07addr; + wire in08addr; + wire in09addr; + wire in010addr; + wire in011addr; + wire in012addr; + wire in013addr; + wire in014addr; + wire in015addr; + wire in016addr; + wire in017addr; + wire in018addr; + wire in019addr; + wire in020addr; + wire in021addr; + wire in022addr; + wire in023addr; + wire in024addr; + wire in025addr; + wire in026addr; + wire in027addr; + wire in028addr; + wire in029addr; + wire in030addr; + wire in031addr; + wire in10addr; + wire in11addr; + wire in12addr; + wire in13addr; + wire in14addr; + wire in15addr; + wire in16addr; + wire in17addr; + wire in18addr; + wire in19addr; + wire in110addr; + wire in111addr; + wire in112addr; + wire in113addr; + wire in114addr; + wire in115addr; + wire in116addr; + wire in117addr; + wire in118addr; + wire in119addr; + wire in120addr; + wire in121addr; + wire in122addr; + wire in123addr; + wire in124addr; + wire in125addr; + wire in126addr; + wire in127addr; + wire in128addr; + wire in129addr; + wire in130addr; + wire in131addr; + + // inverting address + not #10 inv(invaddr, address); + // and all bits in input 0 with inverted address + and #20 and00(in00addr, in0[0], invaddr); + and #20 and01(in01addr, in0[1], invaddr); + and #20 and02(in02addr, in0[2], invaddr); + and #20 and03(in03addr, in0[3], invaddr); + and #20 and04(in04addr, in0[4], invaddr); + and #20 and05(in05addr, in0[5], invaddr); + and #20 and06(in06addr, in0[6], invaddr); + and #20 and07(in07addr, in0[7], invaddr); + and #20 and08(in08addr, in0[8], invaddr); + and #20 and09(in09addr, in0[9], invaddr); + and #20 and010(in010addr, in0[10], invaddr); + and #20 and011(in011addr, in0[11], invaddr); + and #20 and012(in012addr, in0[12], invaddr); + and #20 and013(in013addr, in0[13], invaddr); + and #20 and014(in014addr, in0[14], invaddr); + and #20 and015(in015addr, in0[15], invaddr); + and #20 and016(in016addr, in0[16], invaddr); + and #20 and017(in017addr, in0[17], invaddr); + and #20 and018(in018addr, in0[18], invaddr); + and #20 and019(in019addr, in0[19], invaddr); + and #20 and020(in020addr, in0[20], invaddr); + and #20 and021(in021addr, in0[21], invaddr); + and #20 and022(in022addr, in0[22], invaddr); + and #20 and023(in023addr, in0[23], invaddr); + and #20 and024(in024addr, in0[24], invaddr); + and #20 and025(in025addr, in0[25], invaddr); + and #20 and026(in026addr, in0[26], invaddr); + and #20 and027(in027addr, in0[27], invaddr); + and #20 and028(in028addr, in0[28], invaddr); + and #20 and029(in029addr, in0[29], invaddr); + and #20 and030(in030addr, in0[30], invaddr); + and #20 and031(in031addr, in0[31], invaddr); + // and all bits in input 1 with address + and #20 and10(in10addr, in1[0], address); + and #20 and11(in11addr, in1[1], address); + and #20 and12(in12addr, in1[2], address); + and #20 and13(in13addr, in1[3], address); + and #20 and14(in14addr, in1[4], address); + and #20 and15(in15addr, in1[5], address); + and #20 and16(in16addr, in1[6], address); + and #20 and17(in17addr, in1[7], address); + and #20 and18(in18addr, in1[8], address); + and #20 and19(in19addr, in1[9], address); + and #20 and110(in110addr, in1[10], address); + and #20 and111(in111addr, in1[11], address); + and #20 and112(in112addr, in1[12], address); + and #20 and113(in113addr, in1[13], address); + and #20 and114(in114addr, in1[14], address); + and #20 and115(in115addr, in1[15], address); + and #20 and116(in116addr, in1[16], address); + and #20 and117(in117addr, in1[17], address); + and #20 and118(in118addr, in1[18], address); + and #20 and119(in119addr, in1[19], address); + and #20 and120(in120addr, in1[20], address); + and #20 and121(in121addr, in1[21], address); + and #20 and122(in122addr, in1[22], address); + and #20 and123(in123addr, in1[23], address); + and #20 and124(in124addr, in1[24], address); + and #20 and125(in125addr, in1[25], address); + and #20 and126(in126addr, in1[26], address); + and #20 and127(in127addr, in1[27], address); + and #20 and128(in128addr, in1[28], address); + and #20 and129(in129addr, in1[29], address); + and #20 and130(in130addr, in1[30], address); + and #20 and131(in131addr, in1[31], address); + + // or the and gates + or #20 or0(out[0], in00addr, in10addr); + or #20 or1(out[1], in01addr, in11addr); + or #20 or2(out[2], in02addr, in12addr); + or #20 or3(out[3], in03addr, in13addr); + or #20 or4(out[4], in04addr, in14addr); + or #20 or5(out[5], in05addr, in15addr); + or #20 or6(out[6], in06addr, in16addr); + or #20 or7(out[7], in07addr, in17addr); + or #20 or8(out[8], in08addr, in18addr); + or #20 or9(out[9], in09addr, in19addr); + or #20 or10(out[10], in010addr, in110addr); + or #20 or11(out[11], in011addr, in111addr); + or #20 or12(out[12], in012addr, in112addr); + or #20 or13(out[13], in013addr, in113addr); + or #20 or14(out[14], in014addr, in114addr); + or #20 or15(out[15], in015addr, in115addr); + or #20 or16(out[16], in016addr, in116addr); + or #20 or17(out[17], in017addr, in117addr); + or #20 or18(out[18], in018addr, in118addr); + or #20 or19(out[19], in019addr, in119addr); + or #20 or20(out[20], in020addr, in120addr); + or #20 or21(out[21], in021addr, in121addr); + or #20 or22(out[22], in022addr, in122addr); + or #20 or23(out[23], in023addr, in123addr); + or #20 or24(out[24], in024addr, in124addr); + or #20 or25(out[25], in025addr, in125addr); + or #20 or26(out[26], in026addr, in126addr); + or #20 or27(out[27], in027addr, in127addr); + or #20 or28(out[28], in028addr, in128addr); + or #20 or29(out[29], in029addr, in129addr); + or #20 or30(out[30], in030addr, in130addr); + or #20 or31(out[31], in031addr, in131addr); +endmodule + +// 32 bit adder/subtracter that determines what operation to conduct based on the input command +module adder_subtracter + ( + output[31:0] ans, + output carryout, + output overflow, + output reg zero, + input[31:0] opA, + input[31:0] opB, + input[2:0] command + ); + wire[31:0] invertedB; //wire to invert b in the event of a subtraction + wire[31:0] finalB; + wire normalB; //added b + wire cout0; + wire cout1; + wire cout2; + wire cout3; + wire cout4; + wire cout5; + wire cout6; + wire _; + wire _1; + wire _2; + wire _3; + wire _4; + wire _5; + wire _6; + + // invert B in the case of two's complement + not #10 invertB0(invertedB[0], opB[0]); + not #10 invertB1(invertedB[1], opB[1]); + not #10 invertB2(invertedB[2], opB[2]); + not #10 invertB3(invertedB[3], opB[3]); + not #10 invertB4(invertedB[4], opB[4]); + not #10 invertB5(invertedB[5], opB[5]); + not #10 invertB6(invertedB[6], opB[6]); + not #10 invertB7(invertedB[7], opB[7]); + not #10 invertB8(invertedB[8], opB[8]); + not #10 invertB9(invertedB[9], opB[9]); + not #10 invertB10(invertedB[10], opB[10]); + not #10 invertB11(invertedB[11], opB[11]); + not #10 invertB12(invertedB[12], opB[12]); + not #10 invertB13(invertedB[13], opB[13]); + not #10 invertB14(invertedB[14], opB[14]); + not #10 invertB15(invertedB[15], opB[15]); + not #10 invertB16(invertedB[16], opB[16]); + not #10 invertB17(invertedB[17], opB[17]); + not #10 invertB18(invertedB[18], opB[18]); + not #10 invertB19(invertedB[19], opB[19]); + not #10 invertB20(invertedB[20], opB[20]); + not #10 invertB21(invertedB[21], opB[21]); + not #10 invertB22(invertedB[22], opB[22]); + not #10 invertB23(invertedB[23], opB[23]); + not #10 invertB24(invertedB[24], opB[24]); + not #10 invertB25(invertedB[25], opB[25]); + not #10 invertB26(invertedB[26], opB[26]); + not #10 invertB27(invertedB[27], opB[27]); + not #10 invertB28(invertedB[28], opB[28]); + not #10 invertB29(invertedB[29], opB[29]); + not #10 invertB30(invertedB[30], opB[30]); + not #10 invertB31(invertedB[31], opB[31]); + + // mux chooses between inverted B or normal B based on addition or subtraction + mux addsubmux(finalB[31:0],command[0],opB[31:0], invertedB[31:0]); + + // coupling 4 adders makes a 32-bit adder, note that overflow flags do not matter except for the last one + FullAdder4bit #50 adder0(ans[3:0], cout0, _, opA[3:0], finalB[3:0], command[0]); // put least significant command bit into the adder carryin since it adds 1 for when subtracting, and 0 when adding + FullAdder4bit #50 adder1(ans[7:4], cout1, _1, opA[7:4], finalB[7:4], cout0); + FullAdder4bit #50 adder2(ans[11:8], cout2, _2, opA[11:8], finalB[11:8], cout1); + FullAdder4bit #50 adder3(ans[15:12], cout3, _3, opA[15:12], finalB[15:12], cout2); + FullAdder4bit #50 adder4(ans[19:16], cout4, _4, opA[19:16], finalB[19:16], cout3); + FullAdder4bit #50 adder5(ans[23:20], cout5, _5, opA[23:20], finalB[23:20], cout4); + FullAdder4bit #50 adder6(ans[27:24], cout6, _6, opA[27:24], finalB[27:24], cout5); + FullAdder4bit #50 adder7(ans[31:28], carryout, overflow, opA[31:28], finalB[31:28], cout6); + + always @(*) begin + if (ans === 32'b0) begin + zero <= 1; + end + + else begin + zero <= 0; + end + end +endmodule \ No newline at end of file diff --git a/Core/ALU/alu.t.v b/Core/ALU/alu.t.v new file mode 100644 index 0000000..681da3b --- /dev/null +++ b/Core/ALU/alu.t.v @@ -0,0 +1,512 @@ +`timescale 1 ns / 1 ps +`include "Core/ALU/alu.v" + +module testALU32bit(); + reg[31:0] a; + reg[31:0] b; + reg[2:0] ALUcommand; + wire[31:0] finalALUsig; + wire flag; + wire cout; + + ALUcontrolLUT alu(cout, flag, zero, finalALUsig[31:0], ALUcommand[2:0], a[31:0], b[31:0]); + + initial begin + $dumpfile("Core/ALU/alu.vcd"); + $dumpvars(); + + $display("ALU Command Input A Input B | Output Flag Carryout"); + //Test cases add + ALUcommand = 3'b000; + + // 0 + 0 + a = 32'b00000000000000000000000000000000; + b = 32'b00000000000000000000000000000000; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + // 1 + 1 + a = 32'b00000000000000000000000000000001; + b = 32'b00000000000000000000000000000001; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b00000000000000000000000000000010) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + // positive overflow + a = 32'b01111111111111111111111111111111; + b = 32'b01111111111111111111111111111111; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b11111111111111111111111111111110) || (flag != 1) || (cout != 0)) begin + $display("Test Case Failed"); + end + + // negative overflow + a = 32'b10000000000000000000000000000001; + b = 32'b10000000000000000000000000000001; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b00000000000000000000000000000010) || (flag != 1) || (cout != 1)) begin + $display("Test Case Failed"); + end + + // carryout + a = 32'b11111111111111111111111111111111; + b = 32'b00000000000000000000000000000001; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 1)) begin + $display("Test Case Failed"); + end + + + //Test cases sub + ALUcommand = 3'b001; + + // a=b=0 + a = 32'b00000000000000000000000000000000; + b = 32'b00000000000000000000000000000000; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 1)) begin + $display("Test Case Failed"); + end + + // a=b + a = 32'b00000000000000000000000000000001; + b = 32'b00000000000000000000000000000001; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 1)) begin + $display("Test Case Failed"); + end + + // a>b, both positive + a = 32'b00000000000000000000000000000111; + b = 32'b00000000000000000000000000000101; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + if((finalALUsig != 32'b00000000000000000000000000000010) || (flag != 0) || (cout != 1)) begin + $display("Test Case Failed"); + end + + // a|b|, both negative + a = 32'b11111111111111111111111111111101; + b = 32'b11111111111111111111111111111110; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b11111111111111111111111111111111) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + // |a|<|b|, both negative + a = 32'b111111111111111111111111111111110; + b = 32'b111111111111111111111111111111000; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b00000000000000000000000000000110) || (flag != 0) || (cout != 1)) begin + $display("Test Case Failed"); + end + + // a negative, b positive, no overflow + a = 32'b11111111111111111111111111111101; + b = 32'b00000000000000000000000000000101; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b11111111111111111111111111111000) || (flag != 0) || (cout != 1)) begin + $display("Test Case Failed"); + end + + // a negative, b positive, overflow + a = 32'b10000000000000000000000000000101; + b = 32'b01111100000000000000000000000000; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + if((finalALUsig != 32'b00000100000000000000000000000101) || (flag != 1) || (cout != 1)) begin + $display("Test Case Failed"); + end + + // a positive, b negative, no overflow + a = 32'b00000000000000000000000000000101; + b = 32'b11111111111111111111111111111111; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + //Here + + // Verify expectations and report test result + if((finalALUsig != 32'b00000000000000000000000000000110) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + // a positive, b negative, overflow + a = 32'b01111111111111111111101111111111; + b = 32'b10000000000000001100000000000000; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b11111111111111110011101111111111) || (flag != 1) || (cout != 0)) begin + $display("Test Case Failed"); + end + + //Test cases xor + ALUcommand = 3'b010; + + //a is all 0's + a = 32'b00000000000000000000000000000000; + b = 32'b11111111111111111111111111111111; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b11111111111111111111111111111111) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + //b is all 0's + b = 32'b00000000000000000000000000000000; + a = 32'b11111111111111111111111111111111; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b11111111111111111111111111111111) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + //a and b are all 0's + a = 32'b00000000000000000000000000000000; + b = 32'b00000000000000000000000000000000; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + //a and b are all 1's + a = 32'b11111111111111111111111111111111; + b = 32'b11111111111111111111111111111111; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + + //Test cases slt + ALUcommand = 3'b011; + + //a>b, all positive + a = 32'b00000000000000000000000000000010; + b = 32'b00000000000000000000000000000001; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + //ab, all negative + a = 32'b10000000000000000000000000000010; + b = 32'b10000000000000000000000000000001; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + //a>b, a positive, b negative + a = 32'b00000000000000000000000000000001; + b = 32'b10000000000000000000000000000010; + #25000 + $display("%b %b %b | %b %b %b", ALUcommand, a, b, finalALUsig, flag, cout); + + // Verify expectations and report test result + if((finalALUsig != 32'b00000000000000000000000000000000) || (flag != 0) || (cout != 0)) begin + $display("Test Case Failed"); + end + + //a> 2] <= dataIn; + end + assign dataOut = memory[address >> 2]; + + initial $readmemh("Core/data_memory.dat", memory); + +endmodule diff --git a/Core/regfile.t.v b/Core/regfile.t.v new file mode 100644 index 0000000..d11213f --- /dev/null +++ b/Core/regfile.t.v @@ -0,0 +1,176 @@ +//------------------------------------------------------------------------------ +// Test harness validates hw4testbench by connecting it to various functional +// or broken register files, and verifying that it correctly identifies each +//------------------------------------------------------------------------------ + +`include "Core/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[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), + .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 + + // Once 'begintest' is asserted, start running test cases + always @(posedge begintest) begin + endtest = 0; + dutpassed = 1; + #10 + + // Test Case 1: + // Write '42' to register 2, verify with Read Ports 1 and 2 + WriteRegister = 5'd2; + WriteData = 32'd42; + RegWrite = 1; + ReadRegister1 = 5'd2; + ReadRegister2 = 5'd2; + #5 Clk=1; #5 Clk=0; // Generate single clock pulse + + if((ReadData1 != 42) || (ReadData2 != 42)) begin + dutpassed = 0; // Set to 'false' on failure + $display("Test Case 1 Failed"); + end + + // Test Case 2: + // Write '15' to register 2, verify with Read Ports 1 and 2 + WriteRegister = 5'd2; + WriteData = 32'd15; + RegWrite = 1; + ReadRegister1 = 5'd2; + ReadRegister2 = 5'd2; + #5 Clk=1; #5 Clk=0; + + if(ReadData1 !== ReadData2) begin + dutpassed = 0; + $display("Test Case 2 Failed"); + end + + // Test Case 3: + // Do not enable writing, check to ensure register + // data is not replaced by WriteData; + WriteRegister = 5'd2; + WriteData = 32'd20; + RegWrite = 0; + ReadRegister1 = 5'd2; + ReadRegister2 = 5'd2; + #5 Clk=1; #5 Clk=0; + + if((ReadData1 != 15) || (ReadData2 != 15)) begin + dutpassed = 0; + $display("Test Case 3 Failed"); + end + + // Test Case 4: + // Attempt to write to the zero register. + // Ensure that the data value is still 32'b0. + WriteRegister = 5'd0; + WriteData = 32'd15; + 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 4 Failed"); + end + + // All done! Wait a moment and signal test completion. + #5 + endtest = 1; + +end + +endmodule \ No newline at end of file diff --git a/Core/regfile.v b/Core/regfile.v new file mode 100644 index 0000000..9ebc916 --- /dev/null +++ b/Core/regfile.v @@ -0,0 +1,114 @@ +//------------------------------------------------------------------------------ +// 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 "Core/register.v" +`include "submodules/multiplexer.v" +`include "Core/decoders.v" + +module regfile +( +output[31:0] ReadData1, // Contents of first register read +output[31:0] ReadData2, // Contents of second register read +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) +); + + wire[31:0] decoderOut; // Send a wrenable to at most one register. + wire[31:0] register0out; // The output data of the register. + wire[31:0] register1out; + wire[31:0] register2out; + wire[31:0] register3out; + wire[31:0] register4out; + wire[31:0] register5out; + wire[31:0] register6out; + wire[31:0] register7out; + wire[31:0] register8out; + wire[31:0] register9out; + wire[31:0] register10out; + wire[31:0] register11out; + wire[31:0] register12out; + wire[31:0] register13out; + wire[31:0] register14out; + wire[31:0] register15out; + wire[31:0] register16out; + wire[31:0] register17out; + wire[31:0] register18out; + wire[31:0] register19out; + wire[31:0] register20out; + wire[31:0] register21out; + wire[31:0] register22out; + wire[31:0] register23out; + wire[31:0] register24out; + wire[31:0] register25out; + wire[31:0] register26out; + wire[31:0] register27out; + wire[31:0] register28out; + wire[31:0] register29out; + wire[31:0] register30out; + wire[31:0] register31out; + + // The decoder block. + decoder1to32 decoder(decoderOut, RegWrite, WriteRegister); + + // The 32 register blocks. + register32zero reg0 (register0out, WriteData, decoderOut[0], Clk); // The zero register. + register32 reg1 (register1out, WriteData, decoderOut[1], Clk); + register32 reg2 (register2out, WriteData, decoderOut[2], Clk); + register32 reg3 (register3out, WriteData, decoderOut[3], Clk); + register32 reg4 (register4out, WriteData, decoderOut[4], Clk); + register32 reg5 (register5out, WriteData, decoderOut[5], Clk); + register32 reg6 (register6out, WriteData, decoderOut[6], Clk); + register32 reg7 (register7out, WriteData, decoderOut[7], Clk); + register32 reg8 (register8out, WriteData, decoderOut[8], Clk); + register32 reg9 (register9out, WriteData, decoderOut[9], Clk); + register32 reg10 (register10out, WriteData, decoderOut[10], Clk); + register32 reg11 (register11out, WriteData, decoderOut[11], Clk); + register32 reg12 (register12out, WriteData, decoderOut[12], Clk); + register32 reg13 (register13out, WriteData, decoderOut[13], Clk); + register32 reg14 (register14out, WriteData, decoderOut[14], Clk); + register32 reg15 (register15out, WriteData, decoderOut[15], Clk); + register32 reg16 (register16out, WriteData, decoderOut[16], Clk); + register32 reg17 (register17out, WriteData, decoderOut[17], Clk); + register32 reg18 (register18out, WriteData, decoderOut[18], Clk); + register32 reg19 (register19out, WriteData, decoderOut[19], Clk); + register32 reg20 (register20out, WriteData, decoderOut[20], Clk); + register32 reg21 (register21out, WriteData, decoderOut[21], Clk); + register32 reg22 (register22out, WriteData, decoderOut[22], Clk); + register32 reg23 (register23out, WriteData, decoderOut[23], Clk); + register32 reg24 (register24out, WriteData, decoderOut[24], Clk); + register32 reg25 (register25out, WriteData, decoderOut[25], Clk); + register32 reg26 (register26out, WriteData, decoderOut[26], Clk); + register32 reg27 (register27out, WriteData, decoderOut[27], Clk); + register32 reg28 (register28out, WriteData, decoderOut[28], Clk); + register32 reg29 (register29out, WriteData, decoderOut[29], Clk); + register32 reg30 (register30out, WriteData, decoderOut[30], Clk); + register32 reg31 (register31out, WriteData, decoderOut[31], Clk); + + // The multiplexer choosing the data associated with ReadRegister1. + mux32to1by32 mux1 (ReadData1, ReadRegister1, register0out, register1out, + register2out, register3out, register4out, register5out, register6out, + register7out, register8out, register9out, register10out, register11out, + register12out, register13out, register14out, register15out, register16out, + register17out, register18out, register19out, register20out, register21out, + register22out, register23out, register24out, register25out, register26out, + register27out, register28out, register29out, register30out, register31out); + + // The multiplexer choosing the data associated with ReadRegister2. + mux32to1by32 mux2 (ReadData2, ReadRegister2, register0out, register1out, + register2out, register3out, register4out, register5out, register6out, + register7out, register8out, register9out, register10out, register11out, + register12out, register13out, register14out, register15out, register16out, + register17out, register18out, register19out, register20out, register21out, + register22out, register23out, register24out, register25out, register26out, + register27out, register28out, register29out, register30out, register31out); + +endmodule \ No newline at end of file diff --git a/Core/register.t.v b/Core/register.t.v new file mode 100644 index 0000000..8b4a7f0 --- /dev/null +++ b/Core/register.t.v @@ -0,0 +1,121 @@ +//-------------------------- +// Test the register modules +//-------------------------- +`include "Core/register.v" + +// Unit tests for the single bit register module. +module registerTest(); + wire q; + reg d; + reg wrenable; + reg clk; + + register DUT (q, d, wrenable, clk); + + initial begin + // Test Case 1: + // Write a 1 to the register. + d = 1; wrenable = 1; + #5 clk = 0; + #5 clk = 1; + if (q != d) begin + $display("Register Test Case 1 failed"); + end + + // Test Case 2: + // Write a 0 to the register. + d = 0; wrenable = 1; + #5 clk = 0; + #5 clk = 1; + if (q != d) begin + $display("Register Test Case 2 failed"); + end + + // Test Case 3: + // Write not enabled, the data written should not match the output. + d = 1; wrenable = 0; + #5 clk = 0; + #5 clk = 1; + if (q == d) begin + $display("Register Test Case 3 failed"); + end + end +endmodule // registerTest + +// Unit tests for the 32 bit register module. +module register32Test(); + + wire[31:0] q; + reg[31:0] d; + reg wrenable; + reg clk; + + register32 DUT (q, d, wrenable, clk); + + initial begin + + // Test Case 1: + // Write to the register + d = 32'hFFFAAA; wrenable = 1; + #5 clk = 0; + #5 clk = 1; + if (q != d) begin + $display("32 bit register Test Case 1 failed"); + end + + // Test Case 2: + // Do not enable writing to register + d = 32'hFFF000; wrenable = 0; + #5 clk = 0; + #5 clk = 1; + if (q == d) begin + $display("32 bit register Test Case 1 failed"); + end + end +endmodule // register32Test + +// Unit tests for the 32 bit zero register module. +module register32zeroTest(); + wire[31:0] q; + reg[31:0] d; + reg wrenable; + reg clk; + + register32zero DUT (q, d, wrenable, clk); + + reg dutpassed; // Flag is set to false if any of the tests fail. + + initial begin + dutpassed = 1; + + // Test Case 1: + // Write to the register + d = 32'hFFFAAA; wrenable = 1; + #5 clk = 0; + #5 clk = 1; + if (q != 0) begin + $display("32 bit zero register Test Case 1 failed"); + dutpassed = 0; + end + + // Test Case 2: + // Do not enable writing to register + #5 + d = 32'hFFF000; wrenable = 0; + #5 clk = 0; + #5 clk = 1; + if (q != 0) begin + $display("32 bit zero register Test Case 2 failed"); + dutpassed = 0; + end + + #5 + + if (dutpassed ==1) begin + $display("All register tests passed."); + end + end +endmodule // register32zeroTest + + + diff --git a/Core/register.v b/Core/register.v new file mode 100644 index 0000000..2bed55f --- /dev/null +++ b/Core/register.v @@ -0,0 +1,74 @@ +// Single-bit D Flip-Flop with enable +// Positive edge triggered +module register +( +output reg q, +input d, +input wrenable, +input clk +); + + always @(negedge clk) begin + if(wrenable) begin + q = d; + end + end +endmodule // register + +// 32 bits of D Flip-Flops with enable. +// Positive edge triggered +module register32 +( +output [31:0] q, +input[31:0] d, +input wrenable, +input clk +); + + register r0 (q[0], d[0], wrenable, clk); + register r1 (q[1], d[1], wrenable, clk); + register r2 (q[2], d[2], wrenable, clk); + register r3 (q[3], d[3], wrenable, clk); + register r4 (q[4], d[4], wrenable, clk); + register r5 (q[5], d[5], wrenable, clk); + register r6 (q[6], d[6], wrenable, clk); + register r7 (q[7], d[7], wrenable, clk); + register r8 (q[8], d[8], wrenable, clk); + register r9 (q[9], d[9], wrenable, clk); + register r10 (q[10], d[10], wrenable, clk); + register r11 (q[11], d[11], wrenable, clk); + register r12 (q[12], d[12], wrenable, clk); + register r13 (q[13], d[13], wrenable, clk); + register r14 (q[14], d[14], wrenable, clk); + register r15 (q[15], d[15], wrenable, clk); + register r16 (q[16], d[16], wrenable, clk); + register r17 (q[17], d[17], wrenable, clk); + register r18 (q[18], d[18], wrenable, clk); + register r19 (q[19], d[19], wrenable, clk); + register r20 (q[20], d[20], wrenable, clk); + register r21 (q[21], d[21], wrenable, clk); + register r22 (q[22], d[22], wrenable, clk); + register r23 (q[23], d[23], wrenable, clk); + register r24 (q[24], d[24], wrenable, clk); + register r25 (q[25], d[25], wrenable, clk); + register r26 (q[26], d[26], wrenable, clk); + register r27 (q[27], d[27], wrenable, clk); + register r28 (q[28], d[28], wrenable, clk); + register r29 (q[29], d[29], wrenable, clk); + register r30 (q[30], d[30], wrenable, clk); + register r31 (q[31], d[31], wrenable, clk); +endmodule // register32 + + + +// 1 bit register with constant output 0. +// Inputs are ignored. +module register32zero +( +output [31:0] q, +input[31:0] d, +input wrenable, +input clk +); + assign q = 0; +endmodule // register32zero diff --git a/Core/signextend.v b/Core/signextend.v new file mode 100644 index 0000000..35effe1 --- /dev/null +++ b/Core/signextend.v @@ -0,0 +1,12 @@ +/* +Implement the sign extend immediate operation defined by the MIPS reference guide. +*/ + +module signextend +( +input[15:0] immediate, +output[31:0] signextendimmediate +); + + assign signextendimmediate = {{16{immediate[15]}}, {immediate[15:0]}}; +endmodule \ No newline at end of file diff --git a/DFF.v b/DFF.v new file mode 100644 index 0000000..5b3f96e --- /dev/null +++ b/DFF.v @@ -0,0 +1,18 @@ +// DFF is a d flip flop. + +module DFF #( parameter W = 1 ) +( + input trigger, + input enable, + input [W-1:0] in, + output reg [W-1:0] out +); + always @(posedge trigger or negedge enable) begin + if(enable) begin + out <= in; + end + else begin + out <= 0; + end + end +endmodule diff --git a/Instruction_Parser/Controller.t.v b/Instruction_Parser/Controller.t.v new file mode 100644 index 0000000..c8957ea --- /dev/null +++ b/Instruction_Parser/Controller.t.v @@ -0,0 +1,191 @@ +// Tests the Controller + +`include "Controller.v" + +module testController(); + + reg[5:0] Op, funct; + wire[2:0] ALUCtrl; + wire [1:0] MemToReg, RegDst, PCSel; + wire MemWr, ALUSrc, RegWr, AddSel; + + Controller ctrlr( + .Op(Op), .funct(funct), + .ALUCtrl(ALUCtrl), + .MemToReg(MemToReg), .RegDst(RegDst), + .PCSel(PCSel), .AddSel(AddSel), + .MemWr(MemWr), .ALUSrc(ALUSrc), .RegWr(RegWr) + ); + + // Opcodes + localparam LW = 6'h23; + localparam SW = 6'h2b; + localparam J = 6'h2; + localparam JAL = 6'h3; + localparam BNE = 6'h5; + localparam XORI = 6'he; + localparam ADDI = 6'h8; + + // These instructions all have opcode 0 and are designated by funct + localparam JR_f = 6'h08; + localparam ADD_f = 6'h20; + localparam SLT_f = 6'h2a; + localparam SUB_f = 6'h22; + + // ALU Control mapping + localparam alu_add = 3'd0; + localparam alu_sub = 3'd1; + localparam alu_xor = 3'd2; + localparam alu_slt = 3'd4; + + initial begin + // $dumpfile("Controller.vcd"); + // $dumpvars; + + // Test all instructions where the func field doesn't matter + funct = 6'bxxxxxx; + + Op = LW; #1 + if ((RegDst == 1) && (ALUSrc == 1) && + (RegWr == 1) && (MemWr == 0) && + (ALUCtrl == alu_add) && (MemToReg == 1) && + (PCSel == 1)) begin + $display("Test 1 Passed!"); + end + else begin + $display("Test 1 Failed!"); + end + + Op = SW; #1 + if ((ALUSrc == 1) && + (RegWr == 0) && (MemWr == 1) && + (ALUCtrl == alu_add) && + (PCSel == 1)) begin + $display("Test 2 Passed!"); + end + else begin + $display("Test 2 Failed!"); + end + + Op = J; #1 + if ((RegWr == 0) && (MemWr == 0) && + (PCSel == 0) && (AddSel == 0)) begin + $display("Test 3 Passed!"); + end + else begin + $display("Test 3 Failed!"); + $display("RegWr: %b", RegWr); + $display("MemWr: %b", MemWr); + $display("PCSel: %b", PCSel); + $display("AddSel: %b", AddSel); + end + + Op = JAL; #1 + if ((RegDst == 2'd2) && (RegWr == 1) && + (MemWr == 0) && (MemToReg == 2'd2) && + (PCSel == 0) && (AddSel == 0)) begin + $display("Test 5 Passed!"); + end + else begin + $display("Test 5 Failed!"); + $display("RegWr: %b", RegWr); + $display("MemWr: %b", MemWr); + $display("PCSel: %b", PCSel); + $display("AddSel: %b", AddSel); + end + + Op = BNE; #1 + if ((ALUSrc == 0) && (RegWr == 0) && + (MemWr == 0) && (ALUCtrl == alu_sub) && + (PCSel == 1) && (AddSel == 1)) begin + $display("Test 6 Passed!"); + end + else begin + $display("Test 6 Failed!"); + $display("RegWr: %b", RegWr); + $display("MemWr: %b", MemWr); + $display("PCSel: %b", PCSel); + $display("AddSel: %b", AddSel); + end + + Op = XORI; #1 + if ((RegDst == 1) && (ALUSrc == 1) && + (RegWr == 1) && (MemWr == 0) && + (ALUCtrl == alu_xor) && (MemToReg == 0) && + (PCSel == 1) && (AddSel == 0)) begin + $display("Test 7 Passed!"); + end + else begin + $display("Test 7 Failed!"); + end + + Op = ADDI; #1 + if ((RegDst == 1) && (ALUSrc == 1) && + (RegWr == 1) && (MemWr == 0) && + (ALUCtrl == alu_add) && (MemToReg == 0) && + (PCSel == 1) && (AddSel == 0)) begin + $display("Test 8 Passed!"); + end + else begin + $display("Test 8 Failed!"); + end + + // Test all instructions where the op field is 0 + Op = 0; + + funct = JR_f; #1 + if ((RegWr == 0) && (MemWr == 0) && + (PCSel == 2'd2) && (AddSel == 0)) begin + $display("Test 9 Passed!"); + end + else begin + $display("Test 9 Failed!"); + $display("RegWr: %b", RegWr); + $display("MemWr: %b", MemWr); + $display("PCSel: %b", PCSel); + $display("AddSel: %b", AddSel); + end + + funct = ADD_f; #1 + if ((RegDst == 0) && (ALUSrc == 0) && + (RegWr == 1) && (MemWr == 0) && + (ALUCtrl == alu_add) && (MemToReg == 0) && + (PCSel == 1) && (AddSel == 0)) begin + $display("Test 10 Passed!"); + end + else begin + $display("Test 10 Failed!"); + $display("RegDst: %b", RegDst); + $display("ALUSrc: %b", ALUSrc); + $display("RegWr: %b", RegWr); + $display("MemWr: %b", MemWr); + $display("ALUCtrl: %b", ALUCtrl); + $display("MemToReg: %b", MemToReg); + $display("PCSel: %b", PCSel); + $display("AddSel: %b", AddSel); + end + + funct = SUB_f; #1 + if ((RegDst == 0) && (ALUSrc == 0) && + (RegWr == 1) && (MemWr == 0) && + (ALUCtrl == alu_sub) && (MemToReg == 0) && + (PCSel == 1) && (AddSel == 0)) begin + $display("Test 11 Passed!"); + end + else begin + $display("Test 11 Failed!"); + end + + funct = SLT_f; #1 + if ((RegDst == 0) && (ALUSrc == 0) && + (RegWr == 1) && (MemWr == 0) && + (ALUCtrl == alu_slt) && (MemToReg == 0) && + (PCSel == 1) && (AddSel == 0)) begin + $display("Test 12 Passed!"); + end + else begin + $display("Test 12 Failed!"); + end + end + +endmodule diff --git a/Instruction_Parser/Controller.v b/Instruction_Parser/Controller.v new file mode 100644 index 0000000..efa514a --- /dev/null +++ b/Instruction_Parser/Controller.v @@ -0,0 +1,172 @@ +// Controller generates the correct control signals based on the operation + +module Controller +( + input[5:0] Op, funct, + output reg[2:0] ALUCtrl, + output reg[1:0] MemToReg, RegDst, PCSel, + output reg MemWr, ALUSrc, RegWr, AddSel +); + + // Opcodes + localparam LW = 6'h23; + localparam SW = 6'h2b; + localparam J = 6'h2; + localparam JAL = 6'h3; + localparam BNE = 6'h5; + localparam XORI = 6'he; + localparam ADDI = 6'h8; + + // These instructions all have opcode 0 and are designated by funct + localparam JR_f = 6'h08; + localparam ADD_f = 6'h20; + localparam SLT_f = 6'h2a; + localparam SUB_f = 6'h22; + + // ALU Control mapping + localparam alu_add = 3'd0; + localparam alu_sub = 3'd1; + localparam alu_xor = 3'd2; + localparam alu_slt = 3'd3; + + always @ * begin + case (Op) + LW: begin + RegDst = 1; + ALUSrc = 1; + RegWr = 1; + MemWr = 0; + ALUCtrl = alu_add; + MemToReg = 1; + PCSel = 1; + AddSel = 0; + end + SW: begin + RegDst = 2'bxx; + ALUSrc = 1; + RegWr = 0; + MemWr = 1; + ALUCtrl = alu_add; + MemToReg = 2'bxx; + PCSel = 1; + AddSel = 0; + end + J: begin + RegDst = 2'bxx; + ALUSrc = 1'bx; + RegWr = 0; + MemWr = 0; + ALUCtrl = 3'bxxx; + MemToReg = 2'bxx; + PCSel = 0; + AddSel = 0; + end + JAL: begin + RegDst = 2'd2; + ALUSrc = 1'bx; + RegWr = 1; + MemWr = 0; + ALUCtrl = 3'bxxx; + MemToReg = 2'd2; + PCSel = 0; + AddSel = 0; + end + BNE: begin + RegDst = 2'bxx; + ALUSrc = 0; + RegWr = 0; + MemWr = 0; + ALUCtrl = alu_sub; + MemToReg = 2'bxx; + PCSel = 1; + AddSel = 1; + end + XORI: begin + RegDst = 1; + ALUSrc = 1; + RegWr = 1; + MemWr = 0; + ALUCtrl = alu_xor; + MemToReg = 0; + PCSel = 1; + AddSel = 0; + end + ADDI: begin + RegDst = 1; + ALUSrc = 1; + RegWr = 1; + MemWr = 0; + ALUCtrl = alu_add; + MemToReg = 0; + PCSel = 1; + AddSel = 0; + end + // Multiple functions have an Op of 0 + 0: begin + case (funct) + JR_f: begin + RegDst = 2'bxx; + ALUSrc = 1'bx; + RegWr = 0; + MemWr = 0; + ALUCtrl = 3'bxxx; + MemToReg = 2'bxx; + PCSel = 2'd2; + AddSel = 0; + end + ADD_f: begin + RegDst = 0; + ALUSrc = 0; + RegWr = 1; + MemWr = 0; + ALUCtrl = alu_add; + MemToReg = 0; + PCSel = 1; + AddSel = 0; + end + SLT_f: begin + RegDst = 0; + ALUSrc = 0; + RegWr = 1; + MemWr = 0; + ALUCtrl = alu_slt; + MemToReg = 0; + PCSel = 1; + AddSel = 0; + end + SUB_f: begin + RegDst = 0; + ALUSrc = 0; + RegWr = 1; + MemWr = 0; + ALUCtrl = alu_sub; + MemToReg = 0; + PCSel = 1; + AddSel = 0; + end + default: begin + RegDst = 2'bxx; + ALUSrc = 1'bx; + RegWr = 1'bx; + MemWr = 1'bx; + ALUCtrl = 3'bxxx; + MemToReg = 2'bxx; + PCSel = 2'bxx; + AddSel = 1'bx; + end + endcase + end + default: begin + RegDst = 2'bxx; + ALUSrc = 1'bx; + RegWr = 1'bx; + MemWr = 1'bx; + ALUCtrl = 3'bxxx; + MemToReg = 2'bxx; + PCSel = 2'bxx; + AddSel = 1'bx; + end + endcase + end + +endmodule diff --git a/Instruction_Parser/Decoder.t.v b/Instruction_Parser/Decoder.t.v new file mode 100644 index 0000000..2391fda --- /dev/null +++ b/Instruction_Parser/Decoder.t.v @@ -0,0 +1,55 @@ +// Tests the Decoder + +`include "Decoder.v" + +module testDecoder(); + + reg[31:0] instr; + wire[5:0] Op, funct; + wire[4:0] Rs, Rd, Rt; + wire[15:0] imm; + wire[25:0] addr; + + Decoder dec( + .Instr(instr), .Op(Op), .funct(funct), .Rs(Rs), + .Rd(Rd), .Rt(Rt), .imm(imm), .addr(addr) + ); + + initial begin + // $dumpfile("decoder.vcd"); + // $dumpvars; + instr = 32'b00000000000000000000000000000000; #1 + if ((Op == 6'b000000) && (Rs == 5'b00000) && + (Rd == 5'b00000) && (Rt == 5'b00000) && + (imm == 16'b0000000000000000) && (funct == 6'b000000) && + (addr == 26'b00000000000000000000000000)) begin + $display("Test 1 Passed!"); + end + else begin + $display("Test 1 Failed!"); + end + + instr = 32'b11111111111111111111111111111111; #1 + if ((Op == 6'b111111) && (Rs == 5'b11111) && + (Rd == 5'b11111) && (Rt == 5'b11111) && + (imm == 16'b1111111111111111) && (funct == 6'b111111) && + (addr == 26'b11111111111111111111111111)) begin + $display("Test 2 Passed!"); + end + else begin + $display("Test 2 Failed!"); + end + + instr = 32'b11001100110011001100110011001100; #1 + if ((Op == 6'b110011) && (Rs == 5'b00110) && + (Rd == 5'b11001) && (Rt == 5'b01100) && + (imm == 16'b1100110011001100) && (funct == 6'b001100) && + (addr == 26'b00110011001100110011001100)) begin + $display("Test 3 Passed!"); + end + else begin + $display("Test 3 Failed!"); + end + end + +endmodule diff --git a/Instruction_Parser/Decoder.v b/Instruction_Parser/Decoder.v new file mode 100644 index 0000000..e965593 --- /dev/null +++ b/Instruction_Parser/Decoder.v @@ -0,0 +1,20 @@ +// Decoder splits the insruction into its parts + +module Decoder +( + input[31:0] Instr, + output[5:0] Op, + output[4:0] Rs, Rd, Rt, + output[5:0] funct, + output[15:0] imm, + output[25:0] addr +); + + assign Op = Instr[31:26]; + assign Rs = Instr[25:21]; + assign Rt = Instr[20:16]; + assign Rd = Instr[15:11]; + assign funct = Instr[5:0]; + assign imm = Instr[15:0]; + assign addr = Instr[25:0]; +endmodule diff --git a/Instruction_Parser/Instruction_Parser.t.v b/Instruction_Parser/Instruction_Parser.t.v new file mode 100644 index 0000000..4ae43e6 --- /dev/null +++ b/Instruction_Parser/Instruction_Parser.t.v @@ -0,0 +1,73 @@ +// Tests the Instruction Parser +// To use this test, the Instruction Memory must be dyanmically using the following command: +// ./run_program.sh Instruction_Parser/Instruction_Parser.t.v Instruction_Parser/test_mem.dat + +`include "Instruction_Parser.v" + +module testInstructionParser(); + + reg[31:0] PC; + // Instruction values + wire[4:0] Rs, Rd, Rt; + wire[15:0] imm; + wire[25:0] addr; + // Control Signals + wire[2:0] ALUCtrl; + wire[1:0] MemToReg, RegDst, PCSel; + wire MemWr, ALUSrc, RegWr, AddSel; + + InstructionParser ip( + .PC(PC), + .Rs(Rs), .Rd(Rd), .Rt(Rt), + .imm(imm), .addr(addr), + .ALUCtrl(ALUCtrl), .MemToReg(MemToReg), + .MemWr(MemWr), .ALUSrc(ALUSrc), .PCSel(PCSel), + .RegDst(RegDst), .RegWr(RegWr), .AddSel(AddSel) + ); + + initial begin + + PC = 0; #1; + if ((Rs == 0) && + (Rd == 0) && + (Rt == 0) && + (imm == 0) && + (addr == 0) + ) begin + $display("Test 1 Passed"); + end + else begin + $display("Test 1 Failed"); + end + + PC = 1; #1; + if ((Rs == 5'b11111) && + (Rd == 5'b11111) && + (Rt == 5'b11111) && + (imm == 16'hFFFF) && + (addr == 26'b11111111111111111111111111) + ) begin + $display("Test 2 Passed"); + end + else begin + $display("Test 2 Failed"); + end + + // Addr = 1; + // if (DataOut == 32'hFFFF_FFFF) begin + // $display("Test 2 Passed"); + // end + // else begin + // $display("Test 2 Failed"); + // end + + // Addr = 3; + // if (DataOut == 32'h0F0F_0F0F) begin + // $display("Test 3 Passed"); + // end + // else begin + // $display("Test 3 Failed"); + // end + end + +endmodule diff --git a/Instruction_Parser/Instruction_Parser.v b/Instruction_Parser/Instruction_Parser.v new file mode 100644 index 0000000..cab116f --- /dev/null +++ b/Instruction_Parser/Instruction_Parser.v @@ -0,0 +1,38 @@ +// Instruction Parser parses the relevant data and control signals from the instruction. + +`include "Instruction_Parser/Memory.v" +`include "Instruction_Parser/Decoder.v" +`include "Instruction_Parser/Controller.v" + +module InstructionParser +( + input[31:0] PC, + // Instruction values + output[4:0] Rs, Rd, Rt, + output[15:0] imm, + output[25:0] addr, + output[2:0] ALUCtrl, + output[1:0] MemToReg, RegDst, PCSel, + output MemWr, ALUSrc, RegWr, AddSel +); + wire[31:0] instr; + Memory im(.Addr(PC[9:0] >> 2), .DataOut(instr)); + + wire[5:0] Op, funct; + wire[4:0] Rs, Rd, Rt; + wire[15:0] imm; + wire[25:0] addr; + Decoder dec( + .Instr(instr), .Op(Op), .funct(funct), + .Rs(Rs), .Rd(Rd), .Rt(Rt), .imm(imm), .addr(addr) + ); + + Controller ctrlr( + .Op(Op), .funct(funct), + .ALUCtrl(ALUCtrl), + .MemToReg(MemToReg), .RegDst(RegDst), + .PCSel(PCSel), .AddSel(AddSel), + .MemWr(MemWr), .ALUSrc(ALUSrc), .RegWr(RegWr) + ); + +endmodule diff --git a/Instruction_Parser/Memory.t.v b/Instruction_Parser/Memory.t.v new file mode 100644 index 0000000..c53f553 --- /dev/null +++ b/Instruction_Parser/Memory.t.v @@ -0,0 +1,43 @@ +// Tests the Memory +// To use this test, the memory must be dyanmically using the following command: +// ./run_program.sh Instruction_Parser/Memory.t.v Instruction_Parser/test_mem.dat + + +`include "Memory.v" + +module testMemory(); + + reg clk, regWE; + reg[9:0] Addr; + reg[31:0] DataIn; + wire[31:0] DataOut; + + Memory Instruction_Memory(.Addr(Addr), .DataOut(DataOut)); + + initial begin + Addr = 0; + if (DataOut == 32'h0000_0000) begin + $display("Test 1 Passed"); + end + else begin + $display("Test 1 Failed"); + end + + Addr = 1; + if (DataOut == 32'hFFFF_FFFF) begin + $display("Test 2 Passed"); + end + else begin + $display("Test 2 Failed"); + end + + Addr = 3; + if (DataOut == 32'h0F0F_0F0F) begin + $display("Test 3 Passed"); + end + else begin + $display("Test 3 Failed"); + end + end + +endmodule diff --git a/Instruction_Parser/Memory.v b/Instruction_Parser/Memory.v new file mode 100644 index 0000000..1535d17 --- /dev/null +++ b/Instruction_Parser/Memory.v @@ -0,0 +1,23 @@ +// Memory is a big d flip flop + +module Memory +( + input clk, regWE, + input[9:0] Addr, + input[31:0] DataIn, + output[31:0] DataOut +); + + reg [31:0] mem[1023:0]; + + always @(posedge clk) begin + if (regWE) begin + mem[Addr] <= DataIn; + end + end + + // This file will be loaded dynamically. Do not edit mem.dat directly. + initial $readmemh("mem.dat", mem); + + assign DataOut = mem[Addr]; +endmodule diff --git a/Instruction_Parser/test_mem.dat b/Instruction_Parser/test_mem.dat new file mode 100644 index 0000000..d801a6c --- /dev/null +++ b/Instruction_Parser/test_mem.dat @@ -0,0 +1,1024 @@ +0000_0000 +FFFF_FFFF +0F0F_0F0F +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 diff --git a/PC.v b/PC.v new file mode 100644 index 0000000..b083817 --- /dev/null +++ b/PC.v @@ -0,0 +1 @@ +//PC is a d flip-flop that controls the diff --git a/PC_Calc/PC_Calc.t.v b/PC_Calc/PC_Calc.t.v new file mode 100644 index 0000000..461be89 --- /dev/null +++ b/PC_Calc/PC_Calc.t.v @@ -0,0 +1,44 @@ +`timescale 1 ns / 1 ps +`include "PC_Calc.v" + +module testPCCalc(); + reg[31:0] old_PC; + reg isZero; + reg[1:0] PCSel; + reg AddSel; + reg[31:0] Da; + reg[25:0] addr; + reg[15:0] imm; + wire[31:0] added_PC; + wire[31:0] new_PC; + + wire[31:0] addedSel; + wire[31:0] jump; + + PC_Calc pccalc(old_PC[31:0], isZero, PCSel[1:0], AddSel, Da[31:0], addr[25:0], imm[15:0], added_PC[31:0], new_PC[31:0]); + initial begin + old_PC = 32'd4; + isZero = 0; + PCSel = 0; + AddSel = 0; + Da = 32'd16; + addr = 26'd12; + imm = 16'd10; #1000 + if (added_PC != 32'd8 || new_PC != 32'd48) begin + $display("test case failed, expected 8 and 48"); + $display("added_PC: %b | new_PC: %b", added_PC, new_PC); + end + + old_PC = 32'b01010000000000000000000000000000; + isZero = 0; + PCSel = 0; + AddSel = 0; + Da = 32'd16; + addr = 26'd12; + imm = 16'd10; #1000 + if (added_PC != 32'd8 || new_PC != 32'd48) begin + $display("test case failed, expected 01010000000000000000000000000100 and 01010000000000000000000000110000"); + $display("added_PC: %b | new_PC: %b", added_PC, new_PC); + end + end +endmodule \ No newline at end of file diff --git a/PC_Calc/PC_Calc.v b/PC_Calc/PC_Calc.v new file mode 100644 index 0000000..81635db --- /dev/null +++ b/PC_Calc/PC_Calc.v @@ -0,0 +1,39 @@ +// PC_Calc Calculates the next program counter + +`include "PC_Calc/addr_concat.v" +`include "PC_Calc/imm_concat.v" +`include "PC_Calc/is_zero_and.v" + +module PC_Calc +( + input[31:0] old_PC, + input isZero, + input[1:0] PCSel, + input AddSel, + input[31:0] Da, + input[25:0] addr, + input[15:0] imm, + output[31:0] added_PC, + output[31:0] new_PC +); + wire[31:0] extendedImm; + immConcat iconcat(extendedImm[31:0], imm[15:0]); + + wire[31:0] immZeroed; + wire nIsZero; + not inviszero(nIsZero, isZero); + isZeroAnd immzeroed(immZeroed[31:0], extendedImm[31:0], nIsZero); + + wire[31:0] immZeroed4; + assign immZeroed4 = immZeroed + 4; + + wire[31:0] addedSel; + mux2by32input m2(32'd4, immZeroed4[31:0], AddSel, addedSel[31:0]); + + assign added_PC = addedSel + old_PC; + + wire[31:0] jump; + addrConcat addrconcat(jump[31:0], added_PC[31:0], addr[25:0]); + + mux4by32input m4(jump[31:0], added_PC[31:0], Da[31:0], 32'd0, PCSel[1:0], new_PC[31:0]); +endmodule diff --git a/PC_Calc/addr_concat.t.v b/PC_Calc/addr_concat.t.v new file mode 100644 index 0000000..4cff68e --- /dev/null +++ b/PC_Calc/addr_concat.t.v @@ -0,0 +1,21 @@ +`timescale 1 ns / 1 ps +`include "addr_concat.v" + +module testConcat(); + wire[31:0] ans; + reg[31:0] pc; + reg[25:0] jumpAddr; + + addrConcat concat(ans[31:0], pc[31:0], jumpAddr[25:0]); + initial begin + pc = 32'b11000000000000000000000000000000; + jumpAddr = 26'b10101010101010101010101010; #100 + $display("%b %b %b", pc[31:0], jumpAddr[25:0], ans[31:0]); + pc = 32'b11110000000000000000000000000000; + jumpAddr = 26'b11111111111111111111111111; #100 + $display("%b %b %b", pc[31:0], jumpAddr[25:0], ans[31:0]); + pc = 32'b00000000000000000000000000000000; + jumpAddr = 26'b11111111111111111111111111; #100 + $display("%b %b %b", pc[31:0], jumpAddr[25:0], ans[31:0]); + end +endmodule \ No newline at end of file diff --git a/PC_Calc/addr_concat.v b/PC_Calc/addr_concat.v new file mode 100644 index 0000000..d7e0d6d --- /dev/null +++ b/PC_Calc/addr_concat.v @@ -0,0 +1,8 @@ +module addrConcat +( + output[31:0] out, + input[31:0] pc, + input[25:0] jumpAddr +); + assign out = {pc[31:28], jumpAddr[25:0], 2'b00}; +endmodule \ No newline at end of file diff --git a/PC_Calc/imm_concat.t.v b/PC_Calc/imm_concat.t.v new file mode 100644 index 0000000..8585987 --- /dev/null +++ b/PC_Calc/imm_concat.t.v @@ -0,0 +1,15 @@ +`timescale 1 ns / 1 ps +`include "imm_concat.v" + +module testConcat(); + wire[31:0] ans; + reg[15:0] imm; + + immConcat concat(ans[31:0], imm[15:0]); + initial begin + imm = 16'b1000000000000001; #100 + $display("%b %b", imm[15:0], ans[31:0]); + imm = 16'b0111111111111110; #100 + $display("%b %b", imm[15:0], ans[31:0]); + end +endmodule \ No newline at end of file diff --git a/PC_Calc/imm_concat.v b/PC_Calc/imm_concat.v new file mode 100644 index 0000000..ded9733 --- /dev/null +++ b/PC_Calc/imm_concat.v @@ -0,0 +1,7 @@ +module immConcat +( + output[31:0] out, + input[15:0] imm +); + assign out = {{14{imm[15]}}, imm, 2'b00}; +endmodule \ No newline at end of file diff --git a/PC_Calc/is_zero_and.t.v b/PC_Calc/is_zero_and.t.v new file mode 100644 index 0000000..7d32bd9 --- /dev/null +++ b/PC_Calc/is_zero_and.t.v @@ -0,0 +1,17 @@ +`timescale 1 ns / 1 ps +`include "is_zero_and.v" + +module testIsZero(); + wire[31:0] ans; + reg[31:0] imm; + reg isZero; + + isZeroAnd iszero(ans[31:0], imm[31:0], isZero); + initial begin + imm = 32'b11111111111111111111111111111111; + isZero = 1; #1000 + $display("%b %b %b", imm[31:0], isZero, ans[31:0]); + isZero = 0; #1000 + $display("%b %b %b", imm[31:0], isZero, ans[31:0]); + end +endmodule \ No newline at end of file diff --git a/PC_Calc/is_zero_and.v b/PC_Calc/is_zero_and.v new file mode 100644 index 0000000..6c1530f --- /dev/null +++ b/PC_Calc/is_zero_and.v @@ -0,0 +1,8 @@ +module isZeroAnd +( + output[31:0] out, + input[31:0] imm, + input isZero +); + assign out = (imm & {32{isZero}}); +endmodule \ No newline at end of file diff --git a/README.md b/README.md index 98c1b9f..441218b 100644 --- a/README.md +++ b/README.md @@ -1,128 +1,70 @@ -# CompArch Lab 3: CPU +# Single Cycle CPU -**Work Plan due:** Monday, November 6 +### Computer Architecture Fall 2017 +#### Ariana Olson, Andrew Pan, Jonah Spear -**Assembly test due:** Tuesday, November 14 before class +The goal of this project lab was to design, create, and test a 32-bit CPU. We chose to implement a single-cycle CPU given that time was a large constraint. Even though we only had <2 weeks from start to finish, we were ultimately successful in our goal. -**Lab due:** Friday, November 17 +## Design -The goal of this lab is to design, create, and test a 32-bit CPU. - -You will work in groups of 2-4. You may shuffle teams if you so choose. You should consider the complexity of processor design (e.g. single-cycle, pipelined) you plan to attempt while forming teams. - - -## Work Plan ## - -Draft a work plan for this lab, which should include the type of processor you plan to design. Regardless of the final design you choose, we recommend that you start by building a working single-cycle CPU. Break down the lab in to small portions, and for each portion predict how long it will take (in hours) and when it will be done by (date). - -We strongly suggest you include a mid-point check in with course staff in your plan. One good thing to do at this check-in or earlier would be to review your block diagram. - -Use your work plan reflections from the previous labs to help with this task. You will reflect on your actual path vs. the work plan at the end of the lab. - -**Submit this plan by November 6** by pushing `work_plan.txt` to GitHub. (Markdown/PDF format also OK) Include team member names in your work plan, especially if you have reshuffled. - - -## Processor ## - -Create a 32-bit MIPS-subset CPU that supports (at least) the following instructions: +We designed our 32-bit MIPS-subset CPU to support the following instructions: LW, SW, J, JR, JAL, BNE, XORI, ADDI, ADD, SUB, SLT - -You may choose any processor design style you like (single-cycle, multi-cycle, pipelined) as long as it implements this subset of the ISA. - -Every module of Verilog you write must be **commented and tested**. Running assembly programs only tests the system at a high level – each module needs to be unit tested on its own with a Verilog test bench. Include a master script that runs your entire test suite. - - - -## Programs ## - -You will write, assemble and run a set of programs on your CPU that act as a high-level test-bench. These programs need to exercise all of the portions of your design and give a clear pass/fail response. - -We will work on one test program (Fibonacci) in class. In addition, you must write (at least) one test assembly program of your own. We will collect these test programs and redistribute them to all teams, so that you have a richer variety of assembly tests for your processor. - -### Submitting your test program ### - -**Due: November 14 before class** by GitHub pull request - -In addition to your actual test assembly code, write a short README with: - - 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) - -Submit the test program and README by submitting a pull request to the main course repository. Code should be in `/asmtest//` (you may use subfolders if you submit multiple tests). -After submitting your test program, you may use any of the programs written by your peers to test your processor. +We felt this would give us a good mix of simplicity, while still allowing the execution of complex programs. +We broke up our single-cycle CPU design into three main components: an instruction parser, a PC calculator, and a core module. The instruction parser decoded instructions from instruction memory directly into the control signals we used for the various components in our other modules. Our PC calculator handled the changes that needed to be made to the program counter based on information from the various J-type instructions. Finally, our core module addressed the main functions performed by R and I-type instructions, handling calculations and load/store word operations. +We re-used and modified some modules from previous labs and homework so that we wouldn't have to reimplement a lot of work from scratch. Specifically, we re-used and modified the ALU, register, data memory, muxes, and DFF gates for our CPU. The ALU, register, and data memory were all used in our core module, muxes were used in both the core module and PC calculator, and a DFF gate was used for our program counter. -## Deliverables ## +## Architechture -**Due: Friday, November 17** by pushing to GitHub and submitting a pull request - - Verilog and test benches for your processor design - - Assembly test(s) with README - - Any necessary scripts - - Report (PDF or MarkDown), including: - - 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 +Our first step in designing our CPU was to create a block diagram with which could successfully run every type of instruction that we needed. We split up our CPU into 3 major components, so that we could each work on them in parallel. +![Instruction Parser Diagram](https://github.com/arianaolson419/Lab3/blob/master/Static/Instruction%20Parser.png "Instruction Parser Diagram") -Each team will also demo their work in class after break. - +![PC Calc Diagram](https://github.com/arianaolson419/Lab3/blob/master/Static/PC%20Calc.png "PC Calc Diagram") -## Notes/Hints ## +![Core Diagram](https://github.com/arianaolson419/Lab3/blob/master/Static/Core.png "Core Diagram") -### Design Reuse ### -You may freely reuse code created for previous labs, even code written by another team or the instructors. Reusing code does not change your obligation to understand it and provide appropriate test benches. +Once that was completed, we made a table mapping instruction type to control signal value. -**Each example of reuse should be documented.** +Instruction | RegDst | ALUSrc | RegWR | MemWr | ALUCtrl | MemToReg | PCSel | AddSel | +:----------:|:------:|:------:|:-----:|:-----:|:-------:|:--------:|:-----:|:------:| +LW | 1 | 1 | 1 | 0 | Add | 1 | 1 | 0 | +SW | x | 1 | 0 | 1 | Add | x | 1 | 0 | +J | x | x | 0 | 0 | x | x | 0 | 0 | +JR | x | x | 0 | 0 | x | x | 2 | 0 | +JAL | 2 | x | 1 | 0 | x | 2 | 0 | 0 | +BNE | x | 0 | 0 | 0 | Sub | x | 1 | 1 | +XORI | 1 | 1 | 1 | 0 | Xor | 0 | 1 | 0 | +ADDI | 1 | 1 | 1 | 0 | Add | 0 | 1 | 0 | +ADD | 0 | 0 | 1 | 0 | Add | 0 | 1 | 0 | +SUB | 0 | 0 | 1 | 0 | Sub | 0 | 1 | 0 | +SLT | 0 | 0 | 1 | 0 | Slt | 0 | 1 | 0 | -### Synthesis ### -You are **not** required to implement your design on FPGA. You may want to synthesize your design (or parts of it) with Vivado to collect performance/area data. -### Assembling ### -[MARS](http://courses.missouristate.edu/kenvollmar/mars/) is a very nice assembler. It allows you to see the machine code (actual bits) of the instructions, which is useful for debugging. +Clearly defining the structure of our processor and our control signal mapping from an early point made final implementation and debugging much easier. +## Testing -### Psuedo-Instructions ### -There are many instructions supported by MARS that aren’t "real" MIPS instructions, but instead map onto other instructions. Your processor should only implement instructions from the actual MIPS ISA (see the [Instruction Reference sheet](https://sites.google.com/site/ca16fall/resources/mips) for a complete listing). +Our testing approach was as follows: +1. Unit test every sub-module +2. Unit test top-level module with each instruction type +3. Integration test top-level module with test assmebly programs. -### Initializing Memory ### -You can initialize a memory (e.g. data memory or instruction memory) from a file with `$readmemb` or `$readmemh`. This will make your life very much easier! -For example, you could load a program into your data memory by putting your machine code in hexadecimal format in a file named `file.dat` and using something like this for your instruction memory. +You can run our tests using the following commands: -```verilog -module memory -( - input clk, regWE, - input[9:0] Addr, - input[31:0] DataIn, - output[31:0] DataOut -); - - reg [31:0] mem[1023:0]; - - always @(posedge clk) begin - if (regWE) begin - mem[Addr] <= DataIn; - end - end - - initial $readmemh(“file.dat”, mem); - - assign DataOut = mem[Addr]; -endmodule -``` +`chmod 755 run_tests.sh` -You may need to fiddle with the `Addr` bus to make it fit your design, depending on how you handle the "address is always a multiple of 4" (word alignment) issue. +*Needs to be run once in order for the file to be executable* -This memory initialization only works in simulation; it will be ignored by Vivado (which is ok). +`./run_tests.sh` -### Memory Configuration ### -In MARS, go to "Settings -> Memory Configuration". Changing this to "Compact, Text at Address 0" will give you a decent memory layout to start with. This will put your program (text) at address `0`, your data at address `0x1000`, and your stack pointer will start at `0x3ffc`. +We tested our CPU with unit tests and assembly program tests that attempted to use all of the implemented operations in various patterns. After using the tests and GTKWAVE to examine the waveforms of our CPU, we identified and fixed all of the bugs that prevented our test cases from running correctly. -You will need to manually set your stack pointer in your Verilog simulation. This is done automatically for you in MARS. +## Work Plan Reflection +We created a work plan and allocated sufficient amount of time for each section of the plan in the event that we encountered roadblocks during our CPU creation. We actually stayed on track with our work plan throughout the majority of this lab, only having to spend a couple of extra hours for the debugging of our module integration. Overall, we effectively managed our time thanks to a proper amount of planning in the beginning of the lab and communication amongst team members as we worked on our individual sections. diff --git a/Static/Core.png b/Static/Core.png new file mode 100644 index 0000000..3173369 Binary files /dev/null and b/Static/Core.png differ diff --git a/Static/Instruction Parser.png b/Static/Instruction Parser.png new file mode 100644 index 0000000..7764fb0 Binary files /dev/null and b/Static/Instruction Parser.png differ diff --git a/Static/PC Calc.png b/Static/PC Calc.png new file mode 100644 index 0000000..f6f390f Binary files /dev/null and b/Static/PC Calc.png differ diff --git a/add_test.text b/add_test.text new file mode 100644 index 0000000..be027d5 --- /dev/null +++ b/add_test.text @@ -0,0 +1,11 @@ +20090006 +200a0039 +200bfff7 +200c0014 +200dfffb +200efff5 +012a4020 +016c4020 +01ae4020 +0800000a +0800000a diff --git a/bne_test.text b/bne_test.text new file mode 100644 index 0000000..b4edc90 --- /dev/null +++ b/bne_test.text @@ -0,0 +1,8 @@ +200b0000 +200c0004 +156c0002 +216d0000 +08000007 +216b0001 +08000002 +08000007 diff --git a/main_test.dat b/main_test.dat new file mode 100644 index 0000000..0038c2d --- /dev/null +++ b/main_test.dat @@ -0,0 +1,1024 @@ +2008_0001 +2008_0002 +2008_0003 +0000_0001 +0000_0002 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 +0000_0000 diff --git a/makefile b/makefile new file mode 100644 index 0000000..1ca7e10 --- /dev/null +++ b/makefile @@ -0,0 +1,96 @@ +all: core alu regfile memory signextend CPU_unit CPU_fib CPU_while + +### CPU Module +CPU_unit: CPU.v CPU_unit.t.v + iverilog -Wall -o CPU_unit CPU_unit.t.v + +CPU_fib: CPU.v CPU_fib.t.v + iverilog -Wall -o CPU_fib CPU_fib.t.v + +CPU_while: CPU.v CPU_while.t.v + iverilog -Wall -o CPU_while CPU_while.t.v + +### CPU fib +CPU_fib: CPU.v CPU_fib.t.v + iverilog -Wall -o CPU_fib.out CPU_fib.t.v + +### PC_Calc Modules +# PC_Calc top level module +PC_Calc: PC_Calc/PC_Calc.v PC/PC_Calc.t.v addr_concat imm_concat is_zero_and + iverilog -Wall -o PC_Calc/PC_Calc PC_Calc/PC_Calc.t.v + +addr_concat: PC_Calc/addr_concat.v PC_Calc/addr_concat.t.v + iverilog -Wall -o PC_Calc/addr_concat addr_concat.t.v + +imm_concat: PC_Calc/imm_concat.v PC_Calc/imm_concat.t.v + iverilog -Wall -o PC_Calc/imm_concat imm_concat.t.v + +is_zero_and: PC_Calc/is_zero_and.v PC_Calc/is_zero_and.t.v + iverilog -Wall -o PC_Calc/is_zero_and is_zero_and.t.v + +### Instruction Parser Modules +# Instruction Parser top level module +Instruction_Parser: Instruction_Parser.v Instruction_Parser.t.v Controller Decoder Memory + iverilog -Wall -o Instruction_Parser/Instruction_Parser Instruction_Parser.v + +Controller: Controller.v Controller.t.v + iverilog -Wall -o Instruction_Parser/Controller Instruction_Parser/Controller.t.v + +Decoder: Decoder.v Decoder.t.v + iverilog -Wall -o Instruction_Parser/Decoder Instruction_Parser/Decoder.t.v + +Memory: Memory.v Memory.t.v + iverilog -Wall -o Instruction_Parser/Memory Instruction_Parser/Memory.t.v + + +### Core Modules +# Core top level module +core: Core/Core.v Core/Core.t.v regfile + iverilog -Wall -o Core/core Core/Core.t.v + +# ALU modules +alu: Core/ALU/alu.v Core/ALU/alu.t.v adder_subtracter and nand nor or slt xor + iverilog -Wall -o Core/ALU/alu Core/ALU/alu.t.v + +adder_subtracter: Core/ALU/adder_subtracter.v Core/ALU/adder_subtracter.t.v + iverilog -Wall -o Core/ALU/adder_subtracter Core/ALU/adder_subtracter.t.v + +and: Core/ALU/and_32bit.v Core/ALU/and_32bit.t.v + iverilog -Wall -o Core/ALU/and Core/ALU/and_32bit.t.v + +nand: Core/ALU/nand_32bit.v Core/ALU/nand_32bit.t.v + iverilog -Wall -o Core/ALU/nand Core/ALU/nand_32bit.t.v + +nor: Core/ALU/nor_32bit.v Core/ALU/nor_32bit.t.v + iverilog -Wall -o Core/ALU/nor Core/ALU/nor_32bit.t.v + +or: Core/ALU/or_32bit.v Core/ALU/or_32bit.t.v + iverilog -Wall -o Core/ALU/or Core/ALU/or_32bit.t.v + +slt: Core/ALU/slt.v Core/ALU/slt.t.v + iverilog -Wall -o Core/ALU/slt Core/ALU/slt.t.v + +xor: Core/ALU/xor_32bit.v Core/ALU/xor_32bit.t.v + iverilog -Wall -o Core/ALU/xor Core/ALU/xor_32bit.t.v + +# Regfile modules +regfile: Core/regfile.t.v Core/regfile.v decoder multiplexer register + iverilog -Wall -o Core/regfile Core/regfile.t.v + +decoder: Core/decoders.t.v Core/decoders.v + iverilog -Wall -o Core/decoder Core/decoders.t.v + +register: Core/register.t.v Core/register.v + iverilog -Wall -o Core/register Core/register.t.v + +# Memory modules +memory: Core/memory.v Core/memory.t.v + iverilog -Wall -o Core/memory Core/memory.t.v + +# Concatenation modules +signextend: Core/signextend.v + iverilog -Wall -o Core/signextend Core/signextend.v + +### Submodules +multiplexer: submodules/multiplexer.v submodules/multiplexer.t.v + iverilog -Wall -o multiplexer submodules/multiplexer.t.v \ No newline at end of file diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 0000000..c96623b --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +make + +java -jar ../Mars4_5.jar a dump .text HexText fib.text mc CompactTextAtZero AssemblyPrograms/fibonacci.asm + +cat fib.text > mem.dat + +./CPU_fib + +java -jar ../Mars4_5.jar a dump .text HexText while_loop.text mc CompactTextAtZero AssemblyPrograms/testCPU.asm + +cat while_loop.text > mem.dat + +./CPU_while + +java -jar ../Mars4_5.jar a dump .text HexText combined_unit_tests.text mc CompactTextAtZero AssemblyPrograms/combined_unit_tests.asm + +cat combined_unit_tests.text > mem.dat + +./CPU_unit + +cat Core/file.dat > mem.dat +./Core/core +./Core/ALU/alu +./Core/regfile +./PC_Calc/PC_Calc +./Instruction_Parser/Instruction_Parser \ No newline at end of file diff --git a/slt_test.text b/slt_test.text new file mode 100644 index 0000000..c3a4e97 --- /dev/null +++ b/slt_test.text @@ -0,0 +1,11 @@ +20090006 +200a0039 +200bfff7 +200c0014 +200dfffb +200efff5 +012a402a +016c402a +01ae402a +0800000a +0800000a diff --git a/sub_test.text b/sub_test.text new file mode 100644 index 0000000..3f6cf12 --- /dev/null +++ b/sub_test.text @@ -0,0 +1,11 @@ +20090006 +200a0039 +200bfff7 +200c0014 +200dfffb +200efff5 +012a4022 +016c4022 +01ae4022 +0800000a +0800000a diff --git a/submodules/multiplexer.t.v b/submodules/multiplexer.t.v new file mode 100644 index 0000000..89b6d31 --- /dev/null +++ b/submodules/multiplexer.t.v @@ -0,0 +1,171 @@ +//-------------------------------- +// Test the multiplexer modules. +//-------------------------------- + +`include "submodules/multiplexer.v" + +// Test harness for multiplexer unit test modules. +module multiplexerTestBenchHarness(); + reg begintest0; + reg begintest1; + reg begintest2; + wire endtest0; + wire endtest1; + wire endtest2; + wire dutpassed0; + wire dutpassed1; + wire dutpassed2; + + mux32to1by1Test test0 (begintest0, endtest0, dutpassed0); + mux32to32by1Test test1 (begintest1, endtest1, dutpassed1); + mux4inputTest test2 (begintest2, endtest2, dutpassed2); + + initial begin + begintest0 = 0; + begintest1 = 0; + begintest2 = 0; + #10; + begintest0 = 1; + begintest1 = 1; + begintest2 = 1; + #1000; + end + + always @(posedge endtest0 && endtest1 && endtest2) begin + if (dutpassed0 == 1 || dutpassed1 == 1 || dutpassed2 == 1) begin + $display("All multiplexer tests passed."); + end + end + +endmodule // multiplexerTestBenchHarness + +// Unit test the 32:1 mux module. +module mux32to1by1Test + ( + input begintest, + output reg endtest, + output reg dutpassed + ); + wire out; + reg[4:0] address; + reg[31:0] inputs; + + mux32to1by1 DUT (out, address, inputs); + + always @(posedge begintest) begin + endtest = 0; + dutpassed = 1; + + // Test Case 1: + // Ensure that out is the same as the bit of the input at the + // given address. + inputs = 32'h000FFF; address = 5'd9; + if (out != 1) begin + $display("32:1 mux Test Case 1 Failed."); + dutpassed = 0; + end + + #5 + endtest = 1; + end +endmodule // mux32to1by1Test + +module mux4inputTest + ( + input begintest, + output reg endtest, + output reg dutpassed + ); + + reg[5:0] input0, input1, input2, input3; + reg[1:0] address; + wire[5:0] out; + + mux4input #(.width(6)) DUT (input0, input1, input2, input3, address, out); + + always @(posedge begintest) begin + endtest = 0; + dutpassed = 1; + + // Test Case 1: + // Ensure that the value chosen by the mux matches + // the value at the given address. + input0 = 6'd1; + input1 = 6'd2; + input2 = 6'd3; + input3 = 6'd4; + address = 2'd0; + #5 + if (out != input0) begin + $display("3 wide 6 deep mux test case 1 failed at address 00."); + dutpassed = 0; + end + + address = 2'd1; + #5 + if (out != input1) begin + $display("3 wide 6 deep mux test case 1 failed at address 01."); + dutpassed = 0; + end + + address = 2'd2; + #5 + if (out != input2) begin + $display("3 wide 6 deep mux test case 1 failed at address 10."); + dutpassed = 0; + end + + address = 2'd3; + #5 + if (out != input2) begin + $display("3 wide 6 deep mux test case 1 failed at address 11."); + dutpassed = 0; + end + + #5 + endtest = 1; + end +endmodule + +// Unit test the 32 wide 32 deep mux module. +module mux32to32by1Test( + input begintest, + output reg endtest, + output reg dutpassed + ); + wire[31:0] out; + reg[4:0] address; + reg[31:0] input0, input1, input2, input3, input4, input5, input6, input7, input8; + reg[31:0] input9, input10, input11, input12, input13, input14, input15, input16; + reg[31:0] input17, input18, input19, input20, input21, input22, input23, input24; + reg[31:0] input25, input26, input27, input28, input29, input30, input31; + + mux32to1by32 DUT (out, address, 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); + + always @(posedge begintest) begin + endtest = 0; + dutpassed = 1; + + // Test Case 1: + // Ensure that the value chosen by the mux matches the value at the given address + address = 5'd20; + input0 = 32'd0; input1 = 32'd1; input2 = 32'd2; input3 = 32'd3; input4 = 32'd4; + input5 = 32'd5; input6 = 32'd6; input7 = 32'd7; input8 = 32'd8; input9 = 32'd9; + input10 = 32'd10; input11 = 32'd11; input12 = 32'd12; input13 = 32'd13; input14 = 32'd14; + input15 = 32'd15; input16 = 32'd16; input17 = 32'd17; input18 = 32'd18; input19 = 32'd19; + input20 = 32'd20; input21 = 32'd21; input22 = 32'd22; input23 = 32'd23; input24 = 32'd24; + input25 = 32'd25; input26 = 32'd26; input27 = 32'd27; input28 = 32'd28; input29 = 32'd29; + input30 = 32'd30; input31 = 32'd31; + if (out != 20) begin + $display("32 wide 32 deep mux Test Case 1 failed"); + dutpassed = 0; + end + + #5 + endtest = 1; + end +endmodule // mux32to32by1Test + diff --git a/submodules/multiplexer.v b/submodules/multiplexer.v new file mode 100644 index 0000000..f87a7f3 --- /dev/null +++ b/submodules/multiplexer.v @@ -0,0 +1,106 @@ +module mux2by32input +#( + parameter width = 32 +) +( +input[width-1:0] input0, input1, +input address, +output[width-1:0] out +); + wire[width - 1:0] mux [width-1:0]; + assign mux[0] = input0[width-1:0]; + assign mux[1] = input1[width-1:0]; + assign out = mux[address]; +endmodule + +module mux4by32input +#( + parameter width = 32 +) +( +input[width-1:0] input0, input1, input2, input3, +input[1:0] address, +output[width-1:0] out +); + wire[width - 1:0] mux [width-1:0]; + assign mux[0] = input0[width-1:0]; + assign mux[1] = input1[width-1:0]; + assign mux[2] = input2[width-1:0]; + assign mux[3] = input3[width-1:0]; + assign out = mux[address]; +endmodule + +// Inputs are 6 by 1 addresses +module mux4input +#( + parameter width = 6 +) +( +input[width-1:0] input0, input1, input2, input3, +input[1:0] address, +output[width-1:0] out +); + wire[width-1:0] mux [3:0]; + assign mux[0] = input0; + assign mux[1] = input1[width-1:0]; + assign mux[2] = input2[width-1:0]; + assign mux[3] = input3[width-1:0]; + assign out = mux[address]; +endmodule + +// A 32:1 multiplexer. +module mux32to1by1 +( +output out, +input[4:0] address, +input[31:0] inputs +); + assign out = inputs[address]; +endmodule // mux32to1by1 + +module mux32to1by32 +( +output[31:0] out, +input[4:0] address, +input[31:0] input0, input1, input2, input3, input4, input5, input6, input7, input8, +input[31:0] input9, input10, input11, input12, input13, input14, input15, input16, +input[31:0] input17, input18, input19, input20, input21, input22, input23, input24, +input[31:0] input25, input26, input27, input28, input29, input30, input31 +); + + wire[31:0] mux[31:0]; // Create a 2D array of wires + assign mux[0] = input0; + 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; + assign out = mux[address]; + +endmodule // mux32to1by32 \ No newline at end of file diff --git a/work_plan.txt b/work_plan.txt new file mode 100644 index 0000000..f0520eb --- /dev/null +++ b/work_plan.txt @@ -0,0 +1,11 @@ +Ariana Olson, Andrew Pan, Jonah Spear +Lab 3 Work Plan + + +Steps: +1. Create a circuit diagram (Do by 11/7) - 2 hours +2. Create table mapping instruction to control signal values (Do by 11/8) - 2 hours +3. Implement all sub-components and write unit tests (Do by 11/11) - 4 hours +4. Working Assembly Program (Do by 11/13) - 1.5 hours +5. Integration tests (Do by 11/13) - 1.5 hours +6. Lab Report (Do by 11/17) - 2 hours \ No newline at end of file