I'm writing a design in VHDL and after synthesis I observed that the number of multiplexers (dedicated) used is high. My code has a lot of if-else staments, so it seems logical.
But I wanna know if it is possible to implement if-else (or similar staments) in another way to reduce the number of multiplixers resources used.
Thanks!
You can try to use simple logic elements like and or or. For example:
if (a and b) = '1' then
out_0 <= '1';
else
out_0 <= '0';
end if;
if (c or d) = '1' then
out_1 <= '1';
else
out_1 <= '0';
end if;
This is construction can be replaced with following:
out_0 <= a and b;
out_1 <= c or d;
And so on...
Related
I am new to VHDL and have had some difficulty in performing the assignment of two different values to the same signal inside a process. For example,
process(CLK)
if rising_edge(CLK) then
OUTPUT0 <= X(0);
OUTPUT1 <= X(1);
OUTPUT2 <= X(2);
LED0 <= VALUE;
OUTPUT0 <= Y(0);
OUTPUT1 <= Y(1);
OUTPUT2 <= Y(2);
LED1 <= VALUE;
end if;
end process;
Note that VALUE is an output dependent on the values assigned to OUTPUT0, OUTPUT1, OUTPUT2.
From what I understand in a process is that the last assignment to the same signal is always applied. What I am trying to do is apply two different sets of values to one set of inputs, map the output and it be done sequentially. I have tried separate processes tied to the same clock, a FSM to attempt to move sequentially and so on. At this point I have exhausted my knowledge of things to try.
My question is: What would be the best way to sequentially assign two values to one input and map its output in order?
EDIT:
As per Brian's suggestion on the state machine I had went ahead and implemented one again and found my error and fixed it. This gave the sequential assignment I was looking for.
I was reading 2 addresses from one instance of 32x1 distributed RAM which is the reason for a sequential assignment. Apologies for not providing the best example. Below is my final implementation:
RAM_READ_FSM : process(CLOCK) -- FSM to read the RAM addresses sequentially
begin
if rising_edge(CLOCK) then
case curr_state is
when S0 => if SW2 = '1' then
RAMADDR0 <= XYVEC(5); -- Y addresses
RAMADDR1 <= XYVEC(6);
RAMADDR2 <= XYVEC(7);
RAMADDR3 <= XYVEC(8);
RAMADDR4 <= XYVEC(9);
LED1 <= RAMOUT;
curr_state <= S1;
else
curr_state <= S0;
end if;
when S1 => if SW2 = '1' then
RAMADDR0 <= XYVEC(0); -- X addresses
RAMADDR1 <= XYVEC(1);
RAMADDR2 <= XYVEC(2);
RAMADDR3 <= XYVEC(3);
RAMADDR4 <= XYVEC(4);
LED2 <= RAMOUT;
curr_state <= S0;
else
curr_state <= S1;
end if;
end case;
end if;
end process;
The signals should be driven from the same process : multiple drivers would interfere with each other..
See Is process in VHDL reentrant? on signal assignment semantics.
now you can see there is need for some delay (even just 2 delta cycles, if the logic calculating VALUE is just a simple signal assignment) between the X and LED0 assignments.
You were on the right lines with a state machine but you didn't say anything about how it failed. Worth adding that to the Q to get a fuller answer.
Meanwhile there is a simple way to add delay :
like
LEDS : process is
begin
wait until rising_edge(CLK);
OUTPUT0 <= X(0);
OUTPUT1 <= X(1);
OUTPUT2 <= X(2);
wait until rising_edge(CLK);
LED0 <= VALUE;
wait until rising_edge(CLK);
OUTPUT0 <= Y(0);
-- etc
end process LEDS;
While implementing a state machine on VHDL I was wondering how can I set the output / current state initial condition. I read on one of the questions on here.
One of the answers said we do the initialization before the case structure:
process(currentstate, a)
begin
b <= '1';
c <= '1';
case currentstate is
when s1 =>
if (a = '1') then
c <= '0';
end if;
nextstate <= s2;
However doesn't that make us automatically set b<='1' and c<='1' whenever we get into the process? So if we are at a state say A and we are at the conditions of moving to B whenever we enter the process this directly puts b<='1' and c<='1' isn't that true ?
Or does it actually just run once we start the program and then gets bounded in the case structure ?
Also check this link.
In their FSM implementation they did not specify the initial state how does the compiler or FPGA determine the start state ?
The lines you are looking at are not performing initialization.
b <= '1';
c <= '1';
Remember that VHDL is a hardware description language, not a programming language. What those two assignments do is to set a default assignment for those signals, unless something else contradicts these assignments later in the process. You can assign to the same signal several times in one process, and whichever assignment happens last will take priority. This saves having to write code like:
case State is
when s1 =>
a <= '0';
b <= '1';
c <= '1';
when s2 =>
a <= '1';
b <= '0';
c <= '1';
when s2 =>
a <= '1';
b <= '1';
c <= '0';
end case;
It can end up being quite repetitive and error prone to have the same assignments in many states, so default assignments can really tidy it up:
a <= '1';
b <= '1';
c <= '1';
case State is
when s1 =>
a <= '0';
when s2 =>
b <= '0';
when s2 =>
c <= '0';
end case;
The same pattern works for if statements where you don't want to cover every output signal in every logical branch.
If you want an initial state, there are two approaches that may be applicable depending on the scenario. Here you would assert reset at start-up to set the initial state. Note that the case statement is inside a clocked process:
process (clk)
begin
if (rising_edge(clk)) then
if (reset = '1') then
State <= s1;
else
case State is
when s1 =>
State <= s2;
when s2 =>
State <= s1;
end case;
end if;
end if;
end process;
The other option is to define your state signal with an initial value:
signal State : state_type := s1;
I won't go into the pros and cons of using initial values as there are existing questions that explore this.
I'm new to VHDL and I've been trying to finish my combinatorial code in an assignment, however I don't know how to make cases account for specific combinations of the two 1-bit outputs: Permit and ReturnChange. My concern is is with the WHEN statements. Looking at this block, for example, does that WHEN line work?
WHEN NoBill => Permit <= '0'; ReturnChange <= '0';
IF (Input = "000") THEN NextState <= NoBill;
ELSIF (Input = "001") THEN NextState <= Rec5;
ELSIF (Input = "010") THEN NextState <= Rec10;
ELSIF (Input = "100") THEN NextState <= Rec20;
END IF;
The ReturnChange <= '0'; part is what I'm unsure about. Because I know that WHEN NoBill => Permit <= '0'; would work. However I needed those if-statements to apply when that combination of Permit and ReturnChange outputs are both 0. I wasn't sure how to include both, so I kind of just guessed the ReturnChange <= '0'; part. If my guess is incorrect, how would I properly do it?
I'm unsure if seeing the entire file or my state diagram would be helpful, but if it can help you understand anything better, just let me know. Thanks in advance!
say I have the following state machine:
....
if state_a then
output_a <= '0';
next_state <= state_b;
elsif state_b then
output_a < '0';
if cond then
output_b <= '1';
next_state <= state_a;
else
next_state <= state_b;
end if;
end if;
......
I don't want output_b to change except when being assigned again in state_b. However, when I try to synthesise this code, most synthesis tools will say something along this line:
warning: found 1-bit latch for signal "output_b". latches aren't
recommended for FPGA design because it might result in timing
problems.
Should I worry about this at all? If so, why and what are the alternatives?
Following Xilinx:
If latch inference is intended, you can safely ignore this message. However, some inefficient coding styles can lead to accidental latch inference. You should analyse your code to see if this result is intended.
Some techniques to avoid latch inference:
Make sure any "if / else if" statements have a concluding "else" clause,
Assign to all the same outputs in each case,
Include all possible cases in the case statement (but be aware that WHEN OTHERS clause always works, but can create extraneous logic).
if you have incomplete if/elsif or case statement in a clocked process, it's absolutely harmless.
if rising_edge(clk)
if a then
out <= b;
end if;
end if;
It means that you have flip-flop with some sort of feedback, or, like in this case, you have flip-flop with clock enable pin used, which is even better.
If you have incomplete if/elsif or case statement in not clocked process - it's a latch and it's in most cases:
something you don't really want;
something that point out on a poor design and can be avoided with redesign.
If you complete your little example, someone can help you redesign it. Now it is not enough information.
The problem you have stems from the FSM coding style you're (presumably) using. As other pointed it is not possible to guess what you want the code to do, since you did not provide enough code to figure that out, so I present one possible interpretation, assuming you really wanted to change output_a somehow and that one time (after reset) latching of output_b should happen at the same time FSM state transitions.
Using 2 processes per FSM style, we have code that is not giving latch warnings:
----
signal CLK, RESET, cond : std_logic;
type state_t is (a,b);
signal state, state_next : state_t;
signal ouput_a, output_b, output_b_next : std_logic;
----
FSM_clock: process(all)
begin
if rising_edge(CLK) then
if RESET then
state <= a;
output_b <= '0';
else
state <= state_next;
output_b <= output_b_next;
end if;
end if;
end process;
FSM_next: process(all)
begin
state_next <= state;
output_b_next <= output_b;
output_a <= '0';
case state is
when a =>
state_next <= b;
when b =>
output_a <= '1';
if cond then
output_b_next <= '1';
state_next <= a;
else
state_next <= b;
end if;
end case;
end process;
I am trying to send multiple bytes on the SPI bus during the transmit window. Initially I am acquiring data from the flash ADC when the input pulse is high, then calculating its average and transmitting each average value sequentially on the SPI bus. I got the SPI vhdl module working, it was able to send data when I tried sending a single byte, but when I try to send more than 1 byte it just does not work. There is logic 0 on the MOSI line and the SS line is constantly high. This is the part where I try to send multiple bytes.
process(SPITrig, Clock, TX_Done, data_count, average2A_s, average2B_s)
begin
case data_count is
when 1 =>
TX_Data <= average2A_s;
when 2 =>
TX_Data <= average2B_s;
when others => TX_Data <= "0101010101010101";
end case;
end process;
process(SPIBusy, SPITrig, SPI_Clock_base, data_count, TX_Start)
begin
if falling_edge(SPITrig) then
SPIBusy <= '1';
TX_Start <= '0';
data_count <= 0;
delay_counter <= 0;
end if;
if rising_edge(SPI_Clock_base) and SPIBusy = '1' then
if data_count < 3 then
if delay_counter = 128 then
TX_Start <= not TX_Start;
delay_counter <= 0;
elsif delay_counter < 128 then
delay_counter <= delay_counter + 1;
end if;
elsif data_count >= 3 then
TX_Start <= '0';
delay_counter <= 0;
SPIBusy <= '0';
end if;
end if;
if rising_edge(TX_Start) then
data_count <= data_count + 1;
end if;
end process;
It works perfectly well in simulation, but theres no output on the hardware. Need your help in finding out whats wrong.
PS: This is my first FPGA project, so my code may not be so efficient.
I have also attached the ISIM screenshot.
clickable
tx = TX Done pin
trig = TX Start ping
c1 = data count
Note: SPI transmission sequence starts when average outputs are available and it is triggered using an internal signal"SPITRig".
Take a look at the synthesis and timing (STA) warnings, since these will indicate if the synthesis tool could not implement the design to match the RTL VHDL code.
The edge condition by rising_edge(...) or falling_edge(...) should only be used on a single common clock signal, unless there is a good reason for use of multiple clock signals; and usually only rising_edge(...) is used.
In your design you have three different signal SPITrig, SPI_Clock_base, and TX_Start that work like clocks, and this is likely to give a timing violation.
As example, in the first if of the large process, the TX_Start and data_count are both updated on the falling_edge(SPITrig), and in the last if the rising_edge(TX_Start) is used to update data_count again based on current data_count value. This may work fine in simulation, but in HW you have signal propagation delay, which depends on routing and other factors that may wary for different signals, so a design construction like that is likely to give problems in implementation.
If you have a full Static Timing Analysis (STA) setup for your design, which you probably don't have for a first time FPGA project, then the STA tool will report if the timing can be meet, and a construction like the above is likely to not meet timing.
So instead, rewrite your design to use only a single clock edge, for example rising_edge(SPI_Clock_base). It is also much easier to make a correct STA timing setup for such a design, and the sensitivity list of the processes should then only contain the clock and any asynchronous reset signals, if used, like:
process (SPI_Clock_base) is
begin
if rising_edge(SPI_Clock_base) then
...
end if;
end process;
Finally, the sensitivity list of the initial process should be reduced to only contain the signals that are read in the process, since the process need only to be sensitive to the these signals. The design won't fail if more signals are included, it makes the reader wonder what is wrong; the sensitivity list or the code.
As suggested by Morten Zilmer, I made the necessary changes to synchronize everything with the Clock. following is the code and it is working. Might post a screenshot from an oscilloscope later.
process(SPITrig, data_count, average2A_s, average2B_s)
begin
case data_count is
when 1 =>
TX_Data <= average2A_s;
when 2 =>
TX_Data <= average2B_s;
when others => TX_Data <= x"0000";
end case;
end process;
SPICycler : process(delay_counter, data_count, SPITrig, SPI_Clock_base, SPIBusy)
begin
if rising_edge(SPI_Clock_base) and SPIBusy = '1' then
if delay_counter < 511 then
delay_counter <= delay_counter + 1;
TX_Start <= '0';
else
delay_counter <= 0;
TX_Start <= '1';
data_count <= data_count + 1;
end if;
end if;
if rising_edge(SPI_Clock_base) then
if SPITrig = '1' then
SPIBusy <= '1';
data_count <= 0;
end if;
if data_count = 3 then
SPIBusy <= '0';
end if;
end if;
end process;