aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_fpga
diff options
context:
space:
mode:
Diffstat (limited to 'atk16_fpga')
-rw-r--r--atk16_fpga/cu.v374
-rw-r--r--atk16_fpga/cu_tb.v473
-rw-r--r--atk16_fpga/mem_fsm.v23
-rw-r--r--atk16_fpga/mem_fsm_tb.v32
4 files changed, 824 insertions, 78 deletions
diff --git a/atk16_fpga/cu.v b/atk16_fpga/cu.v
index 915ce8e..13bc804 100644
--- a/atk16_fpga/cu.v
+++ b/atk16_fpga/cu.v
@@ -16,9 +16,10 @@
// R = right operand register select
// I = immediate operand
// S = ALU operation select
+// F = flag select
// A = absolute (1) / relative (0) addressing
-// D = direct (1) / indirect (0) load
-// M = immediate mode (1) / register mode (0)
+// D = direct (1) / indirect (0) load/store
+// X = unused
// ALR (arithmetic-logic, register)
// 0000 TTTL LLRR RSSS
@@ -30,15 +31,41 @@
// 0010 TTTR RRXX XXAD
`define OP_LDR 4'b0010
// STR (store to memory)
-// 0011 XXXL LLRR RMAD
+// 0011 XXXL LLRR RXAD
`define OP_STR 4'b0011
// LDI (load by immediate)
-// 0100 TTTD IIII IIII
+// 0100 TTTI IIII IIAD
`define OP_LDI 4'b0100
+// JPR (jump by register)
+// 0101 ADRR RXXX XXXX
+`define OP_JPR 4'b0101
+// JPI (jump by immediate)
+// 0110 ADII IIII IIII
+`define OP_JPI 4'b0110
+// BRR (branch by register)
+// 0111 ADFF RRRX XXXX
+`define OP_BRR 4'b0111
+// BRI (branch by immediate)
+// 1000 ADFF IIII IIII
+`define OP_BRI 4'b1000
+// LPC (load PC+1)
+// 1001 TTTX XXXX XXXX
+`define OP_LPC 4'b1001
+// RTI (return from interrupt)
+// 1010 XXXX XXXX XXXX
+`define OP_RTI 4'b1010
+`define OP_NOP1 4'b1011
+`define OP_NOP2 4'b1100
+`define OP_NOP3 4'b1101
+`define OP_NOP4 4'b1110
+// HLT (halt)
+// 1111 XXXX XXXX XXXX
+`define OP_HLT 4'b1111
module cu(
input wire clk,
- input wire rst
+ input wire rst,
+ input wire [3:0] int_lines
);
reg [2:0] alu_sel;
reg [15:0] alu_a;
@@ -50,6 +77,12 @@ module cu(
reg [2:0] phase = `PH_RESET;
reg [15:0] pc;
reg [15:0] ir;
+ reg halted = 0;
+
+ // interrupts
+ reg [15:0] int_pc;
+ reg [3:0] int_line_regs;
+ reg int_en = 1;
reg [15:0] mem_addr;
reg [15:0] mem_data_in;
@@ -85,11 +118,44 @@ module cu(
assign rg = regbank[6];
assign rh = regbank[7];
+ always @(posedge int_lines[0]) int_line_regs[0] <= int_lines[0];
+ always @(posedge int_lines[1]) int_line_regs[1] <= int_lines[1];
+ always @(posedge int_lines[2]) int_line_regs[2] <= int_lines[2];
+ always @(posedge int_lines[3]) int_line_regs[3] <= int_lines[3];
+
integer i;
always @(posedge clk or posedge rst) begin
// Handle reset button
if (rst) begin
- phase <= `PH_RESET;
+ phase <= `PH_RESET;
+ halted <= 0;
+ end
+
+ else if (halted) begin
+ // Do nothing
+ end
+
+ else if (int_en && int_line_regs != 4'b00) begin
+ int_en <= 0;
+ int_pc <= pc;
+ casez (int_line_regs)
+ 4'bzzz1: begin
+ pc <= 16'h10;
+ int_line_regs[0] <= 0;
+ end
+ 4'bzz1z: begin
+ pc <= 16'h11;
+ int_line_regs[1] <= 0;
+ end
+ 4'bz1zz: begin
+ pc <= 16'h12;
+ int_line_regs[2] <= 0;
+ end
+ 4'b1zzz: begin
+ pc <= 16'h13;
+ int_line_regs[3] <= 0;
+ end
+ endcase
end
else if (phase == `PH_RESET) begin
@@ -107,57 +173,258 @@ module cu(
// Fetch stage
else if (phase == `PH_FETCH) begin
mem_read_en <= 1;
- mem_write_en <= 0;
- mem_addr <= pc;
+ mem_addr <= pc;
if (mem_done) begin
mem_read_en <= 0;
- mem_write_en <= 0;
- ir <= mem_data_out;
- phase <= `PH_DECODE;
- pc <= pc + 16'd1;
+ ir <= mem_data_out;
+ phase <= `PH_DECODE;
+ pc <= pc + 16'd1;
end
end
// Decode stage
else if (phase == `PH_DECODE) begin
- phase <= `PH_EXECUTE;
-
case (ir[15:12])
`OP_ALR: begin
alu_sel <= ir[2:0]; // select ALU operation
- alu_a <= regbank[ir[8:6]]; // read operand A
- alu_b <= regbank[ir[5:3]]; // read operand B
+ alu_a <= regbank[ir[8:6]]; // read operand A
+ alu_b <= regbank[ir[5:3]]; // read operand B
+ phase <= `PH_EXECUTE;
end
`OP_ALI: begin
alu_sel <= ir[2:0]; // select ALU operation
- alu_a <= regbank[ir[8:6]]; // read operand A
- alu_b <= ir[5:3]; // read immediate operand
+ alu_a <= regbank[ir[8:6]]; // read operand A
+ alu_b <= ir[5:3]; // read immediate operand
+ phase <= `PH_EXECUTE;
end
`OP_LDR: begin
+ // ir[1] = A = absolute (1) / relative (0) addressing
+ // ir[0] = D = direct (1) / indirect (0) store
// set target reg value to address, dereference in execute phase
- if (ir[1] == 1 && ir[0] == 1) // addressing mode: absolute, direct
+ if (ir[1] == 1 && ir[0] == 1) begin // addressing mode: absolute, direct
decoded_tmp <= regbank[ir[8:6]];
- else if (ir[1] == 0 && ir[0] == 1) // addressing mode: pc relative, direct
- decoded_tmp <= regbank[ir[8:6]] + pc - 1;
- /*else if (ir[1] == 1 && ir[0] == 0) begin // addressing mode: absolute, indirect
- bram_wr <= 0;
- bram_rd <= 1;
- bram_addr <= regbank[ir[8:6]];
- decoded_tmp <= bram_data_out;
+ phase <= `PH_EXECUTE;
+ end
+ else if (ir[1] == 0 && ir[0] == 1) begin // addressing mode: pc relative, direct
+ decoded_tmp <= pc + regbank[ir[8:6]] - 1;
+ phase <= `PH_EXECUTE;
+ end
+ else if (ir[1] == 1 && ir[0] == 0) begin // addressing mode: absolute, indirect
+ mem_read_en <= 1;
+ mem_addr <= regbank[ir[8:6]];
+
+ if (mem_done) begin
+ decoded_tmp <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_EXECUTE;
+ end
end
else if (ir[1] == 0 && ir[0] == 0) begin // addressing mode: pc relative, indirect
- bram_wr <= 0;
- bram_rd <= 1;
- bram_addr <= regbank[ir[8:6]] + pc - 1;
- decoded_tmp <= bram_data_out;
- end*/
+ mem_read_en <= 1;
+ mem_addr <= pc + regbank[ir[8:6]] - 1;
+
+ if (mem_done) begin
+ decoded_tmp <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_EXECUTE;
+ end
+ end
end
`OP_STR: begin
- // ir[2] = M = immediate mode (1) / register mode (0)
+ // ir[1] = A = absolute (1) / relative (0) addressing
+ // ir[0] = D = direct (1) / indirect (0) store
+ // ir[5:3] = data reg
+ // ir[8:6] = address reg
+ // decoded_tmp will be the address to write to
+ if (ir[1] == 1 && ir[0] == 1) begin // addressing mode: absolute, direct
+ decoded_tmp <= regbank[ir[8:6]];
+ phase <= `PH_EXECUTE;
+ end
+ else if (ir[1] == 0 && ir[0] == 1) begin // addressing mode: pc relative, direct
+ decoded_tmp <= pc + regbank[ir[8:6]] - 1;
+ phase <= `PH_EXECUTE;
+ end
+ else if (ir[1] == 1 && ir[0] == 0) begin // addressing mode: absolute, indirect
+ mem_read_en <= 1;
+ mem_addr <= regbank[ir[8:6]];
+
+ if (mem_done) begin
+ decoded_tmp <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_EXECUTE;
+ end
+ end
+ else if (ir[1] == 0 && ir[0] == 0) begin // addressing mode: pc relative, indirect
+ mem_read_en <= 1;
+ mem_addr <= pc + regbank[ir[8:6]] - 1;
+
+ if (mem_done) begin
+ decoded_tmp <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_EXECUTE;
+ end
+ end
+ end
+ `OP_LDI: begin
// ir[1] = A = absolute (1) / relative (0) addressing
// ir[0] = D = direct (1) / indirect (0) load
- // TODO
+ // ir[8:2] = immediate
+ // ir[11:9] = target reg
+ if (ir[1] == 1) begin // addressing mode: absolute
+ decoded_tmp <= ir[8:2];
+ end
+ else if (ir[1] == 0) begin // addressing mode: pc relative
+ decoded_tmp <= pc + {{9{ir[8]}}, ir[8:2]} - 1;
+ end
+ phase <= `PH_EXECUTE;
+ end
+ `OP_JPR: begin
+ // ir[11] = A = absolute (1) / relative (0) addressing
+ // ir[10] = D = direct (1) / indirect (0) load
+ // ir[9:6] = address reg
+ if (ir[11] == 1 && ir[10] == 1) begin // addressing mode: absolute, direct
+ pc <= regbank[ir[9:6]];
+ phase <= `PH_FETCH;
+ end
+ else if (ir[11] == 0 && ir[10] == 1) begin // addressing mode: pc relative, direct
+ pc <= pc + regbank[ir[9:6]] - 1;
+ phase <= `PH_FETCH;
+ end
+ else if (ir[11] == 1 && ir[10] == 0) begin // addressing mode: absolute, indirect
+ mem_read_en <= 1;
+ mem_addr <= regbank[ir[9:6]];
+
+ if (mem_done) begin
+ pc <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_FETCH;
+ end
+ end
+ else if (ir[11] == 0 && ir[10] == 0) begin // addressing mode: pc relative, indirect
+ mem_read_en <= 1;
+ mem_addr <= pc + regbank[ir[9:6]] - 1;
+
+ if (mem_done) begin
+ pc <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_FETCH;
+ end
+ end
+ end
+ `OP_JPI: begin
+ // ir[11] = A = absolute (1) / relative (0) addressing
+ // ir[10] = D = direct (1) / indirect (0) load
+ // ir[9:0] = immediate
+ if (ir[11] == 1 && ir[10] == 1) begin // addressing mode: absolute, direct
+ pc <= {6'd0, ir[9:0]};
+ phase <= `PH_FETCH;
+ end
+ else if (ir[11] == 0 && ir[10] == 1) begin // addressing mode: pc relative, direct
+ pc <= pc + {{6{ir[9]}}, ir[9:0]} - 1;
+ phase <= `PH_FETCH;
+ end
+ else if (ir[11] == 1 && ir[10] == 0) begin // addressing mode: absolute, indirect
+ mem_read_en <= 1;
+ mem_addr <= {6'd0, ir[9:0]};
+
+ if (mem_done) begin
+ pc <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_FETCH;
+ end
+ end
+ else if (ir[11] == 0 && ir[10] == 0) begin // addressing mode: pc relative, indirect
+ mem_read_en <= 1;
+ mem_addr <= pc + {{6{ir[9]}}, ir[9:0]} - 1;
+
+ if (mem_done) begin
+ pc <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_FETCH;
+ end
+ end
+ end
+ `OP_BRR: begin
+ // ir[11] = A = absolute (1) / relative (0) addressing
+ // ir[10] = direct (1) / indirect (0) branch
+ // ir[9:8] = flag select
+ // ir[7:5] = address reg
+ if (ir[11] == 1 && ir[10] == 1) begin // addressing mode: absolute, direct
+ decoded_tmp <= regbank[ir[7:5]];
+ phase <= `PH_EXECUTE;
+ end
+ else if (ir[11] == 0 && ir[10] == 1) begin // addressing mode: pc relative, direct
+ decoded_tmp <= pc + regbank[ir[7:5]] - 1;
+ phase <= `PH_EXECUTE;
+ end
+ else if (ir[11] == 1 && ir[10] == 0) begin // addressing mode: absolute, indirect
+ mem_read_en <= 1;
+ mem_addr <= regbank[ir[7:5]];
+
+ if (mem_done) begin
+ decoded_tmp <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_EXECUTE;
+ end
+ end
+ else if (ir[11] == 0 && ir[10] == 0) begin // addressing mode: pc relative, indirect
+ mem_read_en <= 1;
+ mem_addr <= pc + regbank[ir[7:5]] - 1;
+
+ if (mem_done) begin
+ decoded_tmp <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_EXECUTE;
+ end
+ end
+ end
+ `OP_BRI: begin
+ // ir[11] = A = absolute (1) / relative (0) addressing
+ // ir[10] = direct (1) / indirect (0) branch
+ // ir[9:8] = flag select
+ // ir[7:0] = immediate
+ if (ir[11] == 1 && ir[10] == 1) begin // addressing mode: absolute, direct
+ decoded_tmp <= {8'd0, ir[7:0]};
+ phase <= `PH_EXECUTE;
+ end
+ else if (ir[11] == 0 && ir[10] == 1) begin // addressing mode: pc relative, direct
+ decoded_tmp <= pc + {{8{ir[7]}}, ir[7:0]} - 1;
+ phase <= `PH_EXECUTE;
+ end
+ else if (ir[11] == 1 && ir[10] == 0) begin // addressing mode: absolute, indirect
+ mem_read_en <= 1;
+ mem_addr <= {8'd0, ir[7:0]};
+
+ if (mem_done) begin
+ decoded_tmp <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_EXECUTE;
+ end
+ end
+ else if (ir[11] == 0 && ir[10] == 0) begin // addressing mode: pc relative, indirect
+ mem_read_en <= 1;
+ mem_addr <= pc + {{8{ir[7]}}, ir[7:0]} - 1;
+
+ if (mem_done) begin
+ decoded_tmp <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_EXECUTE;
+ end
+ end
+ end
+ `OP_LPC: begin
+ // ir[11:9] = target reg
+ regbank[ir[11:9]] <= pc;
+ phase <= `PH_FETCH;
+ end
+ `OP_RTI: begin
+ pc <= int_pc;
+ int_en <= 1;
+ phase <= `PH_FETCH;
+ end
+ `OP_HLT: begin
+ halted <= 1;
end
default: begin
`ifdef __SYNTHESIS__
@@ -175,20 +442,53 @@ module cu(
phase <= `PH_FETCH;
end
`OP_LDR: begin
- //$display("ir[11:9] %d, reg val: %d, mem_data_out: %d, mem_done: %d\n", ir[11:9], regbank[ir[11:9]], mem_data_out, mem_done);
mem_read_en <= 1;
- mem_write_en <= 0;
mem_addr <= decoded_tmp;
if (mem_done) begin
regbank[ir[11:9]] <= mem_data_out; // dereference address
mem_read_en <= 0;
- mem_write_en <= 0;
phase <= `PH_FETCH;
end
end
`OP_STR: begin
- // TODO
+ mem_write_en <= 1;
+ mem_addr <= decoded_tmp;
+ mem_data_in <= regbank[ir[5:3]];
+
+ if (mem_done) begin
+ mem_write_en <= 0;
+ phase <= `PH_FETCH;
+ end
+ end
+ `OP_LDI: begin
+ // ir[1] = A = absolute (1) / relative (0) addressing
+ // ir[0] = D = direct (1) / indirect (0) load
+ // ir[8:2] = immediate
+ // ir[11:9] = target reg
+ // decoded_tmp = immediate value that takes absolute/relative to account
+ if (ir[0] == 1) begin // direct
+ regbank[ir[11:9]] <= decoded_tmp;
+ phase <= `PH_FETCH;
+ end
+ else if (ir[0] == 0) begin // indirect
+ mem_read_en <= 1;
+ mem_addr <= decoded_tmp;
+
+ if (mem_done) begin
+ regbank[ir[11:9]] <= mem_data_out;
+ mem_read_en <= 0;
+ phase <= `PH_FETCH;
+ end
+ end
+ end
+ `OP_BRR, `OP_BRI: begin
+ // ir[9:8] = flag select
+ // branch if selected flag (0..3) is set (i.e. when anded with flags is non-zero)
+ if ((1 << ir[9:8]) & alu_flags != 4'd0) begin
+ pc <= decoded_tmp;
+ end
+ phase <= `PH_FETCH;
end
default: begin
`ifdef __SYNTHESIS__
diff --git a/atk16_fpga/cu_tb.v b/atk16_fpga/cu_tb.v
index 18a9a37..ce4a21d 100644
--- a/atk16_fpga/cu_tb.v
+++ b/atk16_fpga/cu_tb.v
@@ -5,16 +5,19 @@
module cu_tb();
reg clk, rst;
+ reg [3:0] int_lines;
cu dut(
.clk(clk),
- .rst(rst)
+ .rst(rst),
+ .int_lines(int_lines)
);
// Clock generation
always #5 clk = ~clk; // 100 MHz clock
reg failed;
+ reg [15:0] expected;
initial begin
failed = 0;
$dumpfile(`DUMPSTR(`VCD_OUTPUT));
@@ -22,18 +25,36 @@ module cu_tb();
clk = 0;
rst = 0;
+ int_lines = 4'b0000;
#10 // Wait for reset phase to finish
+ // set up halt instruction at PC = 1, used by all tests
+ dut.mem_fsm_inst.bram_inst.mem[1] = { 4'b1111, 12'd0 }; // HLT
+
// test ALR
dut.regbank[0] = 16'd10;
dut.regbank[1] = 16'd20;
dut.mem_fsm_inst.bram_inst.mem[0] = { 4'b0000, 3'd2, 3'd0, 3'd1, 3'd0 }; // ALR RC, RA, RB, S=PLUS
+ expected = 16'd30;
- #200 if (dut.regbank[2] == 16'd30) begin
+ #200 if (dut.regbank[2] == expected) begin
$display("\033[0;32m[PASS]\033[0m ALR ok");
end else begin
- $display("\033[0;31m[FAIL]\033[0m ALR not working, target reg contains %04h", dut.regbank[2]);
+ $display("\033[0;31m[FAIL]\033[0m ALR not working, target reg contains %04h, expected %04h", dut.regbank[2], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test ALI
+ dut.regbank[0] = 16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[0] = { 4'b0001, 3'd2, 3'd0, 3'd7, 3'd0 }; // ALI RC, RA, 7, S=PLUS
+ expected = 16'd17;
+
+ #200 if (dut.regbank[2] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m ALI ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m ALI not working, target reg contains %04h, expected %04h", dut.regbank[2], expected);
failed = 1;
end
rst = 1; #10 rst = 0; #10
@@ -42,11 +63,12 @@ module cu_tb();
dut.mem_fsm_inst.bram_inst.mem[16'd100] = 16'hffff;
dut.regbank[1] = 16'd100;
dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0010, 3'd0, 3'd1, 4'd0, 1'd1, 1'd1 }; // LDR RA, RB, absolute, direct
+ expected = 16'hffff;
- #200 if (dut.regbank[0] == 16'hffff) begin
- $display("\033[0;32m[PASS]\033[0m LDR absolute ok");
+ #200 if (dut.regbank[0] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m LDR direct absolute ok");
end else begin
- $display("\033[0;31m[FAIL]\033[0m LDR absolute not working, target reg contains %04h", dut.regbank[0]);
+ $display("\033[0;31m[FAIL]\033[0m LDR direct absolute not working, target reg contains %04h, expected %04h", dut.regbank[0], expected);
failed = 1;
end
rst = 1; #10 rst = 0; #10
@@ -55,16 +77,447 @@ module cu_tb();
dut.mem_fsm_inst.bram_inst.mem[16'd10] = 16'hffff;
dut.regbank[1] = 16'd10;
dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0010, 3'd0, 3'd1, 4'd0, 1'd0, 1'd1 }; // LDR RA, RB, relative, direct
+ expected = 16'hffff;
+
+ #200 if (dut.regbank[0] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m LDR direct relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDR direct relative not working, target reg contains %04h, expected %04h", dut.regbank[0], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test LDR, absolute addressing, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = 16'd200;
+ dut.mem_fsm_inst.bram_inst.mem[16'd200] = 16'hffff;
+ dut.regbank[1] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0010, 3'd0, 3'd1, 4'd0, 1'd1, 1'd0 }; // LDR RA, RB, absolute, indirect
+ expected = 16'hffff;
+
+ #200 if (dut.regbank[0] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m LDR indirect absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDR indirect absolute not working, target reg contains %04h, expected %04h", dut.regbank[0], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test LDR, relative addressing, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = 16'd20;
+ dut.mem_fsm_inst.bram_inst.mem[16'd20] = 16'hffff;
+ dut.regbank[1] = 16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0010, 3'd0, 3'd1, 4'd0, 1'd0, 1'd0 }; // LDR RA, RB, relative, indirect
+ expected = 16'hffff;
+
+ #200 if (dut.regbank[0] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m LDR indirect relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDR indirect relative not working, target reg contains %04h, expected %04h", dut.regbank[0], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test STR, absolute addressing, direct
+ dut.regbank[0] = 16'hfafa;
+ dut.regbank[1] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0011, 3'd0, 3'd1, 4'd0, 1'd1, 1'd1 }; // STR RB, RA, absolute, direct
+ expected = 16'hfafa;
+
+ #200 if (dut.mem_fsm_inst.bram_inst.mem[16'd100] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m STR direct absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m STR direct absolute not working, memory location contains %04h, expected %04h", dut.mem_fsm_inst.bram_inst.mem[16'd100], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test STR, relative addressing, direct
+ dut.regbank[0] = 16'hafaf;
+ dut.regbank[1] = 16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0011, 3'd0, 3'd1, 4'd0, 1'd0, 1'd1 }; // STR RB, RA, relative, direct
+ expected = 16'hafaf;
+
+ #200 if (dut.mem_fsm_inst.bram_inst.mem[16'd10] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m STR direct relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m STR direct relative not working, memory location contains %04h, expected %04h", dut.mem_fsm_inst.bram_inst.mem[16'd10], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test STR, absolute addressing, indirect
+ dut.regbank[0] = 16'hfafa;
+ dut.regbank[1] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = 16'd200;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0011, 3'd0, 3'd1, 4'd0, 1'd1, 1'd0 }; // STR RB, RA, absolute, indirect
+ expected = 16'hfafa;
+
+ #200 if (dut.mem_fsm_inst.bram_inst.mem[16'd200] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m STR indirect absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m STR indirect absolute not working, memory location contains %04h, expected %04h", dut.mem_fsm_inst.bram_inst.mem[16'd200], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test STR, relative addressing, indirect
+ dut.regbank[0] = 16'hafaf;
+ dut.regbank[1] = -16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = 16'd20;
+ dut.mem_fsm_inst.bram_inst.mem[16'd20] = { 4'b0011, 3'd0, 3'd1, 4'd0, 1'd0, 1'd0 }; // STR RB, RA, relative, indirect
+ dut.pc = 16'd20;
+ expected = 16'hafaf;
+
+ #200 if (dut.mem_fsm_inst.bram_inst.mem[16'd20] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m STR indirect relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m STR indirect relative not working, memory location contains %04h, expected %04h", dut.mem_fsm_inst.bram_inst.mem[16'd20], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test LDI, absolute addressing, direct
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0100, 3'd0, 7'd123, 1'd1, 1'd1 }; // LDI RA, 1, absolute, direct
+ expected = 16'd123;
+
+ #200 if (dut.regbank[0] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m LDI direct absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDI direct absolute not working, target reg contains %04h, expected %04h", dut.regbank[0], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test LDI, relative addressing, direct
+ dut.mem_fsm_inst.bram_inst.mem[16'd150] = { 4'b0100, 3'd0, -7'd20, 1'd0, 1'd1 }; // LDI RA, 1, relative, direct
+ dut.pc = 16'd150;
+ expected = 16'd130;
+
+ #200 if (dut.regbank[0] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m LDI direct relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDI direct relative not working, target reg contains %04h, expected %04h", dut.regbank[0], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test LDI, absolute addressing, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0100, 3'd0, 7'd50, 1'd1, 1'd0 }; // LDI RA, 1, absolute, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd50] = 16'd123;
+ expected = 16'd123;
+
+ #200 if (dut.regbank[0] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m LDI indirect absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDI indirect absolute not working, target reg contains %04h, expected %04h", dut.regbank[0], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test LDI, relative addressing, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd150] = { 4'b0100, 3'd0, -7'd20, 1'd0, 1'd0 }; // LDI RA, 1, relative, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd130] = 16'd123;
+ dut.pc = 16'd150;
+ expected = 16'd123;
+
+ #200 if (dut.regbank[0] == expected) begin
+ $display("\033[0;32m[PASS]\033[0m LDI indirect relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m LDI indirect relative not working, target reg contains %04h, expected %04h", dut.regbank[0], expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test JPR, absolute addressing, direct
+ dut.regbank[0] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0101, 1'd1, 1'd1, 3'd0, 7'd0 }; // JPR RA, absolute, direct
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd101; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m JPR direct absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m JPR direct absolute not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test JPR, relative addressing, direct
+ dut.regbank[0] = 16'd50;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0101, 1'd0, 1'd1, 3'd0, 7'd0 }; // JPR RA, relative, direct
+ dut.mem_fsm_inst.bram_inst.mem[16'd50] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd51; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m JPR direct relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m JPR direct relative not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test JPR, absolute addressing, indirect
+ dut.regbank[0] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = 16'd200;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0101, 1'd1, 1'd0, 3'd0, 7'd0 }; // JPR RA, absolute, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd200] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd201; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m JPR indirect absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m JPR indirect absolute not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test JPR, relative addressing, indirect
+ dut.regbank[0] = 16'd50;
+ dut.mem_fsm_inst.bram_inst.mem[16'd60] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = { 4'b0101, 1'd0, 1'd0, 3'd0, 7'd0 }; // JPR RA, relative, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = { 4'b1111, 12'd0 }; // HLT
+ dut.pc = 16'd10;
+ expected = 16'd101; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m JPR indirect relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m JPR indirect relative not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test JPI, absolute addressing, direct
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0110, 1'd1, 1'd1, 10'd123 }; // JPI 123, absolute, direct
+ dut.mem_fsm_inst.bram_inst.mem[16'd123] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd124; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m JPI direct absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m JPI direct absolute not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test JPI, relative addressing, direct
+ dut.mem_fsm_inst.bram_inst.mem[16'd30] = { 4'b0110, 1'd0, 1'd1, -10'd20 }; // JPI -20, relative, direct
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = { 4'b1111, 12'd0 }; // HLT
+ dut.pc = 16'd30;
+ expected = 16'd11; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m JPI direct relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m JPI direct relative not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test JPI, absolute addressing, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = { 4'b0110, 1'd1, 1'd0, 10'd50 }; // JPI 50, absolute, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd50] = 16'd123;
+ dut.mem_fsm_inst.bram_inst.mem[16'd123] = { 4'b1111, 12'd0 }; // HLT
+ dut.pc = 16'd10;
+ expected = 16'd124; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m JPI indirect absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m JPI indirect absolute not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test JPI, relative addressing, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd30] = { 4'b0110, 1'd0, 1'd0, -10'd20 }; // JPI -20, relative, indirect
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = 16'd50;
+ dut.mem_fsm_inst.bram_inst.mem[16'd50] = { 4'b1111, 12'd0 }; // HLT
+ dut.pc = 16'd30;
+ expected = 16'd51; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m JPI indirect relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m JPI indirect relative not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRR, absolute addressing, direct, true branch
+ dut.regbank[0] = 16'd100;
+ dut.regbank[2] = 16'd110;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd1] = { 4'b0111, 1'd1, 1'd1, 2'd0, 3'd2, 5'd0 }; // BRR RC, absolute, direct, F=ZERO
+ dut.mem_fsm_inst.bram_inst.mem[16'd2] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd110] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd111; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRR direct absolute true ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRR direct absolute true not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRR, absolute addressing, direct, false branch
+ dut.regbank[0] = 16'd100;
+ dut.regbank[2] = 16'd110;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd1] = { 4'b0111, 1'd1, 1'd1, 2'd1, 3'd2, 5'd0 }; // BRR RC, absolute, direct, F=NEGATIVE
+ dut.mem_fsm_inst.bram_inst.mem[16'd2] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd110] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd3; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRR direct absolute false ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRR direct absolute false not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRR, relative addressing, direct
+ dut.regbank[0] = 16'd100;
+ dut.regbank[2] = 16'd109;
+ dut.pc = 16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd11] = { 4'b0111, 1'd0, 1'd1, 2'd0, 3'd2, 5'd0 }; // BRR RC, relative, direct, F=ZERO
+ dut.mem_fsm_inst.bram_inst.mem[16'd12] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd120] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd121; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRR direct relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRR direct relative not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRR, absolute addressing, indirect
+ dut.regbank[0] = 16'd100;
+ dut.regbank[2] = 16'd110;
+ dut.mem_fsm_inst.bram_inst.mem[16'd110] = 16'd200;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd1] = { 4'b0111, 1'd1, 1'd0, 2'd0, 3'd2, 5'd0 }; // BRR RC, absolute, indirect, F=ZERO
+ dut.mem_fsm_inst.bram_inst.mem[16'd2] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd200] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd201; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRR indirect absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRR indirect absolute not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRR, relative addressing, indirect
+ dut.regbank[0] = 16'd100;
+ dut.regbank[2] = 16'd109;
+ dut.pc = 16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd11] = { 4'b0111, 1'd0, 1'd0, 2'd0, 3'd2, 5'd0 }; // BRR RC, relative, indirect, F=ZERO
+ dut.mem_fsm_inst.bram_inst.mem[16'd12] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd120] = 16'd130;
+ dut.mem_fsm_inst.bram_inst.mem[16'd130] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd131; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRR indirect relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRR indirect relative not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRI, absolute addressing, direct, true branch
+ dut.regbank[0] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd1] = { 4'b1000, 1'd1, 1'd1, 2'd0, 8'd100 }; // BRI 100, absolute, direct, F=ZERO
+ dut.mem_fsm_inst.bram_inst.mem[16'd2] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd101; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRI direct absolute true ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRI direct absolute true not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRI, absolute addressing, direct, false branch
+ dut.regbank[0] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd1] = { 4'b1000, 1'd1, 1'd1, 2'd1, 8'd100 }; // BRI 100, absolute, direct, F=NEGATIVE
+ dut.mem_fsm_inst.bram_inst.mem[16'd2] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd3; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRI direct absolute false ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRI direct absolute false not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRI, relative addressing, direct
+ dut.regbank[0] = 16'd100;
+ dut.pc = 16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd11] = { 4'b1000, 1'd0, 1'd1, 2'd0, 8'd9 }; // BRI 9, relative, direct, F=ZERO
+ dut.mem_fsm_inst.bram_inst.mem[16'd12] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd20] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd21; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRI direct relative ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRI direct relative not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRI, absolute addressing, indirect
+ dut.regbank[0] = 16'd100;
+ dut.mem_fsm_inst.bram_inst.mem[16'd100] = 16'd200;
+ dut.mem_fsm_inst.bram_inst.mem[16'd0] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd1] = { 4'b1000, 1'd1, 1'd0, 2'd0, 8'd100 }; // BRI 100, absolute, indirect, F=ZERO
+ dut.mem_fsm_inst.bram_inst.mem[16'd2] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd200] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd201; // PC ends up at &HLT + 1
+
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRI indirect absolute ok");
+ end else begin
+ $display("\033[0;31m[FAIL]\033[0m BRI indirect absolute not working, PC contains %04h, expected: %04h", dut.pc, expected);
+ failed = 1;
+ end
+ rst = 1; #10 rst = 0; #10
+
+ // test BRI, relative addressing, indirect
+ dut.regbank[0] = 16'd100;
+ dut.pc = 16'd10;
+ dut.mem_fsm_inst.bram_inst.mem[16'd10] = { 4'b0000, 3'd1, 3'd0, 3'd0, 3'd1 }; // ALR RB, RA, RA, S=MINUS
+ dut.mem_fsm_inst.bram_inst.mem[16'd11] = { 4'b1000, 1'd0, 1'd0, 2'd0, 8'd9 }; // BRI 9, relative, indirect, F=ZERO
+ dut.mem_fsm_inst.bram_inst.mem[16'd12] = { 4'b1111, 12'd0 }; // HLT
+ dut.mem_fsm_inst.bram_inst.mem[16'd20] = 16'd130;
+ dut.mem_fsm_inst.bram_inst.mem[16'd130] = { 4'b1111, 12'd0 }; // HLT
+ expected = 16'd131; // PC ends up at &HLT + 1
- #200 if (dut.regbank[0] == 16'hffff) begin
- $display("\033[0;32m[PASS]\033[0m LDR relative ok");
+ #200 if (dut.pc == expected) begin
+ $display("\033[0;32m[PASS]\033[0m BRI indirect relative ok");
end else begin
- $display("\033[0;31m[FAIL]\033[0m LDR relative not working, target reg contains %04h", dut.regbank[0]);
+ $display("\033[0;31m[FAIL]\033[0m BRI indirect relative not working, PC contains %04h, expected: %04h", dut.pc, expected);
failed = 1;
end
rst = 1; #10 rst = 0; #10
- #5
+ #200
if (failed) begin
$display("🛑 \033[0;31mTest suite failed\033[0m");
//$fatal(1);
diff --git a/atk16_fpga/mem_fsm.v b/atk16_fpga/mem_fsm.v
index d5419c5..051705e 100644
--- a/atk16_fpga/mem_fsm.v
+++ b/atk16_fpga/mem_fsm.v
@@ -1,11 +1,8 @@
`default_nettype none
`define ST_IDLE 3'd0
-`define ST_READ1 3'd1
-`define ST_READ2 3'd2
-`define ST_WRITE1 3'd4
-`define ST_WRITE2 3'd5
-`define ST_END 3'd7
+`define ST_READ 3'd1
+`define ST_WRITE 3'd2
module mem_fsm(
input clk,
@@ -23,7 +20,7 @@ module mem_fsm(
bram bram_inst(
.clk(clk),
.addr(bram_addr),
- .cs_n(0),
+ .cs_n(1'd0),
.wr_n(~wr),
.rd_n(~rd),
.bram_data_in(data_in),
@@ -35,29 +32,23 @@ module mem_fsm(
`ST_IDLE: begin
done <= 0;
if (~done && read_en) begin
- state <= `ST_READ1;
+ state <= `ST_READ;
bram_addr <= addr;
rd <= 1;
wr <= 0;
end
else if (~done && write_en) begin
- state <= `ST_WRITE1;
+ state <= `ST_WRITE;
bram_addr <= addr;
rd <= 0;
wr <= 1;
end
end
- `ST_READ1: begin
- state <= `ST_READ2;
- end
- `ST_READ2: begin
+ `ST_READ: begin
state <= `ST_IDLE;
done <= 1;
end
- `ST_WRITE1: begin
- state <= `ST_WRITE2;
- end
- `ST_WRITE2: begin
+ `ST_WRITE: begin
state <= `ST_IDLE;
done <= 1;
end
diff --git a/atk16_fpga/mem_fsm_tb.v b/atk16_fpga/mem_fsm_tb.v
index 5c5029c..8460327 100644
--- a/atk16_fpga/mem_fsm_tb.v
+++ b/atk16_fpga/mem_fsm_tb.v
@@ -4,7 +4,7 @@
module mem_fsm_tb();
- reg clk, rst, start_read, start_write;
+ reg clk, rst, read_en, write_en;
reg [15:0] addr, data_in;
wire done;
wire [15:0] data_out;
@@ -13,8 +13,8 @@ module mem_fsm_tb();
.clk(clk),
.addr(addr),
.data_in(data_in),
- .start_read(start_read),
- .start_write(start_write),
+ .read_en(read_en),
+ .write_en(write_en),
.data_out(data_out),
.done(done)
);
@@ -30,17 +30,18 @@ module mem_fsm_tb();
clk = 0;
rst = 0;
- start_read = 0;
- start_write = 0;
+ read_en = 0;
+ write_en = 0;
#10
// test read
dut.bram_inst.mem[0] = 16'hffff;
addr = 16'd0;
- start_read = 1;
- start_write = 0;
+ read_en = 1;
+ write_en = 0;
+
+ while (!done) #10;
- #40
if (data_out == 16'hffff && done == 1) begin
$display("\033[0;32m[PASS]\033[0m Read: data is available and done is 1 as expected");
end else begin
@@ -48,17 +49,18 @@ module mem_fsm_tb();
failed = 1;
end
- start_read = 0;
- start_write = 0;
+ read_en = 0;
+ write_en = 0;
#10
// test write
addr = 16'd1;
data_in = 16'hffff;
- start_read = 0;
- start_write = 1;
+ read_en = 0;
+ write_en = 1;
+
+ while (!done) #10;
- #40
if (dut.bram_inst.mem[1] == 16'hffff && done == 1) begin
$display("\033[0;32m[PASS]\033[0m Write: data is available and done is 1 as expected");
end else begin
@@ -66,8 +68,8 @@ module mem_fsm_tb();
failed = 1;
end
- start_read = 0;
- start_write = 0;
+ read_en = 0;
+ write_en = 0;
#5
if (failed) begin