diff --git a/cores/c16/mos8501.v b/cores/c16/mos8501.v index 3f862be..23d43cd 100644 --- a/cores/c16/mos8501.v +++ b/cores/c16/mos8501.v @@ -67,9 +67,9 @@ T65 cpu_core( .Mode (2'b00), .Res_n (~reset), - .Enable(enable_cpu), + .Enable(enable), .Clk(clk), - .Rdy(enable_cpu), + .Rdy(rdy), .Abort_n(1), .IRQ_n(irq_n), .NMI_n(1), @@ -183,6 +183,6 @@ always @* end assign port_out=port_data; -assign enable_cpu=(~rdy & ~we)?1'b0:enable; // When RDY is low and cpu would do a read, halt cpu +//assign enable_cpu=(~rdy & ~we)?1'b0:enable; // When RDY is low and cpu would do a read, halt cpu endmodule diff --git a/cores/c16/t65/T65.vhd b/cores/c16/t65/T65.vhd index d6aba9c..e5c993b 100755 --- a/cores/c16/t65/T65.vhd +++ b/cores/c16/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 @@ -152,7 +156,8 @@ entity T65 is DO : out std_logic_vector(7 downto 0); -- 6502 registers (MSB) PC, SP, P, Y, X, A (LSB) Regs : out std_logic_vector(63 downto 0); - DEBUG : out T_t65_dbg + DEBUG : out T_t65_dbg; + NMI_ack : out std_logic ); end T65; @@ -175,6 +180,8 @@ 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 ALU_Op_r : T_ALU_Op; signal Write_Data_r : T_Write_Data; @@ -208,6 +215,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; @@ -230,12 +238,15 @@ 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; signal NMI_entered : std_logic; begin + NMI_ack <= NMIAct; + -- gate Rdy with read/write to make an "OK, it's really OK to stop the processor really_rdy <= Rdy or not(WRn_i); Sync <= '1' when MCycle = "000" else '0'; @@ -265,6 +276,7 @@ begin IR => IR, MCycle => MCycle, P => P, + Rdy_mod => rdy_mod, --outputs LCycle => LCycle, ALU_Op => ALU_Op, @@ -273,6 +285,7 @@ begin Write_Data => Write_Data, Jump => Jump, BAAdd => BAAdd, + BAQuirk => BAQuirk, BreakAtNA => BreakAtNA, ADAdd => ADAdd, AddY => AddY, @@ -338,6 +351,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; @@ -471,9 +491,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... @@ -508,8 +530,8 @@ begin DL <= (others => '0'); elsif Clk'event and Clk = '1' then if (Enable = '1') then - NMI_entered <= '0'; if (really_rdy = '1') then + NMI_entered <= '0'; BusA_r <= BusA; BusB <= DI; @@ -529,7 +551,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; @@ -607,8 +635,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/cores/c16/t65/T65_MCode.vhd b/cores/c16/t65/T65_MCode.vhd index 867e0b8..a0500df 100755 --- a/cores/c16/t65/T65_MCode.vhd +++ b/cores/c16/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;