aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkryptoish <krish_thakur7@icloud.com>2024-12-07 22:12:43 -0800
committerkryptoish <krish_thakur7@icloud.com>2024-12-07 22:12:43 -0800
commitf9d92b31e4bea3037c75f7c7a508c1be09811fd0 (patch)
tree5cd7160603f0841c0661e5c50fca5e3c28b96af4 /src
parentadded files (diff)
Final Working Version
Diffstat (limited to 'src')
-rw-r--r--src/alu.sv17
-rw-r--r--src/cpu.sv94
-rw-r--r--src/datapath.sv38
-rw-r--r--src/lab7bonus_top.sv79
-rw-r--r--src/regfile.sv54
-rw-r--r--src/shifter.sv12
-rw-r--r--src/statemachine.sv246
7 files changed, 540 insertions, 0 deletions
diff --git a/src/alu.sv b/src/alu.sv
new file mode 100644
index 0000000..c6d00bd
--- /dev/null
+++ b/src/alu.sv
@@ -0,0 +1,17 @@
+module ALU(Ain, Bin, op, out, status);
+ input [1:0] op;
+ input [15:0] Ain, Bin;
+ output [2:0] status;
+ output reg [15:0] out;
+
+ assign status[2] = out[15];
+ assign status[1] = (out[15] ^ Ain[15]) & ~(out[15] ^ Bin[15]);
+ assign status[0] = (out == 0);
+
+ always_comb case (op)
+ 2'b00: out = Ain + Bin;
+ 2'b01: out = Ain - Bin;
+ 2'b10: out = Ain & Bin;
+ 2'b11: out = ~Bin;
+ endcase
+endmodule: ALU
diff --git a/src/cpu.sv b/src/cpu.sv
new file mode 100644
index 0000000..0efcd6d
--- /dev/null
+++ b/src/cpu.sv
@@ -0,0 +1,94 @@
+module cpu(clk, reset, mem_data, mem_cmd, mem_addr, out, N, V, Z, halt);
+ input clk, reset;
+ input [15:0] mem_data;
+ output N, V, Z, halt;
+ output [1:0] mem_cmd;
+ output [15:0] out;
+ output reg [8:0] mem_addr;
+
+ wire pc_reset, pc_load, ir_load, addr_sel, write, loada, loadb, loadc,
+ loads, loadm, asel, bsel, csel;
+ wire [1:0] pc_sel, op, sh;
+ wire [2:0] opcode, cond, Rn, Rd, Rm, reg_w_sel, reg_a_sel, reg_b_sel;
+ wire [3:0] vsel;
+ wire [8:0] PC, data_address;
+ wire [15:0] instruction, sximm5, sximm8;
+ reg [2:0] reg_w, reg_a, reg_b;
+ reg [8:0] pc_next;
+
+ register #(16) U0(mem_data, ir_load, clk, instruction);
+ register #(9) U1(pc_next, pc_load, clk, PC);
+
+ statemachine FSM(clk, reset, opcode, op, pc_reset, pc_load, pc_sel,
+ ir_load, addr_sel, mem_cmd, reg_w_sel, reg_a_sel,
+ reg_b_sel, write, loada, loadb, loadc, loads, loadm, asel, bsel,
+ csel, vsel, halt);
+
+ datapath DP(clk, reg_w, reg_a, reg_b, write, loada, loadb, loadc, loads,
+ loadm, op, sh, asel, bsel, csel, vsel, sximm5, sximm8,
+ mem_data, PC, N, V, Z, out, data_address);
+
+ assign mem_addr = addr_sel ? PC : data_address;
+
+ /* Instruction decoder. */
+ assign {opcode, op, Rn, Rd, sh, Rm} = instruction;
+ assign cond = instruction[10:8];
+ assign sximm8 = {{8{instruction[7]}}, instruction[7:0]};
+ assign sximm5 = {{11{instruction[4]}}, instruction[4:0]};
+
+ always_comb begin
+ /* Selector for REGFILE read/write registers. */
+ case (reg_w_sel)
+ 3'b100: reg_w = Rn;
+ 3'b010: reg_w = Rd;
+ 3'b001: reg_w = Rm;
+ default: reg_w = 3'bzzz;
+ endcase
+ case (reg_a_sel)
+ 3'b100: reg_a = Rn;
+ 3'b010: reg_a = Rd;
+ 3'b001: reg_a = Rm;
+ default: reg_a = 3'bzzz;
+ endcase
+ case (reg_b_sel)
+ 3'b100: reg_b = Rn;
+ 3'b010: reg_b = Rd;
+ 3'b001: reg_b = Rm;
+ default: reg_b = 3'bzzz;
+ endcase
+
+ /* Branching logic. */
+ casex ({pc_reset, pc_sel})
+ 3'b1_xx:
+ pc_next = 9'b0;
+ 3'b0_01: begin
+ pc_next = PC;
+ case ({opcode, cond})
+ /* B. */
+ 6'b001_000:
+ pc_next = PC + sximm8[8:0];
+ /* BEQ. */
+ 6'b001_001: if (Z)
+ pc_next = PC + sximm8[8:0];
+ /* BNE. */
+ 6'b001_010: if (~Z)
+ pc_next = PC + sximm8[8:0];
+ /* BLT. */
+ 6'b001_011: if (N !== V)
+ pc_next = PC + sximm8[8:0];
+ /* BLE. */
+ 6'b001_100: if (N !== V | Z)
+ pc_next = PC + sximm8[8:0];
+ endcase
+ end
+ /* BX, BLX. */
+ 3'b0_10:
+ pc_next = out;
+ /* BL. */
+ 3'b0_11:
+ pc_next = PC + sximm8[8:0];
+ /* Next address in memory. */
+ default: pc_next = PC + 1;
+ endcase
+ end
+endmodule: cpu
diff --git a/src/datapath.sv b/src/datapath.sv
new file mode 100644
index 0000000..f0e85a5
--- /dev/null
+++ b/src/datapath.sv
@@ -0,0 +1,38 @@
+module datapath(clk, reg_w, reg_a, reg_b, write, loada, loadb, loadc, loads,
+ loadm, op, shift, asel, bsel, csel, vsel, sximm5, sximm8,
+ mdata, PC, N, V, Z, datapath_out, data_address);
+ input clk, write, loada, loadb, loadc, loads, loadm, asel, bsel, csel;
+ input [1:0] op, shift;
+ input [2:0] reg_w, reg_a, reg_b;
+ input [3:0] vsel;
+ input [8:0] PC;
+ input [15:0] sximm8, sximm5, mdata;
+ output N, V, Z;
+ output [8:0] data_address;
+ output reg [15:0] datapath_out;
+
+ wire [2:0] status;
+ wire [15:0] out_a, out_b, aout, bout, sout, ain, bin, out;
+ reg [15:0] data_in;
+
+ regfile REGFILE(clk, data_in, write, reg_w, reg_a, reg_b, out_a, out_b);
+ shifter U0(bout, shift, sout);
+ ALU U1(ain, bin, op, out, status);
+ register #(16) REG_A(out_a, loada, clk, aout);
+ register #(16) REG_B(out_b, loadb, clk, bout);
+ register #(16) REG_C((csel ? out_b : out), loadc, clk, datapath_out);
+ register #(9) REG_M(out[8:0], loadm, clk, data_address);
+ register #(3) REG_S(status, loads, clk, {N, V, Z});
+
+ assign ain = asel ? 16'b0 : aout;
+ assign bin = bsel ? sximm5 : sout;
+
+ /* One-hot signal: vsel. */
+ always_comb begin
+ data_in = {16{1'bz}};
+ if (vsel[0]) data_in = datapath_out;
+ if (vsel[1]) data_in = mdata;
+ if (vsel[2]) data_in = sximm8;
+ if (vsel[3]) data_in = {7'b0, PC};
+ end
+endmodule: datapath
diff --git a/src/lab7bonus_top.sv b/src/lab7bonus_top.sv
new file mode 100644
index 0000000..2a9e805
--- /dev/null
+++ b/src/lab7bonus_top.sv
@@ -0,0 +1,79 @@
+`define M_NOP 2'b00
+`define M_READ 2'b10
+`define M_WRITE 2'b01
+
+module lab7bonus_top(KEY, SW, LEDR, HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, CLOCK_50);
+ input CLOCK_50;
+ input [3:0] KEY;
+ input [9:0] SW;
+ output [6:0] HEX0, HEX1, HEX2, HEX3, HEX4, HEX5;
+ output [9:0] LEDR;
+
+ wire clk, write, N, V, Z, halt;
+ wire [1:0] mem_cmd;
+ wire [8:0] mem_addr;
+ wire [15:0] din, dout, mem_data;
+
+ ram #(16, 8) MEM(clk, mem_addr[7:0], write, din, dout);
+ cpu CPU(clk, reset, mem_data, mem_cmd, mem_addr, din, N, V, Z, halt);
+
+ disp U0(din[3:0], HEX0);
+ disp U1(din[7:4], HEX1);
+ disp U2(din[11:8], HEX2);
+ disp U3(din[15:12], HEX3);
+ disp U4({1'b0, N, V, Z}, HEX4);
+
+ assign clk = CLOCK_50;
+ assign reset = ~KEY[1];
+ assign LEDR[8] = halt;
+
+ assign mem_data = (mem_cmd == `M_READ & ~mem_addr[8])
+ ? dout : {16{1'bz}};
+ assign write = mem_cmd == `M_WRITE & ~mem_addr[8];
+endmodule: lab7bonus_top
+
+module ram(clk, addr, write, din, dout);
+ parameter data_width = 32;
+ parameter addr_width = 4;
+ parameter filename = "data.txt";
+
+ input clk;
+ input [addr_width-1:0] addr;
+ input write;
+ input [data_width-1:0] din;
+ output [data_width-1:0] dout;
+ reg [data_width-1:0] dout;
+
+ reg [data_width-1:0] mem [2**addr_width-1:0];
+
+ initial $readmemb(filename, mem);
+
+ always @ (posedge clk) begin
+ if (write) mem[addr] <= din;
+ dout <= mem[addr];
+ end
+endmodule: ram
+
+module disp(in, out);
+ input [3:0] in;
+ output reg [6:0] out;
+
+ always_comb case (in)
+ 4'h0: out = 7'b1000000;
+ 4'h1: out = 7'b1111001;
+ 4'h2: out = 7'b0100100;
+ 4'h3: out = 7'b0110000;
+ 4'h4: out = 7'b0011001;
+ 4'h5: out = 7'b0010010;
+ 4'h6: out = 7'b0000010;
+ 4'h7: out = 7'b1111000;
+ 4'h8: out = 7'b0000000;
+ 4'h9: out = 7'b0010000;
+ 4'ha: out = 7'b0001000;
+ 4'hb: out = 7'b0000011;
+ 4'hc: out = 7'b0100111;
+ 4'hd: out = 7'b0100001;
+ 4'he: out = 7'b0000110;
+ 4'hf: out = 7'b0001110;
+ endcase
+endmodule: disp
diff --git a/src/regfile.sv b/src/regfile.sv
new file mode 100644
index 0000000..7c53807
--- /dev/null
+++ b/src/regfile.sv
@@ -0,0 +1,54 @@
+module regfile(clk, data_in, write, reg_w, reg_a, reg_b, out_a, out_b);
+ input clk, write;
+ input [2:0] reg_w, reg_a, reg_b;
+ input [15:0] data_in;
+ output reg [15:0] out_a, out_b;
+
+ wire [7:0] load;
+ wire [15:0] R0, R1, R2, R3, R4, R5, R6, R7;
+
+ register #(16) U0(data_in, load[0], clk, R0);
+ register #(16) U1(data_in, load[1], clk, R1);
+ register #(16) U2(data_in, load[2], clk, R2);
+ register #(16) U3(data_in, load[3], clk, R3);
+ register #(16) U4(data_in, load[4], clk, R4);
+ register #(16) U5(data_in, load[5], clk, R5);
+ register #(16) U6(data_in, load[6], clk, R6);
+ register #(16) U7(data_in, load[7], clk, R7);
+
+ assign load = {8{write}} & (8'b1 << reg_w);
+
+ always_comb begin
+ case (reg_a)
+ 0: out_a = R0;
+ 1: out_a = R1;
+ 2: out_a = R2;
+ 3: out_a = R3;
+ 4: out_a = R4;
+ 5: out_a = R5;
+ 6: out_a = R6;
+ 7: out_a = R7;
+ endcase
+
+ case (reg_b)
+ 0: out_b = R0;
+ 1: out_b = R1;
+ 2: out_b = R2;
+ 3: out_b = R3;
+ 4: out_b = R4;
+ 5: out_b = R5;
+ 6: out_b = R6;
+ 7: out_b = R7;
+ endcase
+ end
+endmodule: regfile
+
+module register(in, load, clk, out);
+ parameter n = 1;
+ input [n-1:0] in;
+ input load, clk;
+ output reg [n-1:0] out;
+
+ always_ff @(posedge clk)
+ if (load) out = in;
+endmodule: register
diff --git a/src/shifter.sv b/src/shifter.sv
new file mode 100644
index 0000000..66e5c74
--- /dev/null
+++ b/src/shifter.sv
@@ -0,0 +1,12 @@
+module shifter(in, shift, sout);
+ input [1:0] shift;
+ input [15:0] in;
+ output reg [15:0] sout;
+
+ always_comb case (shift)
+ 2'b00: sout = in;
+ 2'b01: sout = {in[14:0], 1'b0};
+ 2'b10: sout = {1'b0, in[15:1]};
+ 2'b11: sout = {in[15], in[15:1]};
+ endcase
+endmodule: shifter
diff --git a/src/statemachine.sv b/src/statemachine.sv
new file mode 100644
index 0000000..1a5beb1
--- /dev/null
+++ b/src/statemachine.sv
@@ -0,0 +1,246 @@
+`define STATE_RESET 3'b000
+`define STATE_HALT 3'b001
+`define STATE_IF 3'b010
+`define STATE_DECODE 3'b011
+`define STATE_EXEC 3'b100
+`define STATE_MEM 3'b101
+`define STATE_WRITEBACK 3'b110
+
+module statemachine(clk, reset, opcode, op, pc_reset, pc_load, pc_sel, ir_load,
+ addr_sel, mem_cmd, reg_w_sel, reg_a_sel, reg_b_sel, write,
+ loada, loadb, loadc, loads, loadm, asel, bsel, csel, vsel,
+ halt);
+ input clk, reset;
+ input [1:0] op;
+ input [2:0] opcode;
+ output reg pc_reset, pc_load, ir_load, addr_sel, write, loada, loadb,
+ loadc, loads, loadm, asel, bsel, csel, halt;
+ output reg [1:0] pc_sel, mem_cmd;
+ output reg [2:0] reg_w_sel, reg_a_sel, reg_b_sel;
+ output reg [3:0] vsel;
+
+ reg [3:0] state;
+
+ always_comb begin
+ {pc_reset, pc_load, pc_sel, ir_load, addr_sel, mem_cmd,
+ reg_w_sel, reg_a_sel, reg_b_sel, write, loada, loadb,
+ loadc, loads, loadm, asel, bsel, csel, vsel, halt}
+ = 31'b0;
+
+ casex ({state, opcode, op})
+ /* Reset state. */
+ {`STATE_RESET, 5'bxxx_xx}:
+ {pc_reset, pc_load, addr_sel, mem_cmd}
+ = 5'b111_10;
+
+ /* Instruction fetch. */
+ {`STATE_IF, 5'bxxx_xx}:
+ {pc_load, ir_load, addr_sel, mem_cmd} = 5'b111_10;
+
+ /* MOV immediate to register. */
+ {`STATE_DECODE, 5'b110_10}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_100_1_0100;
+
+ /* MOV register to register. */
+ {`STATE_DECODE, 5'b110_00}:
+ {reg_b_sel, loadb} = 4'b001_1;
+ {`STATE_EXEC, 5'b110_00}:
+ {loadc, asel} = 2'b11;
+ {`STATE_WRITEBACK, 5'b110_00}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0001;
+
+ /* General ALU operations. */
+ {`STATE_DECODE, 5'b101_xx}:
+ {reg_a_sel, reg_b_sel, loada, loadb} = 8'b100_001_11;
+
+ /* ADD. */
+ {`STATE_EXEC, 5'b101_00}:
+ loadc = 1'b1;
+ {`STATE_WRITEBACK, 5'b101_00}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0001;
+
+ /* CMP. */
+ {`STATE_EXEC, 5'b101_01}:
+ {addr_sel, mem_cmd, loads} = 4'b1_10_1;
+
+ /* AND. */
+ {`STATE_EXEC, 5'b101_10}:
+ loadc = 1'b1;
+ {`STATE_WRITEBACK, 5'b101_10}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0001;
+
+ /* MVN. */
+ {`STATE_EXEC, 5'b101_11}:
+ loadc = 1'b1;
+ {`STATE_WRITEBACK, 5'b101_11}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0001;
+
+ /* LDR. */
+ {`STATE_DECODE, 5'b011_xx}:
+ {reg_a_sel, loada} = 4'b100_1;
+ {`STATE_EXEC, 5'b011_xx}:
+ {loadm, bsel} = 2'b11;
+ {`STATE_MEM, 5'b011_xx}:
+ mem_cmd = 2'b10;
+ {`STATE_WRITEBACK, 5'b011_xx}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0010;
+
+ /* STR. */
+ {`STATE_DECODE, 5'b100_xx}:
+ {reg_a_sel, reg_b_sel, csel, loada, loadc}
+ = 9'b100_010_111;
+ {`STATE_EXEC, 5'b100_xx}:
+ {loadm, bsel} = 2'b11;
+ {`STATE_MEM, 5'b100_xx}:
+ mem_cmd = 2'b01;
+ {`STATE_WRITEBACK, 5'b100_xx}:
+ {addr_sel, mem_cmd} = 3'b1_10;
+
+ /* B, BEQ, BNE, BLT, BLE. */
+ {`STATE_DECODE, 5'b001_xx}:
+ {pc_load, pc_sel} = 3'b1_01;
+ {`STATE_EXEC, 5'b001_xx}:
+ {addr_sel, mem_cmd} = 3'b1_10;
+
+ /* BL. */
+ {`STATE_DECODE, 5'b010_11}:
+ {pc_load, pc_sel, reg_w_sel, write, vsel}
+ = 11'b1_11_100_1_1000;
+ {`STATE_EXEC, 5'b010_11}:
+ {addr_sel, mem_cmd} = 3'b1_10;
+
+ /* BX, BLX. */
+ {`STATE_DECODE, 5'b010_xx}:
+ {reg_b_sel, loadc, csel} = 5'b010_11;
+
+ /* BX. */
+ {`STATE_EXEC, 5'b010_00}:
+ {pc_load, pc_sel} = 3'b1_10;
+ {`STATE_WRITEBACK, 5'b010_00}:
+ {addr_sel, mem_cmd} = 3'b1_10;
+
+ /* BLX. */
+ {`STATE_EXEC, 5'b010_10}:
+ {pc_load, pc_sel, reg_w_sel, write, vsel}
+ = 11'b1_10_100_1_1000;
+ {`STATE_WRITEBACK, 5'b010_10}:
+ {addr_sel, mem_cmd}
+ = 3'b1_10;
+
+ {`STATE_HALT, 5'bxxx_xx}:
+ halt = 1'b1;
+
+ default: begin end
+ endcase
+ end
+
+ always_ff @(posedge clk) casex ({reset, state, opcode, op})
+ /* Reset. */
+ 10'b1_xxxx_xxx_xx:
+ state <= `STATE_RESET;
+ {1'b0, `STATE_RESET, 5'bxxx_xx}:
+ state <= `STATE_IF;
+
+ /* Beginning of instruction cycle. */
+ {1'b0, `STATE_IF, 5'bxxx_xx}:
+ state <= `STATE_DECODE;
+
+ /* HALT. */
+ {1'b0, `STATE_DECODE, 5'b111_xx}:
+ state <= `STATE_HALT;
+ {1'b0, `STATE_HALT, 5'bxxx_xx}:
+ state <= `STATE_HALT;
+
+ /* MOV immediate to register. */
+ {1'b0, `STATE_DECODE, 5'b110_10}:
+ state <= `STATE_IF;
+
+ /* MOV register to register. */
+ {1'b0, `STATE_DECODE, 5'b110_00}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b110_00}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b110_00}:
+ state <= `STATE_IF;
+
+ /* ADD. */
+ {1'b0, `STATE_DECODE, 5'b101_00}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b101_00}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b101_00}:
+ state <= `STATE_IF;
+
+ /* CMP. */
+ {1'b0, `STATE_DECODE, 5'b101_01}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b101_01}:
+ state <= `STATE_IF;
+
+ /* AND. */
+ {1'b0, `STATE_DECODE, 5'b101_10}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b101_10}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b101_10}:
+ state <= `STATE_IF;
+
+ /* MVN. */
+ {1'b0, `STATE_DECODE, 5'b101_11}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b101_11}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b101_11}:
+ state <= `STATE_IF;
+
+ /* LDR. */
+ {1'b0, `STATE_DECODE, 5'b011_xx}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b011_xx}:
+ state <= `STATE_MEM;
+ {1'b0, `STATE_MEM, 5'b011_xx}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b011_xx}:
+ state <= `STATE_IF;
+
+ /* STR. */
+ {1'b0, `STATE_DECODE, 5'b100_xx}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b100_xx}:
+ state <= `STATE_MEM;
+ {1'b0, `STATE_MEM, 5'b100_xx}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b100_xx}:
+ state <= `STATE_IF;
+
+ /* B, BEQ, BNE, BLT, BLE. */
+ {1'b0, `STATE_DECODE, 5'b001_xx}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b001_xx}:
+ state <= `STATE_IF;
+
+ /* BL. */
+ {1'b0, `STATE_DECODE, 5'b010_11}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b010_11}:
+ state <= `STATE_IF;
+
+ /* BX, BLX. */
+ {1'b0, `STATE_DECODE, 5'b010_xx}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b010_xx}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b010_xx}:
+ state <= `STATE_IF;
+
+ /* Should not happen. Otherwise, an error occurred. */
+ default:
+ state <= `STATE_RESET;
+ endcase
+endmodule: statemachine