diff --git a/src/cpu.verilog b/src/cpu.verilog index aa58a89..47c825a 100644 --- a/src/cpu.verilog +++ b/src/cpu.verilog @@ -90,6 +90,7 @@ localparam logic [1:0] pending_y_read; logic pending_rel_branch; logic pending_nz_alu_update; + logic pending_c_alu_update; wire is_arith; logic [2:0] extra_timing; reg [3:0] state_after_delay; @@ -107,6 +108,7 @@ initial pending_x_read = 0; initial pending_y_read = 0; initial pending_rel_branch = 0; initial pending_nz_alu_update = 0; +initial pending_c_alu_update = 0; initial mem_aux_addr = 0; initial instr = 0; initial extra_timing = 0; @@ -234,6 +236,46 @@ always_comb alu_op_c = 1'b1; alu_op_sel = OP_SUB; end + else if (decoded_instr == I_ASL) + begin + if (address_code == ADDR_MODE_IMPLIED) + alu_op_1 = A; + else + alu_op_1 = mem_data; + alu_op_2 = SHIFT_LEFT; + alu_op_c = 0; + alu_op_sel = OP_SHF; + end + else if (decoded_instr == I_LSR) + begin + if (address_code == ADDR_MODE_IMPLIED) + alu_op_1 = A; + else + alu_op_1 = mem_data; + alu_op_2 = SHIFT_RIGHT; + alu_op_c = 0; + alu_op_sel = OP_SHF; + end + else if (decoded_instr == I_ROL) + begin + if (address_code == ADDR_MODE_IMPLIED) + alu_op_1 = A; + else + alu_op_1 = mem_data; + alu_op_2 = SHIFT_LEFT; + alu_op_c = P[P_C]; + alu_op_sel = OP_ROT; + end + else if (decoded_instr == I_ROR) + begin + if (address_code == ADDR_MODE_IMPLIED) + alu_op_1 = A; + else + alu_op_1 = mem_data; + alu_op_2 = SHIFT_RIGHT; + alu_op_c = P[P_C]; + alu_op_sel = OP_ROT; + end else begin alu_op_1 = A; @@ -333,6 +375,12 @@ always @(posedge clk) end pending_nz_alu_update <= 0; + if (pending_c_alu_update) + begin + P[P_C] <= alu_c; + end + pending_c_alu_update <= 0; + PC <= PC + 1; state <= STATE_EXECUTE; end @@ -383,7 +431,11 @@ always @(posedge clk) begin mem_sel <= DMUX_AUX; if (decoded_instr == I_INC || - decoded_instr == I_DEC) + decoded_instr == I_DEC || + decoded_instr == I_ASL || + decoded_instr == I_LSR || + decoded_instr == I_ROL || + decoded_instr == I_ROR ) begin state <= STATE_READ_ADDR_ZP; end @@ -397,7 +449,11 @@ always @(posedge clk) begin mem_sel <= DMUX_AUX; if (decoded_instr == I_INC || - decoded_instr == I_DEC) + decoded_instr == I_DEC || + decoded_instr == I_ASL || + decoded_instr == I_LSR || + decoded_instr == I_ROL || + decoded_instr == I_ROR) begin state <= STATE_READ_ADDR_ZP; end @@ -432,6 +488,14 @@ always @(posedge clk) pending_y_read <= READ_SOURCE_ALU; state <= STATE_FETCH; end + else if (decoded_instr == I_ASL || decoded_instr == I_LSR || + decoded_instr == I_ROL || decoded_instr == I_ROR) + begin + pending_a_read <= READ_SOURCE_ALU; + pending_nz_alu_update <= 1; + pending_c_alu_update <= 1; + state <= STATE_FETCH; + end end else if (decoded_instr == I_BNE) begin @@ -487,8 +551,13 @@ always @(posedge clk) pending_a_read <= READ_SOURCE_ALU; end else if (decoded_instr == I_DEC || - decoded_instr == I_INC) + decoded_instr == I_INC || + decoded_instr == I_ASL || + decoded_instr == I_LSR || + decoded_instr == I_ROL || + decoded_instr == I_ROR) begin + pending_c_alu_update <= 1; pending_nz_alu_update <= 1'b1; end @@ -541,7 +610,9 @@ always @(posedge clk) mem_aux_addr[7:0] <= mem_data; mem_sel <= DMUX_AUX; - if (decoded_instr == I_DEC || decoded_instr == I_INC) + if (decoded_instr == I_DEC || decoded_instr == I_INC || + decoded_instr == I_ASL || decoded_instr == I_LSR || + decoded_instr == I_ROL || decoded_instr == I_ROR) begin state <= STATE_EXECUTE_ABS_ALU; end @@ -609,6 +680,12 @@ always @(posedge clk) begin extra_timing <= 1; end + if (decoded_instr == I_ASL || decoded_instr == I_LSR || + decoded_instr == I_ROL || decoded_instr == I_ROR) + begin + pending_nz_alu_update <= 1; + pending_c_alu_update <= 1; + end end else if (state == STATE_WRITE_ABS_ALU) begin @@ -660,7 +737,11 @@ always_comb mem_data_wr = Y; end else if(decoded_instr == I_DEC || - decoded_instr == I_INC) + decoded_instr == I_INC || + decoded_instr == I_ASL || + decoded_instr == I_LSR || + decoded_instr == I_ROL || + decoded_instr == I_ROR) begin mem_wr = 1'b1; mem_data_wr = alu_op_result; @@ -1248,6 +1329,146 @@ always @(posedge clk) assert(Y == f_prev_Y); end +always @(posedge clk) + if (f_prev_valid && state == STATE_EXECUTE) + if (f_prev_instruction == I_ASL || f_prev_instruction == I_LSR || + f_prev_instruction == I_ROL || f_prev_instruction == I_ROR) + begin + cover(f_prev_addr_code == ADDR_MODE_IMPLIED); + cover(f_prev_addr_code == ADDR_MODE_ZP); + cover(f_prev_addr_code == ADDR_MODE_INDEXED_ZP); + cover(f_prev_addr_code == ADDR_MODE_ABSOLUTE); + cover(f_prev_addr_code == ADDR_MODE_INDEXED_ABSOLUTE_X); + + if (f_prev_addr_code != ADDR_MODE_IMPLIED) + begin + assert($past(mem_wr, 2) == 1'b1); + end + + if (f_prev_instruction == I_ASL) + begin + if (f_prev_addr_code == ADDR_MODE_IMPLIED) + begin + assert(f_prev_A[6:0] == A[7:1]); + assert(A[0] == 0); + + assert(f_prev_A[7] == P[P_C]); + assert((A == 0) == P[P_Z]); + assert(A[7] == P[P_N]); + end + else + begin + assert($past(mem_data_wr[7:1], 2) == $past(mem_data[6:0], 2)); + assert($past(mem_data_wr[0], 2) == 0); + + assert($past(mem_data[7], 2) == P[P_C]); + assert(($past(mem_data_wr, 2) == 0) == P[P_Z]); + assert($past(mem_data_wr[7], 2) == P[P_N]); + + assert(A == f_prev_A); + end + end + else if (f_prev_instruction == I_LSR) + begin + if (f_prev_addr_code == ADDR_MODE_IMPLIED) + begin + assert(f_prev_A[7:1] == A[6:0]); + assert(A[7] == 0); + + assert(f_prev_A[0] == P[P_C]); + assert((A == 0) == P[P_Z]); + assert(A[7] == P[P_N]); + end + else + begin + assert($past(mem_data_wr[6:0], 2) == $past(mem_data[7:1], 2)); + assert($past(mem_data_wr[7], 2) == 0); + + assert($past(mem_data[0], 2) == P[P_C]); + assert(($past(mem_data_wr, 2) == 0) == P[P_Z]); + assert($past(mem_data_wr[7], 2) == P[P_N]); + + assert(A == f_prev_A); + end + end + else if (f_prev_instruction == I_ROR) + begin + if (f_prev_addr_code == ADDR_MODE_IMPLIED) + begin + assert(f_prev_A[7:1] == A[6:0]); + assert(A[7] == f_prev_P[P_C]); + + assert(f_prev_A[0] == P[P_C]); + assert((A == 0) == P[P_Z]); + assert(A[7] == P[P_N]); + end + else + begin + assert($past(mem_data_wr[6:0], 2) == $past(mem_data[7:1], 2)); + assert($past(mem_data_wr[7], 2) == f_prev_P[P_C]); + + assert($past(mem_data[0], 2) == P[P_C]); + assert(($past(mem_data_wr, 2) == 0) == P[P_Z]); + assert($past(mem_data_wr[7], 2) == P[P_N]); + + assert(A == f_prev_A); + end + end + else if (f_prev_instruction == I_ROL) + begin + if (f_prev_addr_code == ADDR_MODE_IMPLIED) + begin + assert(f_prev_A[6:0] == A[7:1]); + assert(A[0] == f_prev_P[P_C]); + + assert(f_prev_A[7] == P[P_C]); + assert((A == 0) == P[P_Z]); + assert(A[7] == P[P_N]); + end + else + begin + assert($past(mem_data_wr[7:1], 2) == $past(mem_data[6:0], 2)); + assert($past(mem_data_wr[0], 2) == f_prev_P[P_C]); + + assert($past(mem_data[7], 2) == P[P_C]); + assert(($past(mem_data_wr, 2) == 0) == P[P_Z]); + assert($past(mem_data_wr[7], 2) == P[P_N]); + + assert(A == f_prev_A); + end + end + + if ($past(address_code) == ADDR_MODE_IMPLIED) + begin + assert($past(PC) == $past(f_prev_PC) + 16'd1); + 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 == 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 + + assert(S == f_prev_S); + assert(X == f_prev_X); + assert(Y == f_prev_Y); + end + always @(posedge clk) if (f_past_valid) begin @@ -1268,6 +1489,10 @@ begin decoded_instr == I_INY || decoded_instr == I_DEC || decoded_instr == I_INC || + decoded_instr == I_ASL || + decoded_instr == I_LSR || + decoded_instr == I_ROR || + decoded_instr == I_ROL || decoded_instr == I_BNE || decoded_instr == I_JMP );