Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Altera_Forum
Honored Contributor I
1,019 Views

problem (?) using shared variables

Hi, 

 

I need your kind opinion. Please, anyone explain me why the following code is not running. 

 

VHDL code (sel-explainable) 

------------------------------------------------------ entity counter_with_sharedvar is port (clk: in bit; digit1, digit2: out integer range 0 to 9); end entity; ------------------------------------------------------ architecture counter of counter_with_sharedvar is shared variable temp1, temp2: integer range 0 to 9; begin ---------------------------------- proc1: process (clk) begin if (clk'EVENT and clk='1') then if (temp1=9) then temp1 := 0; else temp1 := temp1 + 1; end if; end if; end process proc1; ---------------------------------- proc2: process (clk) begin if (clk'EVENT and clk='1') then if (temp1=9) then if (temp2=9) then temp2 := 0; else temp2 := temp2 + 1; end if; end if; end if; end process proc2; ---------------------------------- digit1 <= temp1; digit2 <= temp2; end architecture;  

 

 

VHDL testbench code 

 

entity tb_cct is end entity tb_cct; architecture arch of tb_cct is constant T: time := 20 ns; signal t_clk: bit; signal t_d1: integer range 0 to 9; signal t_d2: integer range 0 to 9; begin uut: entity work.counter_with_sharedvar(counter) port map(clk => t_clk, digit1 => t_d1, digit2 => t_d2); process begin t_clk <= '0'; wait for T/2; t_clk <= '1'; wait for T/2; end process; end arch;  

 

simulation result (50 MHz oscilator) 

 

https://www.alteraforum.com/forum/attachment.php?attachmentid=7548  

 

Any ideas? 

Regards 

Jaraqui
0 Kudos
26 Replies
Altera_Forum
Honored Contributor I
97 Views

Im sure I answered this the other day, with the exact same code. 

 

Anyway, its because there are no 'events on variables, and signals need a 'event to update outside a process. Hence they are loaded with the initial value of the shared variables and are never updated again. 

 

Solution - never use shared variables.
Altera_Forum
Honored Contributor I
97 Views

Hi Tricky, 

 

It´s me. lol. 

As I explained to you, this code is present in a book.  

Before I contact the author, I would prefer to listen (read) more opinions. 

 

Regards 

Jaraqui
Altera_Forum
Honored Contributor I
97 Views

Its not really an opinion, its a fact. Hence why its not working.

Altera_Forum
Honored Contributor I
97 Views

 

--- Quote Start ---  

Its not really an opinion, its a fact. Hence why its not working. 

--- Quote End ---  

 

 

Tricky, 

 

It seemed to be a simulation bug. 

Implementing the code, it worked well surprisingly. 

 

The only modifications needed were: converting input/output to std_logic and dividing the 50 MHz frequency oscillator to a 1 Hz (to be visually observable). 

 

Here it´s the modificated version: 

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; ------------------------------------------------------ entity counter_with_sharedvar is port (mclk: in std_logic; rst: in std_logic; digit1, digit2: out std_logic_vector(3 downto 0)); end entity; ------------------------------------------------------ architecture counter of counter_with_sharedvar is shared variable temp1, temp2: integer range 0 to 9; signal clk: std_logic; begin ---------------------------------- proc0: process(mclk, rst) variable count: integer := 0; begin if(rst = '1') then count := 0; elsif(mclk'event and mclk='1') then if(count < 25_000_000) then clk <= '0'; count := count + 1; elsif(count >= 25_000_000) then if(count = 50_000_000) then count := 0; clk <= '0'; else count := count + 1; clk <= '1'; end if; end if; end if; end process proc0; ---------------------------------- proc1: process (clk, rst) begin if(rst = '1') then temp1 := 0; elsif (clk'EVENT and clk='1') then if (temp1=9) then temp1 := 0; else temp1 := temp1 + 1; end if; end if; end process proc1; ---------------------------------- proc2: process (clk, rst) begin if(rst = '1') then temp2 := 0; elsif (clk'EVENT and clk='1') then if (temp1=9) then if (temp2=9) then temp2 := 0; else temp2 := temp2 + 1; end if; end if; end if; end process proc2; ---------------------------------- digit1 <= conv_std_logic_vector(temp1, 4); digit2 <= conv_std_logic_vector(temp2, 4); end architecture;  

 

Best regards 

Jaraqui
Altera_Forum
Honored Contributor I
97 Views

When you say implementing, you mean with quartus? As I think I already stated, it would synthesise fine with quartus, as it just converts it to wires and will connect it up how you expect.  

And you've done the conversion via std_logic_arith, which is non-standard VHDL.
Altera_Forum
Honored Contributor I
97 Views

I am testing with others target device/EDA tool. 

 

In this week, not sure, I will have at hands a DE0, and I will try with it too. The reset on DE0 is '0' sensitive (not '1', as the rst presented in this version). The internal oscillator has the same frequency (50 MHz). 

 

Here is the version with numeric... 

 

library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; ------------------------------------------------------ entity counter_with_sharedvar is port (mclk: in std_logic; rst: in std_logic; digit1, digit2: out std_logic_vector(3 downto 0)); end entity; ------------------------------------------------------ architecture counter of counter_with_sharedvar is shared variable temp1, temp2: integer range 0 to 9; signal clk: std_logic; begin ---------------------------------- proc0: process(mclk, rst) variable count: integer := 0; begin if(rst = '1') then count := 0; elsif(mclk'event and mclk='1') then if(count < 25_000_000) then clk <= '0'; count := count + 1; elsif(count >= 25_000_000) then if(count = 50_000_000) then count := 0; clk <= '0'; else count := count + 1; clk <= '1'; end if; end if; end if; end process proc0; ---------------------------------- proc1: process (clk, rst) begin if(rst = '1') then temp1 := 0; elsif (clk'EVENT and clk='1') then if (temp1=9) then temp1 := 0; else temp1 := temp1 + 1; end if; end if; end process proc1; ---------------------------------- proc2: process (clk, rst) begin if(rst = '1') then temp2 := 0; elsif (clk'EVENT and clk='1') then if (temp1=9) then if (temp2=9) then temp2 := 0; else temp2 := temp2 + 1; end if; end if; end if; end process proc2; ---------------------------------- digit1 <= std_logic_vector(to_unsigned(temp1, 4)); digit2 <= std_logic_vector(to_unsigned(temp2, 4)); end architecture;  

 

regards 

Jaraqui
Altera_Forum
Honored Contributor I
97 Views

All synthesis tools will synthesise it "correctly". I still dont see why you are sticking with shared variables. They are of no benefit in almost all situations (and prone to errors by inexperienced users, as you have found - its not a simulation bug). 

 

On a point about this design - generating a clock like this is not recommended. It can be prone to timing problems from temperature due to the high skew from non-clock nets. 

It is recommended to generate clock enables instead, unless this is a slow clock for an external device (and no internal logic).
Altera_Forum
Honored Contributor I
97 Views

I am studying a VHDL book. There are a lot of codes in this book and one of them is this. For some of them, I practice some simulation or implement it on board. 

This code with shared variables was presented to explain their functioning. Simulating this code, it didn´t present expected results. Curious about this, I posted on forum.  

It´s not a matter of choosing or preferring to use anything. I was just interested to understand if it works. If not, how the log files present to me what´s going on. 

 

In future designs I will consider you recommendation regarding clocks. Could you recommend some good books with practical examples of clock enabling? 

 

Regards 

Jaraqui
Altera_Forum
Honored Contributor I
97 Views

 

--- Quote Start ---  

I am studying a VHDL book. There are a lot of codes in this book and one of them is this. For some of them, I practice some simulation or implement it on board. 

This code with shared variables was presented to explain their functioning. Simulating this code, it didn´t present expected results. Curious about this, I posted on forum.  

It´s not a matter of choosing or preferring to use anything. I was just interested to understand if it works. If not, how the log files present to me what´s going on. 

 

In future designs I will consider you recommendation regarding clocks. Could you recommend some good books with practical examples of clock enabling? 

 

Regards 

Jaraqui 

--- Quote End ---  

 

 

I myself don't use shared variables but it could be your first code example need to initialise temp1, temp2.
Altera_Forum
Honored Contributor I
97 Views

I agree with you. I was trying to change the minimum.  

For instance, the reset (rst) I´ve put only to watcth repeatedly the passages from nine to ten and from 99 to 00.
Altera_Forum
Honored Contributor I
97 Views

Well I just tried modesim and your first code works as temp1 and temp2 increment but digit1 and digit2 stay 0

Altera_Forum
Honored Contributor I
97 Views

 

--- Quote Start ---  

Well I just tried modesim and your first code works as temp1 and temp2 increment 

--- Quote End ---  

 

 

But the outputs digit1 and digit 2 remain at the the initial values of temp1 and temp2 (0)
Altera_Forum
Honored Contributor I
97 Views

true and I get warning saying shared variables must be of type protected. God knows how to protect them.

Altera_Forum
Honored Contributor I
97 Views

I know - and its only for simulation. A protected type is a bit like a class in C++. They contain member variables, functions and procedures and can be extremly useful for behavioural modelling. In VHDL 2002, they made it a LRM rule that shared variables MUST be protected types, but as this would break old VHDL '93 code, and so by default it only throws a warning (you can make it stricter though). 

 

so, as an example: 

 

type DDR_model_t is protected procedure write_data(addr : integer; data : std_logic_vector); impure function read_data(addr: integer) return std_logic_vector; end proteted DDR_Model_t; type ddr_model_t is protected body type mem_row_t is array(0 to 1023) of std_logic_vector(31 downto 0); type mem_row_ptr_t is access mem_row_t; type mem_bank_t is array(0 to 1023) of mem_row_ptr_t; type mem_bank_ptr_t is access mem_bank_t; type mem_t is array(0 to 7) of mem_bank_ptr_t; variable mem : mem_t; procedure write_data(addr: integer; data : std_logic_vector) is variable bank, row, col : integer; begin bank = addr rem 8; row = (addr/8)/1024; col = (addr rem 1024); if mem(bank) = null then mem(bank) := new mem_bank_t; end if; if mem(bank)(row) = null then mem(bank)(row) := new mem_row_t; end if; mem(bank)(row)(col) := data; end procedure write_data; impure function read_data(addr: integer) return std_logic_vector is variable bank, row, col : integer; CONSTANT ALL_U : std_logic_vector(31 downto 0) := (others => 'U'); begin bank = addr rem 8; row = (addr/8)/1024; col = (addr rem 1024); if mem(bank) = null or mem(bank)(row) = null then return ALL_U; else return mem(bank)(row)(col); end if; end function read_data; end protected ddr_model_t; shared variable ddr_model : ddr_model_t; --to use it: ddr_model.write_data(a); some_var := ddr_model.read_data(b);  

 

And then wrap an entity around this shared variable to make it behave like a DDR chip, but it will only use system ram as individual rows are accesses, so you dont need to use a massive amount of ram during simulation to model the memory, and it runs much faster.
Altera_Forum
Honored Contributor I
97 Views

They also can be useful for handling event queues (like a load of packets arriving on a PCIe bus) - as you can have pointers in VHDL you can make linked lists of an infinite size during simulation

Altera_Forum
Honored Contributor I
97 Views

Tricky, 

 

Without your help, without the help from another collegue from another forum, without the collaboration of another collegue from here (variable initialization), it couldn´t be possible for me to exit from step zero to step one. And I thank you for this. 

 

I thank also all the people here for the "temperature" in this forum. The objectivity of the problem stay fixed, withou any extreme "ego" unecessary discussions. 

Of course the "nerd-Big-Bang-theory-discussion" must exist because is part of us. This kind of discussion is obviously different from the former cited. I think all we enter in this type discussion at some moment, even when the impulse is involutary. 

 

Two paragraphs of "speech" to do an invitment. 

 

I like posts such this because the code is small and easly reproductible and we talking about only one specific problem. Someone who googles the problem can find here the solution. 

To finish gracefully, to eliminate the last "evil", it is necessary to generate a 1 Hz clock without logic, as Tricky and other people already did recommend. 

Can someone who is interested (and knows how to do it) modificate this last version with the so called clock enabling version (plus initializing temp1/temp2). 

Is it dificult? I ask this because I don´t know how to do at this time (I will look for good books or expect someone recommend one...). 

 

Let me know if someone can do! 

 

Regards 

Jaraqui
Altera_Forum
Honored Contributor I
97 Views

 

--- Quote Start ---  

true and I get warning saying shared variables must be of type protected. God knows how to protect them. 

--- Quote End ---  

 

 

I saw something at ASHENDEN(2008, p. 585), but I assure to you: I don´t have the appropriate patiente to follow that book. 

 

ASHENDEN, Peter J. the designer's guide to vhdl. 3rd ed. Burlington: Morgan Kaufmann Series, 2008.
Altera_Forum
Honored Contributor I
97 Views

 

--- Quote Start ---  

 

Can someone who is interested (and knows how to do it) modificate this last version with the so called clock enabling version (plus initializing temp1/temp2). 

Is it dificult? I ask this because I don´t know how to do at this time (I will look for good books or expect someone recommend one...). 

 

 

--- Quote End ---  

 

 

Ill give you the outline - its very similar to what you're doing: 

 

process(clk) begin if rising_edge(clk) then cnt <= cnt + 1; if cnt = N then -- this will give you an enable rate of clk/N clk_en <= '1'; else clk_en <= '0'; end if; if clk_en = '1' then --do something once every N clocks end if; end process;
Altera_Forum
Honored Contributor I
97 Views

 

--- Quote Start ---  

Ill give you the outline - its very similar to what you're doing: 

 

process(clk) begin if rising_edge(clk) then cnt <= cnt + 1; if cnt = N then -- this will give you an enable rate of clk/N clk_en <= '1'; else clk_en <= '0'; end if; if clk_en = '1' then --do something once every N clocks end if; end process;  

--- Quote End ---  

 

 

Forgetting momentarily the shared variables stuff and concentrating only in a simple clock generator based on this piece of code you provided, I developed the following code: 

library ieee; use ieee.std_logic_1164.all; entity clock_gen is generic(N: integer := 50_000_000); port( mclk: in std_logic; rst: in std_logic; clk: out std_logic); end clock_gen; architecture arch of clock_gen is signal cnt: integer := 0; signal clk_en: integer := 0; signal state: integer := 0; begin process(mclk, rst) begin if(rst = '1') then cnt <= 0; clk_en <= 0; state <= 0; elsif(rising_edge(mclk)) then cnt <= cnt + 1; if(cnt = N) then -- this will give you an enable rate of clk/N clk_en <= 1; else clk_en <= 0; end if; if(clk_en = 1) then --do something once every N clocks if(state = 0) then clk <= '1'; state <= 1; else clk <= '0'; state <=0; end if; end if; end if; end process; end arch;  

 

Implementing it to blink a simple led receiving clk at expected 1 Hz, this doesn´t work. The led blinks (full period) at every 174 seconds. This period stay fixed no matter N is changed. 

 

Any idea? 

 

 

Regards 

Jaraqui
Reply