Shift Right And Shift Left (SLL/SRL) - vhdl

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.

Related

VHDL: big slv array slicing indexed by integer (big mux)

I want to slice a std_logic_vector in VHDL obtaining parts of it of fixed dimensions.
The general problem is:
din N*M bits
dout M bits
sel clog2(N) bits
Expected behaviour in an example (pseudocode): input 16 bit, want to slice it in 4 subvectors of 4bit each.
signal in: std_logic_vector(N*M-1 downto 0);
signal sel: integer;
-- with sel = 0
output <= in(N-1:0);
--with sel = 1 output <= in(2N-1:N)
-- with sel = 2
output <= in(3N-1:2N)
.....
--with sel = M-1
output <= in(M*N-1:(M-1)N)
I know a couples of way to do this, but I don't know which one is the best practice and give the best results in synthesis.
the entity
din: in std_logic_vector(15 downto 0);
dout: out std_logic_vector(3 downto 0);
sel: in std_logic_vecotor(1 downto 0)
CASE STATEMENT
case sel is
when "00" => dout <= din(3:0);
when "01" => dout <= din(7:4);
when "10" => dout <= din(11:8);
when "11" => dout <= din(15:12);
when others => ....`
It clearly implement a mux, but it's not generic at all and If the input gets big it's really hard to write and to codecover.
INTEGER INDEXING
sel_int <= to_integer(unsigned(sel));
dout <= din(4*(sel_int+1) - 1 downto 4*sel_int);
Extremely easy to write and to mantain, BUT it can have problems when the input is not a power of 2. For example, if I want to slice a 24bit vector in chunks of 4, what happen when the integer conversion of sel brings to the index 7?
A STRANGE TRADEOFF
sel_int <= to_integer(unsigned(sel));
for i in 0 to 4 generate
din_slice(i) <= din(4*(i+1)-1 downto 4*i);
end generate dout <= din_slice(sel_int);
I'm searching a solution that is general enough to be used with various input/output relationships and safe enough to be synthesized consistently everytime.
The Case statement is the only one with the Others case (that feels really safe), the other solutions rely on the slv to integer conversion and indexing that feels really comfortable but not so reliable.
Which solution would you use?
practical usecase
I have a 250bit std_logic_vector and I need to select 10 contigous bits inside of it starting from a certain point from 0 to 239. How can I do that in a way that is good for synthesis?
There is another option that is accepted by tools that allow VHDL 2008 (which includes Vivado and Prime Pro). You can use an unconstrained 2d type from a package:
type slv_array_t is array(natural range <>) of std_logic_vector; --vhdl 2008 unconstrained array type
then you can simply select which port you want. And it is as generic as you like.
library ieee;
use ieee.std_logic_1164.all;
use work.my_pkg.all;
entity mux is
generic (
N : natural;
M : natural
);
port (
sel : in natural;
ip : in slv_array_t (N-1 downto 0)(M-1 downto 0);
op : out std_logic_vector (M-1 downto 0);
);
end entity;
architecture rtl of mux is
begin
op <= ip(sel);
end architecture;
First you must extend the incoming data to be sure to have always as much bits as you need for connecting all multiplexer inputs (see the code below, process p_extend).
This will not create any logic at synthesis.
Second you must convert the resulting vector into an array, which you can access later by an index (see the code below, process p_create_array).
Again this will not create any logic at synthesis.
At last you must access this array by the select input signal (see the code below, process p_mux).
library ieee;
use ieee.std_logic_1164.all;
entity mux is
generic (
g_data_width : natural := 250;
g_slice_width : natural := 10;
g_sel_width : natural := 5;
g_start_point : natural := 27
);
port (
d_i : in std_logic_vector(g_data_width-1 downto 0);
sel_i : in std_logic_vector(g_sel_width-1 downto 0);
d_o : out std_logic_vector(g_slice_width-1 downto 0)
);
end entity mux;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture struct of mux is
signal data : std_logic_vector(g_slice_width * 2**g_sel_width-1 downto 0);
type t_std_logic_slice_array is array (natural range <>) of std_logic_vector(g_slice_width-1 downto 0);
signal mux_in : t_std_logic_slice_array (2**g_sel_width-1 downto 0);
begin
p_extend: process(d_i)
begin
for i in 0 to g_slice_width * 2**g_sel_width-1 loop
if i+g_start_point<g_data_width then
data(i) <= d_i(i+g_start_point);
else
data(i) <= '0';
end if;
end loop;
end process;
p_create_array: process (data)
begin
for i in 0 to 2**g_sel_width-1 loop
mux_in(i) <= data((i+1)*g_slice_width-1 downto i*g_slice_width);
end loop;
end process;
p_mux: d_o <= mux_in(to_integer(unsigned(sel_i)));
end architecture;

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;

How to declare an output with multiple zeros in 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.

Resources