1 -------------------------------------------------------------------------------
3 -- $Id: fjmem_core.vhd 1071 2008-02-21 20:34:04Z arniml $
5 -- jmem_core - a generic interface module for accessing on-chip and off-chip
6 -- memory and peripherals
8 -- For host software support visit
11 -- This program is free software; you can redistribute it and/or
12 -- modify it under the terms of the GNU General Public License
13 -- as published by the Free Software Foundation; either version 2
14 -- of the License, or (at your option) any later version.
16 -- This program is distributed in the hope that it will be useful,
17 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
18 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 -- GNU General Public License for more details.
21 -- You should have received a copy of the GNU General Public License
22 -- along with this program; if not, write to the Free Software
23 -- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26 -- Written by Arnim Laeuger <arniml@users.sourceforge.net>, 2008.
28 -------------------------------------------------------------------------------
31 use ieee.std_logic_1164.all;
33 use work.fjmem_config_pack.all;
34 use work.fjmem_pack.all;
39 -- JTAG Interface ---------------------------------------------------------
40 clkdr_i : in std_logic;
41 trst_i : in std_logic;
42 shift_i : in std_logic;
43 update_i : in std_logic;
45 tdo_o : out std_logic;
46 -- Memory Interface -------------------------------------------------------
49 strobe_o : out std_logic;
50 read_o : out std_logic;
51 write_o : out std_logic;
53 cs_o : out std_logic_vector(num_blocks_c-1 downto 0);
54 addr_o : out std_logic_vector(max_addr_width_c-1 downto 0);
55 din_i : in std_logic_vector(max_data_width_c-1 downto 0);
56 dout_o : out std_logic_vector(max_data_width_c-1 downto 0)
63 use ieee.numeric_std.all;
65 architecture rtl of fjmem_core is
67 signal trst_s : boolean;
69 capture_en_s : boolean;
71 signal shift_q : std_logic_vector(shift_range_t);
72 signal update_q : std_logic_vector(shift_range_t);
74 signal res_s : boolean;
76 signal din_q : std_logic_vector(data_range_t);
78 ack_for_shift_q : std_logic;
80 signal instr_q : std_logic_vector(instr_range_t);
81 signal block_q : std_logic_vector(block_range_t);
82 signal strobe_toggle_q : std_logic;
83 signal addr_q : std_logic_vector(addr_range_t);
84 signal dout_q : std_logic_vector(data_range_t);
86 signal strobe_sync_q : std_logic_vector(1 downto 0);
87 signal strobe_edge_q : std_logic;
91 -----------------------------------------------------------------------------
92 -- Mapping of input signals to internal flags
93 -----------------------------------------------------------------------------
94 trst_s <= trst_i = trst_act_level_c;
95 shift_en_s <= shift_i = shift_act_level_c;
96 capture_en_s <= shift_i /= shift_act_level_c;
98 res_s <= res_i = res_act_level_c;
101 -----------------------------------------------------------------------------
105 -- Implements the shift register between tdi_i and tdo_o.
107 -- Instruction are handled as follows.
110 -- detect : a dedicated pattern is captured that allows that marks the
111 -- variable length fields:
112 -- * block field marked with '1'
113 -- * address field marked with '0'
114 -- * data field marked with '1'
115 -- This allows the host software to detect how these fields are
116 -- located inside the bit stream (total length of bitstream has
117 -- been determined previously).
118 -- query : Based on the shifted block number, the used bits in the
119 -- address and data field are marked with '1'. This reports the
120 -- specific addr and data widths of the specified block.
122 shift: process (trst_s, clkdr_i)
123 variable addr_width_v,
124 data_width_v : natural;
125 variable idx_v : natural;
128 shift_q <= (others => '0');
130 elsif rising_edge(clkdr_i) then
133 shift_q(shift_width_c-2 downto 0) <= shift_q(shift_width_c-1 downto 1);
134 shift_q(shift_width_c-1) <= tdi_i;
138 idx_v := to_integer(unsigned(shift_q(block_range_t)));
139 if idx_v < num_blocks_c then
140 addr_width_v := blocks_c(idx_v).addr_width;
141 data_width_v := blocks_c(idx_v).data_width;
149 shift_q(instr_range_t) <= instr_q;
150 shift_q(shift_ack_pos_c) <= ack_for_shift_q;
151 shift_q(data_range_t) <= din_q;
153 when instr_write_c =>
154 shift_q(instr_range_t) <= instr_q;
157 shift_q <= (others => '0');
159 when instr_detect_c =>
160 shift_q <= (others => '0');
161 shift_q(instr_range_t) <= instr_q;
162 -- mark block field with '1'
163 shift_q(block_range_t) <= (others => '1');
164 -- mark address field with '0'
165 shift_q(addr_range_t) <= (others => '0');
166 -- mark data field with '1'
167 shift_q(data_range_t) <= (others => '1');
169 when instr_query_c =>
170 if idx_v < num_blocks_c then
171 shift_q <= (others => '0');
172 -- mark used address bits of this block in the address field with '1'
173 for idx in addr_range_t loop
174 if idx < shift_addr_pos_c + addr_width_v then
178 -- mark used data bits of this block in the data field '1'
179 for idx in data_range_t loop
180 if idx < shift_data_pos_c + data_width_v then
186 shift_q <= (others => '0');
188 shift_q(instr_range_t) <= instr_q;
191 shift_q <= (others => '-');
192 shift_q(instr_range_t) <= instr_q;
199 -----------------------------------------------------------------------------
202 -----------------------------------------------------------------------------
206 -- Stores the provided data at din_i for later capture.
207 -- The ack_i input is stored in a two-stage pipeline to allow din_q to
208 -- settle before ack is actually detected in the clkdr clock domain.
210 din: process (res_s, clk_i)
213 din_q <= (others => '0');
215 ack_for_shift_q <= '0';
217 elsif rising_edge(clk_i) then
222 ack_for_shift_q <= ack_q;
224 if ack_for_shift_q = '1' then
225 -- reset for the moment, functionality not yet complete
232 -----------------------------------------------------------------------------
235 -----------------------------------------------------------------------------
239 -- Stores the updated block, instruction, address and data fields.
241 dout: process (trst_s, update_i)
244 instr_q <= instr_idle_c;
245 block_q <= (others => '0');
246 addr_q <= (others => '0');
247 dout_q <= (others => '0');
248 strobe_toggle_q <= '0';
250 elsif rising_edge(update_i) then
251 instr_q <= shift_q(instr_range_t);
252 block_q <= shift_q(block_range_t);
253 addr_q <= shift_q(addr_range_t);
254 dout_q <= shift_q(data_range_t);
256 strobe_toggle_q <= not strobe_toggle_q;
261 -----------------------------------------------------------------------------
264 -----------------------------------------------------------------------------
265 -- Process strobe_sync
268 -- Implements the synchronizer for the strobe signal from clkdr_i to
269 -- clk_i domain. This is a toggle synchronizer.
271 strobe_sync: process (res_s, clk_i)
274 strobe_sync_q <= (others => '0');
275 strobe_edge_q <= '0';
277 elsif rising_edge(clk_i) then
278 strobe_sync_q(1) <= strobe_toggle_q;
279 strobe_sync_q(0) <= strobe_sync_q(1);
281 strobe_edge_q <= strobe_sync_q(0);
283 end process strobe_sync;
285 -----------------------------------------------------------------------------
288 -----------------------------------------------------------------------------
292 -- Generates the cs_o output vector.
294 cs_gen: process (block_q)
296 for idx in 0 to num_blocks_c-1 loop
297 if idx = to_integer(unsigned(block_q)) then
305 -----------------------------------------------------------------------------
308 -----------------------------------------------------------------------------
310 -----------------------------------------------------------------------------
312 strobe_o <= strobe_sync_q(0) xor strobe_edge_q;
313 read_o <= '1' when instr_q = instr_read_c else '0';
314 write_o <= '1' when instr_q = instr_write_c else '0';