From e1107b450f4a3f120d9b7adc0d4c8144c5ee83e2 Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi <8644936+gyurco@users.noreply.github.com> Date: Sun, 11 Dec 2022 18:40:58 +0100 Subject: [PATCH] T65: update IRQ dispatching --- common/CPU/T65/README | 68 ++++++++++++++++++++++++++++++++++++++++++ common/CPU/T65/T65.qip | 8 ++--- common/CPU/T65/T65.vhd | 60 +++++++++++++++++++++++-------------- 3 files changed, 109 insertions(+), 27 deletions(-) create mode 100644 common/CPU/T65/README diff --git a/common/CPU/T65/README b/common/CPU/T65/README new file mode 100644 index 00000000..c698998d --- /dev/null +++ b/common/CPU/T65/README @@ -0,0 +1,68 @@ +-- 65xx compatible microprocessor core +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author(s), but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- ----- IMPORTANT NOTES ----- +-- +-- Limitations: +-- 65C02 and 65C816 modes are incomplete (and definitely untested after all 6502 undoc fixes) +-- 65C02 supported : inc, dec, phx, plx, phy, ply +-- 65D02 missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8 +-- Some interface signals behave incorrect +-- NMI interrupt handling not nice, needs further rework (to cycle-based encoding). +-- +-- Usage: +-- The enable signal allows clock gating / throttling without using the ready signal. +-- Set it to constant '1' when using the Clk input as the CPU clock directly. +-- +-- TAKE CARE you route the DO signal back to the DI signal while R_W_n='0', +-- otherwise some undocumented opcodes won't work correctly. +-- EXAMPLE: +-- CPU : entity work.T65 +-- port map ( +-- R_W_n => cpu_rwn_s, +-- [....all other ports....] +-- DI => cpu_din_s, +-- DO => cpu_dout_s +-- ); +-- cpu_din_s <= cpu_dout_s when cpu_rwn_s='0' else +-- [....other sources from peripherals and memories...] +-- +-- ----- IMPORTANT NOTES ----- +-- diff --git a/common/CPU/T65/T65.qip b/common/CPU/T65/T65.qip index 09161f2d..3de9d396 100644 --- a/common/CPU/T65/T65.qip +++ b/common/CPU/T65/T65.qip @@ -1,4 +1,4 @@ -set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T65.vhd ] -set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T65_MCode.vhd ] -set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T65_ALU.vhd ] -set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T65_Pack.vhd ] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T65_Pack.vhd] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T65_ALU.vhd] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T65_MCode.vhd] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T65.vhd] diff --git a/common/CPU/T65/T65.vhd b/common/CPU/T65/T65.vhd index c049d4a3..48f6942e 100644 --- a/common/CPU/T65/T65.vhd +++ b/common/CPU/T65/T65.vhd @@ -194,6 +194,8 @@ architecture rtl of T65 is signal RstCycle : std_logic; signal IRQCycle : std_logic; signal NMICycle : std_logic; + signal IRQReq : std_logic; + signal NMIReq : std_logic; signal SO_n_o : std_logic; signal IRQ_n_o : std_logic; @@ -354,6 +356,9 @@ begin MF_i <= '1'; XF_i <= '1'; + NMICycle <= '0'; + IRQCycle <= '0'; + 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. @@ -376,16 +381,24 @@ begin Mode_r <= Mode; BCD_en_r <= BCD_en; - if IRQCycle = '0' and NMICycle = '0' then + if IRQReq = '0' and NMIReq = '0' then PC <= PC + 1; end if; - if IRQCycle = '1' or NMICycle = '1' then + if IRQReq = '1' or NMIReq = '1' then IR <= "00000000"; else IR <= DI; end if; + IRQCycle <= '0'; + NMICycle <= '0'; + if NMIReq = '1' then + NMICycle <= '1'; + elsif IRQReq = '1' then + IRQCycle <= '1'; + end if; + if LDS = '1' then -- LAS won't work properly if not limited to machine cycle 0 S(7 downto 0) <= unsigned(ALU_Q); end if; @@ -499,20 +512,12 @@ begin 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... - NMI_n_o <= NMI_n; - end if; end if; -- act immediately on SO pin change -- The signal is sampled on the trailing edge of phi1 and must be externally synchronized (from datasheet) SO_n_o <= SO_n; - if SO_n_o = '1' and SO_n = '0' then - P(Flag_V) <= '1'; + if SO_n_o = '1' and SO_n = '0' then + P(Flag_V) <= '1'; end if; end if; @@ -671,29 +676,38 @@ begin if Res_n_i = '0' then MCycle <= "001"; RstCycle <= '1'; - IRQCycle <= '0'; - NMICycle <= '0'; NMIAct <= '0'; + IRQReq <= '0'; + NMIReq <= '0'; elsif Clk'event and Clk = '1' then if (Enable = '1') then if (really_rdy = '1') then if MCycle = LCycle or Break = '1' then MCycle <= "000"; RstCycle <= '0'; - IRQCycle <= '0'; - NMICycle <= '0'; - if NMIAct = '1' and IR/=x"00" then -- delay NMI further if we just executed a BRK - NMICycle <= '1'; - NMIAct <= '0'; -- reset NMI edge detector if we start processing the NMI - elsif IRQ_n_o = '0' and P(Flag_I) = '0' then - IRQCycle <= '1'; - end if; else MCycle <= std_logic_vector(unsigned(MCycle) + 1); end if; + + if (IR(4 downto 0)/="10000" or Jump/="11") then -- taken branches delay the interrupts + if NMIAct = '1' and IR/=x"00" then + NMIReq <= '1'; + else + NMIReq <= '0'; + end if; + if IRQ_n_o = '0' and P(Flag_I) = '0' then + IRQReq <= '1'; + else + IRQReq <= '0'; + end if; + end if; end if; + + IRQ_n_o <= IRQ_n; + NMI_n_o <= NMI_n; + --detect NMI even if not rdy - if NMI_n_o = '1' and (NMI_n = '0' and (IR(4 downto 0)/="10000" or Jump/="01")) then -- branches have influence on NMI start (not best way yet, though - but works...) + if NMI_n_o = '1' and NMI_n = '0' then NMIAct <= '1'; end if; -- we entered NMI during BRK instruction