Hi every one, I had a problem this morning in a functionnal simulation that I finally traced to the unisim library. Basically, internally they do : prcs_clk: process (clk) begin if (clk'event) then clk_wire <= clk; end if; end process; Then, they use clk_wire in their processes and co, to sample the data that I generated using clk. I can understand that it fails ... Because clk_wire will toggle 1 delta after clk and so then the "rising_edges(clk_wire)" will be evaluated, the value of my FF clocked on clk will already have switched ... Now, to my _BIG_ surprise, doing clk_wire <= clk; -- (no process, just an asignement ... ) ALSO fails ... with the same problem. I personnly think it should not, because an assignement should be like an alias, I don't do any operation on it so there is no point in making it "toggle" one delta later ... I've done a little testbench ( see http://pastebin.com/m133bbae0 , or also at the end of this post) and that leads to surprising results ... Any one can enlighten me on _why_ this happens ? Sylvain -------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library unisim; use unisim.vcomponents.all; entity xlx_bug_test is end xlx_bug_test; architecture xbt_a of xlx_bug_test is signal cnt : std_logic_vector(7 downto 0) := x"00"; signal data_me : std_logic_vector(7 downto 0); signal addr_xlx : std_logic_vector(7 downto 0); signal sample_data_me1 : std_logic_vector(7 downto 0); signal sample_addr_me1 : std_logic_vector(7 downto 0); signal sample_data_me2 : std_logic_vector(7 downto 0); signal sample_addr_me2 : std_logic_vector(7 downto 0); signal sample_data_xlx : std_logic_vector(7 downto 0); signal sample_addr_xlx : std_logic_vector(7 downto 0); signal clk : std_logic := '0'; signal clk_2_me : std_logic := '0'; signal clk_2_xlx : std_logic; begin clk <= not clk after 10 ns; -- Create a simple counter --------------------------- process (clk) begin if rising_edge(clk) then cnt <= cnt + 1; end if; end process; -- Sample it two times ------------------------ -- Once 'normally' and say it's the data process (clk) begin if rising_edge(clk) then data_me <= cnt; end if; end process; -- Once using FD instances and call it address fdgen: for i in 7 downto 0 generate fd_i: FD port map ( D => cnt(i), Q => addr_xlx(i), C => clk ); end generate; -- Assign a clock signal without changing it --------------------------------------------- -- One way to do it ... clk_2_me <= clk; -- The Xilinx (tm) way ... -- ( $XILINX/vhdl/src/unisims/unisim_VITAL.vhd : 145946 in the RAMB16 model) prcs_clk: process (clk) begin if (clk'event) then clk_2_xlx <= clk; end if; end process; -- Sampling the data ---------------------- process (clk) begin if rising_edge(clk) then sample_addr_me1 <= addr_xlx; sample_data_me1 <= data_me; end if; end process; process (clk_2_me) begin if rising_edge(clk_2_me) then sample_addr_me2 <= addr_xlx; sample_data_me2 <= data_me; end if; end process; process (clk_2_xlx) begin if rising_edge(clk_2_xlx) then sample_addr_xlx <= addr_xlx; sample_data_xlx <= data_me; end if; end process; end xbt_a;
Xilinx/ModelSim bug ? Clocking headache ...
Started by ●July 31, 2007
Reply by ●July 31, 20072007-07-31
On Jul 31, 7:25 am, Sylvain Munaut <tnt-at-246tNt- dot-...@youknowwhattodo.com> wrote:> Hi every one, > > I had a problem this morning in a functionnal simulation that I finally > traced to the unisim library. > > Basically, internally they do : > > prcs_clk: process (clk) > begin > if (clk'event) then > clk_wire <= clk; > end if; > end process; > > Then, they use clk_wire in their processes and co, to sample the data > that I generated using clk. > I can understand that it fails ... Because clk_wire will toggle 1 delta > after clk and so then the "rising_edges(clk_wire)" will be evaluated, > the value of my FF clocked on clk will already have switched ... > > Now, to my _BIG_ surprise, doing > > clk_wire <= clk; -- (no process, just an asignement ... ) > > ALSO fails ... with the same problem. I personnly think it should not, > because an assignement should be like an alias, I don't do > any operation on it so there is no point in making it > "toggle" one delta later ... > > I've done a little testbench ( seehttp://pastebin.com/m133bbae0, or also > at the end of this post) and that leads to surprising results ... > > Any one can enlighten me on _why_ this happens ? > > Sylvain > > -------------------------------------- > > library ieee; > use ieee.std_logic_1164.all; > use ieee.std_logic_arith.all; > use ieee.std_logic_unsigned.all; > > library unisim; > use unisim.vcomponents.all; > > entity xlx_bug_test is > end xlx_bug_test; > > architecture xbt_a of xlx_bug_test is > > signal cnt : std_logic_vector(7 downto 0) := x"00"; > > signal data_me : std_logic_vector(7 downto 0); > signal addr_xlx : std_logic_vector(7 downto 0); > > signal sample_data_me1 : std_logic_vector(7 downto 0); > signal sample_addr_me1 : std_logic_vector(7 downto 0); > signal sample_data_me2 : std_logic_vector(7 downto 0); > signal sample_addr_me2 : std_logic_vector(7 downto 0); > signal sample_data_xlx : std_logic_vector(7 downto 0); > signal sample_addr_xlx : std_logic_vector(7 downto 0); > > signal clk : std_logic := '0'; > > signal clk_2_me : std_logic := '0'; > signal clk_2_xlx : std_logic; > > begin > > clk <= not clk after 10 ns; > > -- Create a simple counter > --------------------------- > > process (clk) > begin > if rising_edge(clk) then > cnt <= cnt + 1; > end if; > end process; > > -- Sample it two times > ------------------------ > > -- Once 'normally' and say it's the data > process (clk) > begin > if rising_edge(clk) then > data_me <= cnt; > end if; > end process; > > -- Once using FD instances and call it address > fdgen: for i in 7 downto 0 generate > fd_i: FD port map ( > D => cnt(i), > Q => addr_xlx(i), > C => clk > ); > end generate; > > -- Assign a clock signal without changing it > --------------------------------------------- > > -- One way to do it ... > clk_2_me <= clk; > -- The Xilinx (tm) way ... > -- ( $XILINX/vhdl/src/unisims/unisim_VITAL.vhd : 145946 in the RAMB16 model) > prcs_clk: process (clk) > begin > if (clk'event) then > clk_2_xlx <= clk; > end if; > end process; > > -- Sampling the data > ---------------------- > > process (clk) > begin > if rising_edge(clk) then > sample_addr_me1 <= addr_xlx; > sample_data_me1 <= data_me; > end if; > end process; > > process (clk_2_me) > begin > if rising_edge(clk_2_me) then > sample_addr_me2 <= addr_xlx; > sample_data_me2 <= data_me; > end if; > end process; > > process (clk_2_xlx) > begin > if rising_edge(clk_2_xlx) then > sample_addr_xlx <= addr_xlx; > sample_data_xlx <= data_me; > end if; > end process; > > end xbt_a;A concurrent assignment statement (unlike a port assignment), is not like an alias. Concurrent assignment statements are implied processes with a sensitivity list made up of all signals on the RHS of the assignment. So, they would incur a delta delay for the assignment as well. Andy
Reply by ●July 31, 20072007-07-31
Andy wrote:> On Jul 31, 7:25 am, Sylvain Munaut <tnt-at-246tNt- > dot-...@youknowwhattodo.com> wrote: > >> I had a problem this morning in a functionnal simulation that I finally >> traced to the unisim library. >> >> Basically, internally they do : >> >> prcs_clk: process (clk) >> begin >> if (clk'event) then >> clk_wire <= clk; >> end if; >> end process; >> >> Then, they use clk_wire in their processes and co, to sample the data >> that I generated using clk. >> I can understand that it fails ... Because clk_wire will toggle 1 delta >> after clk and so then the "rising_edges(clk_wire)" will be evaluated, >> the value of my FF clocked on clk will already have switched ... >> >> Now, to my _BIG_ surprise, doing >> >> clk_wire <= clk; -- (no process, just an asignement ... ) >> >> ALSO fails ... with the same problem. I personnly think it should not, >> because an assignement should be like an alias, I don't do >> any operation on it so there is no point in making it >> "toggle" one delta later ... >> >> I've done a little testbench ( seehttp://pastebin.com/m133bbae0, or also >> at the end of this post) and that leads to surprising results ... >> >> Any one can enlighten me on _why_ this happens ? >> >> Sylvain > > A concurrent assignment statement (unlike a port assignment), is not > like an alias. Concurrent assignment statements are implied processes > with a sensitivity list made up of all signals on the RHS of the > assignment. So, they would incur a delta delay for the assignment as > well.well, that sucks ... For normal signals that doesn't matter much but for clock I'd like a way to force a "zero delta assigment". Basically at several place I have a "GENERIC" that tells me either to be synchronous or not. If it's true, all of my block will run at clk_1 and instanciate a synchronous fifo. When it's false, part of the process are clocked on clk_2 and I instanciate a async FIFO. Something like : ---- CUT ---- port ( ... ... clk_1 : in std_logic; clk_1 : in std_logic; ... ); ... signal clk_i : std_logic; sync: if SYNC generate -- Assign clock clk_i <= clk_1; -- Synchronous FIFO instance -- ... (using clk_1 only) end generate async: if SYNC generate -- Assign clock clk_i <= clk_2; -- ASynchronous FIFO instance -- ... (using clk_1 on writeclk and clk_2 on readclk ) end generate -- Sub Block (either clocked on my_subblock_i: subblock port map ( -- The fifo signals -- .... clk => clk_i; ... ); ---- END OF CUT ---- But then clk_i is 1 delta too late ... that sucks. Sylvain
Reply by ●July 31, 20072007-07-31
I just noticed I didn't even mention what Xilinx had to do with that ;) In the BRAM simulation model, they do such a clock assignement : clk_wire <= CLKA; And they do it also for addra, addrb, wea and web. So these also receive a 1 delta delay ... So that makes the read work (kinda, because EN, SSR adn REGCE are not delayed by 1 delta). But the write happen 1 cycle too early. And since some signal receive a delay and some other not, ... that makes the whole thing weird. Sylvain
Reply by ●July 31, 20072007-07-31
Sylvain Munaut wrote:> For normal signals that doesn't matter much but for clock I'd like a > way to force a "zero delta assigment".Then don't declare the signal clk_wire. Just use clk everywhere. -- Mike Treseler
Reply by ●July 31, 20072007-07-31
Mike Treseler wrote:> Sylvain Munaut wrote: > >> For normal signals that doesn't matter much but for clock I'd like a >> way to force a "zero delta assigment". > > Then don't declare the signal clk_wire. > Just use clk everywhere. > > -- Mike TreselerYes, but I can't do that in every case : - In one case, this is _inside_ the Xilinx Unisim library ... - In another case, I want to be able to select one clock or another depending on a GENERIC. - Finally in another case I want to export an interface (in a port), where the sub block exports the clk. like : port ( video_out_data : out std_logic_vector(24 downto 0); video_out_en : out std_logic; video_out_clk : out std_logic; ); For this case, I can probably solve the issue by making video_out_data and video_out_en first in some internal signals, then assign them to the output port. For the other cases, that's a whole lot harder ... And I don't find this behavior correct, because it's pretty far from what the real hw do ... IMHO direct assigments (without operation) should be handled as having no delta delay. And maybe force a way to have one (like after 1 delta). Or _at_least_ offer some way to force a zero delta assignement .... like clk_1 <0= clk; ... If you have a solution for my two other use cases, please, tell me ;) Sylvain
Reply by ●July 31, 20072007-07-31
On Tue, 31 Jul 2007 16:38:13 +0200, Sylvain Munaut <tnt-at-246tNt-dot-com@youknowwhattodo.com> wrote:>In the BRAM simulation model, they do such a clock assignement : > > clk_wire <= CLKA; > >And they do it also for addra, addrb, wea and web. So these also >receive a 1 delta delay ... > >So that makes the read work (kinda, because EN, SSR adn REGCE are not delayed by 1 delta). >But the write happen 1 cycle too early. >And since some signal receive a delay and some other not, ... that makes the whole thing weird.It's a standard source of unexpected behaviour in zero-delay VHDL models, and one of the very few reasons why I sometimes prefer Verilog for behavioural modelling - you can do zero-delay combinational signal assignment in Verilog. I don't understand what's going on in your Xilinx models. I can't believe they put out code that doesn't work with zero delays. You can be fairly sure it will work correctly when all the non-zero (post place-and-route) delays are backannotated into it. If you're desperate, introduce a tiny non-zero delay in all input signals except the clock, by copying them with a delay: port_signal <= input_signal after 1 ns; But that sucks, doesn't it? -- Jonathan Bromley, Consultant DOULOS - Developing Design Know-how VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK jonathan.bromley@MYCOMPANY.com http://www.MYCOMPANY.com The contents of this message may contain personal views which are not the views of Doulos Ltd., unless specifically stated.
Reply by ●August 1, 20072007-08-01
> It's a standard source of unexpected behaviour in zero-delay > VHDL models, and one of the very few reasons why I sometimes > prefer Verilog for behavioural modelling - you can do zero-delay > combinational signal assignment in Verilog.I wish that too now ...> I don't understand what's going on in your Xilinx models. I > can't believe they put out code that doesn't work with > zero delays.But they did ... Here's a test case : http://pastebin.com/m71704926 And the simulation output : http://www.246tnt.com/files/bram_write.png http://www.246tnt.com/files/bram_read.png Basically cnt, cnt_d1, cnt_d2 and cnt_d3 are connected to the BRAM Data In. And they are assignement one of another : cnt_d1 <= cnt; cnt_d2 <= cnt_d1; cnt_d3 <= cnt_d3; So when we write at address 1DC0 the value 12121212 with wren = 1100, we expect it to store 12120000 ... but when you look at the read result (the output register is active so there's 2 clock delay), we get ... 13120000 ...> You can be fairly sure it will work correctly > when all the non-zero (post place-and-route) delays are > backannotated into it.Yes sure that will work. And all their models have a 100 ps delay output btw .. so that post synthesis simulation work OK.> If you're desperate, introduce a tiny non-zero delay in all > input signals except the clock, by copying them with a delay: > > port_signal <= input_signal after 1 ns; > > But that sucks, doesn't it?Yes that sucks _big_time_ Sylvain
Reply by ●August 1, 20072007-08-01
Jonathan Bromley wrote:> I don't understand what's going on in your Xilinx models. I > can't believe they put out code that doesn't work with > zero delays.They do. So did micron with their sdram models.> You can be fairly sure it will work correctly > when all the non-zero (post place-and-route) delays are > backannotated into it. > > If you're desperate, introduce a tiny non-zero delay in all > input signals except the clock, by copying them with a delay:Or make a delayed clock for the pseudo-zero-delay models. This is one reason I stick to synchronous functional simulation and I leave the timing to STA. -- Mike Treseler
Reply by ●August 1, 20072007-08-01
On Jul 31, 8:25 am, Sylvain Munaut <tnt-at-246tNt- dot-...@youknowwhattodo.com> wrote:> Andy wrote: > > On Jul 31, 7:25 am, Sylvain Munaut <tnt-at-246tNt- > > dot-...@youknowwhattodo.com> wrote: > > >> I had a problem this morning in a functionnal simulation that I finally > >> traced to the unisim library. > > >> Basically, internally they do : > > >> prcs_clk: process (clk) > >> begin > >> if (clk'event) then > >> clk_wire <= clk; > >> end if; > >> end process; > > >> Then, they use clk_wire in their processes and co, to sample the data > >> that I generated using clk. > >> I can understand that it fails ... Because clk_wire will toggle 1 delta > >> after clk and so then the "rising_edges(clk_wire)" will be evaluated, > >> the value of my FF clocked on clk will already have switched ... > > >> Now, to my _BIG_ surprise, doing > > >> clk_wire <= clk; -- (no process, just an asignement ... ) > > >> ALSO fails ... with the same problem. I personnly think it should not, > >> because an assignement should be like an alias, I don't do > >> any operation on it so there is no point in making it > >> "toggle" one delta later ... > > >> I've done a little testbench ( seehttp://pastebin.com/m133bbae0, or also > >> at the end of this post) and that leads to surprising results ... > > >> Any one can enlighten me on _why_ this happens ? > > >> Sylvain > > > A concurrent assignment statement (unlike a port assignment), is not > > like an alias. Concurrent assignment statements are implied processes > > with a sensitivity list made up of all signals on the RHS of the > > assignment. So, they would incur a delta delay for the assignment as > > well. > > well, that sucks ... > For normal signals that doesn't matter much but for clock I'd like a > way to force a "zero delta assigment". > > Basically at several place I have a "GENERIC" that tells me either to > be synchronous or not. If it's true, all of my block will run at clk_1 > and instanciate a synchronous fifo. When it's false, part of the process > are clocked on clk_2 and I instanciate a async FIFO. > > Something like : > > ---- CUT ---- > > port ( > ... > ... > clk_1 : in std_logic; > clk_1 : in std_logic; > ... > ); > > ... > > signal clk_i : std_logic; > > sync: if SYNC generate > > -- Assign clock > clk_i <= clk_1; > > -- Synchronous FIFO instance > -- ... (using clk_1 only) > > end generate > > async: if SYNC generate > > -- Assign clock > clk_i <= clk_2; > > -- ASynchronous FIFO instance > -- ... (using clk_1 on writeclk and clk_2 on readclk ) > > end generate > > -- Sub Block (either clocked on > my_subblock_i: subblock > port map ( > -- The fifo signals > -- .... > clk => clk_i; > ... > ); > > ---- END OF CUT ---- > > But then clk_i is 1 delta too late ... that sucks. > > SylvainInstead of wrapping the clk_i assignments in generate statements, wrap the my_sublock instantiation in two generate statements, one with clk_1, and one with clk_2. Maybe not the solution you were looking for, but it will work. Andy






