Split n long bit logic vector to n individual binary values - vhdl

I was wondering if there was a method where you can split a n bit long vector for example:
10100111
Into n individual binary units to be used later on? I'm trying to incorporate a method where i can get a 8 bit long vector and have 8 LED's light up depending if that n'th value is 0 or 1. Googling the question returns people cutting up a larger vector into smaller ones, but if we were to have 16 bits for example then i'd have to make 16 separate variables for it work using:
entity test is
port (
myVector : in std_logic_vector(16 downto 0);
LED : out std_logic_vector(16 downto 0)
);
END test
architecture behavior of test is
SIGNAL led1 : std_logic;
...
SIGNAL led16 : std_logic;
BEGIN
led1 <= myVector(0);
...
led16 <= myVector(16);
LED(1) <= '1' when led1 = '1' else '0';
...
LED(16) <= '1' when led16 = '1' else '0';
END behavior
Doesn't seem tidy when it needs to be repeated several times in the code.

If you want to declare and assign to identifiers with different names, then you have to make a line for each name, since there is no loop statement for identifier name manipulation in VHDL.
But VHDL provides arrays, where you can loop over the entries, like with this example code:
...
signal led_sig : std_logic_vector(16 downto 0);
begin
loop_g: for idx in myVector'range generate
led_sig(idx) <= myVector(idx);
LED(idx) <= '1' when led_sig(idx) = '1' else '0';
end generate;
...
Where the assigns are equivalent to the shorter:
led_sig <= myVector;
LED <= led_sig;

Related

Multiplier via Repeated Addition

I need to create a 4 bit multiplier as a part of a 4-bit ALU in VHDL code, however the requirement is that we have to use repeated addition, meaning if A is one of the four bit number and B is the other 4 bit number, we would have to add A + A + A..., B number of times. I understand this requires either a for loop or a while loop while also having a temp variable to store the values, but my code just doesn't seem to be working and I just don't really understand how the functionality of it would work.
PR and T are temporary buffer standard logic vectors and A and B are the two input 4 bit numbers and C and D are the output values, but the loop just doesn't seem to work. I don't understand how to loop it so it keeps adding the A bit B number of times and thus do the multiplication of A * B.
WHEN "010" =>
PR <= "00000000";
T <= "0000";
WHILE(T < B)LOOP
PR <= PR + A;
T <= T + 1;
END LOOP;
C <= PR(3 downto 0);
D <= PR(7 downto 4);
This will never work, because when a line with a signal assignment (<=) like this one:
PR <= PR + A;
is executed, the target of the signal assignment (PR in this case) is not updated immediately; instead an event (a future change) is scheduled. When is this event (change) actioned? When all processes have suspended (reached wait statements or end process statements).
So, your loop:
WHILE(T < B)LOOP
PR <= PR + A;
T <= T + 1;
END LOOP;
just schedules more and more events on PR and T, but these events never get actioned because the process is still executing. There is more information here.
So, what's the solution to your problem? Well, it depends what hardware you are trying to achieve. Are you trying to achieve a block of combinational logic? Or sequential? (where the multiply takes multiple clock cycles)
I advise you to try not to think in terms of "temporary variables", "for loops" and "while loops". These are software constructions that can be useful, but ultimately you are designing a piece of hardware. You need to try to think about what physical pieces of hardware can be connected together to achieve your design, then how you might describe them using VHDL. This is difficult at first.
You should provide more information about what exactly you want to achieve (and on what kind of hardware) to increase the probability of getting a good answer.
You don't mention whether your multiplier needs to operate on signed or unsigned inputs. Let's assume signed, because that's a bit harder.
As has been noted, this whole exercise makes little sense if implemented combinationally, so let's assume you want a clocked (sequential) implementation.
You also don't mention how often you expect new inputs to arrive. This makes a big difference in the implementation. I don't think either one is necessarily more difficult to write than the other, but if you expect frequent inputs (e.g. every clock cycle), then you need a pipelined implementation (which uses more hardware). If you expect infrequent inputs (e.g. every 16 or more clock cycles) then a cheaper serial implementation should be used.
Let's assume you want a serial implementation, then I would start somewhere along these lines:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity loopy_mult is
generic(
g_a_bits : positive := 4;
g_b_bits : positive := 4
);
port(
clk : in std_logic;
srst : in std_logic;
-- Input
in_valid : in std_logic;
in_a : in signed(g_a_bits-1 downto 0);
in_b : in signed(g_b_bits-1 downto 0);
-- Output
out_valid : out std_logic;
out_ab : out signed(g_a_bits+g_b_bits-1 downto 0)
);
end loopy_mult;
architecture rtl of loopy_mult is
signal a : signed(g_a_bits-1 downto 0);
signal b_sign : std_logic;
signal countdown : unsigned(g_b_bits-1 downto 0);
signal sum : signed(g_a_bits+g_b_bits-1 downto 0);
begin
mult_proc : process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
out_valid <= '0';
countdown <= (others => '0');
else
if in_valid = '1' then -- (Initialize)
-- Record the value of A and sign of B for later
a <= in_a;
b_sign <= in_b(g_b_bits-1);
-- Initialize countdown
if in_b(g_b_bits-1) = '0' then
-- Input B is positive
countdown <= unsigned(in_b);
else
-- Input B is negative
countdown <= unsigned(-in_b);
end if;
-- Initialize sum
sum <= (others => '0');
-- Set the output valid flag if we're already finished (B=0)
if in_b = 0 then
out_valid <= '1';
else
out_valid <= '0';
end if;
elsif countdown > 0 then -- (Loop)
-- Let's assume the target is an FPGA with efficient add/sub
if b_sign = '0' then
sum <= sum + a;
else
sum <= sum - a;
end if;
-- Set the output valid flag when we get to the last loop
if countdown = 1 then
out_valid <= '1';
else
out_valid <= '0';
end if;
-- Decrement countdown
countdown <= countdown - 1;
else
-- (Idle)
out_valid <= '0';
end if;
end if;
end if;
end process mult_proc;
-- Output
out_ab <= sum;
end rtl;
This is not immensely efficient, but is intended to be relatively easy to read and understand. There are many, many improvements you could make depending on your requirements.

How does this SIPO Works?

I am making an UART transceiver, and In that for Receiver section, I need a SIPO to convert the serial data into parallel one, A web search threw out a code which does the required function, I am not able to understand how this particular code works, googling didn't help. I am grateful if someone can point out how this works
library ieee;
use ieee.std_logic_1164.all;
entity RXN_CNTRL is
port(
reset : in std_logic;
clk : in std_logic;
din : in std_logic;
dout : out std_logic_vector(3 downto 0)
);
end entity;
architecture behave of RXN_CNTRL is
signal s : std_logic_vector(3 downto 0) := "0000" ;
begin
sipo : process (clk, reset)
begin
if (reset='1') then
s <= "0000";
elsif (rising_edge (clk)) then
s <= (din & s(3 downto 1));
end if;
end process;
dout <= s;
end architecture;
I am not able to understand how the line s <= (din & s(3 downto 1));
works. please clear me in this, I am new to vhdl and want to learn how this works. Thanks
In VHDL & is the concatenation operator. It is used to make bigger arrays from smaller arrays and single array elements by concatenating them, ie joining them together. So,
s <= (din & s(3 downto 1));
takes the single bit din and joins it to the leftmost 3 bits of s (s(3 downto 1)) to give a new value of s:
din s(3) s(2) s(1)
So, you can see that s has been shifted one place to the right and the empty space has been filled with din - exactly the behaviour you'd want for a SIPO.
In VHDL I would recommend always using the combination of concatenation and slicing (taking part of an array, like s(3 downto 1)) for implementing shift-registers and so on. The builtin operators (sla etc) behave in strange ways.
& is the concatenation operator in VHDL.
So what this does is to shift in the newly received bit (din) into s from the left (disposing the lowest bit of s).
Suppose s is "0000" initially. If din = '1', then s <= din & s(3 downto 1) takes din ('1'), concatenates s(3 downto 1)("000") to it and assigns the result to s. The lowest bit of s is 'lost' through this.
I recommend playing through this until you understand what happens.

How to convert std_logic to unsigned in an expression

So if wanted to assign a std_logic to a 1-bit usnigned I could just write...
signal X : unsigned(0 downto 0);
signal Y : std_logic;
X(0) <= unsigned(Y)
But what s the best way to convert a std_logic to an unsigned when used in an expression.
That is to say, without directly doing an assignment to a signal of type unsigned.
The scenario I have is this. I have two flags A and B that are signals of type std_logic.
Each flag has a strobe (A_valid , B_valid) of type std_logic that assert for 1 clock cycle each time their flag (A , B) is valid.
I have a counter (CNT) that is a signal of type unsigned that must count the number of times that either of the flags is '1'.
On any given clock cycle I must incrment CNT by 0, 1, or 2 depending on how many flags are 1.
Here is the straight forward way of doing it with an "if" statement.
signal A : std_logic;
signal A_valid : std_logic;
signal B : std_logic;
signal B_valid : std_logic;
signal CNT : unsigned;
if rising_edge(clk) then
if (A and A_valid and B and B_valid) = '1' then
CNT <= CNT + 2;
elsif (A and A_valid) = '1' then
CNT <= CNT + 1;
elsif (B and B_valid) = '1' then
CNT <= CNT + 1;
end if;
end if;
The problem with the code above is that it doesn't generalize very well since the number of cases goes up exponentially with the number of flags. For example if I had 5 flags I would have to write out 32 branches in the IF statement.
A more compact way of representing the same thing using an aggregate and a type mark is...
This is better becasue I just write one expression for each flag.
if rising_edge(clk) then
CNT <= CNT + unsigned'(0=> A AND A_valid) + unsigned'(0=> B AND B_valid);
end if;
Are there any other built-in ways (other than writing a function) to convert std_logic to unsigned in an expression in VHDL?
The easiest way is to concatenate the std_logic with a null array, yielding an array of length 1.
Cnt <= cnt + ("" & a_valid);
It should be able to work out the type from the context, otherwise you may need to qualify it with unsigned'

VHDL Shift Register Program different results when using signals and variables

So I've been using VHDL to make a register, where it loads in the input X if LOAD is '1' , and outputs the data in serial fashion , basically a parallel in serial out register. The input X is a 4 bit ( 3 downto 0 ) input , what I want to make the program do is constantly output 0 when the register has successfully output all the btis in the input.
It works when "count" is defined as a signal , however , when count is defined as a variable , the output is a constant 0 , regardless of whether load is '1' or not. My code is as shown:
entity qn14 is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
LOAD : in STD_LOGIC;
X : in STD_LOGIC_VECTOR (3 downto 0);
output : out STD_LOGIC);
end qn14;
architecture qn14_beh of qn14 is
type states is ( IDLE , SHIFT );
signal state : states;
signal count: STD_LOGIC_VECTOR(1 downto 0);
begin
process(clk , reset)
variable temp: STD_LOGIC;
variable data: STD_LOGIC_VECTOR(3 downto 0);
begin
if reset = '1' then
state <= IDLE;
count <= "00";
output <= '0';
elsif clk'event and clk = '1' then
case state is
when IDLE =>
if LOAD = '1' then
data := X;
output <= '0';
state <= SHIFT;
elsif LOAD = '0' then
output <= '0';
end if;
when SHIFT =>
if LOAD ='1' then
output <= '0';
elsif LOAD = '0' then
output <= data( conv_integer(count) );
count <= count + 1;
if (count >= 3) then
state <= IDLE ;
end if;
end if;
end case;
end if;
end process;
end qn14_beh;
Hoping to seek clarification on this.
Thank you.
This may not fully answer your question, but I will cover several issues that I see.
The elsif LOAD = '0' then could just be else unless you're trying to cover the other states (X,U...) but you would still want an else to cover those.
count = 3 is clearer than count >= 3. count is a 2-bit vector, so it can never be greater than 3.
Although you output 0 when LOAD is asserted while in the SHIFT state, you don't actually load a new value. Did you intend to?
Changing count to a variable without changing the position of the assignments will cause your first X -> output sequence to abort a cycle early (you increment count before you test it against 3). It will cause subsequent X -> output sequences to go "X(3), X(0), X(1), X(2)"
The variable temp is never used. The variable data would work just as well as a signal. You do not need the properties of variables for this use. This also brings up the question of why you tried count as variable; unless you need the instant assignments of variables, it is typically better to use a signal because signals are easier to view in (most) simulators and harder to make mistakes with. I hope that you aren't trying to end up with count as a variable, but just have an academic curiosity why it doesn't work.
Have you looked at this in a simulator? Are you changing states properly? Are all the bits of all your inputs strongly driven to a defined value ('1' or '0')?
I don't see anything that would cause the failure you described merely from changing count to a variable from a signal, but the change would cause the undesired behavior described above. My best guess is that your symptom arises from an issue with how you drive your inputs.

Shift Right And Shift Left (SLL/SRL)

so, I'm developing an ALU for MIPS architecture and I'm trying to make a shift left and a shift right so that the ALU can shift any amount of bits.
the Idea I had is to convert the shift value to an integer and select the piece of the entry that'll be on the result(the integer is stored in X) but Quartus doesn't accept a variable value, only constants.
What could I do to make this?
(Cases are on lines "WHEN "1000" =>..." and "WHEN "1001" =>...")
Thanks.
PROCESS ( ALU_ctl, Ainput, Binput, X )
BEGIN
-- Select ALU operation
--ALU_output_mux <= X"00000000"; --padrao
CASE ALU_ctl IS
WHEN "1000" => ALU_output_mux(31 DOWNTO X) <= (Ainput( 31-X DOWNTO 0 ));
WHEN "1001" => ALU_output_mux(31-X DOWNTO 0) <= (Ainput( 31 DOWNTO X ));
WHEN OTHERS => ALU_output_mux <= X"00000000";
END CASE;
END PROCESS;
If Quartus doesn't like it you have two choices:
Write it some way that Quartus does like - you're trying to infer a barrel shifter, so you could write one out longhand and then instantiate that. Potentially expensive in time
Get a different synthesizer that will accept it. Potentially expensive in money.
I have had issues with this in Quartus as well, although your code also has some implicit latches (you are not assigning all bits of the output in your two shift cases).
The work-around I use is to define an intermediate array with all the possible results, then select one of those results using your selector. In your case, something like the following:
subtype DWORD_T is std_logic_vector( 31 downto 0);
type DWORD_A is array (natural range <>) of DWORD_T;
signal shift_L : DWORD_A(31 downto 0);
signal shift_R : DWORD_A(31 downto 0);
signal zero : DWORD_T;
...
zero <= (others=>'0');
process (Ainput)
begin
for index in Ainput'range loop
shift_L(index) <= Ainput(31 - index downto 0) & zero(index - 1 downto 0);
shift_R(index) <= zero(index - 1 downto 0) & Ainput(31 downto index);
end loop;
end process;
ALR_output_mux <= shift_L(to_integer(X)) when ALU_ctl="1000",
shift_R(to_integer(X)) when ALU_ctl="1001",
(others=>'0') when others;
You could work around this by using generate or for to create each shift/rotate level, or you can use the standard functions ({shift,rotate}_{left,right}) for shifting and rotating.

Resources