From 3358706760688f86df9141b6bc980b2f4ae905a5 Mon Sep 17 00:00:00 2001 From: Denis Tereshkin Date: Sat, 6 Dec 2025 11:52:11 +0700 Subject: [PATCH] Add compare instructions --- src/alu.verilog | 6 ++ src/cpu.verilog | 153 +++++++++++++++++++++++++++++++++++++++++++++- src/parameters.vh | 1 + 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/src/alu.verilog b/src/alu.verilog index 5954282..69cba7f 100644 --- a/src/alu.verilog +++ b/src/alu.verilog @@ -53,6 +53,12 @@ always_comb r_c = sum[8]; r_v = !(A[7] ^ B[7]) & (A[7] ^ sum[7]); end + OP_CMP: + begin + result = {1'b0, A} - {1'b0, B}; + r_c = diff[8]; + r_v = 0; + end OP_SUB: begin result = diff; diff --git a/src/cpu.verilog b/src/cpu.verilog index 783dd0a..c5d871e 100644 --- a/src/cpu.verilog +++ b/src/cpu.verilog @@ -276,6 +276,20 @@ always_comb alu_op_c = P[P_C]; alu_op_sel = OP_ROT; end + else if (decoded_instr == I_CPX) + begin + alu_op_1 = X; + alu_op_2 = mem_data; + alu_op_c = 1'b1; + alu_op_sel = OP_CMP; + end + else if (decoded_instr == I_CPY) + begin + alu_op_1 = Y; + alu_op_2 = mem_data; + alu_op_c = 1'b1; + alu_op_sel = OP_CMP; + end else begin alu_op_1 = A; @@ -305,6 +319,11 @@ always_comb alu_op_c = P[P_C]; alu_op_sel = OP_SUB; end + else if (decoded_instr == I_CMP) + begin + alu_op_c = 1; + alu_op_sel = OP_CMP; + end end end @@ -423,6 +442,13 @@ always @(posedge clk) begin pending_a_read <= READ_SOURCE_ALU; end + else if (decoded_instr == I_CMP || + decoded_instr == I_CPX || + decoded_instr == I_CPY) + begin + pending_nz_alu_update <= 1; + pending_c_alu_update <= 1; + end state <= STATE_FETCH; PC <= PC + 1; @@ -590,7 +616,10 @@ always @(posedge clk) decoded_instr == I_ASL || decoded_instr == I_LSR || decoded_instr == I_ROL || - decoded_instr == I_ROR) + decoded_instr == I_ROR || + decoded_instr == I_CMP || + decoded_instr == I_CPX || + decoded_instr == I_CPY) begin pending_c_alu_update <= 1; pending_nz_alu_update <= 1'b1; @@ -686,6 +715,13 @@ always @(posedge clk) begin PC <= mem_addr; end + else if(decoded_instr == I_CMP || + decoded_instr == I_CPX || + decoded_instr == I_CPY) + begin + pending_c_alu_update <= 1; + pending_nz_alu_update <= 1; + end end else if (state == STATE_READ_ADDR_ZP) begin @@ -716,7 +752,9 @@ always @(posedge clk) extra_timing <= 1; end if (decoded_instr == I_ASL || decoded_instr == I_LSR || - decoded_instr == I_ROL || decoded_instr == I_ROR) + decoded_instr == I_ROL || decoded_instr == I_ROR || + decoded_instr == I_CMP || decoded_instr == I_CPX || + decoded_instr == I_CPY ) begin pending_nz_alu_update <= 1; pending_c_alu_update <= 1; @@ -1320,6 +1358,114 @@ always @(posedge clk) assert(Y == f_prev_Y); end + +always @(posedge clk) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_CMP) + begin + cover($past(address_code) == ADDR_MODE_IMMEDIATE); + cover($past(address_code) == ADDR_MODE_ZP); + cover($past(address_code) == ADDR_MODE_INDEXED_ZP); + cover($past(address_code) == ADDR_MODE_ABSOLUTE); + cover($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_X); + cover($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_Y); + cover($past(address_code) == ADDR_MODE_PREINDEXED_INDIRECT); + cover($past(address_code) == ADDR_MODE_POSTINDEXED_INDIRECT); + + if ($past(address_code) == ADDR_MODE_IMMEDIATE) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 2); + end + else if ($past(address_code) == ADDR_MODE_ZP) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 3); + end + else if ($past(address_code) == ADDR_MODE_INDEXED_ZP) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 4); + end + else if ($past(address_code) == ADDR_MODE_ABSOLUTE) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 4); + end + else if ($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_X) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 4); + end + else if ($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_Y) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 4); + end + else if ($past(address_code) == ADDR_MODE_PREINDEXED_INDIRECT) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 6); + end + else if ($past(address_code) == ADDR_MODE_POSTINDEXED_INDIRECT) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 5); + end + + assert(P[P_Z] == (A == $past(mem_data))); + assert(P[P_C] == ({1'b0, f_prev_A} - {1'b0, $past(mem_data)} >= 9'h100)); + assert(P[P_N] == (((A - $past(mem_data)) & 8'h80) == 8'h80)); + assert(P[P_V] == f_prev_P[P_V]); + assert(A == f_prev_A); + assert(S == f_prev_S); + assert(X == f_prev_X); + assert(Y == f_prev_Y); + end + +always @(posedge clk) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_CPX || f_prev_instruction == I_CPY) + begin + cover($past(address_code) == ADDR_MODE_IMMEDIATE); + cover($past(address_code) == ADDR_MODE_ZP); + cover($past(address_code) == ADDR_MODE_ABSOLUTE); + + if ($past(address_code) == ADDR_MODE_IMMEDIATE) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 2); + end + else if ($past(address_code) == ADDR_MODE_ZP) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 3); + end + else if ($past(address_code) == ADDR_MODE_ABSOLUTE) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 4); + end + + if (f_prev_instruction == I_CPX) + begin + assert(P[P_Z] == (X == $past(mem_data))); + assert(P[P_C] == ({1'b0, f_prev_X} - {1'b0, $past(mem_data)} >= 9'h100)); + assert(P[P_N] == (((X - $past(mem_data)) & 8'h80) == 8'h80)); + end + else if (f_prev_instruction == I_CPY) + begin + assert(P[P_Z] == (Y == $past(mem_data))); + assert(P[P_C] == ({1'b0, f_prev_Y} - {1'b0, $past(mem_data)} >= 9'h100)); + assert(P[P_N] == (((Y - $past(mem_data)) & 8'h80) == 8'h80)); + end + assert(P[P_V] == f_prev_P[P_V]); + assert(A == f_prev_A); + assert(S == f_prev_S); + assert(X == f_prev_X); + assert(Y == f_prev_Y); + end + always @(posedge clk) if (f_prev_valid && state == STATE_EXECUTE) if (f_prev_instruction == I_INC || @@ -1627,6 +1773,9 @@ begin decoded_instr == I_CLI || decoded_instr == I_SEI || decoded_instr == I_CLV || + decoded_instr == I_CMP || + decoded_instr == I_CPX || + decoded_instr == I_CPY || decoded_instr == I_BNE || decoded_instr == I_JMP ); diff --git a/src/parameters.vh b/src/parameters.vh index 114854d..ca527f5 100644 --- a/src/parameters.vh +++ b/src/parameters.vh @@ -18,6 +18,7 @@ localparam OP_ADC = 3; localparam OP_SUB = 4; localparam OP_ROT = 5; localparam OP_SHF = 6; +localparam OP_CMP = 7; localparam SHIFT_LEFT = 0; localparam SHIFT_RIGHT = 1;