Array aggregation on self-defined types? - vhdl

I'm trying to implement an FSM with a RAM behavior. There are multiple addresses of this ram that should be initialized while describing this FSM. So, I'm using the array aggregation technique to initialize the first 20 addresses of the ram_block. However, I'm getting a bad syntax error on each line the aggregation has occurred or the partial section of the ram_block(i) has initialized. Any helps would be appreciated.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
entity RegisterController is
port(
r1_p: inout std_logic_vector(31 downto 0);
r2_p: inout std_logic_vector(31 downto 0);
write_p: in std_logic;
enable_p: in std_logic;
clk_p: in std_logic;
ram_rw: in std_logic; -- 0 => Read from ram | 1 => Write to the ram
reset_p: in std_logic
);
end RegisterController;
architecture RTL of RegisterController is
-- Create the ram word
subtype ram_word is std_logic_vector(66 downto 0);
-- Create the ram block of 32 ram_words
type ram_block is array (31 downto 0) of ram_word;
-- Address to read from the ram
signal R_ADDR_S: std_logic_vector(4 downto 0) := "00000";
begin
RAM_LOAD: process(clk)
begin
-- We're gonna load the 32 words of this ram with clock first
-- Outputs are being updated in the runtime :D
if(rising_edge(clk)) then
if(ram_rw = '1') then
-- STATE 0 DESCRIPTION
ram_block(0) <= ("000", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsgined(0, 32)));
ram_block(1) <= ("000", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32)));
ram_block(2) <= ("001", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32)));
ram_block(3) <= ("001", std_logic_vector(to_unsigned(0, 32)), std_logic_vector(to_unsigned(0, 32)));
-- STATE 1 DESCRIPTION
ram_block(4) <= (66 downto 64) => "001";
ram_block(5) <= (66 downto 64) => "001";
ram_block(6) <= ("001", r2_p, r1_p);
ram_block(7) <= (66 downto 64) => "010";
-- STATE 2 DESCRIPTION
ram_block(8) <= (66 downto 64) => "010";
ram_block(9) <= (66 downto 64) => "010";
ram_block(10) <= (66 downto 64) => "011";
ram_block(11) <= (66 downto 64) => "011";
-- STATE 3 DESCRIPTION
ram_block(12) <= (66 downto 64) => "011";
ram_block(13) <= (66 downto 64) => "011";
ram_block(14) <= (66 downto 64) => "100";
ram_block(15) <= (66 downto 64) => "100";
-- STATE 4 DESCRIPTION
ram_block(16) <= (66 downto 64) => "100";
ram_block(17) <= (66 downto 64) => "100";
ram_block(18) <= (66 downto 64) => "001";
ram_block(19) <= (66 downto 64) => "001";
ram_block(31 downto 20) <= std_logic_vector(to_unsigned(0, 67));
end if;
end if;
end process;
START_FSM: process(clk)
-- TEMPORARY VARIABLE TO STORE THE READ VALUE FROM THE RAM BLOCK
variable temp_read_ram: std_logic_vector(66 downto 0);
variable temp_read_ram2: std_logic_vector(66 downto 0);
-- R3 Declaration as a variable
variable R3_V: std_logic_vector(31 downto 0);
begin
if(rising_edge(clk)) then
if(ram_rw = '0') then
-- START READING THE RAM FROM ADDRESS 0
temp_read_ram := ram_block(to_integer(unsigned(R_ADDR_S)));
R_ADDR_S(4 downto 2) <= temp_read_ram(66 downto 64);
R_ADDR_S(1 downto 0) <= (enable_p, write_p);
-- UPDATE THE OUTPUTS
if(R_ADDR_S = "00110") then
-- READ THE PREVIOUS VALUE IN THAT ADDRESS
temp_read_ram2 <= ram_block(R_ADDR_S);
-- UPDATE THE OUTPUT VALUES INSIDE RAM
ram_block(R_ADDR_S) <= (temp_read_ram2(66 downto 64), r2_p, r1_p);
-- NO NEED TO UPDATE r2_p and r1_p
elsif(R_ADDR_S = "00111") then
-- PUT THE CURRENT VALUE OF R1 TO THE R3
temp_read_ram2 <= ram_block(R_ADDR_S);
-- SAVE R1 TO THE R3_V
R3_V := temp_read_ram2(31 downto 0);
elsif(R_ADDR_S = "01110" or R_ADDR_S = "01111") then
-- READ THE PREVIOUS VALIE IN THOSE ADDRESSES
temp_read_ram2 <= ram_block(R_ADDR_S);
-- UPDATE THE OUTPUT VALUE OF R2 INSIDE RAM
ram_block(R_ADDR_S) <= (temp_read_ram2(66 downto 64), R3_V, temp_read_ram2(31 downto 0));
-- UPDATE THE OUTPUT VALUE OF r2_p
r2_p <= R3_V;
else
else
-- NO CHANGE
ram_block(R_ADDR_S) <= ram_block(R_ADDR_S);
end if;
end if;
end if;
end process;
end RTL;

There's not one, but many syntax errors in your code.
First off, ram_block is a type, not a signal. So why are you assigning values to it? You need to declare a signal first. I.e.
-- Create the ram block of 32 ram_words
type ram_block_type is array (31 downto 0) of ram_word;
signal ram_block : ram_block_type := (others => (others => '0'));
^ what I also include here, is initialization of the signal. Same can be done for:
signal R_ADDR_S: std_logic_vector(4 downto 0) := (others => '0');
In the process, you are assigning values to many locations in the RAM at the same time! That is not RAM-like. A random access memory usually only has 1 or 2 ports, accessing 1 resp. 2 elements at a time. You are designing generic distributed memory, so imho should not call it RAM.
Assigning to part of the array has a specific syntax. You can either assign the whole matrix in one go (this is VHDL-2008 by the way):
ram_block <= (4 => (66 downto 64 => "001", others => '0'), others => '0');
Note: you need to assign all values here, hence the others statement.
Second option, assign one sub-array
ram_block(4) <= (66 downto 64 => "001", others => '0');
Finally, and probably what you want, assign a specific sub-set of a sub-array:
ram_block(4)(66 downto 64) <= "001";
But in this case, you want to initialize the array, as else unassigned std_logic's will have the default value 'U'.
Then:
ram_block(31 downto 20) <= std_logic_vector(to_unsigned(0, 67));
This will not work. You're assigning an array structure to an array-of-arrays.
Variable R3_V is assigned in one situation, but not used directly: It is used a different clock cycle. In that case do not use a variable: that is bad coding style. It should be a signal.
And you must remember that signals assigned in a clocked process will not have access to their new value until the next delta cycle. Thus the assignment of signal R_ADDR_S(4 downto 2) <= temp_read_ram(66 downto 64); will not be available for the following if-statements!
Other things:
clk should probably be clk_p
to_unsgined -> to_unsigned
in line 79 you use the correct ram_block(to_integer(unsigned(R_ADDR_S))), but later (line 86) you do it wrong ram_block(R_ADDR_S)
in line 79 you also correctly assign a variable using :=, but later (line 86 again) you use the incorrect <=.
there's a double else at the end of the code.

Related

Error: /..integrator.vhd(47): near "process": (vcom-1576) expecting IF VHDL

I'm trying to add two registers storing signed bits one of 3-bit[FRQ(2 downto 0)] and other is 7-bit[PHS(6 downto 0)]...and has to store the addition of these two registers in 7-bit register [PHS(6 downto 0)]. Thanks in advance for your helpful gesture.
the error I get is..>>>
Error: /..integrator.vhd(47): near "process": (vcom-1576) expecting IF VHDL
here is my code:
library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--use ieee.std_logic_unsigned.all;
entity integ is
port (
SMP_CLK : in std_logic;
RESET : in std_logic;
PHS : out signed (6 downto 0);
FRQ : in signed (2 downto 0)
);
end integ;
architecture behaviour of integ is
signal sig_FRQ : signed(2 downto 0) := (others => '0');
signal ext_FRQ : signed(6 downto 0) := (others => '0');
signal sig_PHS : signed(6 downto 0) := (others => '0');
signal temp_PHS : signed(6 downto 0) := (others => '0');
begin
sig_FRQ <=FRQ;
temp_PHS <= sig_PHS;
--PHS <=signal_PHS;
process (SMP_CLK, RESET)
begin
if sig_FRQ(2)='1' then
ext_FRQ(6 downto 3) <= b"0000";
else
ext_FRQ(6 downto 3) <= b"1111";
--end if;
if RESET='1' then
sig_PHS <= b"0000000";
elsif (rising_edge(SMP_CLK) ) then
-- temp_PHS <= sig_PHS;
sig_PHS <= signed(ext_FRQ) + signed(temp_PHS);
end process;
sig_PHS => PHS;
end behaviour;
You have some mess with if-elsif-else statement. After the line with ext_FRQ(6 downto 3) <= b"1111"; you have commented --end if; if you want to continue if-elsif-else statement next condition should start with elsif word rather than simple if as in your code.
And you need to close the if-elsif-else construction in the end.
As well as you need to add to sensitivity list sig_FRQ signal because you use it in comparison, if you don't add it to sensitivity list the following construction
if sig_FRQ(2)='1' then
ext_FRQ(6 downto 3) <= b"0000";
else
ext_FRQ(6 downto 3) <= b"1111";
end if;
will work wrong.
In your case I suppose right version of the if-elsif-else constructions looks like:
process (sig_FRQ)
begin
if sig_FRQ(2)='1' then
ext_FRQ(6 downto 3) <= b"0000";
else
ext_FRQ(6 downto 3) <= b"1111";
end if;
end process;
process (SMP_CLK, RESET)
if RESET='1' then
sig_PHS <= b"0000000";
elsif (rising_edge(SMP_CLK)) then
--temp_PHS <= sig_PHS;
sig_PHS <= ext_FRQ + temp_PHS;
end if;
end process;
In the end, if you would like to assign result to output, you need to use another operator
PHS <= sig_PHS;.

Bundle statements in VHDL

How can I combine/bundle statements for further use and better handling? For example some assignments like this which would be used many times more in future calls of the routine.
ADDR_PC <= "0000000000";
ADDR_OP_A <= "00000";
ADDR_OP_B <= "00000";
OP_CODE <= OP_NOP;
OP_IMMED <= IMMED_NULL;
WE_SREG <= "00000"; -- S V N C Z
Into something like this.
NOP = {ADDR_PC <= "00000000", ADDR_OP_A <= "00000", ...}
I don't know if there are any possibilities to do that in VHDL. Any tip would be helpful.
Records and/or aggregates:
library ieee;
use ieee.std_logic_1164.all;
entity op_decoded is
end entity;
architecture foo of op_decoded is
-- These declarations probably want to be in a package
constant IMMED_NULL: std_logic_vector (8 downto 0) := (others => '0');
constant OP_NOP: std_logic_vector (5 downto 0) := (others => '0');
type decode_op is
record
PC: std_logic_vector (7 downto 0);
OP_A: std_logic_vector (4 downto 0);
OP_B: std_logic_vector (4 downto 0);
OP_CODE: std_logic_vector (5 downto 0);
OP_IMMED: std_logic_vector (8 downto 0);
WE_SREG: std_logic_vector (4 downto 0); -- S V N C Z
end record;
constant NOP: decode_op := (
PC => "00000000",
OP_A => "00000",
OP_B => "00000",
OP_CODE => OP_NOP,
OP_IMMED => IMMED_NULL,
WE_SREG => "00000"
);
-- actual signals
signal ADDR_PC: std_logic_vector (7 downto 0);
signal ADDR_OP_A: std_logic_vector (4 downto 0);
signal ADDR_OP_B: std_logic_vector (4 downto 0);
signal OP_CODE: std_logic_vector (5 downto 0);
signal OP_IMMED: std_logic_vector (8 downto 0);
signal WE_SREG: std_logic_vector (4 downto 0);
signal pipe1: decode_op;
signal pipe_disc: decode_op;
begin
(ADDR_PC, ADDR_OP_A, ADDR_OP_B, OP_CODE, OP_IMMED, WE_SREG) <= NOP;
pipe1 <= NOP;
pipe_disc <= (pipe1.PC, pipe1.OP_A, pipe1.OP_B, pipe1.OP_CODE,
pipe1.OP_IMMED, pipe1.WE_SREG);
end architecture;
This analyzes, elaborates and simulates (showing it's syntactically and semantically correct).
There's also an aggregate target with an aggregate right hand side (with the type provided):
(ADDR_PC, ADDR_OP_A, ADDR_OP_B, OP_CODE, OP_IMMED, WE_SREG) <=
decode_op'(pipe1.PC, pipe1.OP_A, pipe1.OP_B, pipe1.OP_CODE,
pipe1.OP_IMMED, pipe1.WE_SREG);
VHDL has records (C calls it struct).
Declaration example:
type T_MY_RECORD is record
Member1 : STD_LOGIC;
Member2 : STD_LOGIC_VECTOR(15 downto 0);
end record;
signal mySignal1 : T_MY_RECORD;
signal mySignal2 : T_MY_RECORD;
Usage examples:
mySignal1 <= (
Member1 => '1',
Member2 => x"12FC"
);
mySignal2.Member1 <= '0';
Records can be nested, e.g. for the flags.
Records and/or aggregates are one possibility, but and alternative is to declare a procedure in the process where the signals are driven, and then call the procedure, like:
process (clk_i) is
procedure NOP is
begin
ADDR_PC <= "0000000000";
ADDR_OP_A <= "00000";
ADDR_OP_B <= "00000";
OP_CODE <= OP_NOP;
OP_IMMED <= IMMED_NULL;
WE_SREG <= "00000"; -- S V N C Z
end procedure;
begin
if rising_edge(clk_i) then
...
NOP;
...
end if;
end process;
This work both for simulation and synthesizable code.

padding out std_logic_vector with leading zeros

ok, what I would like to do is assign a smaller std_vector to a large one, padding out the upper bits with zeros. But, I want something generic and simple that doesn't involve knowing the size of each first.
for instance if I have:
signal smaller_vec: std_logic_vector(15 downto 0);
signal larger_vec: std_logic_vector(31 downto 0);
I could do:
larger_vec <= X"0000" & smaller_vec;
But what if I don't know the size of the smaller vector. Is there a was of specifying that all upper bits are zero.
I know about the others clause, but that would get messy as I'd need a couple of lines:
larger_vec(smaller_vec'high downto 0) <= smaller_vec;
larger_vec(31 downto smaller_vec'length) <= (others => '0');
I thought I could use:
larger_vec <= "" & smaller_vec;
but this didn't work. any ideas?
Have you tried:
larger_vec <= (31 downto smaller_vec'length => '0') & smaller_vec;
In the past I have had synthesis tool issues with code like that, so I have used:
constant ZERO : std_logic_vector(larger_vec'range) := (others => '0');
. . .
larger_vec <= ZERO(31 downto smaller_vec'length) & smaller_vec;
James0's 2nd post was close, but the <= is facing the wrong direction, see below for a working example from duolos. I would edit, but at the time of this post I did not have enough reputation.
In https://www.doulos.com/knowhow/vhdl_designers_guide/vhdl_2008/vhdl_200x_ease/ in the Vectors in aggregates section it says:
variable V : std_logic_vector(7 downto 0);
begin
V := (others => '0'); -- "00000000"
V := ('1', '0', others => '0'); -- "10000000"
V := (4 => '1', others => '0'); -- "00010000"
V := (3 downto 0 => '0', others => '1'); -- "11110000"
-- V := ("0000", others => '1'); -- illegal!
larger_vec <= (smaller_vec'high downto 0 => smaller_vec, others => '0');
should work.
in my case I also like the following:
larger_vec <= (smaller_vec'high downto 0 <= smaller_vec, others => '0');
Which does my final answer in one line. This works, yes?
I have encountered similar issues and tried the following:
larger_vec <= (larger_vec'range => '0') + shorter_vec;
You need to use IEEE.std_logic_unsigned.all for this approach.
Zero-Pad or Truncate any std_logic_vector or std_logic to exactly 16 bits:
function pad16(x: std_logic_vector)
return std_logic_vector is
constant ZERO : std_logic_vector(15 downto 0) := (others => '0');
begin
if (x'length < 16) then
return ZERO(15 downto x'length) & x;
else
return x(15 downto 0);
end if;
end function;
--overload function for single bit
function pad16(x: std_logic)
return std_logic_vector is
constant ZERO : std_logic_vector(15 downto 0) := (others => '0');
begin
return ZERO(15 downto 1) & x;
end function;
-- USAGE:
--
-- reg16 <= pad16(X"3");

4bit ALU VHDL code

I am writing a code for a 4 bit ALU and I have a problem when I want to write for shift left operation. I have two inputs (operandA and operandB ). I want to convert the operandB into decimal (for example "0010" into '2') and then shift operandA 2 times to the left. my code is compiled but I am not sure that it is true. Thank you in advance.
entity ALU is
port(
reset_n : in std_logic;
clk : in std_logic;
OperandA : in std_logic_vector(3 downto 0);
OperandB : in std_logic_vector(3 downto 0);
Operation : in std_logic_vector(2 downto 0);
Start : in std_logic;
Result_Low : out std_logic_vector(3 downto 0);
Result_High : out std_logic_vector(3 downto 0);
Ready : out std_logic;
Errorsig : out std_logic);
end ALU;
architecture behavior of ALU is
signal loop_nr : integer range 0 to 15;
begin
process (reset_n, clk, operation)
variable tempHigh : std_logic_vector(4 downto 0);
begin
if (reset_n = '0') then
Result_Low <= (others => '0');
Result_High <= (others => '0');
Errorsig <= '0';
elsif (clk'event and clk = '1') then
case operation is
when "001" =>
for i in 0 to loop_nr loop
loop_nr <= to_integer(unsigned(OperandB));
Result_Low <= OperandA(2 downto 0)&'0';
Result_High <= tempHigh(2 downto 0) & OperandA(3);
end loop;
Ready <= '1';
Errorsig <= '0';
when "010" =>
Result_Low <= OperandB(0)& OperandA(3 downto 1);
Result_High <= OperandB(3 downto 1);
Ready <= '1';
when others =>
Result_Low <= (others => '0');
ready <= '0';
Errorsig <= '0';
end case;
end if;
end process;
end behavior;
For shifting left twice the syntax should be the following:
A <= A sll 2; -- left shift logical 2 bits
I don't quite understand why is it required to convert operand B in decimal. It can be used as a binary or decimal value or for that matter hexadecimal value at any point of time irrelevant of the base it was saved in.
The operator sll may not always work as expected before VHDL-2008 (read more
here),
so consider instead using functions from ieee.numeric_std for shifting, like:
y <= std_logic_vector(shift_left(unsigned(OperandA), to_integer(unsigned(OperandB))));
Note also that Result_High is declared in port as std_logic_vector(3 downto
0), but is assigned in line 41 as Result_High <= OperandB(3 downto 1), with
assign having one bit less than size.
Assumption for code is that ieee.numeric_std is used.
The reason you've been urged to use the likes of sll is because in general
synthesis tools don't support loop statements with non-static bounds
(loop_nr). Loops are unfolded which requires a static value to determine how
many loop iterations are unfolded (how much hardware to generate).
As Morten points out your code doesn't analyze, contrary to you assertion
that it compiles.
After inserting the following four lines at the beginning of your code we see
an error at line 41:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--(blank, a spacer that doesn't show up in the code highlighter)
ghdl -a ALU.vhdl
ALU.vhdl:41:26: length of value does not match length of target
ghdl: compilation error
Which looks like
Result_High <= '0' & OperandB(3 downto 1);
was intended in the case statement, choice "010" (an srl equivalent hard
coded to a distance of 1, presumably to match the correct behavior of the sll
equivalent). After which your design description analyzes.
Further there are other algorithm description errors not reflected in VHDL
syntax or semantic errors.
Writing a simple test bench:
library ieee;
use ieee.std_logic_1164.all;
entity alu_tb is
end entity;
architecture foo of alu_tb is
signal reset_n: std_logic := '0';
signal clk: std_logic := '0';
signal OperandA: std_logic_vector(3 downto 0) :="1100"; -- X"C"
signal OperandB: std_logic_vector(3 downto 0) :="0010"; -- 2
signal Operation: std_logic_vector(2 downto 0):= "001"; -- shft right
signal Start: std_logic; -- Not currently used
signal Result_Low: std_logic_vector(3 downto 0);
signal Result_High: std_logic_vector(3 downto 0);
signal Ready: std_logic;
signal Errorsig: std_logic;
begin
DUT:
entity work.ALU
port map (
reset_n => reset_n,
clk => clk,
OperandA => OperandA,
OperandB => OperandB,
Operation => Operation,
Start => Start,
Result_Low => Result_Low,
Result_High => Result_High,
Ready => Ready,
Errorsig => Errorsig
);
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 100 ns then
wait;
end if;
end process;
STIMULUS:
process
begin
wait for 20 ns;
reset_n <= '1';
wait;
end process;
end architecture;
Gives us a demonstration:
The first thing that sticks out is that Result_High gets some 'U's. This is
caused by tempHigh not being initialized or assigned.
The next thing to notice is that the shift result is wrong (both Result_Low
and Result_High). I'd expect you'd want a "0011" in Result_High and "0000" in
Result_Low.
You see the result of exactly one left shift - ('U','U','U','1') in
Result_High and "1000" in Result_Low.
This is caused by executing a loop statement in delta cycles (no intervening
simulation time passage). In a process statement there is only one driver for
each signal. The net effect of that is that there is only one future value
for the current simulation time and the last value assigned is going to be
the one that is scheduled in the projected output waveform for the current
simulation time. (Essentially, the assignment in the loop statement to a
signal occurs once, and because successive values depend on assignment
occurring it looks like there was only one assignment).
There are two ways to fix this behavior. The first is to use variables
assigned inside the loop and assign the corresponding signals to the
variables following the loop statement. As noted before the loop bound isn't
static and you can't synthesis the loop.
The second way is to eliminate the loop by executing the shift assignments
sequentially. Essentially 1 shift per clock, signaling Ready after the last
shift occurs.
There's also away to side step the static bounds issue for loops by using a
case statement (or in VHDL 2008 using a sequential conditional signal
assignment of sequential selected signal assignment should your synthesis
tool vendor support them). This has the advantage of operating in one clock.
Note all of these require having an integer variable holding
to_integer(unsigned(OperandB)).
And all of this can be side stepped when your synthesis tool vendor supports
sll (and srl for the other case) or SHIFT_LEFT and SHIFT_RIGHT from package
numeric_std, and you are allowed to use them.
A universal (pre VHDL 2008) fix without using sll or SHIFT_LEFT might be:
begin
process (reset_n, clk, operation)
variable tempHigh : std_logic_vector(4 downto 0);
variable loop_int: integer range 0 to 15;
begin
if (reset_n = '0') then
Result_Low <= (others => '0');
Result_High <= (others => '0');
Errorsig <= '0';
elsif (clk'event and clk = '1') then
case operation is
when "001" =>
loop_int := to_integer(unsigned(OperandB));
case loop_int is
when 0 =>
Result_Low <= OperandA;
Result_High <= (others => '0');
when 1 =>
Result_Low <= OperandA(2 downto 0) & '0';
Result_High <= "000" & OperandA(3);
when 2 =>
Result_Low <= OperandA(1 downto 0) & "00";
Result_High <= "00" & OperandA(3 downto 2);
when 3 =>
Result_Low <= OperandA(0) & "000";
Result_High <= "0" & OperandA(3 downto 1);
when 4 =>
Result_Low <= (others => '0');
Result_High <= OperandA(3 downto 0);
when 5 =>
Result_Low <= (others => '0');
Result_High <= OperandA(2 downto 0) & '0';
when 6 =>
Result_Low <= (others => '0');
Result_High <= OperandA(1 downto 0) & "00";
when 7 =>
Result_Low <= (others => '0');
Result_High <= OperandA(0) & "000";
when others =>
Result_Low <= (others => '0');
Result_High <= (others => '0');
end case;
-- for i in 0 to loop_nr loop
-- loop_nr <= to_integer(unsigned(OperandB));
-- Result_Low <= OperandA(2 downto 0)&'0';
-- Result_High <= tempHigh(2 downto 0) & OperandA(3);
-- end loop;
Ready <= '1';
Errorsig <= '0';
Which gives:
The right answer (all without using signal loop_nr).
Note that all the choices in the case statement aren't covered by the simple
test bench.
And of course like most things there's more than two ways to get the desired
result.
You could use successive 2 to 1 multiplexers for both Result_High and
Result_Low, with each stage fed from the output of the previous stage (or
OperandA for the first stage) as the A input the select being the appropriate
'bit' from OperandB, and the B input to the multiplexers the previous stage
output shifted by 1 logically ('0' filled).
The multiplexers can be functions, components or procedure statements. By
using a three to one multiplexer you can implement both symmetrical shift
Operation specified operations (left and right). Should you want to include signed shifts,
instead of '0' filled right shifts you can fill with the sign bit value. ...
You should also be assigning Ready <= '0' for those cases where valid
successive Operation values can be dispatched.
And because your comment on one of the answers requires the use of a loop with an integer value:
process (reset_n, clk, operation)
variable tempHigh : std_logic_vector(4 downto 0);
variable tempLow: std_logic_vector(3 downto 0); --added
variable loop_int: integer range 0 to 15; --added
begin
if (reset_n = '0') then
Result_Low <= (others => '0');
Result_High <= (others => '0');
Errorsig <= '0';
elsif (clk'event and clk = '1') then
case operation is
when "001" =>
tempLow := OperandA; --added
tempHigh := (others => '0'); --added
loop_int := to_integer(unsigned(OperandB)); --added
-- for i in 0 to loop_nr loop
-- loop_nr <= to_integer(unsigned(OperandB));
-- Result_Low <= OperandA(2 downto 0)&'0';
-- Result_High <= tempHigh(2 downto 0) & OperandA(3);
-- end loop;
-- More added:
if loop_int /= 0 then
for i in 1 to loop_int loop
tempHigh (3 downto 0) := tempHigh (2 downto 0) & tempLow(3);
-- 'read' tempLow(3) before it's updated
tempLow := tempLow(2 downto 0) & '0';
end loop;
Result_Low <= tempLow;
Result_High <= tempHigh(3 downto 0);
else
Result_Low <= OperandA;
Result_High <= (others => '0');
end if;
Ready <= '1';
Errorsig <= '0';
Which gives:
And to demonstrate both halves of Result are working OperandA's default value has been changed to "0110":
Also notice the loop starts at 1 instead of 0 to prevent you from having an extra shift and there's a check for non-zero loop_int to prevent the for loop from executing at least once.
And is it possible to make a synthesizable loop in these circumstances?
Yes.
The loop has to address all possible shifts (the range of loop_int) and test whether or not i falls under the shift threshold:
process (reset_n, clk, operation)
variable tempHigh : std_logic_vector(4 downto 0);
variable tempLow: std_logic_vector(3 downto 0); --added
subtype loop_range is integer range 0 to 15;
variable loop_int: integer range 0 to 15; --added
begin
if (reset_n = '0') then
Result_Low <= (others => '0');
Result_High <= (others => '0');
Errorsig <= '0';
elsif (clk'event and clk = '1') then
case operation is
when "001" =>
tempLow := OperandA; --added
tempHigh := (others => '0'); --added
loop_int := to_integer(unsigned(OperandB)); --added
for i in loop_range loop
if i < loop_int then
tempHigh (3 downto 0) := tempHigh (2 downto 0) & tempLow(3);
-- 'read' tempLow(3) before it's updated
tempLow := tempLow(2 downto 0) & '0';
end if;
end loop;
Result_Low <= tempLow;
Result_High <= tempHigh(3 downto 0);

VHDL: std_logic_vector Leftshift and right shift operator?

How would anyone peform a rightshift or left shift in VHDL on a STD_LOGIC_VECTor...
It will not work , why??`
AN <= "0001";
CounterProcess: process(CLK,Switch)
begin
if rising_edge(CLK) then
if prescaler < limit then
prescaler <= prescaler + 1;
else
prescaler <= (others => '0');
counter <= counter + 1;
AN sll 1;
end if;
end if;
end process;
An <= anode;
Segment <= counter;
end Behavioral;
I get the Error message: sll can not have such operands in this context.
But in which context can it then be used in, and how can perform my left shift?
these are my includes:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
isn't the one needed to perform my leftshift operations included??
Complete code
entity Main is
PORT(
CLK: in std_logic;
LED: out std_logic_vector (7 downto 0);
Switch: in std_logic_vector(7 downto 0);
Segment: out std_logic_vector (7 downto 0);
AN: out std_logic_vector (3 downto 0)
);
end Main;
architecture Behavioral of Main is
signal counter: std_logic_vector (7 downto 0);
signal prescaler: std_logic_vector(25 downto 0);
signal limit: std_logic_vector (25 downto 0);
signal anode: std_logic_vector (3 downto 0);
begin
AN <= "0001";
ScalerChoice: Process(switch)
begin
CASE Switch IS
when "00000001" => limit <= "10111110101111000010000000"; -- 1 Hz;
when "00000010" => limit <= "00111111100101000000101011"; -- 3 HZ
When "00000100" => limit <= "00010011000100101101000000"; -- 10 Hz
when "00001000" => limit <= "00000111101000010010000000"; -- 25 Hz
When "00010000" => limit <= "00000011110100001001000000"; -- 50 Hz;
when "00100000" => limit <= "00000001111010000100100000"; -- 100 hz
when others => limit <= "00000000000000000000000001"; -- 50 MHz
end case;
end process;
CounterProcess: process(CLK,Switch)
begin
if rising_edge(CLK) then
if prescaler < limit then
prescaler <= prescaler + 1;
else
prescaler <= (others => '0');
counter <= counter + 1;
AN sll AN 1;
end if;
end if;
end process;
Segment <= counter;
end Behavioral;
In addition to what trumpetlicks said, use these packages instead. Make sure to enable the VHDL-2008 switch. Also try this with your FPGA vendor first as these require VHDL-2008 updates:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
use ieee.numeric_std_unsigned.all;
The above packages are all IEEE standards. The packages STD_LOGIC_ARITH and std_logic_unsigned are not IEEE standards. Note also that numeric_std and STD_LOGIC_ARITH conflict with each other and make it difficult (way beyond basic usage) to use the types signed and unsigned. Note that std_logic_unsigned conflicts with numeric_std_unsigned. So if your synthesis tool supports numeric_std_unsigned, I recommend using it instead. Furthermore, if it does not you should submit a bug report against it.
EDIT 1:
Your Code Edited with reset logic, notice the addition of the RESET signal to the ports list, the deletion of the asynchronous line setting that value, addition of RESET to the sensitivity list of your CounterProcess process, the addition of the if(RESET = '1') line, and change of your if to an elsif, as well as the change of your shifting line:
I actually don't know what your An <= Anode line is doing, and believe this to be in error also.
entity Main is PORT(
RESET: in std_logic;
CLK: in std_logic;
LED: out std_logic_vector(7 downto 0);
Switch: in std_logic_vector(7 downto 0);
Segment: out std_logic_vector(7 downto 0);
AN: out std_logic_vector(3 downto 0)
);
end Main;
architecture Behavioral of Main is
signal counter: std_logic_vector(7 downto 0);
signal prescaler: std_logic_vector(25 downto 0);
signal limit: std_logic_vector(25 downto 0);
signal anode: std_logic_vector(3 downto 0);
begin
ScalerChoice: Process(switch)
begin
CASE Switch IS
when "00000001" => limit <= "10111110101111000010000000"; -- 1 Hz;
when "00000010" => limit <= "00111111100101000000101011"; -- 3 HZ
When "00000100" => limit <= "00010011000100101101000000"; -- 10 Hz
when "00001000" => limit <= "00000111101000010010000000"; -- 25 Hz
When "00010000" => limit <= "00000011110100001001000000"; -- 50 Hz;
when "00100000" => limit <= "00000001111010000100100000"; -- 100 hz
when others => limit <= "00000000000000000000000001"; -- 50 MHz
end case;
end process;
CounterProcess: process(RESET, CLK, Switch)
begin
if(RESET = '1') then
AN <= "0001";
elsif rising_edge(CLK) then
if prescaler < limit then
prescaler <= prescaler + 1;
else
prescaler <= (others => '0');
counter <= counter + 1;
AN <= std_logic_vector(unsigned(AN) sll 1);
end if;
end if;
end process;
An <= anode;
Segment <= counter;
end Behavioral;
you need to write the line that you currently have:
AN sll 1;
as
AN <= AN sll 1;
Remember that AN is essentially like a variable that needs to be "set". Like your line above
counter <= counter + 1;

Resources