Skip to content
This repository was archived by the owner on Aug 21, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions CPU.t.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
`include "CPU.v"

//------------------------------------------------------------------------
// Simple fake CPU testbench sequence
//------------------------------------------------------------------------

module cpu_test ();

reg clk;
reg reset;

// Clock generation
initial clk=0;
always #10 clk = !clk;

// Instantiate fake CPU
CPU cpu(.clk(clk), .reset(reset));

// Filenames for memory images and VCD dump file
reg [1023:0] mem_text_fn;
reg [1023:0] mem_data_fn;
reg [1023:0] dump_fn;
reg init_data = 1; // Initializing .data segment is optional

// Test sequence
initial begin
$display("Starting CPU tests.");

// Get command line arguments for memory image(s) and VCD dump file
// http://iverilog.wikia.com/wiki/Simulation
// http://www.project-veripage.com/plusarg.php
if (! $value$plusargs("mem_text_fn=%s", mem_text_fn)) begin
$display("ERROR: provide +mem_text_fn=[path to .text memory image] argument");
$finish();
end
if (! $value$plusargs("mem_data_fn=%s", mem_data_fn)) begin
$display("INFO: +mem_data_fn=[path to .data memory image] argument not provided; data memory segment uninitialized");
init_data = 0;
end

if (! $value$plusargs("dump_fn=%s", dump_fn)) begin
$display("ERROR: provide +dump_fn=[path for VCD dump] argument");
$finish();
end


// Load CPU memory from (assembly) dump files
// Assumes compact memory map, _word_ addressed memory implementation
// -> .text segment starts at word address 0
// -> .data segment starts at word address 2048 (byte address 0x2000)
$readmemh(mem_text_fn, cpu.memory.memory, 0);
if (init_data) begin
$readmemh(mem_data_fn, cpu.memory.memory, 2048);
end

// Dump waveforms to file
// Note: arrays (e.g. memory) are not dumped by default
$dumpfile(dump_fn);
$dumpvars();

// Assert reset pulse
reset = 0; #10;
reset = 1; #10;
reset = 0; #10;

// Display a few cycles just for quick checking
// Note: I'm just dumping instruction bits, but you can do some
// self-checking test cases based on your CPU and program and
// automatically report the results.
// $display("Time | PC | Instruction");
// repeat(3) begin
// $display("%4t | %h | %h", $time, cpu.programCounter, cpu.instruction); #20 ;
// end
// $display("... more execution (see waveform)");

// End execution after some time delay - adjust to match your program
// or use a smarter approach like looking for an exit syscall or the
// PC to be the value of the last instruction in your program.
#50000
if(cpu.register.mux1.input2==32'h3a)
$display("Fib Test Successful");
$finish();
end

endmodule
219 changes: 219 additions & 0 deletions CPU.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
`include "regfile.v"
`include "mux.v"
`include "memReg.v"
`include "alu.v"
`include "adder.v"
`include "regWrLUT.v"
`include "signExtender.v"

module CPU (
input clk,
input reset
);
//wire declaration
wire[31:0] pcAfterAdd, pcPlusFour, Da, immediate;
wire opcode0Inv, opcode1Inv, opcode2Inv, opcode3Inv, opcode4Inv, opcode5Inv;

wire isBranch, isBneOrBeq, zero, wEnable;

//Program Counter Logic
reg[31:0] programCounter;
wire [31:0] instruction, nextProgramCounter;

//advances the program to the next step
always @(posedge clk) begin
if (reset) programCounter <= 32'b0;
else programCounter <= nextProgramCounter;
end

wire[25:0] jump;
wire[31:0] finalJumpValue;
assign jump = instruction[25:0];
assign finalJumpValue = {pcPlusFour[31:26], jump};

wire isJumpSel;
not(opcode5Inv, opcode[5]);
and(isJumpSel, opcode5Inv, opcode4Inv, opcode3Inv, opcode2Inv, opcode[1]);
wire[31:0] jumpNextPC;
mux isJumpMux(
.input0(pcAfterAdd),
.input1(finalJumpValue),
.out(jumpNextPC),
.sel(isJumpSel)
);

wire jrOr, jrNor;
or(jrOr, opcode[0], opcode[1], opcode[2], opcode[3], opcode[4], opcode[5], funct[5]); // if all of these are zero then its JR
not(jrNor, jrOr);
mux isNotJRMux(
.input1(Da), //R[rs]
.input0(jumpNextPC),
.out(nextProgramCounter),
.sel(jrNor)
);

wire[31:0] fourOrBranch;
Adder programCounterAdder(
.operandA(programCounter),
.operandB(fourOrBranch),
.result(pcAfterAdd),
.carryout(),
.overflow()
);

wire isBranchOrAddSel;
mux isBranchOrAddMux(
.input1(immediate + 1'b1), // has already been extended
.input0(32'd1),
.out(fourOrBranch),
.sel(isBranchOrAddSel)
);

and(isBranchOrAddSel, isBranch, isBneOrBeq);

and(isBranch, opcode1Inv, opcode[2]); //is true if BNE or BEQ
wire zeroInv;
not(zeroInv, zero);
defparam isBneOrBeqMux.data_width = 1;
mux isBneOrBeqMux(
.input0(zero),
.input1(zeroInv),
.out(isBneOrBeq),
.sel(opcode[0])
);

wire[5:0] opcode;
assign opcode = instruction[31:26];
wire[5:0] funct;
assign funct = instruction[5:0];

//Register File Logic
wire[4:0] Rs, Rt, Rd;
wire[4:0] regWrite;
assign Rs = instruction[25:21];
assign Rt = instruction[20:16];
assign Rd = instruction[15:11];
wire[31:0] Db, Dw;

regfile register(
.ReadData1(Da),
.ReadData2(Db),
.WriteData(Dw),
.ReadRegister1(Rs),
.ReadRegister2(Rt),
.WriteRegister(regWrite),
.wEnable(wEnable),
.Clk(clk)
);

regWrLUT isRegWrite(
.opcode(opcode),
.funct(funct),
.regwr(wEnable)
);

wire rTypeOr;
wire[4:0] regWriteRdOrRt;
or(rTypeOr, opcode[0], opcode[1], opcode[2], opcode[3], opcode[4], opcode[5]);
//determines if you are writing to Rd or Rt
mux #(5) writeRegisterMuxRtOrRd(
.input0(Rd),
.input1(Rt),
.out(regWriteRdOrRt),
.sel(rTypeOr)
);

wire isJumpandLink;
not(opcode0Inv, opcode[0]);
not(opcode1Inv, opcode[1]);
not(opcode2Inv, opcode[2]);
not(opcode3Inv, opcode[3]);
not(opcode4Inv, opcode[4]);
and(isJumpandLink, opcode[0], opcode[1], opcode2Inv, opcode3Inv, opcode4Inv, opcode5Inv);
//determines if write address is set my Rt or Rd or is "31" because of the opcode
mux #(5) writeRegister31Mux(
.input0(regWriteRdOrRt),
.input1(5'd31),
.out(regWrite),
.sel(isJumpandLink)
);

//ALU Logic

wire[31:0] DbOrImmediate;
wire DbOrImmediateSel;
or(DbOrImmediateSel, opcode[1], opcode[3]);

mux isDbOrImmediateMux(
.input0(Db),
.input1(immediate),
.out(DbOrImmediate),
.sel(DbOrImmediateSel)
);

wire[15:0] preExtendedImm;
assign preExtendedImm = instruction[15:0];

signExtend sExtend(
.extend(preExtendedImm),
.extended(immediate)
);

wire[31:0] aluResult;
wire overflow, carryout;

ALU alu(
.operandA(Da),
.operandB(DbOrImmediate),
.opcode(opcode),
.funct(funct),
.zero(zero),
.res(aluResult),
.overflow(overflow),
.carryout(carryout)
);

//Memory Logic

wire[31:0] dataOut;
wire dataWrite;
and(dataWrite, opcode[5], opcode[3]);
memoryReg memory(
.clk(clk),
.dataOutRW(dataOut),
.dataOutRead(instruction),
.addressRW(aluResult[31:2]),
.addressRead(programCounter),
.addressWrite(9'b0), //Don't actually need the second write port
.writeEnableRW(dataWrite),
.writeEnableWrite(1'b0),
.dataInRW(Db),
.dataInWrite(32'b0)
);

wire isAluOrDout;
wire[31:0] aluOrDout;
and(isAluOrDout, opcode[5], opcode3Inv);

mux isAluOrDoutMux(
.input1(dataOut),
.input0(aluResult),
.out(aluOrDout),
.sel(isAluOrDout)
);

mux isJalAluOrDoutMux(
.input0(aluOrDout),
.input1(pcPlusFour),
.out(Dw),
.sel(isJumpandLink)
);

Adder pcPlusFourAdder(
.operandA(programCounter),
.operandB(32'd1),
.result(pcPlusFour),
.carryout(),
.overflow()
);
endmodule
Binary file added Lab 3 Writeup.pdf
Binary file not shown.
52 changes: 52 additions & 0 deletions adder.t.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
`include "adder.v"

module testAdder();
reg[31:0] operandA;
reg[31:0] operandB;
wire[31:0] result;
wire overflow;
wire carryout;

initial begin
$display();

$display("Starting Adder Tests.");
$display("TESTING ADD");
operandA=32'd7000;operandB=32'd14000; #4000
if(result != 32'd21000) $display("p + p = p TEST FAILED - result: %d", result);
if(overflow != 0) $display("p + p = p OVERFLOW FAILED");
if(carryout != 0) $display("p + p = p CARRYOUT FAILED");
operandA=32'd2147483647;operandB=32'd14000; #4000
if(result != 32'd2147497647) $display("p + p = n TEST FAILED - result: %d", result);
if(overflow != 1) $display("p + p = n OVERFLOW FAILED");
if(carryout != 0) $display("p + p = n CARRYOUT FAILED");
operandA=32'd0;operandB=32'd87000; #4000
if(result != 32'd87000) $display("0 + p = p TEST FAILED - result: %d", result);
if(overflow != 0) $display("0 + p = p OVERFLOW FAILED");
if(carryout != 0) $display("0 + p = p CARRYOUT FAILED");
operandA=32'd3657483652;operandB=32'd2997483652; #4000
if(result != 32'd2360000008) $display("n + n = n TEST FAILED - result: %d", result);
if(overflow != 0) $display("n + n = n OVERFLOW FAILED");
if(carryout != 1) $display("n + n = n CARRYOUT FAILED");
operandA=32'd2147483652;operandB=32'd2147483652; #4000
if(result != 32'd8) $display("n + n = p TEST FAILED - result: %d", result);
if(overflow != 1) $display("n + n = p OVERFLOW FAILED");
if(carryout != 1) $display("n + n = p CARRYOUT FAILED");
operandA=32'd3657483652;operandB=32'd637483644; #4000
if(result != 32'd0) $display("n + p = 0 TEST FAILED - result: %d", result);
if(overflow != 0) $display("n + p = 0 OVERFLOW FAILED");
if(carryout != 1) $display("n + p = 0 CARRYOUT FAILED");
operandA=32'd3657483652;operandB=32'd637483645; #4000
if(result != 32'd1) $display("n + p = p TEST FAILED - result: %d", result);
if(overflow != 0) $display("n + p = p OVERFLOW FAILED");
if(carryout != 1) $display("n + p = p CARRYOUT FAILED");
operandA=32'd3657483652;operandB=32'd637483643; #4000
if(result != 32'd4294967295) $display("n + p = n TEST FAILED - result: %d", result);
if(overflow != 0) $display("n + p = n OVERFLOW FAILED");
if(carryout != 0) $display("n + p = n CARRYOUT FAILED");

$display("Finished Adder Testing");
$display();
end

endmodule // testAdder
Loading