1 |
2 |
jamro |
-- logic analyser (LA) for FPGAs
|
2 |
|
|
-- ver 1.0
|
3 |
|
|
-- Author: Ernest Jamro
|
4 |
|
|
|
5 |
|
|
--//////////////////////////////////////////////////////////////////////
|
6 |
|
|
--//// Copyright (C) 2001 Authors and OPENCORES.ORG ////
|
7 |
|
|
--//// ////
|
8 |
|
|
--//// This source file may be used and distributed without ////
|
9 |
|
|
--/// restriction provided that this copyright statement is not ////
|
10 |
|
|
--//// removed from the file and that any derivative work contains ////
|
11 |
|
|
--//// the original copyright notice and the associated disclaimer. ////
|
12 |
|
|
--//// ////
|
13 |
|
|
--//// This source file is free software; you can redistribute it ////
|
14 |
|
|
--//// and/or modify it under the terms of the GNU Lesser General ////
|
15 |
|
|
--//// Public License as published by the Free Software Foundation; ////
|
16 |
|
|
--//// either version 2.1 of the License, or (at your option) any ////
|
17 |
|
|
--//// later version. ////
|
18 |
|
|
--//// ////
|
19 |
|
|
--//// This source is distributed in the hope that it will be ////
|
20 |
|
|
--//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
21 |
|
|
--//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
22 |
|
|
--//// PURPOSE. See the GNU Lesser General Public License for more ////
|
23 |
|
|
--//// details. ////
|
24 |
|
|
--//// ////
|
25 |
|
|
--//// You should have received a copy of the GNU Lesser General ////
|
26 |
|
|
--//// Public License along with this source; if not, download it ////
|
27 |
|
|
--//// from <http://www.opencores.org/lgpl.shtml> ////
|
28 |
|
|
|
29 |
|
|
|
30 |
|
|
------------------------------------------------------------------------------------
|
31 |
|
|
------------------------------------------------------------------------------------
|
32 |
|
|
-- logic analyser (LA) - probes signals states every rising clk, before/after the triger sequence
|
33 |
|
|
|
34 |
|
|
library IEEE;
|
35 |
|
|
use IEEE.std_logic_1164.all;
|
36 |
|
|
use IEEE.std_logic_unsigned.all;
|
37 |
|
|
|
38 |
|
|
|
39 |
|
|
entity log_anal is
|
40 |
|
|
generic(data_width: integer:= 16; -- width of the data that are analysed (must be power of 2)
|
41 |
|
|
mem_adr_width: integer:= 9; -- internal memory address width
|
42 |
|
|
adr_width: integer:= 11; -- adr_I address width
|
43 |
|
|
trig_width: integer:= 8; -- width of the triger logic
|
44 |
|
|
two_clocks: integer:= 0); -- two seperate clocks for control interface and logic analyser
|
45 |
|
|
-- the following rules must!!! be satysfied for generic:
|
46 |
|
|
-- data_width= 8, 16 or 32
|
47 |
|
|
-- adr_width= mem_adr_width + 1 + log2(data_width/8); 4<=mem_adr_width<=16
|
48 |
|
|
-- mem_adr_width<=16
|
49 |
|
|
-- trig_width<= 32
|
50 |
|
|
-- two_clocks= 0 (only wb_clk_I clock is used) 1- f_clk= k*f_wb_clk_I, 2- two asynchronous clocks
|
51 |
|
|
|
52 |
|
|
-- mem_adr_width optimal selection for 4kb BRAM (Virtex):
|
53 |
|
|
-- mem_adr_width<= 9 then number of BRAM block used= data_width/8
|
54 |
|
|
|
55 |
|
|
port (arst: in std_logic; -- global asynchronous set reset signal (mainly for simulation purposes)
|
56 |
|
|
-- interface for logic analyser
|
57 |
|
|
clk: in std_logic; -- seperate clock for logic analyzer (the same as wb_clk_I when two_clocks= 0)
|
58 |
|
|
data: in std_logic_vector(data_width-1 downto 0); -- data that are analysied
|
59 |
|
|
ce_data: in std_logic; -- clock enable -- should be used if data are recorded e.g. every second la_clk
|
60 |
|
|
trig: in std_logic_vector(trig_width-1 downto 0); -- triger bus (can be different that data bus
|
61 |
|
|
ce_trig: in std_logic; -- clock enable for triger bus
|
62 |
|
|
-- control WISHBOBE slave interface - interface for setting logic analyser options and transfering analysed data to computer
|
63 |
|
|
wb_clk_I: in STD_LOGIC; -- clock (common for every logic every logic analyser signals) - common for loagic analyser and WISHBONE control interface
|
64 |
|
|
wb_adr_I: in std_logic_vector(adr_width-1 downto 0); -- address bus (one bit wider than mem_adr_width)
|
65 |
|
|
wb_dat_I: in std_logic_vector(7 downto 0);
|
66 |
|
|
wb_dat_O: out std_logic_vector(7 downto 0);
|
67 |
|
|
wb_stb_I, wb_we_I: in std_logic;
|
68 |
|
|
-- wb_cyc_I: in std_logic; -- signal is ignored
|
69 |
|
|
-- wb_rst_I: in std_logic; -- the WISHBONE interface need not be reseted
|
70 |
|
|
wb_ack_O: buffer std_logic);
|
71 |
|
|
end log_anal;
|
72 |
|
|
|
73 |
|
|
architecture LA of log_anal is
|
74 |
|
|
-- TECHNOLOGY DEPENDENT MEMORY
|
75 |
|
|
component la_mem
|
76 |
|
|
generic ( data_width: integer:= 8; -- width of the data (la interface)
|
77 |
|
|
mem_adr_width: integer:= 9; -- width of the address (address width cannot be greater than max_address width (for data_width=1)
|
78 |
|
|
c_adr_width: integer:= 9; -- control interface address width = adr_width + log2(data_width/8)
|
79 |
|
|
two_clocks: integer:= 0 -- one or two seperate clocks are used
|
80 |
|
|
);
|
81 |
|
|
port (arst: in std_logic; -- asynchronous reset (mainly for simulation purposes
|
82 |
|
|
-- first port interface (for control and data read)
|
83 |
|
|
c_clk: in std_logic; -- clock
|
84 |
|
|
c_do: out std_logic_vector(7 downto 0); -- control interface signals
|
85 |
|
|
c_adr: in std_logic_vector(c_adr_width-1 downto 0);
|
86 |
|
|
-- second port for logic analyser data write
|
87 |
|
|
la_clk: in std_logic; -- clock (ignored when two_clocks=0)
|
88 |
|
|
la_we: in std_logic; -- write enable
|
89 |
|
|
la_di: in std_logic_vector(data_width-1 downto 0);
|
90 |
|
|
la_adr: in std_logic_vector(mem_adr_width-1 downto 0));
|
91 |
|
|
end component;
|
92 |
|
|
|
93 |
|
|
component la_trigger
|
94 |
|
|
generic (trig_width: integer); -- width of the trig data 1<=trig_width<=32
|
95 |
|
|
port (clk, arst: in std_logic;
|
96 |
|
|
-- LA interface
|
97 |
|
|
trig_data: in std_logic_vector(trig_width-1 downto 0); -- data that are alasysed for triger
|
98 |
|
|
trig_now: out std_logic; -- triger data is now presented on the trig_data bus
|
99 |
|
|
-- Control interface (to set and read triger values)
|
100 |
|
|
wr: in std_logic; -- when 1 writes din to triger configuration registers
|
101 |
|
|
adr: in std_logic_vector(3 downto 0);
|
102 |
|
|
dout: out std_logic_vector(7 downto 0);
|
103 |
|
|
din: in std_logic_vector(7 downto 0) );
|
104 |
|
|
end component;
|
105 |
|
|
|
106 |
|
|
signal ackR: std_logic; -- ack_O for (mainly for memory access)
|
107 |
|
|
signal data_q: std_logic_vector(data_width-1 downto 0); -- flip-flop to allow better routing of the data bus (the LA less influences Place&Route program)
|
108 |
|
|
signal trig_q: std_logic_vector(trig_width-1 downto 0); -- similar like data_q but for triger
|
109 |
|
|
signal ce_data_q: std_logic; -- flip-flop for clock enable signal
|
110 |
|
|
-- control signals
|
111 |
|
|
signal run: std_logic; -- LA is now acquiring new data (after triger has been found)
|
112 |
|
|
signal status_reg: std_logic_vector(7 downto 0); -- status register that will be read
|
113 |
|
|
signal trig_now: std_logic; -- proper triger is now presented at the trig input
|
114 |
|
|
signal trig_wr: std_logic; -- write to the triger configuration register
|
115 |
|
|
signal trig_datR: std_logic_vector(7 downto 0); -- read data form configuration register
|
116 |
|
|
signal wr_trig_counter: std_logic; -- a write to trig counter is done by the control interface
|
117 |
|
|
signal mem_we: std_logic; -- memory write enable
|
118 |
|
|
-- signals read/written by control interace
|
119 |
|
|
signal wb_reg_wr, wb_reg_wr_q: std_logic; -- wishbone writes to an internal control register (clock sinchronisation is considered)
|
120 |
|
|
signal reg_do, reg_do_q: std_logic_vector(7 downto 0); -- internal registers data out (according to the wb_adr_I
|
121 |
|
|
signal mem_do: std_logic_vector(7 downto 0); -- memory output data
|
122 |
|
|
signal counter: std_logic_vector(mem_adr_width-1 downto 0); -- counter which runs continuosly untill the LA finishes data acquisition
|
123 |
|
|
-- this counter point to the current data write possition, should be read to show the start (end) point for data reading
|
124 |
|
|
signal counter_rd: std_logic_vector(15 downto 0); -- like counter but MSBs are fill with zeros
|
125 |
|
|
signal trig_counter: std_logic_vector(mem_adr_width downto 0); -- counter which shows how much
|
126 |
|
|
-- data is still to be acquired, "10000..0"- full, "00..0"-empty
|
127 |
|
|
-- this counter can be written to point the triger position: "100..0" - do not triger
|
128 |
|
|
-- "011..1"- triger at the end, "00..0"- triger at the beginning, "0100..0"- triger at the half, "0XXXXX" - somewhere between
|
129 |
|
|
signal trig_counter_down: std_logic_vector(mem_adr_width downto 0); -- this counter checkes that
|
130 |
|
|
-- the proper number of data before the triger have been already recorded
|
131 |
|
|
-- this counter is especially importent when triger is at the end of the recorded data
|
132 |
|
|
-- therefore the data before the triger has to be written just before the triger (not a random data from the previous record)
|
133 |
|
|
type sel_type is (s_mem_data, s_status_reg, s_counter, s_triger, s_none); -- which device is selected
|
134 |
|
|
signal sel_dev: sel_type;
|
135 |
|
|
begin
|
136 |
|
|
-----------------------------------------------------------
|
137 |
|
|
-- clock synchronisation region
|
138 |
|
|
-- la_clk and stb_i_q selection
|
139 |
|
|
clk_g0: if two_clocks=0 generate
|
140 |
|
|
reg_do_q<= reg_do;
|
141 |
|
|
wb_reg_wr<= wb_we_i and wb_stb_i;
|
142 |
|
|
wb_ack_O<= wb_stb_i and ackR;
|
143 |
|
|
end generate;
|
144 |
|
|
|
145 |
|
|
clk_g1: if two_clocks>0 generate
|
146 |
|
|
-- wb_reg_wr flip-flop
|
147 |
|
|
process(clk, arst) begin
|
148 |
|
|
if arst='1' then wb_reg_wr<= '0';
|
149 |
|
|
elsif clk'event and clk='1' then
|
150 |
|
|
if wb_we_i='1' and -- write
|
151 |
|
|
ackR='1' and -- wait for one whole wb_clk_I cycle
|
152 |
|
|
wb_reg_wr='0' and wb_reg_wr_q='0' then-- wb_reg_wr is active only for one clk cycle
|
153 |
|
|
wb_reg_wr<= '1';
|
154 |
|
|
else
|
155 |
|
|
wb_reg_wr<= '0';
|
156 |
|
|
end if;
|
157 |
|
|
end if;
|
158 |
|
|
end process;
|
159 |
|
|
|
160 |
|
|
-- wb_reg_wr_q flip-flop
|
161 |
|
|
process(clk, arst, ackR) begin
|
162 |
|
|
if arst='1' or ackR='0' then -- ackR='0' if stb_i=0 or in the previous wb_clk a data transfer took place
|
163 |
|
|
wb_reg_wr_q<= '0';
|
164 |
|
|
elsif clk'event and clk='1' then
|
165 |
|
|
if wb_reg_wr='1' then
|
166 |
|
|
wb_reg_wr_q<= '1'; -- wait for asynchronous reset
|
167 |
|
|
end if;
|
168 |
|
|
end if;
|
169 |
|
|
end process;
|
170 |
|
|
-- reg_do_q flip-flops
|
171 |
|
|
process(wb_clk_I, arst) begin
|
172 |
|
|
if arst='1' then reg_do_q<="00000000";
|
173 |
|
|
elsif wb_clk_i='1' and wb_clk_i'event then
|
174 |
|
|
reg_do_q<= reg_do;
|
175 |
|
|
end if;
|
176 |
|
|
end process;
|
177 |
|
|
|
178 |
|
|
|
179 |
|
|
wb_ack_O<= wb_stb_i and ackR when wb_we_i='0' -- for control register read and memory read
|
180 |
|
|
else wb_stb_i and wb_reg_wr_q; -- for control register write
|
181 |
|
|
|
182 |
|
|
end generate; -- two_clocks>1
|
183 |
|
|
|
184 |
|
|
--------------------------------------------------------------
|
185 |
|
|
-- logic analyzer data region
|
186 |
|
|
-- data flip-flops
|
187 |
|
|
process(arst, clk) begin
|
188 |
|
|
if arst='1' then data_q<= (others=>'0');
|
189 |
|
|
elsif clk'event and clk='1' then
|
190 |
|
|
data_q<= data;
|
191 |
|
|
end if;
|
192 |
|
|
end process;
|
193 |
|
|
-- triger flip-flops
|
194 |
|
|
process(arst, clk) begin
|
195 |
|
|
if arst='1' then trig_q<= (others=> '0');
|
196 |
|
|
elsif clk'event and clk='1' then
|
197 |
|
|
if ce_trig='1' then
|
198 |
|
|
trig_q<= trig;
|
199 |
|
|
end if;
|
200 |
|
|
end if;
|
201 |
|
|
end process;
|
202 |
|
|
-- clock enable for data
|
203 |
|
|
process(arst, clk) begin
|
204 |
|
|
if arst='1' then ce_data_q<= '0';
|
205 |
|
|
elsif clk'event and clk='1' then
|
206 |
|
|
ce_data_q<= ce_data;
|
207 |
|
|
end if;
|
208 |
|
|
end process;
|
209 |
|
|
-- counter (increased every clk when analysed data are writen to memory)
|
210 |
|
|
process(arst, clk) begin
|
211 |
|
|
if arst='1' then counter<= (others=>'0');
|
212 |
|
|
elsif clk'event and clk='1' then
|
213 |
|
|
if trig_counter(mem_adr_width)='0' and ce_data_q='1' then -- when data acquisition has not been finished
|
214 |
|
|
counter<= counter + 1;
|
215 |
|
|
end if;
|
216 |
|
|
end if;
|
217 |
|
|
end process;
|
218 |
|
|
|
219 |
|
|
-- trig_counter (shows how many analysed data are still to be recorded) recording stops if the counter is overflowed
|
220 |
|
|
process(arst, clk) begin
|
221 |
|
|
if arst='1' then trig_counter<= (others=>'0');
|
222 |
|
|
elsif clk'event and clk='1' then
|
223 |
|
|
if wr_trig_counter='1' then
|
224 |
|
|
if mem_adr_width>=6 then
|
225 |
|
|
trig_counter(mem_adr_width downto mem_adr_width-6)<= wb_dat_i(6 downto 0); -- write only 7 MSBs of the trig_counter
|
226 |
|
|
trig_counter(mem_adr_width-7 downto 0)<= (others=> '0');
|
227 |
|
|
else
|
228 |
|
|
trig_counter<= wb_dat_i(6 downto 6-mem_adr_width);
|
229 |
|
|
end if;
|
230 |
|
|
elsif run='1' and ce_data_q='1' then -- acquisition is not finished
|
231 |
|
|
trig_counter<= trig_counter + 1;
|
232 |
|
|
end if;
|
233 |
|
|
end if;
|
234 |
|
|
end process;
|
235 |
|
|
-- trig counter down - triger is enable when a proper number of data before triger has been recorded
|
236 |
|
|
process(arst, clk) begin
|
237 |
|
|
if arst='1' then trig_counter_down<= (others=>'0');
|
238 |
|
|
elsif clk'event and clk='1' then
|
239 |
|
|
if wr_trig_counter='1' then
|
240 |
|
|
if mem_adr_width>=6 then
|
241 |
|
|
trig_counter_down(mem_adr_width downto mem_adr_width-6)<= wb_dat_i(6 downto 0); -- write only 7 MSBs of the trig_counter
|
242 |
|
|
trig_counter_down(mem_adr_width-7 downto 0)<= (others=> '0');
|
243 |
|
|
else --mem_adr_width< 6
|
244 |
|
|
trig_counter_down<= wb_dat_i(6 downto 6-mem_adr_width);
|
245 |
|
|
end if;
|
246 |
|
|
elsif trig_counter_down(mem_adr_width)='0' and ce_data_q='1' then -- not enought data has been written to the memory before the triger
|
247 |
|
|
trig_counter_down<= trig_counter_down - 1;
|
248 |
|
|
end if;
|
249 |
|
|
end if;
|
250 |
|
|
end process;
|
251 |
|
|
-- run logic
|
252 |
|
|
process(arst, clk) begin
|
253 |
|
|
if arst='1' then run<='0';
|
254 |
|
|
elsif clk'event and clk='1' then
|
255 |
|
|
if wr_trig_counter='1' then
|
256 |
|
|
run<= wb_dat_i(7); -- remember that if datW(7)=1 then datW(6 downto 0) should be "00..0"
|
257 |
|
|
elsif trig_counter(mem_adr_width)='1' then
|
258 |
|
|
run<= '0'; -- whole memory have been written
|
259 |
|
|
elsif trig_now='1' and trig_counter_down(mem_adr_width)='1' then -- activate run only if proper number of data has been recorded before the triger
|
260 |
|
|
run<= '1';
|
261 |
|
|
end if;
|
262 |
|
|
end if;
|
263 |
|
|
end process;
|
264 |
|
|
wr_trig_counter<= '1' when sel_dev = s_status_reg and wb_reg_wr='1' else '0';
|
265 |
|
|
|
266 |
|
|
|
267 |
|
|
----- triger logic
|
268 |
|
|
trigger: la_trigger
|
269 |
|
|
generic map (trig_width=>trig_width)
|
270 |
|
|
port map (clk=>clk, arst=> arst, trig_data=> trig_q, trig_now=> trig_now,
|
271 |
|
|
-- Control interface (to set and read triger values)
|
272 |
|
|
wr=> trig_wr, adr=> wb_adr_I(3 downto 0), dout=> trig_datR, din=> wb_dat_I);
|
273 |
|
|
|
274 |
|
|
trig_wr<= '1' when wb_reg_wr='1' and sel_dev=s_triger else '0';
|
275 |
|
|
|
276 |
|
|
|
277 |
|
|
-- addrss space
|
278 |
|
|
-- 0-1FF - main LA memory (for a single BRAM 4kb)
|
279 |
|
|
-- 200 control registers based address
|
280 |
|
|
-- 200 - status (b7=run, b6= finish, b5-b0 - triger start, 111111- at the end, 000001- at the beginning
|
281 |
|
|
-- 204 - stop counter - points where the last recorded data is in the LA main memory
|
282 |
|
|
-- 208-20B - trigger value (0- triger when 0, 1- triger when the trig data is 1)
|
283 |
|
|
-- 20C-20F - trigger consider (0- do not care about the input (X), 1- consider the input bit)
|
284 |
|
|
|
285 |
|
|
sel_dev<= s_mem_data when wb_adr_I(adr_width-1)='0' else -- data memory
|
286 |
|
|
s_triger when wb_adr_I(3)='1' else
|
287 |
|
|
s_counter when wb_adr_I(2 downto 1)= "10" else
|
288 |
|
|
s_status_reg when wb_adr_I(2 downto 0)= "000" else
|
289 |
|
|
s_none;
|
290 |
|
|
|
291 |
|
|
|
292 |
|
|
mem_we<= ce_data_q and not trig_counter(mem_adr_width); -- when valid data and not whole buffer written
|
293 |
|
|
-- memory block
|
294 |
|
|
mem: la_mem
|
295 |
|
|
generic map (data_width=> data_width, mem_adr_width=> mem_adr_width,
|
296 |
|
|
c_adr_width=> adr_width-1, two_clocks=> two_clocks)
|
297 |
|
|
port map (arst=> arst, c_clk=> wb_clk_I, c_do=> mem_do,
|
298 |
|
|
c_adr=> wb_adr_I(adr_width-2 downto 0),
|
299 |
|
|
-- second port for logic analyser data write
|
300 |
|
|
la_clk=> clk, la_we=> mem_we, la_di=> data_q, la_adr=> counter);
|
301 |
|
|
|
302 |
|
|
-- read registers
|
303 |
|
|
counter_rd(mem_adr_width-1 downto 0)<= counter;
|
304 |
|
|
gc15: if mem_adr_width<=15 generate -- fill MSB of counter width 0s
|
305 |
|
|
counter_rd(15 downto mem_adr_width)<= (others=> '0');
|
306 |
|
|
end generate;
|
307 |
|
|
-- status register
|
308 |
|
|
gs8: if mem_adr_width>=6 generate
|
309 |
|
|
status_reg<= run & trig_counter(mem_adr_width downto mem_adr_width-6);
|
310 |
|
|
end generate;
|
311 |
|
|
gs7: if mem_adr_width<= 5 generate
|
312 |
|
|
status_reg(7 downto 6-mem_adr_width)<= run & trig_counter;
|
313 |
|
|
status_reg(5-mem_adr_width downto 0)<= (others=>'0');
|
314 |
|
|
end generate;
|
315 |
|
|
|
316 |
|
|
-- data out multiplexer
|
317 |
|
|
wb_dat_o<= mem_do when sel_dev=s_mem_data else -- memory is clocked by wb_clk_I so need not additional register
|
318 |
|
|
reg_do_q; -- reg_out is registered only when two_clocks=1
|
319 |
|
|
|
320 |
|
|
reg_do<= trig_datR when sel_dev= s_triger else
|
321 |
|
|
counter_rd(15 downto 8) when sel_dev= s_counter and wb_adr_I(0)='1' else
|
322 |
|
|
counter_rd(7 downto 0) when sel_dev= s_counter and wb_adr_I(0)='0' else
|
323 |
|
|
status_reg when sel_dev = s_status_reg else
|
324 |
|
|
"00000000";
|
325 |
|
|
|
326 |
|
|
-- ackR logic (ack_O for reading) BRAM needs 2 clock cycles for reading
|
327 |
|
|
process(arst, wb_clk_I) begin
|
328 |
|
|
if arst='1' then ackR<= '0';
|
329 |
|
|
elsif wb_clk_I'event and wb_clk_I='1' then
|
330 |
|
|
ackR<= not wb_ack_O and wb_stb_I; -- strobe is active (valid address) and not data transfer
|
331 |
|
|
end if;
|
332 |
|
|
end process;
|
333 |
|
|
|
334 |
|
|
-- check generic values:
|
335 |
|
|
assert data_width=32 or data_width=16 or data_width=8
|
336 |
|
|
report "Error in log_anal: data_width must be: 8, 16 or 32"
|
337 |
|
|
severity failure;
|
338 |
|
|
assert mem_adr_width<=16 and mem_adr_width>=4
|
339 |
|
|
report "Error in log_anal: mem_adr_width must not be in range 4 to 16"
|
340 |
|
|
severity failure;
|
341 |
|
|
assert (adr_width = mem_adr_width+1 and data_width=8) or
|
342 |
|
|
(adr_width = mem_adr_width+2 and data_width=16) or
|
343 |
|
|
(adr_width = mem_adr_width+3 and data_width=32)
|
344 |
|
|
report "Error in log_anal: c_adr_width should be: adr_width + 1 + log2(data_width/8)"
|
345 |
|
|
severity failure;
|
346 |
|
|
assert trig_width<=32
|
347 |
|
|
report "Error in log_anal: trig_width must not be greater than 32"
|
348 |
|
|
severity failure;
|
349 |
|
|
end LA;
|