Since no core I tried is consistent with the real 65C02 when it comes to 'decimal mode' results for non-BCD operands, here is a piece of Verilog that I created for my own 65C02 core, that actually
is consistent with the real thing.
Note that C is valid as well, and N and Z are 'result[7]' and 'result == 8'h00' as usual. Make up your very own V flag (personally, I find the notion that BCD numbers can be negative and specifically, then, 0x80 and up, ludicrous and completely arbitrary).
Enjoy (if this is useful to you).
Code:
module BCD_ADD
(
a_in,
data_in,
carry_in,
fixup_in,
sbc_else_adc,
data_out,
carry_out,
fixup_out
);
input [3:0] a_in;
input [3:0] data_in;
input carry_in;
input fixup_in;
input sbc_else_adc;
output [3:0] data_out;
output carry_out;
output fixup_out;
wire [3:0] adder_data;
wire [4:0] adder_result;
wire adder_carry;
wire digit_not_bcd;
reg [3:0] digit_add_data;
reg digit_add_carry;
wire [4:0] digit_result;
assign adder_data = sbc_else_adc ? ~data_in : data_in;
assign adder_result = a_in + adder_data + carry_in;
assign adder_carry = adder_result[4];
assign digit_not_bcd = (adder_result[3:0] > 4'd9);
always @(*)
casex ({ sbc_else_adc, adder_carry, digit_not_bcd })
3'b000 : { digit_add_data, digit_add_carry } = { 4'h0, 1'b0 };
3'b0xx : { digit_add_data, digit_add_carry } = { 4'h6, 1'b0 };
3'b10x : { digit_add_data, digit_add_carry } = { 4'h9, fixup_in };
3'b11x : { digit_add_data, digit_add_carry } = { 4'hF, fixup_in };
endcase
assign digit_result = adder_result[3:0] + digit_add_data + digit_add_carry;
assign data_out = digit_result[3:0];
assign carry_out = adder_carry | (~sbc_else_adc & digit_not_bcd);
assign fixup_out = digit_result[4];
endmodule
BCD_ADD nibble_0
(
.a_in(a_in[3:0]),
.data_in(data_in[3:0]),
.carry_in(carry_in),
.fixup_in(1'b1),
.sbc_else_adc(operation[2]),
.data_out(d_adder_result[3:0]),
.carry_out(d_nibble_carry),
.fixup_out(d_nibble_fixup)
);
BCD_ADD nibble_1
(
.a_in(a_in[7:4]),
.data_in(data_in[7:4]),
.carry_in(d_nibble_carry),
.fixup_in(d_nibble_fixup),
.sbc_else_adc(operation[2]),
.data_out(d_adder_result[7:4]),
.carry_out(d_adder_result[8]),
.fixup_out()
);