summaryrefslogtreecommitdiffstats
path: root/zpu/hdl/tap/tap.vhd
blob: 41dc07b5370e5488fd31a13f3c13599a9bdcc135 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
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;
OpenPOWER on IntegriCloud