From 4053c24317478af7884abb32820cf31b65f25931 Mon Sep 17 00:00:00 2001 From: David Banks Date: Mon, 1 Aug 2016 12:02:45 +0100 Subject: [PATCH] Arlet 65C02 WIP: Implement correct 65C02 BCD N/Z flags (optional, disabled) Change-Id: Ib72bcc1a100ee3c642048ce195bf1424feb4bf50 --- cpu_65c02.v | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/cpu_65c02.v b/cpu_65c02.v index 564c80f..832acd8 100644 --- a/cpu_65c02.v +++ b/cpu_65c02.v @@ -28,6 +28,16 @@ `define IMPLEMENT_NOPS +/* + * Two things were needed to correctly implement 65C02 BCD arithmentic + * 1. The Z flag needs calculating over the BCD adjusted ALU output + * 2. The N flag needs calculating over the BCD adjusted ALU output + * + * If IMPLEMENT_CORRECT_BCD_FLAGS is defined, this additional logic is added + */ + +// `define IMPLEMENT_CORRECT_BCD_FLAGS + module cpu_65c02( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY ); input clk; // CPU clock @@ -65,9 +75,11 @@ reg D = 0; // decimal flag reg V = 0; // overflow flag reg N = 0; // negative flag wire AZ; // ALU Zero flag +wire AZ1; // ALU Zero flag (BCD adjusted) reg AZ2; // ALU Second Zero flag, set using TSB/TRB semantics wire AV; // ALU overflow flag wire AN; // ALU negative flag +wire AN1; // ALU negative flag (BCD adjusted) wire HC; // ALU half carry reg [7:0] AI; // ALU Input A @@ -75,6 +87,7 @@ reg [7:0] BI; // ALU Input B wire [7:0] DI; // Data In wire [7:0] IR; // Instruction register reg [7:0] DO; // Data Out +wire [7:0] AO; // ALU output after BCD adjustment reg WE; // Write Enable reg CI; // Carry In wire CO; // Carry Out @@ -554,6 +567,20 @@ always @* begin endcase end +assign AO = { ADD[7:4] + ADJH, ADD[3:0] + ADJL }; + +`ifdef IMPLEMENT_CORRECT_BCD_FLAGS + +assign AN1 = AO[7]; +assign AZ1 = ~|AO; + +`else + +assign AN1 = AN; +assign AZ1 = AZ; + +`endif + /* * write to a register. Usually this is the (BCD corrected) output of the * ALU, but in case of the JSR0 we use the S register to temporarily store @@ -562,7 +589,7 @@ end */ always @(posedge clk) if( write_register & RDY ) - AXYS[regsel] <= (state == JSR0) ? DIMUX : { ADD[7:4] + ADJH, ADD[3:0] + ADJL }; + AXYS[regsel] <= (state == JSR0) ? DIMUX : AO; /* * register select logic. This determines which of the A, X, Y or @@ -805,26 +832,26 @@ always @(posedge clk) always @(posedge clk) if( state == WRITE) - Z <= txb_ins ? AZ2 : AZ; + Z <= txb_ins ? AZ2 : AZ1; else if( state == RTI2 ) Z <= DIMUX[1]; else if( state == DECODE ) begin if( plp ) Z <= ADD[1]; else if( (load_reg & (regsel != SEL_S)) | compare | bit_ins ) - Z <= AZ; + Z <= AZ1; end always @(posedge clk) if( state == WRITE && ~txb_ins) - N <= AN; + N <= AN1; else if( state == RTI2 ) N <= DIMUX[7]; else if( state == DECODE ) begin if( plp ) N <= ADD[7]; else if( (load_reg & (regsel != SEL_S)) | compare ) - N <= AN; + N <= AN1; end else if( state == FETCH && bit_ins_nv ) N <= DIMUX[7];