Is it legal to have an independent if-clause for the D flip-flop reset in VHDL? - vhdl

I have the following code describing some registers:
DCR_WR_REGS_P: process (CLK)
begin
if rising_edge(CLK) then
if DCR_WRITE = '1' then
if C_BASEADDR(0 to 6) = DCR_ABUS(0 to 6) then
case to_integer(unsigned(DCR_ABUS(7 to 9))) is
when REG_DMA_RD_ADDR_OFFS =>
dma_rd_addr_reg <= DCR_WR_DBUS (0 to DMA_RD_ADDR_SZ-1);
when REG_DMA_RD_LENG_OFFS =>
dma_rd_leng_reg <= DCR_WR_DBUS (0 to DMA_RD_LENG_SZ-1);
rd_dma_req <= '1';
-- more registers here...
when
when
----------------------
when others =>
end case;
end if;
else
if clear_rd_dma_req='1' then
rd_dma_req <='0';
end if;
end if;
end if;
end process DCR_WR_REGS_P;
This code works except for the fact that the clear_rd_dma_req is ignored when DCR_WRITE is active. So, can I somehow make the "if clear_rd_dma_req='1'" clause an independent one? I realize that I can create a separate process just for the rd_dma_req bit, but I am trying to avoid that as I have a few bits like that.
Here's a version with a separate process:
DCR_WR_REGS_P: process (CLK)
begin
if rising_edge(CLK) then
if DCR_WRITE = '1' then
if C_BASEADDR(0 to 6) = DCR_ABUS(0 to 6) then
case to_integer(unsigned(DCR_ABUS(7 to 9))) is
when REG_DMA_RD_ADDR_OFFS =>
dma_rd_addr_reg <= DCR_WR_DBUS (0 to DMA_RD_ADDR_SZ-1);
when REG_DMA_RD_LENG_OFFS =>
dma_rd_leng_reg <= DCR_WR_DBUS (0 to DMA_RD_LENG_SZ-1);
-- more registers here...
when
when
----------------------
when others =>
end case;
end if;
end if;
end if;
end process DCR_WR_REGS_P;
RD_DMA_REQ_P: process (CLK)
begin
if rising_edge(CLK) then
if clear_rd_dma_req='1' then
rd_dma_req <='0';
elsif DCR_WRITE = '1' then
if C_BASEADDR(0 to 6) = DCR_ABUS(0 to 6) then
if to_integer(unsigned(DCR_ABUS(7 to 9))) = REG_DMA_RD_LENG_OFFS then
rd_dma_req <= '1';
end if;
end if;
end if;
end if;
end process RD_DMA_REQ_P;
And here's a version with an independent if-clause, which is probably illegal:
DCR_WR_REGS_P: process (CLK)
begin
if rising_edge(CLK) then
if DCR_WRITE = '1' then
if C_BASEADDR(0 to 6) = DCR_ABUS(0 to 6) then
case to_integer(unsigned(DCR_ABUS(7 to 9))) is
when REG_DMA_RD_ADDR_OFFS =>
dma_rd_addr_reg <= DCR_WR_DBUS (0 to DMA_RD_ADDR_SZ-1);
when REG_DMA_RD_LENG_OFFS =>
dma_rd_leng_reg <= DCR_WR_DBUS (0 to DMA_RD_LENG_SZ-1);
rd_dma_req <= '1';
-- more registers here...
when
when
----------------------
when others =>
end case;
end if;
end if;
if clear_rd_dma_req='1' then
rd_dma_req <='0';
end if;
end if;
end process DCR_WR_REGS_P;
Thanks

Yes you can make it an independent one (still inside the if rising_edge(clk) statement). What makes you think this version (last in the modified question) should be illegal?
Anything it does will override assignments made to the same signals by the if DCR_Write statement, thanks to the "last assignment wins" rule.
HOWEVER why not simply reverse the prioritisation and tidy it up, like this?
if clear_rd_dma_req='1' then
...
elsif DCR_Write = '1' then
...
end if;

Related

FIFO implementation - VHDL

I come across one more difficulty while instantiate the fifo code to my top module. I want to store some set of data say "WELCOME TO THE WORLD OF FPGA" from my serial port ( receiving subsystem) then i want to retrieve it back say when button on fpga board is pressed or FIFO is full. I have my fifo code and serial communication code written. Idea is data sent from keyboard ->receiving subsystem -> FIFO -> transmitting subsystem -> hyperterminal. I am at present using fifo of 8 bit wide and say 28 deep just to store some small data. Please help me in this regard how can I implement it.I have byte coming from receiver saved in register_save.
fifo code
inst_bit8_recieve_unit : entity work.byte_recieve_8N1
port map ( ck => ck,
reset => reset,
new_byte_in_buffer => new_byte_in_buffer,
byte_read_from_buffer => byte_read_from_buffer,
recieve_buffer => register_save,
JA_2 => JA(2));
---------------------FIFO instantiate-------------------------------
inst_of_fifo_Recieve_unit : entity work.fifo
generic map (B => data_bits, W => fifo_width)
port map ( ck => ck,
reset => reset,
rd => rd_rx,
wr => wr_rx,
write_data => num_recieved,
read_data => num_recieved_fifo,
empty => empty_rx,
full => full_rx );
inst_bit8_transmit_unit : entity work.byte_transmit_8N1
port map ( ck => ck,
reset => reset,
send_byte_ready => send_byte_ready,
send_byte_done => send_byte_done ,
send_buffer => num_send,
JAOUT_0 => JAOUT );
proc_send5byte: process(ck, reset, state_byte5, send_byte_done, num_send, state_button_0, num_recieved_fifo, rd_rx)
begin
if reset = '1' THEN
state_byte5 <= idle;
send_byte_ready <='0';
num_send <= "00000000" ;
else
if rising_edge(ck) then
case state_byte5 is
when idle => ---- in this, if btn(0) is high i.e pressed then only state_byte5 will go to next state
if state_button_0 = transit_pressed then
state_byte5 <= byte;
end if;
-----===============================================================
when byte =>
if (not empty_rx = '1') then
if send_byte_ready ='0' and send_byte_done = '0' then ----here if condition is satified the send_byte_ready will be set
send_byte_ready <='1'; --------- shows next byte is ready
num_send <= num_recieved_fifo;
rd_rx <='1';
end if;
end if;
if send_byte_ready = '1' and send_byte_done = '1' then --- during load state send_byte will be resets
send_byte_ready <='0';
rd_rx <= '0';
state_byte5 <= idle; ----------- go back to idle
end if;
--end if;
---===============================================================
when others =>
state_byte5 <= idle; ------------- for other cases state state _byte5 will be in idle
send_byte_ready <= '0';
rd_rx <= '0';
end case;
end if;
end if;
end process;
proc_recieving_byte : process (ck, reset, register_save, new_byte_in_buffer, full_rx, num_recieved, wr_rx)
begin
if reset = '1' then
byte_read_from_buffer <= '0';
else
if rising_edge(ck) then
if full_rx = '0' then
if new_byte_in_buffer = '1' and byte_read_from_buffer = '0' then
byte_read_from_buffer <= '1';
wr_rx <= '1';
num_recieved(7 downto 0 ) <= register_save( 7 downto 0);
end if;
end if;
if new_byte_in_buffer = '0' then
byte_read_from_buffer <= '0';
wr_rx <= '0';
end if;
--end if;
end if;
end if;
end process;
Just added the corrected code now which seems to be working. Problem araises when increase the depth of fifo. When depth>2 then every third byte is missing.
Please help, why I am loosing data.
The principe of a fifo is First In First Out. You have not to manage it.
You place your data on input of fifo
You set write enable bit to '1'
You wait for one clock cycle
You set write enable bit to '0'
then the data is store, you do it again to store another value.
When you want to read all data (Fifo full / any case you want)
You set Read enable bit to '1' and every clock cycle, you will receive a data.
--- process for recieving bytes and sent to fifo input with write enable signal------------
proc_recieving_byte : process (ck, reset, register_save, new_byte_in_buffer, full_rx, num_recieved, wr_rx)
begin
if reset = '1' then
byte_read_from_buffer <= '0';
else
if rising_edge(ck) then
if full_rx = '0' then
if new_byte_in_buffer = '1' and byte_read_from_buffer = '0' then
byte_read_from_buffer <= '1';
wr_rx <= '1';
num_recieved(7 downto 0 ) <= register_save( 7 downto 0);
else
wr_rx <= '0';
end if;
end if;
if new_byte_in_buffer = '0' then
byte_read_from_buffer <= '0';
wr_rx <= '0';
end if;
end if;
end if;
end process;
-------------------------------------------------------------------------------------------------------------------
---- this process checks first button state and then transmission occurs from fifo untill empty------
proc_send5byte: process(ck, reset, state_byte5, send_byte_done, num_send, state_button_0, num_recieved_fifo, rd_rx)
begin
if reset = '1' THEN
state_byte5 <= idle;
send_byte_ready <='0';
num_send <= "00000000" ;
else
if rising_edge(ck) then
case state_byte5 is
when idle => ---- in this, if btn(0) is high i.e pressed then only state_byte5 will go to next state
if state_button_0 = transit_pressed then
state_byte5 <= byte;
end if;
-----===============================================================
when byte =>
if (not empty_rx = '1') then
if send_byte_ready ='0' and send_byte_done = '0' then ----here if condition is satified the send_byte_ready will be set
send_byte_ready <='1'; --------- shows next byte is ready
num_send <= num_recieved_fifo;
rd_rx <='1';
else
rd_rx <='0';
end if;
end if;
if send_byte_ready = '1' and send_byte_done = '1' then --- during load state send_byte will be resets
send_byte_ready <='0';
rd_rx <= '0';
state_byte5 <= idle; ----------- go back to idle
end if;
---===============================================================
when others =>
state_byte5 <= idle;
send_byte_ready <= '0';
rd_rx <= '0';
end case;
end if;
end if;
end process;
Just found the error and corrected as above which works very well. Comments to improve are welcome.

Creating strings for lcd-data

I want to create dynamic string array, so I can transmit it to the lcd module on my Altera DE2-115 board. So far the most part is working, but the last part is not wrking in the following code:
CREATE_STRING: PROCESS (CLK, RESET, X)
BEGIN
IF RESET = '1' THEN
FOR i IN 0 TO 31 LOOP
lcd_data(i) <= x"30";
END LOOP;
END IF;
IF X /= 0 THEN
FOR i IN 0 TO 15 LOOP
IF X(15-i) = '0' THEN
lcd_data(i) <= x"30";
END IF;
IF X(15-i) ='1' THEN
lcd_data(i) <= x"31";
END IF;
END LOOP;
END IF;
IF char_count > 15 AND lcd_y = '1' THEN
ELSIF CLK = '1' AND CLK'event THEN
lcd_data(to_integer(char_count)) <= x"31";
END IF;
END PROCESS CREATE_STRING;
I'm getting this error message:
Error (10818): Can't infer register for "lcd_data[31][0]" at seqdec.vhd(75) because it does not hold its value outside the clock edge
for every lcd_data[31][x].
I googled the error and if I am not completly on the wrong thought I think i understood it, but I'm still not able the get it right...
Would be great if somebody could help with advice.
Best regards
Adrian
Did this change:
CREATE_STRING: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
FOR i IN 0 TO 31 LOOP
lcd_data(i) <= x"30";
END LOOP;
ELSIF CLK = '1' AND CLK'event THEN
IF X /= 0 THEN
FOR i IN 0 TO 15 LOOP
IF X(15-i) = '0' THEN
lcd_data(i) <= x"30";
END IF;
IF X(15-i) ='1' THEN
lcd_data(i) <= x"31";
END IF;
END LOOP;
END IF;
ELSIF lcd_y = '1' THEN
lcd_data(to_integer(pos_count)) <= x"31";
END IF;
END PROCESS CREATE_STRING;
But still the same problem.
To properly describe a register, you must reverse the order of the if statements as follows:
CREATE_STRING: PROCESS (CLK, RESET)
BEGIN
IF RESET = '1' THEN
FOR i IN 0 TO 31 LOOP
lcd_data(i) <= x"30";
END LOOP;
ELSIF CLK = '1' AND CLK'event THEN
IF X /= 0 THEN
FOR i IN 0 TO 15 LOOP
IF X(15-i) = '0' THEN
lcd_data(i) <= x"30";
END IF;
IF X(15-i) ='1' THEN
lcd_data(i) <= x"31";
END IF;
END LOOP;
END IF;
IF char_count > 15 AND lcd_y = '1' THEN
lcd_data(to_integer(char_count)) <= x"31";
END IF;
END IF;
END PROCESS CREATE_STRING;

how to call a state machine from another state machine and get the response back in VHDL

I want to do VHDL programming of a state machine. In this state machine one state is itself another state machine. how can i call this state machine from the main state machine?
Example of what i actually want to do is as follows:
main state machine (sm_main.vhd) :-
clk_process : process (clk, reset)
begin
if(reset = '1') then
state_reg <= start;
elsif (clk'event and clk =' 1' ) then
state_reg <= state_next;
end if;
end process;
state_process : process (state_reg,input,enable)
begin
case state_reg is
when start =>
if (input =1) then
state_next <= wait;
else
state_next <= start;
end if;
when wait =>
if (enable =1) then
output <= '1';
state_next <= execute;
else
output <='0';
state_next <= wait;
end if ;
when execute =>
if (enable =1) then
state_next <= done;
else
state_next <= start;
end if;
when done =>
if(result = 1) then
state_next <= execute;
else
state_next <= start;
end if;
end case;
end process;
sub state machine (sm_execute.vhd):-
The execute state of the above state machine is itself another state machine program.
state_process : process (state_reg,a,b)
begin
case state_reg is
when start =>
if (a=1) then
state_next <= s1;
else
state_next <= s2;
end if;
when s1 =>
if (b =1) then
state_next <= s3;
else
state_next <= s3;
end if ;
when s3=>
if(c=1) then
result <= '1';
state_next <= s3
else
result <='0';
state_next <= start
end case;
end process;
What i want is to call this sm_execute.vhd in the execute state of sm_main.vhd. The output from the sm_execute which is result, is to be used as an input to determine the next state after execute in sm_main.vhd. That means i want to call the sub state machine program and also return the value to main state machine program once the sub state machine program finishes its execution.
thanks in advance
Sruthi Rajan
Handshaking. The first machine signals the second one to start, and waits for it to acknowledge. Then it retracts the start signal and waits for the second one to complete.
This is not the only way, but where you can separate the second state machine into its own process, it is probably the simplest.
First SM (master):
SM_1 : process(clock,reset)
begin
if reset = '1' then
State_1 <= Idle;
elsif rising_edge(clock) then
-- default actions
Start <= '0';
-- state machine proper
case State_1 is
...
when Need_Result =>
Start <= '1';
-- wait here until slave SM starts processing
if Done = '0' then
State_1 <= Wait_Result;
end if;
when Wait_Result =>
if Done = '1' then
State_1 <= Have_Result;
end if;
...
when others => State_1 <= Idle;
end case;
end if;
end process;
Second SM (slave) :
SM_2 : process(clock,reset)
begin
if reset = '1' then
State_2 <= Idle;
elsif rising_edge(clock) then
case State_2 is
when Idle =>
Done <= '1';
if Start = '1' then
Done <= '0';
State_2 <= Start_Process;
end if;
when Start_Process =>
State_2 <= Process_Done;
when Process_Done =>
Done <= '1';
if Start = '0' then
State_2 <= Idle;
end if;
when others => State_2 <= Idle;
end case;
end if;
end process;
Notice that in this implementation, the master waits for the slave to start processing (done = '0';). This covers cases where the slave may not be able to respond immediately. It does not cover cases where Done='0' already because the slave is processing data for another master.
Also the slave waits for the master to retract Start before returning to Idle. Usually Start will already be '0' but if it isn't, you probably don't want the slave to retrigger immediately.
If you can guarantee neither of these cases will happen you can simplify the handshaking a little, but the design becomes more sensitive to changes in signal timings.
Notice also that Start defaults to '0', because of the default assignment, but Done has no default assignment so it retains its state during processing. Unless you return to Idle (perhaps via an error path) when Done is set to indicate that processing has stopped.
If there is uncertainty about whether processing will complete, you may want the master to time out, rather than deadlock waiting for something that won't happen. I do this by adding a delay timer which can be used by different states for different purposes : here it detects a frozen slave and lets us handle the error.
First SM (master):
SM_1 : process(clock,reset)
variable Delay : natural range 0 to 100;
constant Timeout : natural := 50;
begin
if reset = '1' then
State_1 <= Idle;
Delay := 0;
elsif rising_edge(clock) then
-- default actions
Start <= '0';
if Delay > 0 then
Delay := Delay - 1;
end if;
-- state machine proper
case State_1 is
...
when Need_Result =>
Start <= '1';
-- wait here until slave SM starts processing
if Done = '0' then
Delay := Timeout;
State_1 <= Wait_Result;
end if;
when Wait_Result =>
if Done = '1' then
State_1 <= Have_Result;
elsif Delay = 0 then
State_1 <= Timed_Out; -- do error processing
end if;
...
when others => State_1 <= Idle;
end case;
end if;
end process;

Simplifying A State Machine To Reduce Logic Levels and Meet Timing

My design at the moment isn't meeting timing. I've tried putting it on a slower clock and pipelining the inputs/outputs. The problem is always the same - too many levels of logic. Have any of you got any tips on making this logic more clock friendly?
signal ctr : std_logic_vector(9 downto 0);
signal sig_bit_shift : std_logic_vector (15 downto 0);
begin
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' or nuke = '1' then
ctr <= (others => '0');
state <= ST_IDLE;
elsif unsigned(event_settings) < 1 then -- disables
state <= ST_IDLE;
elsif unsigned(event_settings) = 1 then -- always on
state <= ST_ENABLE;
else
case state is
when ST_IDLE =>
if ctr = (unsigned(event)-2) then
state <= ST_ENABLE;
elsif unsigned(ctr) = 1 and sig = '0' then --catches first word
state <= ST_ENABLE;
elsif sig = '1' then
ctr <= ctr + 1;
end if;
when ST_ENABLE =>
if s_sig = '1' then
state <= ST_IDLE;
if unsigned(s_evt) > 1 then
ctr <= (others => '0');
end if;
end if;
end case;
end if;
end if;
end process;
UPDATE:
process(clk_p)
begin
if rising_edge(clk_p) then
if rst_i = '1' or nuke = '1' then
ctr <= x"00" & "10";
state <= ST_IDLE;
elsif settings = '1' then
case state is
when ST_IDLE =>
if ctr = (unsigned(event)) then
state <= ST_ENABLE;
elsif unsigned(ctr) = 1 and sig = '0' then --catches first word -- this is the part which when added, fails timing
state <= ST_ENABLE;
elsif sig = '1' then
ctr <= ctr + 1;
end if;
when ST_ENABLE =>
if s_sig = '1' then
state <= ST_IDLE;
if unsigned(s_evt) > 1 then
ctr <= X"00" & "10";
end if;
end if;
end case;
end if;
end if;
end process;
I think too it's slowed down by where the signal comes from:
sig <= sig_token when unsigned(SIG_DELAY) < 1 else (sig_bit_shift(to_integer(unsigned(SIG_DELAY)-1)));
process(clk_p) -- delays sig
begin
if rising_edge(clk_p) then
if rst = '1' then
sig_bit_shift <= (others => '0');
else
sig_bit_shift <= l1a_bit_shift(sig_bit_shift'high-1 downto 0) & sig_token;
end if;
end if;
end process;
UPDATE 2 :
Seems like half the routing went into the above delay so i'm going to try and fix with this:
signal sig_del_en : std_logic;
signal sig_del_sel : integer;
begin
process(clk_p)
begin
if rising_edge(clk_p) then
if unsigned(SIG_DELAY) = 0 then
sig_del_en <= '0';
else
sig_del_en <= '1';
end if;
sig_del_sel <= to_integer(unsigned(SIG_DELAY)-1);
end if;
end process;
sig <= sig_token when sig_del_en = '0' else (sig_bit_shift(sig_del_sel));
Some of the "slow" operations are array = which requires compare over all bits in the argument, and < and > which requires subtraction over all bits in the argument. So you may improve timing in a cycle, if there is sufficient time in the previous cycle to generate the compare result up front as a std_logic. It may be relevant for these:
unsigned(event_settings) < 1
unsigned(event_settings) = 1
ctr = (unsigned(event)-2)
unsigned(ctr) = 1
unsigned(s_evt) > 1
The code to generate the different std_logic values depends on the way the related signal is generated, but an example can be:
process (clk) is
variable event_settings_v : event_settings'range;
begin
if rising_edge(clk) then
...
event_settings_v := ... code for generating event_settings; -- Variable with value
event_settings <= event_settings_v; -- Signal drive from variable
if unsigned(event_settings_v) < 1 then
unsigned_event_settings_tl_1 <= '1';
else
unsigned_event_settings_tl_1 <= '0';
end if;
end if;
end process;
The code unsigned(event_settings) < 1 in the state machine can then be changed to unsigned_event_settings_tl_1 = '1', which may improve timing if this compare is in the critical path.
Using the asynchronous reset typically available on the the flip-flop for rst_i = '1' may also improve timing, since it removes logic from the synchronous part. It is unlikely to give a significant improvement, but it's typically a good design practice in order to maximize the time for synchronous logic. The asynchronous reset is used through coding style like:
process (rst_i, clk_p) is
begin
if rst_i = '1' then
... Apply asynchronous reset value to signals
elsif rising_edge(clk_p) then
... Synchronous update of signals

Communication between processes in VHDL

I have problems on communicating between the processes. I used to use flag and clearFlag to tackle this, but it's kind of annoying and not looking good. What is the best practice to handle this? Here is a sample code on how I did it before:
Proc_A : process (clk, reset, clrFlag)
begin
if clrFlag = '1' then
flag <='0';
elsif reset = '0' then
A <= (others => '0');
elsif rising_edge (clk) then
A <= in;
flag <= '1';
end if;
end process;
Proc_B : process (clk, reset)
begin
if reset = '0' then
B <= (others => '0');
elsif rising_edge (clk) then
if flag = '1' then
B <= data;
clrFlag <= '1';
else
clrFlag <= '0';
end if;
end if;
end process;
This way works but I don't think it is nice method. I have to write a flag and clrFlag couple to do this task. All I want to do is when something happened (e.g. A <= in;), it triggers another proc, Proc_B for example, to run once or a number of times. What is the best practice to this problem? Thanks!
For simulation, you can make a process wait on a signal:
Proc_B : process
begin
wait until flag'event;
B <= data;
end process;
and just write the flag with its inverse every time you need something to happen.
In synthesisable logic, you either have to exchange flag signals, as you do, or use some other higher-level communication (like a FIFO, messagebox, or similar).
However, if all your proc_b logic takes place in a single cycle - so you can guarantee not to miss a flag, and to be able to keep up even if flag is asserted all the time (as it looks like you do) - you can do this (and combine the two processes):
Proc : process (clk, reset, clrFlag)
begin
flag <='0';
if reset = '0' then
A <= (others => '0');
B <= (others => '0');
elsif rising_edge (clk) then
if some_trigger_event = '1' then
A <= in;
flag <= '1';
end if;
-- recall that due to VHDL's scheduling rules, this "if" will take place
-- one clock cycle after the flag is written to, just as if it were in a
-- separate process
if flag = '1' then
B <= data;
end if;
end if;
end process;
Side note - your code is not ideal for synthesis... you really only want the reset part outside the clocked part:
Proc_A : process (clk, reset)
begin
if reset = '0' then
A <= (others => '0');
elsif rising_edge (clk) then
if clrFlag = '1' then
flag <='0';
else
A <= in;
flag <= '1';
end if;
end process;

Resources