diff options
Diffstat (limited to 'zpu/hdl/tap/tap.vhd')
-rw-r--r-- | zpu/hdl/tap/tap.vhd | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/zpu/hdl/tap/tap.vhd b/zpu/hdl/tap/tap.vhd new file mode 100644 index 0000000..41dc07b --- /dev/null +++ b/zpu/hdl/tap/tap.vhd @@ -0,0 +1,217 @@ +-- Example Test Access Port (TAP) controller implementation +-- (c) 2005-2011 Martin Strubel <hackfin@section5.ch> + +-- General behaviour summary: + +-- * JtagController entity decodes the TMS and TDI sequences +-- * IR and DR are decoded by this TAP controller +-- * Signals to a CPU core are generated by the TAP. See +-- "Core emulation signals" below. These are mapped into a control register: +-- emuctl [W] +-- * Signals from a CPU core are mapped into a status register: +-- emustat [R] + +-- Note: Fixed size IR register is clocked in LSB first, +-- Variable size DR register is clocked in MSB first. + +-- The default EMUIR value on a state machine reset is set to +-- INS_NOP, which should be defined properly by the parent module. +-- This is necessary for the core to not run any spurious command when +-- a breakpoint was hit and the JTAG state machine enters Run-Test-Idle. + +-- This TAP is supported by a generic software library as part of the +-- ICEbear software suite. + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.jtag.all; +-- TAP register definitions (generated): +use work.tap_registers.all; + +entity tap is + generic (EMUDAT_SIZE : natural := 32; + EMUIR_SIZE : natural := 8; + IDCODE : std_logic_vector(32-1 downto 0) := x"deadbeef"; + INS_NOP : std_logic_vector(8-1 downto 0) := x"00"); + port ( + -- JTAG signals: + tck, trst, tms, tdi : in std_logic; + tdo : out std_logic; + -- Core <-> TAP signals: + core_reset : out std_logic; -- Reset core logic + emuexec : out std_logic; -- Execute opcode on rising edge + emurequest : out std_logic; -- Emulation request to core + emuack : in std_logic; -- Core has acknowledged EMULATION request + emurdy : in std_logic; -- Core ready to execute next instruction + pulse : in std_logic; -- Pulse event counter + -- PC of possibly running core. Allows to access PC without + -- entering emulation. + dbgpc : in std_logic_vector(EMUDAT_SIZE-1 downto 0); -- PC + + -- Extra status bits, core dependent + exstat : in std_logic_vector(7 downto 0); + + emudata_i : in std_logic_vector(EMUDAT_SIZE-1 downto 0); + emudata_o : out std_logic_vector(EMUDAT_SIZE-1 downto 0); + -- Not implemented in this version + -- emudat_wr : in std_logic; + -- emudat_rd : in std_logic; + emuir : out std_logic_vector(EMUIR_SIZE-1 downto 0) + ); +end tap; + +architecture behaviour of tap is + + -- Use generated registers from tap_pkg.vhd + + -- Note: all ones is always reserved for BYPASS + -- all zeros is normally reserved for EXTEST + + signal jtag_state : jtag_state_type; + + signal exec : std_logic := '0'; + + -- Emulation control/status registers: + signal emustat : std_logic_vector(16-1 downto 0); + signal emuctl : std_logic_vector(16-1 downto 0) := x"0000"; + + -- Core emulation signals: + + signal dr_in : std_logic_vector(EMUDAT_SIZE-1 downto 0); + signal dr_out : std_logic_vector(EMUDAT_SIZE-1 downto 0); + + signal count1 : unsigned(32-1 downto 0); + signal count1_reset : std_logic; + signal count2 : unsigned(16-1 downto 0); + + signal ir : std_logic_vector(4-1 downto 0); + + -- Position of MSB of data register when not in BYPASS + -- (defines length of DR register). See also jtag_config.vhd + signal msbpos : bitpos_type := 31; + + -- Emulation auxiliaries: + + -- Emulation data register for exchange between core and JTAG: + signal emudat_i : std_logic_vector(EMUDAT_SIZE-1 downto 0); + signal emudat_o : std_logic_vector(EMUDAT_SIZE-1 downto 0); +-- These signals are just stubs. Not implemented in this version. + -- signal emudat_rxf : std_logic; -- Receive full + -- signal emudat_txe : std_logic := '0'; -- Transmit empty + -- signal emudat_ovr : std_logic := '0'; -- Overrun + -- signal emudat_unr : std_logic := '0'; -- Underrun + +begin +i_jtag : JtagController + port map ( + tck => tck, + tms => tms, + tdi => tdi, + tdo => tdo, + trst => trst, + state => jtag_state, + dr_out => dr_out, + msbpos => msbpos, + dr_in => dr_in, + ir_out => ir + ); + +-- Select DR register according to supported IRs +-- We sample this with tck to avoid gated clock issues + +select_dr: + process (tck) + begin + if rising_edge(tck) then + case ir is + when TAP_IDCODE => + dr_in <= IDCODE; + msbpos <= 31; + when TAP_EMUDATA => + dr_in <= emudata_i; + msbpos <= emudata_i'length - 1; + when TAP_EMUSTAT => + dr_in(emustat'length-1 downto 0) <= emustat; + msbpos <= emustat'length - 1; + when TAP_DBGPC => + dr_in <= dbgpc; + msbpos <= dbgpc'length - 1; + when TAP_COUNT1 => + dr_in(count1'length-1 downto 0) <= std_logic_vector(count1); + msbpos <= count1'length - 1; + when TAP_COUNT2 => + dr_in(count2'length-1 downto 0) <= std_logic_vector(count2); + msbpos <= count2'length - 1; + when others => + dr_in <= (others => 'X'); + msbpos <= 31; + end case; + end if; + end process; + + +-- NOTE: action is being taken when ENTERING the concerning state +-- on rising edge of tck. + +-- exec is the signal sent to the core. It is like an IRQ event, thus +-- it must be properly treated as an exception (edge sensitive) +-- inside the core logic. + +decode_scanchain_w: + process (tck) + begin + if rising_edge(tck) then + count1_reset <= '0'; + exec <= '0'; + case jtag_state is + when UPDATE_DR => + if ir = TAP_EMUCTRL then + emuctl <= dr_out(15 downto 0); + elsif ir = TAP_EMUDATA then + emudat_o <= dr_out; + elsif ir = TAP_EMUIR then + emuir <= dr_out(EMUIR_SIZE-1 downto 0); + end if; + when TEST_LOGIC_RESET => + count1_reset <= '1'; + count2 <= (others => '0'); + emuctl <= (others => '0'); + emudat_o <= (others => '0'); +-- Important to reset the EMUIR to NOP for sane JTAG operation: + emuir <= INS_NOP; + when RUN_TEST_IDLE => + count2 <= count2 + 1; + exec <= '1'; + when others => + end case; + end if; + end process; + +pulse_count: + process (count1_reset, pulse) + begin + if count1_reset = '1' then + count1 <= (others => '0'); + elsif rising_edge(pulse) then + count1 <= count1 + 1; + end if; + end process; + +emuexec <= exec; +emurequest <= emuctl(0); +core_reset <= emuctl(15); + +-- Registers: +emudata_o <= emudat_o; + +-- FIXME: +-- These mappings should probably move to glue between TAP and core +-- to be more generic. + +emustat <= exstat & + "0000" & "00" & emurdy & emuack; + +end behaviour; |