How to declare an output with multiple zeros in VHDL - vhdl

Hello i am trying to find a way to replace this command: Bus_S <= "0000000000000000000000000000000" & Ne; with something more convenient. Counting zeros one by one is not very sophisticated. The program is about an SLT unit for an ALU in mips. The SLT gets only 1 bit(MSB of an ADDSU32) and has an output of 32 bits all zeros but the first bit that depends on the Ne=MSB of ADDSU32. (plz ignore ALUop for the time being)
entity SLT_32x is
Port ( Ne : in STD_LOGIC;
ALUop : in STD_LOGIC_VECTOR (1 downto 0);
Bus_S : out STD_LOGIC_VECTOR (31 downto 0));
end SLT_32x;
architecture Behavioral of SLT_32x is
begin
Bus_S <= "0000000000000000000000000000000" & Ne;
end Behavioral;
Is there a way to use (30 downto 0)='0' or something like that? Thanks.

Try this: bus_S <= (0 => Ne, others => '0')
It means: set bit 0 to Ne, and set the other bits to '0'.

alternative to the given answers:
architecture Behavioral of SLT_32x is
begin
Bus_S <= (others => '0');
Bus_S(0) <= ne;
end Behavioral;
Always the last assignment in a combinatoric process is taken into account. This makes very readable code when having a default assignment for most of the cases and afterwards adding the special cases, i.e. feeding a wide bus (defined as record) through a hierarchical block and just modifying some of the signals.

Related

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 write std_logic_vector assignment with input-dependent range in VHDL?

I am trying to copy some part of a std_logic_vector into another, at a position (index) depending on an input. This can be synthesized in Vivado, but I want to use another tool (SymbiYosys, https://github.com/YosysHQ/SymbiYosys) for formal verification. SymbiYosys can use Verific as frontend to process VHDL, but Verific does not accept this. Here is a small piece of code which reproduces the problem. Verific complains that the "left range bound is not constant". So, is there a workaround to make Verific accept such variable range assignments ?
I already found this post VHDL: slice a various part of an array which proposes to use a loop and to assign values bit per bit, but I would rather not change my code now that it works with Vivado. Also I think such a loop would impair code readability, and perhaps implementation efficiency. Therefore, I am looking for a different method (maybe a way to turn this error into a warning, or a less drastic code modification).
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
entity test is
port(
clk : in std_logic;
prefix : in std_logic_vector( 8*8 -1 downto 0);
msgIn : in std_logic_vector(128*8 -1 downto 0);
msgLength : in integer range 1 to 128;
test_out : out std_logic_vector((128+8)*8 -1 downto 0)
);
end test;
architecture behav of test is
begin
process (clk)
begin
if rising_edge(clk) then
test_out <= (others => '0');
test_out((msgLength+8)*8 -1 downto msgLength*8) <= prefix;
test_out( msgLength *8 -1 downto 0) <= msgIn(msgLength*8 -1 downto 0);
end if;
end process;
end behav;
A bit of shifting should make it (if your tools support the srl and sll operators). First left-align your message (left shift), left-pad it with your prefix and, finally, right-shift it:
process (clk)
variable tmp1: std_logic_vector(128*8 -1 downto 0);
variable tmp2: std_logic_vector((128+8)*8 -1 downto 0);
begin
if rising_edge(clk) then
tmp1 := msgIn sll (8 * (128 - msgLength)); -- left-align
tmp2 := prefix & tmp1; -- left-pad
test_out <= tmp2 srl (8 * (128 - msgLength)); -- right-shift
end if;
end process;
Remarks:
In case your tools do not support the srl and sll operators on std_logic_vector, try to work with bit_vector, instead. srl and sll have been introduced in the standard in 1993. Example:
process (clk)
variable tmp1: bit_vector(128*8 -1 downto 0);
variable tmp2: bit_vector((128+8)*8 -1 downto 0);
begin
if rising_edge(clk) then
tmp1 := to_bitvector(msgIn) sll (8 * (128 - msgLength));
tmp2 := to_bitvector(prefix) & tmp1;
test_out <= to_stdlogicvector(tmp2 srl (8 * (128 - msgLength)));
end if;
end process;
The synthesis result may be huge and slow because this 1088 bits barrel shifter with 128 possible different shifts is a kind of monster.
If you have time (I mean several clock cycles) to do it, there are probably much smaller and more efficient solutions.

Use of conv_integer in VHDL

I am in the process of trying to write some code that will simply just shift a 32 bit vector left or right, with a 5 bit input that will be used for the shift amount (shamt). The issue I am having is trying to convert an std_logic_vector to an integer. My code is this:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x : in std_logic_vector(31 downto 0);
shamt : in std_logic_vector( 4 downto 0);
y : out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
signal shift : integer;
signal temp : std_logic_vector(31 downto 0);
begin
shift <= conv_integer(unsigned(shamt));
temp <= x(shift downto 0);
y <= temp;
end beh;
The code is not complete I know, but to test some ideas I am trying to pass "00010" (2) into shamt, but shift comes out to be -2147483648. But I cannot figure out why it is doing this, nor can I find any resources online that shows anything different than what I am doing. I greatly appreciate any help.
-2147483648 (-2**31) is the default initial value for integers, being the leftmost, most negative value in its range. It suggests that the signal assignment to shift has not executed. Most likely because it is a continuous assignment and there hasn't been an event on shamt to cause it to update.
std_logic_arith is not an IEEE standard library. You should use to_integer() from ieee.numeric_std instead. It is also beneficial to keep numeric ports as unsigned or signed so that your intent is clear and to minimize type conversions. Also, you cannot directly assign the variable length slice of x to temp since their lengths do not match. You should use resize() (from numeric_std) to extend the length back to 32-bits or rethink your approach.
I fixed the obvious typo in the entity name, started the simulation (ModelSim) and forced the signal shamt to "00010". Then just after trying to run for 1 ps, ModelSim complains about:
Fatal: (vsim-3420) Array lengths do not match. Left is 32 (31 downto 0). Right is 0 (-2147483648 downto 0 (null array)).
Time: 0 ps Iteration: 0 Process: /shiftlogical/line__16 File: shiftlogical.vhdl
Fatal error in Architecture beh at shiftlogical.vhdl line 16
That is because all your concurrent statements are executed in parallel. The new signal values are scheduled for the next delta cycle within the simulation. Thus, the line
temp <= x(shift downto 0);
is executed with the old value of shift which is the initial value of this signal. The initial value of an integer is -2**31 as also Kevin pointed out.
Of course you can initialize the signal shift, but the only value which will not result in an error will be 31 because in this asignment the signal on the left and the expression on the right must match in array (std_logic_vector) size. The signal shamt must be forced to "11111" as well, so that shift keeps 31.
You cannot easily fix this, because for a left shift you must add zeros at the right (LSB) and for a right shift zeros or the sign at the left (MSB).
#Martin Zabel what I had really tested there was to see if shift would hold an integer value which it did until I tried to pass it in for temp <= x(shift downto 0); What I realized was that the signal needed to really be a variable to work as intended and as follows my code consists of:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x: in std_logic_vector(31 downto 0);
shamt: in std_logic_vector(4 downto 0);
dir: in std_logic;
y: out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
begin
process(dir)
variable shift : integer;
begin
shift := conv_integer(unsigned(shamt));
if(dir = '0') then --Left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
elsif(dir = '1') then --Right shift
y(31-shift downto 0) <= x(31 downto shift);
y(31 downto 31-shift) <= (others => '0');
else --Always left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
end if;
end process;
end beh;

Dynamic Arrray Size in VHDL

I want to use dynamic range of array , so using "N" for converting an incoming vector signal to integer. Using the specifc incoming port "Size" gives me an error, while fixed vector produces perfect output.
architecture EXAMPLE of Computation is
signal size :std_logic_vector (7 downto 0);
process (ACLK, SLAVE_ARESETN) is
variable N: integer:=conv_integer ("00000111") ; ---WORKING
--variable N: integer:=conv_integer (size) ; -- Not working
type memory is array (N downto 0 ) of std_logic_vector (31 downto 0 );
variable RAM :memory;
Only reason to do this type of coding is send as much data as possible to FPGA .As I need to send Data from DDR to Custom IP via DMA in vivado may be more than 100 MB. so kindly guide me if I am trying to implement in wrong way as stated above.
You can't do that in VHDL. What kind of hardware would be generated by your code? If you don't know, the synthesizer won't either.
The way to do this kind of thing is to set N to the largest value you want to support, and use size in your logic to control your logic appropriately. It's difficult to give more pointers without more information, but as an example, you could use a counter to address your ram, and have it reset when it's greater than size.
Update
Here's a counter example. You have to make sure that size doesn't change while operating or it will fall into an unknown state. A real design should have reset states to ensure correct behaviour.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity example is
port (
clk : std_logic;
rst : in std_logic;
size : in unsigned(7 downto 0);
wr : in std_logic;
din : in std_logic_vector(31 downto 0)
);
end entity;
architecture rtl of example is
signal counter : unsigned(7 downto 0);
type ram_t is array(0 to 255) of std_logic_vector(31 downto 0);
signal ram : ram_t;
begin
RAM_WR: process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
counter <= (others => '0');
else
if wr = '1' then
ram(to_integer(counter)) <= din;
if counter = size then
counter <= (others => '0');
else
counter <= counter + 1;
end if;
end if;
end if;
end if;
end process RAM_WR;
end architecture rtl;
I believe you can only have a generic an array constraint in a process. Otherwise, the compiler cannot elaborate.
In a function or procedure, you can have truly variable array bounds.

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