Added files into modelsim folder

This commit is contained in:
TroubleElectrical committed 2026-10-16 10:10:37 +11:00
1 parent 8ed06d38e1
commit dca673b039
14 files changed
+436 -13

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
`include "rom.sv"
module ByteIM #(parameter m=5,n=2) (
input logic [m-1:0] Ad,
output logic [(2**n)*8-1:0] Dout );
// 2**n byte wide words
// m bit wide byte address
// 2**m bytes of memory
// 2**(m-n) memory words
// 2**(n+3) bit wide words
// Reads the whole word that contains the addressed byte
ROM #(m-n,2**(n+3)) wordrom(Ad[m-1:n],Dout)
endmodule
+7 -4
View File
@@ -8,11 +8,13 @@
// flags[1:1] = Overflow
module alu #(parameter width=2)(input logic [3:0] op,
input logic [2**width-1:0] A, input logic [2**width-1:0] B,
output logic [2**width-1:0] OUT_1, output logic[1:0] flags);
output logic [2**width-1:0] OUT_1, output logic[2:0] flags
);
// intermediate logic for handling asu output
logic [0:0] asu_op;
logic [2**width-1:0] asu_out;
logic [1:0] asu_flags;
logic [2:0] asu_flags;
asu #(width) adder_unit(asu_op[op[1]], A, B, asu_out, asu_flags[0], asu_flags[1]);
logic [2**width-1:0] lu_out;
@@ -32,6 +34,7 @@ module alu #(parameter width=2)(input logic [3:0] op,
4'b1011: begin OUT_1 = ~asu_flags[0] & {{(width-1){1'b0}}, 1'b1}; flags = asu_flags; end
default: begin OUT_1 = {(2**width){1'b0}}; flags = asu_flags; end
endcase
asu_flags[2] = OUT_1 == 0;
end
endmodule
`endif
`endif
+107
View File
@@ -0,0 +1,107 @@
`ifndef ASS_2_SV
`define ASS_2_SV
`include "rom.sv"
`include "ram.sv"
`include "register_file.sv"
`include "instruction_counter.sv"
`include "control_unit.sv"
`include "alu.sv"
`include "shifter.sv"
`include "sign_extender.sv"
`include "seven_seg_4digit.sv"
module assignment2 #(width=5, ramsz=9, romsz=10) (
input logic [0:0] clk
`ifdef QUARTUS_SYNTH
,
input logic [4:0] HID_Register,
input logic [0:0] HID_PC,
input logic [0:0] HID_Hi_Low,
output logic[7:0] out_seg_0,
output logic[7:0] out_seg_1,
output logic[7:0] out_seg_2,
output logic[7:0] out_seg_3
`endif
);
// Intermediate for displaying high / low of PC or Register
logic[15:0] PC_Reg_Display;
// Program / Instruction Counter Intermediates
logic [romsz-1:0] pc_addr;
logic [romsz-1:0] pc_addr_write;
logic [0:0] pc_we;
logic [2**width-1:0] instruction;
// Instruction Classifier Intermediates
logic [0:0] M2R;
logic [0:0] M2W;
logic [0:0] B;
logic [3:0] ALU_FN;
logic [0:0] ALU_SRC;
logic [0:0] RDST;
logic [0:0] RW;
// Register File intermediates
logic [2:0] flags;
logic [2**width-1:0] rs;
logic [2**width-1:0] rt;
logic [2**width-1:0] rd;
logic [0:0] rd_we;
logic [31:0] regs_out [32];
instruction_counter #(width) PC (clk, pc_we, pc_addr_write, pc_addr);
rom #(romsz, 2**width) ROM (pc_addr, instruction);
logic [2**width-1:0] rd_mem;
ram #(ramsz, 2**width) RAM (clk, rd_alu, M2W, rt, rd_mem);
control_unit CONTROL_UNIT (instruction[31:26], instruction[5:0],
M2R, M2W, B, ALU_FN, ALU_SRC, RDST, RW
);
register_file #(width, 5) REGS (
clk, rd_we,
instruction[20:16], rd,
(RDST) ? instruction[15:11] : instruction[20:16], rt,
instruction[25:21], rs,
regs_out
);
// Always use sign-extension
logic [2**width-1:0] rt_imm;
sign_extender #(4, width) SIGNEXT(1'b1, instruction[15:0], rt_imm);
// TODO:
// - ALU srcB
// - PCBranch (rel jump of 4-byte words)
logic [2**width-1:0] rd_alu;
logic [2**width-1:0] rt_alu;
alu #(width) ALU (ALU_FN, rs, rt_alu, rd_alu, flags[1:0]);
assign rt_alu = (ALU_SRC) ? (rt_imm) : (rt);
assign pc_we = B & flags[2];
assign pc_addr_write = (rt_imm << 2) + pc_addr;
assign rd_we = RW;
assign rd = (M2R) ? rd_alu : rd_mem;
// Temporary Test output
// assign PC_Reg_Display = 16'hC342;
assign PC_Reg_Display = (HID_Hi_Low) ? regs_out[HID_Register][31:16] : regs_out[HID_Register][15:0];
seven_seg_4digit display (
.num(PC_Reg_Display),
.segments0(out_seg_0),
.segments1(out_seg_1),
.segments2(out_seg_2),
.segments3(out_seg_3)
);
endmodule
`endif
+5 -2
View File
@@ -4,9 +4,11 @@
module asu #(parameter width = 2)(
input logic [0:0] op,
input logic[2**width-1:0] A, input logic[2**width-1:0] B,
output logic[2**width-1:0] OUT_1, output logic[0:0] COUT, output logic[0:0] OUT_CIN);
output logic[2**width-1:0] OUT_1, output logic[0:0] COUT, output logic[0:0] OUT_CIN
);
logic [2**width-1:0] operand;
always_comb begin
// A + (sub) ? B : -B
// Adds an extra bit to all operands to calculate the carry bit. Not optimal for hardware synthesis
@@ -18,5 +20,6 @@ module asu #(parameter width = 2)(
// Need to do this outside of the always_comb block because parameter-based bitslicing/indexing isn't supported?
// Cin for final bit in adder to later be xor'ed with COUT to determine if a signed overflow occured for the MIPS architecture
assign OUT_CIN = A[2**width-1] ^ operand[2**width-1] ^ OUT_1[2**width-1];
endmodule
`endif
`endif
+36
View File
@@ -0,0 +1,36 @@
`ifndef CONTROL_UNIT_H
`define CONTROL_UNIT_H
`include "instruction_classifier.sv"
module control_unit (
input logic [5:0] op, input logic [5:0] func,
output logic [0:0] M2R, // Enables writing data stored in memory at the address (rs/A)+(ALU_SRC ? imm : rt/B) into rd
output logic [0:0] M2W, // Enable writing data stored in rt/B into memory at the address (rs/A)+(ALU_SRC ? imm : rt/B)
output logic [0:0] B, // AND'ed with flags to determine if branch is permitted
output logic [3:0] ALU_FN, // Controls what function the ALU is to perform
output logic [0:0] ALU_SRC, // Controls whether to use the rt/B register read port or 16-bit immediate
output logic [0:0] RDST, // Controls where to look in the instruction encoding for the register write address
output logic [0:0] RW // Enable register write port
);
logic [0:0] TYPE_R;
logic [0:0] TYPE_B1;
logic [0:0] TYPE_J;
logic [0:0] TYPE_B2;
logic [0:0] TYPE_I;
logic [0:0] TYPE_F;
logic [0:0] TYPE_M;
instruction_classifier CLASSIFIER (op, TYPE_R, TYPE_B1, TYPE_J, TYPE_B2, TYPE_I, TYPE_F, TYPE_M);
always_comb begin
M2R = TYPE_M & op[3];
M2W = TYPE_M & ~op[3];
B = TYPE_B1 | TYPE_B2 | TYPE_J;
ALU_FN = (func & {(6){TYPE_R}}) | ( {4'b0000, op[1:0]} & {(6){TYPE_I}});
ALU_SRC = TYPE_B1 | TYPE_B2 | TYPE_I | TYPE_M;
RDST = TYPE_I; // Imm ops store back into rt
RW = TYPE_R | TYPE_I | (TYPE_M & op[3]); // All ALU R-type ops, Addi/Addiu ops, and memory loads
end
endmodule
`endif
+21
View File
@@ -0,0 +1,21 @@
`ifndef INSTRUCTION_COUNTER_H
`define INSTRUCTION_COUNTER_H
module instruction_counter #(parameter width=5)(
input logic [0:0] clk, input logic [0:0] we,
input logic [2**width-1:0] W,
output logic [2**width-1:0] addr
);
logic [2**width-1:0] pc;
always_ff @(posedge clk) begin
if (we) begin
pc <= W;
end else begin
pc <= pc + 4;
end
end
assign addr = pc;
endmodule
`endif
+4 -4
View File
@@ -1,13 +1,13 @@
`ifndef LU_H_SV
`define LU_H_SV
module lu #(parameter width = 2) (
input logic [1:0] op,
input logic [2**width-1:0] A,
input logic [1:0] op, // 2 bit operand
input logic [2**width-1:0] A, // width defined as 2^n
input logic [2**width-1:0] B,
output logic [2**width-1:0] Y);
always_comb begin
case (op)
case (op) // different operations of A and B based on operand
2'b00: Y = A & B;
2'b01: Y = A | B;
2'b10: Y = A ^ B;
@@ -16,4 +16,4 @@ module lu #(parameter width = 2) (
endcase
end
endmodule
`endif
`endif
+95
View File
@@ -0,0 +1,95 @@
`include "assignment2.sv"
`define PRINT_REGISTERS(regs)\
$display("\tt0-t8: \t0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n\ts0-s8: \t0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x 0x%0x\n",\
regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15], \
regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23] \
);
`define TEST_CHECK(cond) if (cond) begin end else begin \
$display("Check %s failed\n", `"cond`"); \
`PRINT_REGISTERS(CPU.REGS.regs); \
num_errors += 1; \
end
module mips_tb(input logic [0:0] clk);
assignment2 #(5) CPU (clk);
integer num_errors = 0;
initial begin
// Zero out lower registers
$display("Beginning MIPS tests");
assign num_errors = 0;
for (integer N = 1; N < 32; ++N)
CPU.REGS.regs[N] = 32'd0;
// Check R-type / initialise
#1;
`TEST_CHECK(CPU.REGS.regs[8] == 32'd0);
#1;
`TEST_CHECK(CPU.REGS.regs[9] == (CPU.REGS.regs[8] + 32'd7));
// Check load-store
#1;
`TEST_CHECK(CPU.RAM.mem[0] == CPU.REGS.regs[9]);
#1;
`TEST_CHECK(CPU.REGS.regs[10] == CPU.RAM.mem[0]);
// Check arithmetic
#1;
`TEST_CHECK(CPU.REGS.regs[11] == (CPU.REGS.regs[9] + CPU.REGS.regs[10]));
#1;
`TEST_CHECK(CPU.REGS.regs[12] == (CPU.REGS.regs[9] - CPU.REGS.regs[11]));
#1;
`TEST_CHECK(CPU.REGS.regs[13] == (CPU.REGS.regs[9] + 3));
#1;
`TEST_CHECK(CPU.REGS.regs[14] == (CPU.REGS.regs[12] + CPU.REGS.regs[13]));
// Check logic instructions
#1;
`TEST_CHECK(CPU.REGS.regs[16] == (CPU.REGS.regs[9] & CPU.REGS.regs[13]));
#1;
`TEST_CHECK(CPU.REGS.regs[17] == (CPU.REGS.regs[9] | CPU.REGS.regs[13]));
#1;
`TEST_CHECK(CPU.REGS.regs[18] == (CPU.REGS.regs[9] ^ CPU.REGS.regs[13]));
#1;
`TEST_CHECK(CPU.REGS.regs[19] == ( ~(CPU.REGS.regs[9] | CPU.REGS.regs[13]) ));
// Check SLT instructions
#1;
`TEST_CHECK(CPU.REGS.regs[20] == $signed(CPU.REGS.regs[12]) < $signed(CPU.REGS.regs[14]));
#1;
`TEST_CHECK(CPU.REGS.regs[21] == $unsigned(CPU.REGS.regs[12]) < $unsigned(CPU.REGS.regs[14]));
// Check loop branching
for (integer N = 1; N < 11; ++N) begin
#1;
`TEST_CHECK(CPU.REGS.regs[0] == 32'(N));
#1;
`TEST_CHECK(CPU.REGS.regs[22] == $unsigned(CPU.REGS.regs[8]) < $unsigned(CPU.REGS.regs[13]));
end
// Final state check
#1;
`TEST_CHECK(CPU.REGS.regs[8] == 32'd10);
`TEST_CHECK(CPU.REGS.regs[9] == 32'd7);
`TEST_CHECK(CPU.REGS.regs[10] == 32'd7);
`TEST_CHECK(CPU.REGS.regs[11] == 32'd14);
`TEST_CHECK(CPU.REGS.regs[12] == -32'sd7);
`TEST_CHECK(CPU.REGS.regs[13] == 32'd10);
`TEST_CHECK(CPU.REGS.regs[14] == 32'd3);
`TEST_CHECK(CPU.REGS.regs[15] == 32'd0);
`TEST_CHECK(CPU.REGS.regs[16] == 32'd2);
`TEST_CHECK(CPU.REGS.regs[17] == 32'd15);
`TEST_CHECK(CPU.REGS.regs[18] == 32'd13);
`TEST_CHECK(CPU.REGS.regs[19] == -32'sd16);
`TEST_CHECK(CPU.REGS.regs[20] == 32'd1);
`TEST_CHECK(CPU.REGS.regs[21] == 32'd0);
`TEST_CHECK(CPU.REGS.regs[22] == 32'd0);
`TEST_CHECK(CPU.REGS.regs[23] == 32'd0);
if (num_errors == 0) $display("\x1b[38;5;10mAll MIPS tests passing\x1b[m");
else $display("\x1b[38;5;9m%0d MIPS test(s) failing\x1b[m", num_errors);
end
endmodule
+31
View File
@@ -0,0 +1,31 @@
`ifndef RAM_H
`define RAM_H
module ram #(addrwidth=9, datawidth=5)(
input logic [0:0] clk,
input logic [2**addrwidth-1:0] addr,
input logic [0:0] we,
input logic [datawidth-1:0] data_in,
output logic [datawidth-1:0] data_out
);
// TODO: Make this byte-sized, NOT word-sized!
logic [2**datawidth-1:0] mem[(2**(addrwidth+$clog2(datawidth)-3))-1:0];
// NOTE: Possible issue with assignments still pending by end of initial block
initial begin
for (integer ADDR = 0; ADDR < 2**(addrwidth+$clog2(datawidth)-3); ++ADDR) begin
mem[ADDR] <= 8'b0;
end
end
always_ff @(posedge clk) begin
if (we) begin
mem[addr] <= data_in;
end
end
assign data_out = mem[addr];
endmodule
`endif
+28
View File
@@ -0,0 +1,28 @@
`ifndef REGISTER_FILE_H
`define REGISTER_FILE_H
module register_file #(parameter width=5, parameter nregs=5)(
input logic [0:0] clk, input logic[0:0] we,
input logic [nregs-1:0] WA, input logic [2**width-1:0] WD,
input logic [nregs-1:0] RA1, output logic [2**width-1:0] RD1,
input logic [nregs-1:0] RA2, output logic [2**width-1:0] RD2,
output logic [2**width-1:0] regs_out [2**nregs]
);
localparam BW = 2**width;
logic [2**width-1:0] regs[2**nregs];
initial begin
regs[0] = {(2**width){1'b0}};
end
always_ff @(posedge clk) begin
if (we & (WA != {(2**width){1'b0}} )) begin
regs[WA] <= WD;
end
end
assign RD1 = regs[RA1];
assign RD2 = regs[RA2];
assign regs_out = regs; // Expose registers externally
endmodule
`endif
+24
View File
@@ -0,0 +1,24 @@
`ifndef ROM_H
`define ROM_H
module rom #(parameter m=7,p=4) (
input logic [m-1:0] Ad,
output logic [p-1:0] Dout
);
logic [p-1:0] mem[2**m-1:0];
assign Dout = mem[Ad];
//Load the program in memory
// The machine code stored in text file program.dat written in Hex format
initial begin
`ifdef QUARTUS_SYNTH
$readmemh("../../asm/bin/ELEC4720-2026s2-Ass-02-Demo.txt",mem); //$readmemb for binary
`else
$readmemh("./asm/bin/ELEC4720-2026s2-Ass-02-Demo.txt",mem); //$readmemb for binary
`endif
end
endmodule // end rom module
`endif
+44
View File
@@ -0,0 +1,44 @@
`ifndef SEVEN_SEG_4_H_SV
`define SEVEN_SEG_4_H_SV
`include "seven_seg.sv"
module seven_seg_4digit (
input logic [15:0] num,
output logic [7:0] segments0,
output logic [7:0] segments1,
output logic [7:0] segments2,
output logic [7:0] segments3
);
// Rightmost digit
seven_seg digit0 (
.num(num[3:0]),
.rbi_inv(1'b0),
.segments(segments0)
);
// Second digit from right
seven_seg digit1 (
.num(num[7:4]),
.rbi_inv(1'b0),
.segments(segments1)
);
// Third digit from right
seven_seg digit2 (
.num(num[11:8]),
.rbi_inv(1'b0),
.segments(segments2)
);
// Leftmost digit
seven_seg digit3 (
.num(num[15:12]),
.rbi_inv(1'b0),
.segments(segments3)
);
endmodule
`endif
+3 -3
View File
@@ -1,9 +1,9 @@
`ifndef SHIFTER_H_SV
`define SHIFTER_H_SV
module shifter #(width=2)(input logic [2:0] op,
input logic[2**width-1:0] A, input logic[2**width-1:0] B, input logic[width-1:0] C,
input logic[2**width-1:0] A, input logic[2**width-1:0] B, input logic[width-1:0] C,
output logic[2**width-1:0] OUT_1);
// A and B are 2^n bits wide and C is n bits wide as according to the docs
always_comb begin
case (op)
3'b000: OUT_1 = A << C;
@@ -16,4 +16,4 @@ module shifter #(width=2)(input logic [2:0] op,
endcase
end
endmodule
`endif
`endif
+17
View File
@@ -0,0 +1,17 @@
`ifndef SIGN_EXTENDER_H
`define SIGN_EXTENDER_H
module sign_extender #(in_width=4, out_width=5)(
input logic [0:0] op,
input logic [2**in_width-1:0] val,
output logic [2**out_width-1:0] ext_val
);
always_comb begin
if (op) begin
ext_val = { {(2**(out_width-in_width)){val[2**in_width-1]}}, val};
end else begin
ext_val = ({{(2**(out_width-in_width)){1'b0}}, val});
end
end
endmodule
`endif