diff --git a/src/cpu.verilog b/src/cpu.verilog index da29808..aa58a89 100644 --- a/src/cpu.verilog +++ b/src/cpu.verilog @@ -26,7 +26,10 @@ module cpu localparam STATE_EXECUTE_IDX_2 = 9; localparam STATE_EXECUTE_POST_IDX_1 = 10; localparam STATE_EXECUTE_POST_IDX_2 = 11; - localparam STATE_DELAY = 12; + localparam STATE_READ_ADDR_ZP = 12; + localparam STATE_READ_ADDR_ZP_2 = 13; + localparam STATE_EXECUTE_ABS_ALU = 14; + localparam STATE_WRITE_ABS_ALU = 15; localparam READ_SOURCE_NONE = 2'h0, @@ -50,7 +53,7 @@ localparam reg [7:0] tmp; - reg [3:0] state; + reg [4:0] state; reg [7:0] instr; @@ -86,6 +89,7 @@ localparam logic [1:0] pending_x_read; logic [1:0] pending_y_read; logic pending_rel_branch; + logic pending_nz_alu_update; wire is_arith; logic [2:0] extra_timing; reg [3:0] state_after_delay; @@ -102,6 +106,7 @@ initial pending_a_read = 0; initial pending_x_read = 0; initial pending_y_read = 0; initial pending_rel_branch = 0; +initial pending_nz_alu_update = 0; initial mem_aux_addr = 0; initial instr = 0; initial extra_timing = 0; @@ -215,6 +220,20 @@ always_comb alu_op_c = 1'b1; alu_op_sel = OP_SUB; end + else if (decoded_instr == I_INC) + begin + alu_op_1 = mem_data; + alu_op_2 = 1'b1; + alu_op_c = 0; + alu_op_sel = OP_ADC; + end + else if (decoded_instr == I_DEC) + begin + alu_op_1 = mem_data; + alu_op_2 = 1'b1; + alu_op_c = 1'b1; + alu_op_sel = OP_SUB; + end else begin alu_op_1 = A; @@ -307,6 +326,13 @@ always @(posedge clk) end pending_y_read <= READ_SOURCE_NONE; + if (pending_nz_alu_update) + begin + P[P_Z] <= alu_z; + P[P_N] <= alu_n; + end + pending_nz_alu_update <= 0; + PC <= PC + 1; state <= STATE_EXECUTE; end @@ -320,6 +346,12 @@ always @(posedge clk) begin PC <= PC + 1; state <= STATE_FETCH_DATA_2; + if (decoded_instr == I_STA && + (address_code == ADDR_MODE_INDEXED_ABSOLUTE_X || + address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y)) + begin + extra_timing <= 1; + end end else if (address_code == ADDR_MODE_IMMEDIATE) begin @@ -350,13 +382,29 @@ always @(posedge clk) else if (address_code == ADDR_MODE_ZP) begin mem_sel <= DMUX_AUX; - state <= STATE_EXECUTE_ZP; + if (decoded_instr == I_INC || + decoded_instr == I_DEC) + begin + state <= STATE_READ_ADDR_ZP; + end + else + begin + state <= STATE_EXECUTE_ZP; + end PC <= PC + 1; end else if (address_code == ADDR_MODE_INDEXED_ZP) begin mem_sel <= DMUX_AUX; - state <= STATE_EXECUTE_ZPX; + if (decoded_instr == I_INC || + decoded_instr == I_DEC) + begin + state <= STATE_READ_ADDR_ZP; + end + else + begin + state <= STATE_EXECUTE_ZPX; + end PC <= PC + 1; end else if (address_code == ADDR_MODE_PREINDEXED_INDIRECT) @@ -374,12 +422,12 @@ always @(posedge clk) end else if (address_code == ADDR_MODE_IMPLIED) begin - if (decoded_instr == I_DEX) + if (decoded_instr == I_DEX || decoded_instr == I_INX) begin pending_x_read <= READ_SOURCE_ALU; state <= STATE_FETCH; end - else if (decoded_instr == I_DEY) + else if (decoded_instr == I_DEY || decoded_instr == I_INY) begin pending_y_read <= READ_SOURCE_ALU; state <= STATE_FETCH; @@ -438,6 +486,11 @@ always @(posedge clk) begin pending_a_read <= READ_SOURCE_ALU; end + else if (decoded_instr == I_DEC || + decoded_instr == I_INC) + begin + pending_nz_alu_update <= 1'b1; + end state <= STATE_FETCH; end @@ -488,7 +541,14 @@ always @(posedge clk) mem_aux_addr[7:0] <= mem_data; mem_sel <= DMUX_AUX; - state <= STATE_EXECUTE_DATA_2; + if (decoded_instr == I_DEC || decoded_instr == I_INC) + begin + state <= STATE_EXECUTE_ABS_ALU; + end + else + begin + state <= STATE_EXECUTE_DATA_2; + end PC <= PC + 1'b1; end else if (state == STATE_EXECUTE_DATA_2) @@ -521,12 +581,50 @@ always @(posedge clk) PC <= mem_addr; end end + else if (state == STATE_READ_ADDR_ZP) + begin + mem_sel <= DMUX_AUX2; + mem_aux2_addr <= (mem_data + X) & 16'hff; + state <= STATE_READ_ADDR_ZP_2; + if (address_code == ADDR_MODE_INDEXED_ZP) + begin + extra_timing <= 1; + end + end + else if (state == STATE_READ_ADDR_ZP_2) + begin + state <= STATE_EXECUTE_ZP; + end + else if (state == STATE_EXECUTE_ABS_ALU) + begin + mem_sel <= DMUX_AUX2; + state <= STATE_WRITE_ABS_ALU; + mem_aux2_addr[7:0] <= mem_aux_addr[7:0]; + mem_aux2_addr[15:8] <= mem_data[7:0]; + if (address_code == ADDR_MODE_INDEXED_ABSOLUTE_X) + begin + extra_timing <= 2; + end + else if (address_code == ADDR_MODE_ABSOLUTE) + begin + extra_timing <= 1; + end + end + else if (state == STATE_WRITE_ABS_ALU) + begin + mem_sel <= DMUX_PC; + state <= STATE_FETCH; + end always_comb begin mem_data_wr = 0; mem_wr = 0; - if (state == STATE_EXECUTE_DATA_2) + if (extra_timing != 0) + begin + mem_wr = 0; + end + else if (state == STATE_EXECUTE_DATA_2) begin if (decoded_instr == I_STA) begin @@ -561,6 +659,17 @@ always_comb mem_wr = 1'b1; mem_data_wr = Y; end + else if(decoded_instr == I_DEC || + decoded_instr == I_INC) + begin + mem_wr = 1'b1; + mem_data_wr = alu_op_result; + end + end + else if (state == STATE_WRITE_ABS_ALU) + begin + mem_wr = 1'b1; + mem_data_wr = alu_op_result; end end @@ -576,16 +685,37 @@ always_comb logic [7:0] f_prev_instruction; logic [4:0] f_prev_addr_code; logic f_prev_instruction_is_branch; + logic [4:0] f_prev_instr_cycles; + logic [4:0] f_instr_cycles; + logic f_prev_valid; + logic [7:0] f_prev_X; + logic [7:0] f_prev_Y; + logic [7:0] f_prev_A; + logic [15:0] f_prev_PC; + logic [7:0] f_prev_S; + logic [7:0] f_prev_P; + +initial f_prev_instr_cycles = 0; +initial f_instr_cycles = 0; initial f_prev_instruction = 0; initial f_prev_addr_code = 0; +initial f_prev_valid = 0; +initial f_prev_X = 0; +initial f_prev_Y = 0; +initial f_prev_A = 0; +initial f_prev_PC = 0; +initial f_prev_S = 0; +initial f_prev_P = 0; + initial f_past_valid = 0; initial f2_past_valid = 0; initial f3_past_valid = 0; initial f4_past_valid = 0; initial f5_past_valid = 0; initial f6_past_valid = 0; + always @(posedge clk) f_past_valid <= 1; @@ -616,10 +746,44 @@ always @(posedge clk) f_instr_count <= f_instr_count + 1'b1; always @(posedge clk) - if (f2_past_valid && state == STATE_FETCH && $past(state) != STATE_FETCH) + if (state == STATE_FETCH && $past(state) != STATE_FETCH) + begin + f_instr_cycles <= 1'b1; + f_prev_instr_cycles <= f_instr_cycles; + end + else begin - f_prev_instruction <= $past(decoded_instr); - f_prev_addr_code <= $past(address_code); + f_instr_cycles <= f_instr_cycles + 1'b1; + end + + + logic [15:0] f_abs_address; + +initial f_abs_address = 0; +always @(posedge clk) + begin + if (f_past_valid && address_code == ADDR_MODE_ABSOLUTE && state == STATE_EXECUTE_DATA_2) + begin + f_abs_address[15:8] = mem_data; + f_abs_address[7:0] = $past(mem_data); + end + end + +always @(posedge clk) + cover(f_instr_count > 16); + +always @(posedge clk) + if (f_past_valid && state == STATE_FETCH && $past(state) != STATE_FETCH) + begin + f_prev_valid <= 1; + f_prev_instruction <= decoded_instr; + f_prev_addr_code <= address_code; + f_prev_X <= X; + f_prev_Y <= Y; + f_prev_A <= A; + f_prev_PC <= PC; + f_prev_S <= S; + f_prev_P <= P; end always @(*) @@ -638,11 +802,12 @@ always @(*) f_prev_instruction == I_RTI); always @(posedge clk) - if (f2_past_valid && state == STATE_EXECUTE) - if ($past(decoded_instr) == I_DEX) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_DEX) begin - assert(X == $past(X, 2) - 8'd1); - assert($past(PC) == $past(PC, 3) + 16'd1); + assert(S == f_prev_S); + assert(X == f_prev_X - 8'd1); + assert($past(PC) == $past(f_prev_PC) + 16'd1); assert(P[P_Z] == (X == 0)); assert(P[P_N] == (X[7] == 1)); assert($stable(P[P_C])); @@ -650,14 +815,16 @@ always @(posedge clk) assert($stable(P[P_B])); assert($stable(P[P_D])); assert($stable(P[P_I])); + assert(f_prev_instr_cycles == 2); end always @(posedge clk) - if (f2_past_valid && state == STATE_EXECUTE) - if ($past(decoded_instr) == I_DEY) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_DEY) begin - assert(Y == $past(Y, 2) - 8'd1); - assert($past(PC) == $past(PC, 3) + 16'd1); + assert(S == f_prev_S); + assert(Y == f_prev_Y - 8'd1); + assert($past(PC) == $past(f_prev_PC) + 16'd1); assert(P[P_Z] == (Y == 0)); assert(P[P_N] == (Y[7] == 1)); assert($stable(P[P_C])); @@ -665,403 +832,448 @@ always @(posedge clk) assert($stable(P[P_B])); assert($stable(P[P_D])); assert($stable(P[P_I])); + assert(f_prev_instr_cycles == 2); end always @(posedge clk) - if (f2_past_valid && state == STATE_EXECUTE) - if ($past(decoded_instr) == I_LDY && $past(address_code) == ADDR_MODE_IMMEDIATE) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_LDY) begin + cover($past(address_code) == ADDR_MODE_IMMEDIATE); + cover($past(address_code) == ADDR_MODE_ABSOLUTE); + cover($past(address_code) == ADDR_MODE_ZP); + cover($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_X); + cover($past(address_code) == ADDR_MODE_INDEXED_ZP); + + 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_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_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_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_ZP) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 4); + end + assert(Y == $past(mem_data)); assert(P[P_Z] == (Y == 0)); assert(P[P_N] == (Y[7] == 1)); - if (f3_past_valid) - begin - assert($past(PC) == $past(PC, 3) + 16'd2); - end + assert(X == f_prev_X); + assert(A == f_prev_A); + assert(S == f_prev_S); end always @(posedge clk) - if (f2_past_valid && state == STATE_EXECUTE) - if ($past(decoded_instr) == I_LDA && $past(address_code) == ADDR_MODE_IMMEDIATE) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_LDX) begin - assert(A == $past(mem_data)); - assert(P[P_Z] == (A == 0)); - assert(P[P_N] == (A[7] == 1)); - if (f3_past_valid) + cover($past(address_code) == ADDR_MODE_IMMEDIATE); + cover($past(address_code) == ADDR_MODE_ABSOLUTE); + cover($past(address_code) == ADDR_MODE_ZP); + cover($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_Y); + cover($past(address_code) == ADDR_MODE_INDEXED_ZP); + + if ($past(address_code) == ADDR_MODE_IMMEDIATE) begin - assert($past(PC) == $past(PC, 3) + 16'd2); + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 2); + 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_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_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_INDEXED_ZP) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 4); end - end - - logic [15:0] f_abs_address; - -initial f_abs_address = 0; -always_comb - begin - f_abs_address = 0; - if (f_past_valid) - begin - f_abs_address[15:8] = mem_data; - f_abs_address[7:0] = mem_aux_addr; - end - end - -always @(posedge clk) - if (f_past_valid) -begin - assume(decoded_instr == I_LDA || - decoded_instr == I_LDX || - decoded_instr == I_LDY || - decoded_instr == I_STA || - decoded_instr == I_STX || - decoded_instr == I_STY || - decoded_instr == I_AND || - decoded_instr == I_EOR || - decoded_instr == I_ORA || - decoded_instr == I_ADC || - decoded_instr == I_SBC || - decoded_instr == I_DEX || - decoded_instr == I_DEY || - decoded_instr == I_BNE || - decoded_instr == I_JMP -); - assume(address_code != ADDR_MODE_INDIRECT); - end -always @(posedge clk) - if (f6_past_valid && state == STATE_EXECUTE && $past(state) == STATE_FETCH) - begin - if (f_prev_instruction == I_EOR) - assert(A == ($past(A) ^ $past(mem_data))); - else if (f_prev_instruction == I_AND) - assert(A == ($past(A) & $past(mem_data))); - else if (f_prev_instruction == I_ORA) - assert(A == ($past(A) | $past(mem_data))); - else if (f_prev_instruction == I_ADC) - assert(A == ($past(A) + $past(mem_data) + $past(P[P_C]))); - else if (f_prev_instruction == I_SBC) - assert(A == ($past(A) - $past(mem_data) - (1'b1 - $past(P[P_C])))); - else if (f_prev_instruction == I_LDA) - assert(A == $past(mem_data)); - else if (f_prev_instruction == I_LDX) + assert(S == f_prev_S); assert(X == $past(mem_data)); - else if (f_prev_instruction == I_LDY) - assert(Y == $past(mem_data)); - else if (f_prev_instruction == I_STA) - assert(A == $past(A)); - else if (f_prev_instruction == I_STX) - assert(X == $past(X)); - else if (f_prev_instruction == I_STY) - assert(Y == $past(Y)); - - if (f_prev_instruction == I_STA) - begin - assert($past(mem_wr, 2) == 1'b1); - assert($past(mem_data_wr, 2) == $past(A, 2)); - end - else if (f_prev_instruction == I_STX) - begin - assert($past(mem_wr, 2) == 1'b1); - assert($past(mem_data_wr, 2) == $past(X, 2)); - end - else if (f_prev_instruction == I_STY) - begin - assert($past(mem_wr, 2) == 1'b1); - assert($past(mem_data_wr, 2) == $past(Y, 2)); - end - else - begin - assert($past(mem_wr, 2) == 1'b0); - end - - if ($past(address_code, 2) == ADDR_MODE_ABSOLUTE) - assert($past(f_abs_address, 2) == $past(mem_addr_eff, 2)); - else if ($past(address_code, 2) == ADDR_MODE_ZP) - assert($past(mem_data, 2) == $past(mem_addr_eff, 2)); - else if ($past(address_code, 2) == ADDR_MODE_INDEXED_ZP) - begin - if (f_prev_instruction != I_LDX) - assert((($past(mem_data, 3) + $past(X, 3)) & 16'hff) == $past(mem_addr_eff, 2)); - else - assert((($past(mem_data, 3) + $past(Y, 3)) & 16'hff) == $past(mem_addr_eff, 2)); - end - else if ($past(address_code, 2) == ADDR_MODE_INDEXED_ABSOLUTE_X) - assert((($past(f_abs_address, 2) + $past(X, 2)) & 16'hffff) == $past(mem_addr_eff, 2)); - else if ($past(address_code, 2) == ADDR_MODE_INDEXED_ABSOLUTE_Y) - assert((($past(f_abs_address, 2) + $past(Y, 2)) & 16'hffff) == $past(mem_addr_eff, 2)); - else if ($past(address_code, 2) == ADDR_MODE_PREINDEXED_INDIRECT) - begin - assert($past(f_abs_address, 2) == $past(mem_addr_eff, 2)); - assert($past(mem_addr_eff, 4) == (($past(mem_data, 5) + $past(X, 5)) & 8'hff)); - end - else if ($past(address_code, 2) == ADDR_MODE_POSTINDEXED_INDIRECT) - begin - assert(($past(f_abs_address, 2) + $past(Y, 2)) == $past(mem_addr_eff, 2)); - end + assert(P[P_Z] == (X == 0)); + assert(P[P_N] == (X[7] == 1)); + assert(Y == f_prev_Y); + assert(A == f_prev_A); + end - if (f_prev_instruction == I_LDX || - f_prev_instruction == I_DEX) +always @(posedge clk) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_LDA) + begin + cover($past(address_code) == ADDR_MODE_IMMEDIATE); + cover($past(address_code) == ADDR_MODE_ABSOLUTE); + cover($past(address_code) == ADDR_MODE_ZP); + cover($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_X); + cover($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_Y); + cover($past(address_code) == ADDR_MODE_INDEXED_ZP); + 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(P[P_Z] == (X == 0)); - assert(P[P_N] == (X[7] == 1)); + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 2); end - else if (f_prev_instruction == I_LDY || - f_prev_instruction == I_DEY) + else if ($past(address_code) == ADDR_MODE_ABSOLUTE) begin - assert(P[P_Z] == (Y == 0)); - assert(P[P_N] == (Y[7] == 1)); + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 4); + 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_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_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_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 - else if (f_prev_instruction == I_LDA || - f_prev_instruction == I_ORA || - f_prev_instruction == I_AND || - f_prev_instruction == I_EOR || - f_prev_instruction == I_ADC || - f_prev_instruction == I_SBC) - begin - assert(P[P_Z] == (A == 0)); - assert(P[P_N] == (A[7] == 1)); - end - else - begin - assert(P[P_Z] == $past(P[P_Z], 2)); - assert(P[P_N] == $past(P[P_N], 2)); - end - if (f_prev_instruction == I_ADC) - begin - assert(P[P_C] == ({1'b0, $past(A)} + - {1'b0, $past(mem_data)} + - {8'b0, $past(P[P_C])} >= 9'h100)); - assert(P[P_V] == (($past(A[7]) ^ A[7]) & ($past(mem_data[7]) ^ A[7]))); - end - else if (f_prev_instruction == I_SBC) - begin - assert(P[P_C] == ({1'b0, $past(A)} - - {1'b0, $past(mem_data)} - - {8'b0, ~$past(P[P_C])} >= 9'h100)); - assert(P[P_V] == (($past(A[7]) ^ A[7]) & ($past(mem_data[7]) ^ A[7]))); - end - else - begin - assert(P[P_C] == $past(P[P_C], 2)); - assert(P[P_V] == $past(P[P_V], 2)); - end - assert(P[P_B] == $past(P[P_B], 2)); - assert(P[P_D] == $past(P[P_D], 2)); - assert(P[P_I] == $past(P[P_I], 2)); - assert(S == $past(S, 2)); - if (f_prev_instruction != I_LDX && - f_prev_instruction != I_DEX && - f_prev_instruction != I_INX) - begin - assert(X == $past(X, 2)); - end - if (f_prev_instruction != I_LDY && - f_prev_instruction != I_DEY && - f_prev_instruction != I_INY) - begin - assert(Y == $past(Y, 2)); - end - if (f6_past_valid && !f_prev_instruction_is_branch) - begin - if ($past(address_code, 2) == ADDR_MODE_ABSOLUTE) - assert($past(PC, 1) == $past(PC, 5) + 16'd3); - else if ($past(address_code, 2) == ADDR_MODE_ZP) - assert($past(PC, 1) == $past(PC, 4) + 16'd2); - else if ($past(address_code, 2) == ADDR_MODE_INDEXED_ZP) - assert($past(PC, 1) == $past(PC, 5) + 16'd2); - else if ($past(address_code, 2) == ADDR_MODE_IMMEDIATE) - assert($past(PC, 1) == $past(PC, 3) + 16'd2); - else if ($past(address_code, 2) == ADDR_MODE_PREINDEXED_INDIRECT) - assert($past(PC, 1) == $past(PC, 7) + 16'd2); - - if (f_prev_instruction != I_STA) - begin - if ($past(address_code, 2) == ADDR_MODE_INDEXED_ABSOLUTE_X) - assert($past(PC, 1) == $past(PC, 5) + 16'd3); - else if ($past(address_code, 2) == ADDR_MODE_INDEXED_ABSOLUTE_Y) - assert($past(PC, 1) == $past(PC, 5) + 16'd3); - else if ($past(address_code, 2) == ADDR_MODE_POSTINDEXED_INDIRECT) - assert($past(PC, 1) == $past(PC, 6) + 16'd2); - end - else - begin - if ($past(address_code, 2) == ADDR_MODE_INDEXED_ABSOLUTE_X) - assert($past(PC, 1) == $past(PC, 5) + 16'd3); - else if ($past(address_code, 2) == ADDR_MODE_INDEXED_ABSOLUTE_Y) - assert($past(PC, 1) == $past(PC, 5) + 16'd3); - else if ($past(address_code, 2) == ADDR_MODE_POSTINDEXED_INDIRECT) - assert($past(PC, 1) == $past(PC, 7) + 16'd2); - end - end - end + assert(S == f_prev_S); + assert(A == $past(mem_data)); + assert(P[P_Z] == (A == 0)); + assert(P[P_N] == (A[7] == 1)); + assert(X == f_prev_X); + assert(Y == f_prev_Y); + end always @(posedge clk) - if (f2_past_valid && state == STATE_FETCH) - if ($past(decoded_instr) == I_BNE && $past(address_code) == ADDR_MODE_RELATIVE) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_STA) begin - if ($past(state) == STATE_BRANCH) + cover($past(address_code) == ADDR_MODE_ABSOLUTE); + cover($past(address_code) == ADDR_MODE_ZP); + cover($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_X); + cover($past(address_code) == ADDR_MODE_INDEXED_ABSOLUTE_Y); + cover($past(address_code) == ADDR_MODE_INDEXED_ZP); + cover($past(address_code) == ADDR_MODE_PREINDEXED_INDIRECT); + cover($past(address_code) == ADDR_MODE_POSTINDEXED_INDIRECT); + + if ($past(address_code) == ADDR_MODE_ABSOLUTE) begin - assert(PC == $past(PC) + {{8{$past(mem_data[7])}}, mem_data[7:0]} + 1'b1); - assert(!$past(P[P_Z])); + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 4); + assert(f_abs_address == $past(mem_addr_eff, 2)); end - else + 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_ABSOLUTE_X) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 5); + 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 == 5); + end + else if ($past(address_code) == ADDR_MODE_INDEXED_ZP) begin - assert(PC == $past(PC) + 1'b1); - assert($past(P[P_Z])); + assert($past(PC) == $past(f_prev_PC) + 16'd2); + 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 == 6); + end + + assert(S == f_prev_S); + assert(A == $past(mem_data_wr, 2)); + assert(1 == $past(mem_wr, 2)); + assert(A == f_prev_A); + assert(X == f_prev_X); + assert(Y == f_prev_Y); end always @(posedge clk) - if (f3_past_valid && state == STATE_FETCH) - if ($past(decoded_instr) == I_JMP && $past(address_code) == ADDR_MODE_ABSOLUTE) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_STX) begin - assert(PC == $past(f_abs_address)); - assert(P == $past(P, 3)); - assert(S == $past(S, 3)); - assert(A == $past(A, 3)); - assert(X == $past(X, 3)); - assert(Y == $past(Y, 3)); + cover($past(address_code) == ADDR_MODE_ABSOLUTE); + cover($past(address_code) == ADDR_MODE_ZP); + cover($past(address_code) == ADDR_MODE_INDEXED_ZP); + + if ($past(address_code) == ADDR_MODE_ABSOLUTE) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 4); + assert(f_abs_address == $past(mem_addr_eff, 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 + + assert(S == f_prev_S); + assert(X == $past(mem_data_wr, 2)); + assert(1 == $past(mem_wr, 2)); + assert(X == f_prev_X); + assert(A == f_prev_A); + assert(Y == f_prev_Y); end always @(posedge clk) - cover(state == STATE_EXECUTE); + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_STY) + begin + cover($past(address_code) == ADDR_MODE_ABSOLUTE); + cover($past(address_code) == ADDR_MODE_ZP); + cover($past(address_code) == ADDR_MODE_INDEXED_ZP); -always @(posedge clk) - cover(f6_past_valid); + if ($past(address_code) == ADDR_MODE_ABSOLUTE) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 4); + assert(f_abs_address == $past(mem_addr_eff, 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 -always @(posedge clk) - cover(f_instr_count > 16); + assert(S == f_prev_S); + assert(Y == $past(mem_data_wr, 2)); + assert(1 == $past(mem_wr, 2)); + assert(X == f_prev_X); + assert(A == f_prev_A); + assert(Y == f_prev_Y); + end always @(posedge clk) - begin - if (decoded_instr == I_ADC) - begin - cover(address_code == ADDR_MODE_IMMEDIATE); - cover(address_code == ADDR_MODE_ABSOLUTE); - cover(address_code == ADDR_MODE_ZP); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_X); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y); - cover(address_code == ADDR_MODE_INDEXED_ZP); - cover(address_code == ADDR_MODE_PREINDEXED_INDIRECT); - cover(address_code == ADDR_MODE_POSTINDEXED_INDIRECT); - end - end + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_EOR || + f_prev_instruction == I_AND || + f_prev_instruction == I_ORA || + f_prev_instruction == I_ADC || + f_prev_instruction == I_SBC) + 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 (f_prev_instruction == I_EOR) + assert(A == ($past(A) ^ $past(mem_data))); + else if (f_prev_instruction == I_AND) + assert(A == ($past(A) & $past(mem_data))); + else if (f_prev_instruction == I_ORA) + assert(A == ($past(A) | $past(mem_data))); + else if (f_prev_instruction == I_ADC) + assert(A == ($past(A) + $past(mem_data) + $past(P[P_C]))); + else if (f_prev_instruction == I_SBC) + assert(A == ($past(A) - $past(mem_data) - (1'b1 - $past(P[P_C])))); + + 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 -always @(posedge clk) - begin - if (decoded_instr == I_SBC) - begin - cover(address_code == ADDR_MODE_IMMEDIATE); - cover(address_code == ADDR_MODE_ABSOLUTE); - cover(address_code == ADDR_MODE_ZP); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_X); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y); - cover(address_code == ADDR_MODE_INDEXED_ZP); - cover(address_code == ADDR_MODE_PREINDEXED_INDIRECT); - cover(address_code == ADDR_MODE_POSTINDEXED_INDIRECT); - end - end + assert(P[P_Z] == (A == 0)); + assert(P[P_N] == (A[7] == 1)); + if (f_prev_instruction == I_ADC) + begin + assert(P[P_C] == ({1'b0, f_prev_A} + + {1'b0, $past(mem_data)} + + {8'b0, f_prev_P[P_C]} >= 9'h100)); + assert(P[P_V] == ((f_prev_A[7] ^ A[7]) & ($past(mem_data[7]) ^ A[7]))); + end + else if (f_prev_instruction == I_SBC) + begin + assert(P[P_C] == ({1'b0, f_prev_A} - + {1'b0, $past(mem_data)} - + {8'b0, ~f_prev_P[P_C]} >= 9'h100)); + assert(P[P_V] == ((f_prev_A[7] ^ A[7]) & ($past(mem_data[7]) ^ A[7]))); + end + else + begin + assert(P[P_C] == f_prev_P[P_C]); + assert(P[P_V] == f_prev_P[P_V]); + end -always @(posedge clk) - begin - if (decoded_instr == I_LDA) - begin - cover(address_code == ADDR_MODE_IMMEDIATE); - cover(address_code == ADDR_MODE_ABSOLUTE); - cover(address_code == ADDR_MODE_ZP); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_X); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y); - cover(address_code == ADDR_MODE_INDEXED_ZP); - cover(address_code == ADDR_MODE_PREINDEXED_INDIRECT); - cover(address_code == ADDR_MODE_POSTINDEXED_INDIRECT); - end - end + assert(S == f_prev_S); + assert(X == f_prev_X); + assert(Y == f_prev_Y); + end always @(posedge clk) - begin - if (decoded_instr == I_STA) - begin - cover(address_code == ADDR_MODE_ZP); - cover(address_code == ADDR_MODE_INDEXED_ZP); - cover(address_code == ADDR_MODE_ABSOLUTE); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_X); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y); - cover(address_code == ADDR_MODE_PREINDEXED_INDIRECT); - cover(address_code == ADDR_MODE_POSTINDEXED_INDIRECT); - end - end + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_INC || + f_prev_instruction == I_DEC) + begin + 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); -always @(posedge clk) - begin - if (decoded_instr == I_LDX) - begin - cover(address_code == ADDR_MODE_IMMEDIATE); - cover(address_code == ADDR_MODE_ABSOLUTE); - cover(address_code == ADDR_MODE_ZP); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y); - cover(address_code == ADDR_MODE_INDEXED_ZP); - end - end + assert($past(mem_wr, 2) == 1'b1); -always @(posedge clk) - begin - if (decoded_instr == I_EOR) - begin - cover(address_code == ADDR_MODE_IMMEDIATE); - cover(address_code == ADDR_MODE_ABSOLUTE); - cover(address_code == ADDR_MODE_ZP); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_X); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y); - cover(address_code == ADDR_MODE_INDEXED_ZP); - cover(address_code == ADDR_MODE_PREINDEXED_INDIRECT); - cover(address_code == ADDR_MODE_POSTINDEXED_INDIRECT); - end - end + if (f_prev_instruction == I_DEC) + assert($past(mem_data_wr, 2) == (($past(mem_data, 2) - 1) & 8'hff)); + else if (f_prev_instruction == I_INC) + assert($past(mem_data_wr, 2) == (($past(mem_data, 2) + 1) & 8'hff)); -always @(posedge clk) - begin - if (decoded_instr == I_AND) - begin - cover(address_code == ADDR_MODE_IMMEDIATE); - cover(address_code == ADDR_MODE_ABSOLUTE); - cover(address_code == ADDR_MODE_ZP); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_X); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y); - cover(address_code == ADDR_MODE_INDEXED_ZP); - cover(address_code == ADDR_MODE_PREINDEXED_INDIRECT); - end - end + if ($past(address_code) == ADDR_MODE_ZP) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd2); + assert(f_prev_instr_cycles == 5); + 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 == 6); + end + else if ($past(address_code) == ADDR_MODE_ABSOLUTE) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd3); + assert(f_prev_instr_cycles == 6); + 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 == 7); + end -always @(posedge clk) - begin - if (decoded_instr == I_ORA) - begin - cover(address_code == ADDR_MODE_IMMEDIATE); - cover(address_code == ADDR_MODE_ABSOLUTE); - cover(address_code == ADDR_MODE_ZP); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_X); - cover(address_code == ADDR_MODE_INDEXED_ABSOLUTE_Y); - cover(address_code == ADDR_MODE_INDEXED_ZP); - cover(address_code == ADDR_MODE_PREINDEXED_INDIRECT); - end - end + assert(S == f_prev_S); + assert(A == f_prev_A); + assert(X == f_prev_X); + assert(Y == f_prev_Y); + end always @(posedge clk) - begin - if (decoded_instr == I_DEX) - begin - cover(address_code == ADDR_MODE_IMPLIED); - end - end + if (f_past_valid) +begin + assume(decoded_instr == I_LDA || + decoded_instr == I_LDX || + decoded_instr == I_LDY || + decoded_instr == I_STA || + decoded_instr == I_STX || + decoded_instr == I_STY || + decoded_instr == I_AND || + decoded_instr == I_EOR || + decoded_instr == I_ORA || + decoded_instr == I_ADC || + decoded_instr == I_SBC || + decoded_instr == I_DEX || + decoded_instr == I_DEY || + decoded_instr == I_INX || + decoded_instr == I_INY || + decoded_instr == I_DEC || + decoded_instr == I_INC || + decoded_instr == I_BNE || + decoded_instr == I_JMP +); + assume(address_code != ADDR_MODE_INDIRECT); + end -always @(posedge clk) - begin - if (decoded_instr == I_DEY) - begin - cover(address_code == ADDR_MODE_IMPLIED); - end - end `endif endmodule diff --git a/src/decoder.verilog b/src/decoder.verilog index 9b5d1aa..be276b2 100644 --- a/src/decoder.verilog +++ b/src/decoder.verilog @@ -175,11 +175,11 @@ always_comb begin address_code = ADDR_MODE_IMPLIED; end else if (column == 3) begin - if (row == 2) begin - address_code = ADDR_MODE_ABSOLUTE; + if (row == 3) begin + address_code = ADDR_MODE_INDIRECT; end else begin - address_code = ADDR_MODE_INDIRECT; + address_code = ADDR_MODE_ABSOLUTE; end end else if (column == 4) begin @@ -293,6 +293,41 @@ always_comb assert (address_code == ADDR_MODE_IMMEDIATE); end; +always_comb + if (instr == 8'hA0) // LDY imm + begin + assert (decoded == I_LDY); + assert (address_code == ADDR_MODE_IMMEDIATE); + end; + +always_comb + if (instr == 8'hA4) // LDY zp + begin + assert (decoded == I_LDY); + assert (address_code == ADDR_MODE_ZP); + end; + +always_comb + if (instr == 8'hB4) // LDY zp,X + begin + assert (decoded == I_LDY); + assert (address_code == ADDR_MODE_INDEXED_ZP); + end; + +always_comb + if (instr == 8'hAC) // LDY abs + begin + assert (decoded == I_LDY); + assert (address_code == ADDR_MODE_ABSOLUTE); + end; + +always_comb + if (instr == 8'hBC) // LDY abs,X + begin + assert (decoded == I_LDY); + assert (address_code == ADDR_MODE_INDEXED_ABSOLUTE_X); + end; + always_comb if (instr == 8'hCA) // DEX begin @@ -300,6 +335,11 @@ always_comb assert (address_code == ADDR_MODE_IMPLIED); end; +always_comb + if (instr == 8'hE0) // CPX + begin + assert (decoded == I_CPX); + end; always_comb if (instr == 8'hE0) // CPX begin