diff --git a/common/CPU/T65/T65.vhd b/common/CPU/T65/T65.vhd index 76bd5314..e04d79f0 100644 --- a/common/CPU/T65/T65.vhd +++ b/common/CPU/T65/T65.vhd @@ -1,6 +1,10 @@ -- **** -- T65(b) core. In an effort to merge and maintain bug fixes .... -- +-- Ver 315 SzGy April 2020 +-- Reduced the IRQ detection delay when RDY is not asserted (NMI?) +-- Undocumented opcodes behavior change during not RDY and page boundary crossing (VICE tests - cpu/sha, cpu/shs, cpu/shxy) +-- -- Ver 313 WoS January 2015 -- Fixed issue that NMI has to be first if issued the same time as a BRK instruction is latched in -- Now all Lorenz CPU tests on FPGAARCADE C64 core (sources used: SVN version 1021) are OK! :D :D :D @@ -130,14 +134,16 @@ library IEEE; entity T65 is port( Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 + BCD_en : in std_logic := '1'; -- '0' => 2A03/2A07, '1' => others + Res_n : in std_logic; Enable : in std_logic; Clk : in std_logic; - Rdy : in std_logic; - Abort_n : in std_logic; - IRQ_n : in std_logic; - NMI_n : in std_logic; - SO_n : in std_logic; + Rdy : in std_logic := '1'; + Abort_n : in std_logic := '1'; + IRQ_n : in std_logic := '1'; + NMI_n : in std_logic := '1'; + SO_n : in std_logic := '1'; R_W_n : out std_logic; Sync : out std_logic; EF : out std_logic; @@ -176,7 +182,10 @@ architecture rtl of T65 is signal IR : std_logic_vector(7 downto 0); signal MCycle : std_logic_vector(2 downto 0); + signal DO_r : std_logic_vector(7 downto 0); + signal Mode_r : std_logic_vector(1 downto 0); + signal BCD_en_r : std_logic; signal ALU_Op_r : T_ALU_Op; signal Write_Data_r : T_Write_Data; signal Set_Addr_To_r : T_Set_Addr_To; @@ -209,6 +218,7 @@ architecture rtl of T65 is signal Write_Data : T_Write_Data; signal Jump : std_logic_vector(1 downto 0); signal BAAdd : std_logic_vector(1 downto 0); + signal BAQuirk : std_logic_vector(1 downto 0); signal BreakAtNA : std_logic; signal ADAdd : std_logic; signal AddY : std_logic; @@ -231,6 +241,7 @@ architecture rtl of T65 is signal Res_n_i : std_logic; signal Res_n_d : std_logic; + signal rdy_mod : std_logic; -- RDY signal turned off during the instruction signal really_rdy : std_logic; signal WRn_i : std_logic; @@ -268,6 +279,7 @@ begin IR => IR, MCycle => MCycle, P => P, + Rdy_mod => rdy_mod, --outputs LCycle => LCycle, ALU_Op => ALU_Op, @@ -276,6 +288,7 @@ begin Write_Data => Write_Data, Jump => Jump, BAAdd => BAAdd, + BAQuirk => BAQuirk, BreakAtNA => BreakAtNA, ADAdd => ADAdd, AddY => AddY, @@ -299,6 +312,7 @@ begin alu : entity work.T65_ALU port map( Mode => Mode_r, + BCD_en => BCD_en_r, Op => ALU_Op_r, BusA => BusA_r, BusB => BusB, @@ -330,6 +344,7 @@ begin DBR <= (others => '0'); Mode_r <= (others => '0'); + BCD_en_r <= '1'; ALU_Op_r <= ALU_OP_BIT; Write_Data_r <= Write_Data_DL; Set_Addr_To_r <= Set_Addr_To_PBR; @@ -341,6 +356,13 @@ begin elsif Clk'event and Clk = '1' then if (Enable = '1') then + -- some instructions behavior changed by the Rdy line. Detect this at the correct cycles. + if MCycle = "000" then + rdy_mod <= '0'; + elsif ((MCycle = "011" and IR /= x"93") or (MCycle = "100" and IR = x"93")) and Rdy = '0' then + rdy_mod <= '1'; + end if; + if (really_rdy = '1') then WRn_i <= not Write or RstCycle; @@ -352,6 +374,7 @@ begin if MCycle = "000" then Mode_r <= Mode; + BCD_en_r <= BCD_en; if IRQCycle = '0' and NMICycle = '0' then PC <= PC + 1; @@ -474,9 +497,11 @@ begin P<=tmpP;--new way - if IR(4 downto 0)/="10000" or Jump/="01" then -- delay interrupts during branches (checked with Lorenz test and real 6510), not best way yet, though - but works... - IRQ_n_o <= IRQ_n; - end if; + end if; + + -- detect irq even if not rdy + if IR(4 downto 0)/="10000" or Jump/="01" or really_rdy = '0' then -- delay interrupts during branches (checked with Lorenz test and real 6510), not best way yet, though - but works... + IRQ_n_o <= IRQ_n; end if; -- detect nmi even if not rdy if IR(4 downto 0)/="10000" or Jump/="01" then -- delay interrupts during branches (checked with Lorenz test and real 6510) not best way yet, though - but works... @@ -532,7 +557,13 @@ begin when "11" => -- BA Adj if BAL(8) = '1' then - BAH <= std_logic_vector(unsigned(BAH) + 1); + -- Handle quirks with some undocumented opcodes crossing page boundary + case BAQuirk is + when "00" => BAH <= std_logic_vector(unsigned(BAH) + 1); -- no quirk + when "01" => BAH <= std_logic_vector(unsigned(BAH) + 1) and DO_r; + when "10" => BAH <= DO_r; + when others => null; + end case; end if; when others => end case; @@ -610,8 +641,10 @@ begin -- This is the P that gets pushed on stack with correct B flag. I'm not sure if NMI also clears B, but I guess it does. PwithB<=(P and x"ef") when (IRQCycle='1' or NMICycle='1') else P; + DO <= DO_r; + with Write_Data_r select - DO <= + DO_r <= DL when Write_Data_DL, ABC(7 downto 0) when Write_Data_ABC, X(7 downto 0) when Write_Data_X, diff --git a/common/CPU/T65/T65_ALU.vhd b/common/CPU/T65/T65_ALU.vhd index c58d7a13..2b67ea46 100644 --- a/common/CPU/T65/T65_ALU.vhd +++ b/common/CPU/T65/T65_ALU.vhd @@ -57,6 +57,7 @@ use work.T65_Pack.all; entity T65_ALU is port( Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + BCD_en : in std_logic; Op : in T_ALU_OP; BusA : in std_logic_vector(7 downto 0); BusB : in std_logic_vector(7 downto 0); @@ -83,7 +84,7 @@ architecture rtl of T65_ALU is begin - process (P_In, BusA, BusB) + process (P_In, BusA, BusB, BCD_en) variable AL : unsigned(6 downto 0); variable AH : unsigned(6 downto 0); variable C : std_logic; @@ -102,7 +103,7 @@ begin ADC_Z <= '0'; end if; - if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' then + if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' and BCD_en = '1' then AL(6 downto 1) := AL(6 downto 1) + 6; end if; @@ -116,7 +117,7 @@ begin if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; -- pragma translate_on - if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' then + if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' and BCD_en = '1' then AH(6 downto 1) := AH(6 downto 1) + 6; end if; @@ -125,7 +126,7 @@ begin ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); end process; - process (Op, P_In, BusA, BusB) + process (Op, P_In, BusA, BusB, BCD_en) variable AL : unsigned(6 downto 0); variable AH : unsigned(5 downto 0); variable C : std_logic; @@ -165,7 +166,7 @@ begin SBX_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); - if P_In(Flag_D) = '1' then + if P_In(Flag_D) = '1' and BCD_en = '1' then if AL(5) = '1' then AL(5 downto 1) := AL(5 downto 1) - 6; end if; @@ -181,7 +182,7 @@ begin process (Op, P_In, BusA, BusB, ADC_Z, ADC_C, ADC_V, ADC_N, ADC_Q, SBC_Z, SBC_C, SBC_V, SBC_N, SBC_Q, - SBX_Q) + SBX_Q, BCD_en) variable Q_t : std_logic_vector(7 downto 0); variable Q2_t : std_logic_vector(7 downto 0); begin @@ -226,7 +227,7 @@ begin Q_t := P_In(Flag_C) & (BusA(7 downto 1) and BusB(7 downto 1)); P_Out(Flag_V) <= Q_t(5) xor Q_t(6); Q2_t := Q_t; - if P_In(Flag_D)='1' then + if P_In(Flag_D)='1' and BCD_en = '1' then if (BusA(3 downto 0) and BusB(3 downto 0)) > "0100" then Q2_t(3 downto 0) := std_logic_vector(unsigned(Q_t(3 downto 0)) + x"6"); end if; diff --git a/common/CPU/T65/T65_MCode.vhd b/common/CPU/T65/T65_MCode.vhd index 7af12a31..f5564148 100644 --- a/common/CPU/T65/T65_MCode.vhd +++ b/common/CPU/T65/T65_MCode.vhd @@ -61,6 +61,7 @@ entity T65_MCode is IR : in std_logic_vector(7 downto 0); MCycle : in T_Lcycle; P : in std_logic_vector(7 downto 0); + Rdy_mod : in std_logic; LCycle : out T_Lcycle; ALU_Op : out T_ALU_Op; Set_BusA_To : out T_Set_BusA_To; -- DI,A,X,Y,S,P,DA,DAO,DAX,AAX @@ -68,6 +69,7 @@ entity T65_MCode is Write_Data : out T_Write_Data; -- DL,A,X,Y,S,P,PCL,PCH,AX,AXB,XB,YB Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj + BAQuirk : out std_logic_vector(1 downto 0); -- None,And,Copy BreakAtNA : out std_logic; ADAdd : out std_logic; AddY : out std_logic; @@ -106,7 +108,7 @@ begin not P(Flag_Z) when "110", P(Flag_Z) when others; - process (IR, MCycle, P, Branch, Mode) + process (IR, MCycle, P, Branch, Mode, Rdy_mod) begin lCycle <= Cycle_1; Set_BusA_To <= Set_BusA_To_ABC; @@ -114,6 +116,7 @@ begin Write_Data <= Write_Data_DL; Jump <= (others => '0'); BAAdd <= "00"; + BAQuirk <= "00"; BreakAtNA <= '0'; ADAdd <= '0'; PCAdd <= '0'; @@ -140,14 +143,22 @@ begin when "00" => -- IR: $80,$84,$88,$8C,$90,$94,$98,$9C Set_BusA_To <= Set_BusA_To_Y; if IR(4 downto 2)="111" then -- SYA ($9C) - Write_Data <= Write_Data_YB; + if Rdy_mod = '0' then + Write_Data <= Write_Data_YB; + else + Write_Data <= Write_Data_Y; + end if; else Write_Data <= Write_Data_Y; end if; when "10" => -- IR: $82,$86,$8A,$8E,$92,$96,$9A,$9E Set_BusA_To <= Set_BusA_To_X; if IR(4 downto 2)="111" then -- SXA ($9E) - Write_Data <= Write_Data_XB; + if Rdy_mod = '0' then + Write_Data <= Write_Data_XB; + else + Write_Data <= Write_Data_X; + end if; else Write_Data <= Write_Data_X; end if; @@ -159,7 +170,11 @@ begin Set_BusA_To <= Set_BusA_To_ABC; end if; if IR(4 downto 2)="111" or IR(4 downto 2)="110" or IR(4 downto 2)="100" then -- SHA ($9F, $93), SHS ($9B) - Write_Data <= Write_Data_AXB; + if Rdy_mod = '0' then + Write_Data <= Write_Data_AXB; + else + Write_Data <= Write_Data_AX; + end if; else Write_Data <= Write_Data_AX; end if; @@ -843,6 +858,9 @@ begin BAAdd <= "11"; -- BA Adj if IR(7 downto 5) = "100" then Write <= '1'; + if IR(3 downto 0) = x"3" then + BAQuirk <= "10"; -- COPY + end if; elsif IR(1)='0' or IR=x"B3" then -- Dont do this on $x3, except undoc LAXiy $B3 (says real CPU and Lorenz tests) BreakAtNA <= '1'; end if; @@ -956,6 +974,9 @@ begin BAAdd <= "11"; -- BA adj if IR(7 downto 5) = "100" then--99/9b Write <= '1'; + if IR(3 downto 0) = x"B" then + BAQuirk <= "01"; -- AND + end if; elsif IR(1)='0' or IR=x"BB" then -- Dont do this on $xB, except undoc $BB (says real CPU and Lorenz tests) BreakAtNA <= '1'; end if; @@ -1045,8 +1066,13 @@ begin Set_Addr_To <= Set_Addr_To_BA; when Cycle_3 => BAAdd <= "11"; -- BA adj - if IR(7 downto 5) = "100" then -- ($9E,$9F) + if IR(7 downto 5) = "100" then -- ($9C,$9D,$9E,$9F) Write <= '1'; + case IR(1 downto 0) is + when "00"|"10" => BAQuirk <= "01"; -- AND + when "11" => BAQuirk <= "10"; -- COPY + when others => null; + end case; else BreakAtNA <= '1'; end if; diff --git a/common/mist/osd.v b/common/mist/osd.v index 7e41ed27..4efbbe61 100644 --- a/common/mist/osd.v +++ b/common/mist/osd.v @@ -27,13 +27,15 @@ module osd ( output [5:0] B_out ); -parameter OSD_X_OFFSET = 10'd0; -parameter OSD_Y_OFFSET = 10'd0; +parameter OSD_X_OFFSET = 11'd0; +parameter OSD_Y_OFFSET = 11'd0; parameter OSD_COLOR = 3'd0; parameter OSD_AUTO_CE = 1'b1; -localparam OSD_WIDTH = 10'd256; -localparam OSD_HEIGHT = 10'd128; +localparam OSD_WIDTH = 11'd256; +localparam OSD_HEIGHT = 11'd128; + +localparam OSD_WIDTH_PADDED = OSD_WIDTH + (OSD_WIDTH >> 1); // 25% padding left and right // ********************************************************************************* // spi client @@ -84,36 +86,40 @@ end // ********************************************************************************* // horizontal counter -reg [9:0] h_cnt; -reg [9:0] hs_low, hs_high; -wire hs_pol = hs_high < hs_low; -wire [9:0] dsp_width = hs_pol ? hs_low : hs_high; +reg [10:0] h_cnt; +reg [10:0] hs_low, hs_high; +wire hs_pol = hs_high < hs_low; +wire [10:0] dsp_width = hs_pol ? hs_low : hs_high; // vertical counter -reg [9:0] v_cnt; -reg [9:0] vs_low, vs_high; -wire vs_pol = vs_high < vs_low; -wire [9:0] dsp_height = vs_pol ? vs_low : vs_high; +reg [10:0] v_cnt; +reg [10:0] vs_low, vs_high; +wire vs_pol = vs_high < vs_low; +wire [10:0] dsp_height = vs_pol ? vs_low : vs_high; wire doublescan = (dsp_height>350); reg auto_ce_pix; always @(posedge clk_sys) begin - integer cnt = 0; - integer pixsz, pixcnt; - reg hs; + reg [15:0] cnt = 0; + reg [1:0] pixsz; + reg [1:0] pixcnt; + reg hs; - cnt <= cnt + 1; + cnt <= cnt + 1'd1; hs <= HSync; - pixcnt <= pixcnt + 1; + pixcnt <= pixcnt + 1'd1; if(pixcnt == pixsz) pixcnt <= 0; auto_ce_pix <= !pixcnt; if(hs && ~HSync) begin - cnt <= 0; - if (cnt <= 512) pixsz = 0; - else pixsz <= (cnt >> 9) - 1; + cnt <= 0; + if(cnt <= OSD_WIDTH_PADDED * 2) pixsz <= 0; + else if(cnt <= OSD_WIDTH_PADDED * 3) pixsz <= 1; + else if(cnt <= OSD_WIDTH_PADDED * 4) pixsz <= 2; + else pixsz <= 3; + pixcnt <= 0; auto_ce_pix <= 1; end @@ -161,14 +167,22 @@ always @(posedge clk_sys) begin end // area in which OSD is being displayed -wire [9:0] h_osd_start = ((dsp_width - OSD_WIDTH)>> 1) + OSD_X_OFFSET; -wire [9:0] h_osd_end = h_osd_start + OSD_WIDTH; -wire [9:0] v_osd_start = ((dsp_height- (OSD_HEIGHT<> 1) + OSD_Y_OFFSET; -wire [9:0] v_osd_end = v_osd_start + (OSD_HEIGHT<> 1) + OSD_X_OFFSET; + h_osd_end <= h_osd_start + OSD_WIDTH; + v_osd_start <= ((dsp_height- (OSD_HEIGHT<> 1) + OSD_Y_OFFSET; + v_osd_end <= v_osd_start + (OSD_HEIGHT<