vhdl equivalent for initial block in verilog - vhdl

I am trying to convert some Verilog code to VHDL. I have difficulties to translate initial block in Verilog to VHDL properly.
As far as I know, the initial block corresponds to the process statement without a sensitivity list but we have to add a "wait" statement before the "end process".I tried it but it did not work. I tried some other methods too (using exit clause, conditional clause ( wait until), "for- generate" without process, etc) but none was successful.
Here is the Verilog code I want to convert, and it works properly
module MyRAM #(parameter DATA_WIDTH=24, parameter ADDR_WIDTH=10)
(
input [(DATA_WIDTH-1):0] data,
input [(ADDR_WIDTH-1):0] read_addr, write_addr,
input we, clk,
output reg [(DATA_WIDTH-1):0] q
);
// Declare the RAM variable
reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];
initial
begin : INIT
integer i;
for(i = 1; i < ((2**ADDR_WIDTH)-1); i = i+1) begin
if (i == 132) ram[i] = 24'h550000;
else if (i == 133) ram[i] = 24'h005500;
else if (i == 134) ram[i] = 24'h000055;
else ram[i] = 24'h000000;
end
//*/
end
always # (negedge clk)
begin
// Write
if (we)
ram[write_addr] <= data;
q <= ram[read_addr];
end
endmodule
and this is the VHDL code I have written so far:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity MyRAM is
generic
(DATA_WIDTH: integer;
ADDR_WIDTH: integer);
port
(
data :in std_logic_vector ((DATA_WIDTH-1) downto 0);
read_addr :in std_logic_vector((ADDR_WIDTH-1) downto 0);
write_addr :in std_logic_vector(( DATA_WIDTH-1) downto 0);
we :in std_logic;
clk :in std_logic;
q :out std_logic_vector( 23 downto 0)
);
end MyRAM;
architecture behavioral of MyRAM is
constant case1:std_logic_vector(23 downto 0):=
(16=>'1',18=>'1',20=>'1',22=>'1',others=>'0');
constant case2:std_logic_vector(23 downto 0):=
(8=>'1',10=>'1',12=>'1',14=>'1',others=>'0');
constant case3:std_logic_vector(23 downto 0):=
(0=>'1',2=>'1',4=>'1',6=>'1',others=>'0');
type ram is array ( 0 to (2**ADDR_WIDTH-1)) of
std_logic_vector((DATA_WIDTH-1) downto 0);
shared variable origram:ram;
signal s_q: std_logic_vector(23 downto 0);
begin
process
begin
for ii in 1 to (2**ADDR_WIDTH-1) loop
if (ii = 132) then
origram(ii) := case1;
elsif (ii = 133) then
origram(ii) := case2;
elsif (ii = 134) then
origram(ii) := case3;
else
origram(ii) :=(others=>'0');
end if;
end loop;
wait;
end process;
process (clk)
begin
if falling_edge(clk) then
if (we ='1') then
origram(to_integer(unsigned(write_addr))) := data;
s_q <= origram(to_integer(unsigned(read_addr)));
end if;
end if;
end process;
q<=s_q;
end behavioral;
And this is the error message:
Error (10533): VHDL Wait Statement error at MyRAM.vhd(88): Wait Statement must contain condition clause with UNTIL keyword
I do not have much experience in these languages, so I would appreciate any kind of help

The answer is both yes and no. While yes, you can do pretty much what you can do in an initial block in a process, in your situation the answer is you are actually initialising a signal. For this you need to use a function, and set the initial value:
type ram is array ( 0 to (2**ADDR_WIDTH-1)) of std_logic_vector((DATA_WIDTH-1) downto 0);
function init_ram return ram is
variable r : ram;
begin
-- set the contents of the ram
end function init_ram;
shared variable origram:ram := init_ram;
Processes with wait at the end are only for simulation (which would mimic an initial block in verilog used for testbench stimulus)
Note: from VHDL 2002, using a shared variable like this is illegal as it should be a protected type (which is not synthesisable currently). The only reason you might want a shared variable (rather than a signal) to infer a ram is to get write-before-read behaviour in a RAM. It is very annoying most of the Xilinx Inference examples use a shared variable. Switching your code to VHDL2008 will throw the error mentioned above.

A process with a ram variable instead of a shared variable can provide an initial value as well:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity MyRAM is
generic (
DATA_WIDTH: integer;
ADDR_WIDTH: integer
);
port (
data: in std_logic_vector (DATA_WIDTH - 1 downto 0);
read_addr: in std_logic_vector (ADDR_WIDTH - 1 downto 0);
write_addr: in std_logic_vector (DATA_WIDTH - 1 downto 0);
we: in std_logic;
clk: in std_logic;
q: out std_logic_vector (DATA_WIDTH - 1 downto 0)
);
end entity MyRAM;
architecture behavioral of MyRAM is
constant case1: std_logic_vector(23 downto 0) :=
(16 => '1', 18 => '1', 20 => '1', 22 => '1', others => '0');
constant case2: std_logic_vector(23 downto 0) :=
( 8 => '1', 10 => '1', 12 => '1', 14 => '1', others => '0');
constant case3: std_logic_vector(23 downto 0) :=
( 0 => '1', 2 => '1', 4 => '1', 6 => '1', others => '0');
type ram is array ( 0 to 2 ** ADDR_WIDTH - 1) of
std_logic_vector(DATA_WIDTH - 1 downto 0);
begin
MY_RAM:
process (clk)
function init_origram return ram is
variable ramval: ram;
begin
for ii in ram'left to ram'right loop
if ii = 132 then -- note the presumption ram has at least 135 elements
ramval(ii) := case1;
elsif ii = 133 then
ramval(ii) := case2;
elsif ii = 134 then
ramval(ii) := case3;
else
ramval(ii) := (others => '0');
end if;
end loop;
return ramval;
end function;
variable origram: ram := init_origram;
begin
if falling_edge(clk) then
if we = '1' then -- write before read
origram(to_integer(unsigned(write_addr))) := data;
end if;
q <= origram(to_integer(unsigned(read_addr)));
end if;
end process;
end architecture behavioral;
This would be useful in IEEE Std 1076-2000, -2002 and -2008 compliant tool chains where shared variables are required to be protected types as well as earlier standard revisions.
IEEE Std 1076-2008
9.3.3 Aggregates
9.3.3.1 General:
element_association ::=
[ choices => ] expression
choices ::= choice { | choice }
You can also use the separator '|` to provide multiple values for choices:
constant case1: std_logic_vector(23 downto 0) :=
-- (16 => '1', 18 => '1', 20 => '1', 22 => '1', others => '0');
(16 | 18 | 20 | 22 => '1', others => '0');
or even provide a base specifier X bit string for a hexidecimal value here (15.8 Bit string literals).

Related

In VHDL, how to initialize MSB's of std_logic_vector to zeros and LSB's to a std_logic_vector literal such as "10101111001"

In VHDL, how to initialize MSB's of std_logic_vector to zeros and LSBS to a std_logic_vector literal such as "10101111001". I'm thinking its something like this... of course its a syntax error:
library ieee;
use ieee.std_logic_1164.all;
entity tb is
end entity;
architecture beh of tb is
begin
process
-- ERROR!!!
variable p : std_logic_vector(1000 downto 0) := (
(others => '0'),
"10101011111000011010101"
);
begin
end process;
end architecture;
The rules for aggregates are troublesome. Instead, I recommend avoid their issues here by using concatenation:
variable p : std_logic_vector(1000 downto 0) :=
(1000 downto 23 => '0') & "10101011111000011010101" ;
You can avoid counting (number of lower bits) by:
constant C : std_logic_vector := "10101011111000011010101" ;
variable p : std_logic_vector(1000 downto 0) :=
(1000 downto C'length => '0') & C ;
Using -2008:
See IEEE Std 1076-2008 9.3.3.3 Array aggregates
Prior to -2008 an association would be of the element type of the aggregate type, here std_logic. In -2008 the association can be of the type of the aggregate itself as well, here std_logic_vector. A choice must be static:
library ieee;
use ieee.std_logic_1164.all;
entity tb is
end entity;
architecture beh of tb is
begin
process
constant lb: std_logic_vector := "10101011111000011010101";
variable p : std_logic_vector(1000 downto 0) := (
lb'reverse_range => lb, others => '0'
);
begin
report lf & ht & "p(lb'reverse_range) = " &
to_string (p(lb'reverse_range));
wait;
end process;
end architecture;
And that produces:
%: ghdl -a --std=08 tb.vhdl
%: ghdl -e --std=08 tb
%: ghdl -r tb
tb.vhdl:16:9:#0ms:(report note):
p(lb'reverse_range) = 10101011111000011010101
%:
The string literal is assigned to a constant of the type of the aggregate (the type of p). Without specifying the range it will be an ascending natural range (the index type of std_logic_vector). If my eyes didn't go square counting elements in the string literal that would be 0 to 22, but getting it right doesn't matter. lb'reverse_range gets it right and it's a static range.
And if you're willing to determine the length of the string literal as well as it's location in p:
architecture beh of tb is
begin
process
variable p : std_logic_vector(1000 downto 0) := (
22 downto 0 => "10101011111000011010101", others => '0'
);
begin
report lf & ht & "p(22 downto 0) = " &
to_string (p(22 downto 0));
wait;
end process;
end architecture;
which gives us the now familiar result.
%: ghdl -a --std=08 tb.vhdl
%: ghdl -e --std=08 tb
%: ghdl -r tb_string
tb_string.vhdl:14:9:#0ms:(report note):
p(22 downto 0) = 10101011111000011010101
%:
Using any VHDL revision (the hard way):
library ieee;
use ieee.std_logic_1164.all;
entity tb is
end entity;
architecture beh of tb is
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
begin
process
variable p : std_logic_vector(1000 downto 0) := (
22|20|18|16 downto 12|7 downto 6|4|2|0 => '1', others => '0'
);
begin
report lf & ht & "p(22 downto 0) = " &
to_string (p(22 downto 0));
wait;
end process;
end architecture;
Which produces:
%: ghdl -a tb.vhdl
%: ghdl -e tb
%: ghdl -r tb
tb.vhdl:23:9:#0ms:(report note):
p(22 downto 0) = 10101011111000011010101
%:
the same transformation but is much more cumbersome, where you've separately provide a list of elements that will be set to '1' (and requires you to actual count the index values, and yes the indexes had to corrected to get them right while proof reading this answer). Note the choices are still static. Here the choices are all of the element type of p.
And of course you could assign the initial value to all '0's and as a first statement assign the range of p to the value of the string literal to avoid defining the choices.
Would be nice if I could initialize with a std_logic_vector string... but apparently this only works one bit at at time:
variable p :std_logic_vector(1000 downto 0) := (
32 downto 25 => '1',
24 downto 14 => '0',
13 downto 0 => '1',
others => '0'
);
variable p :std_logic_vector(1000 downto 0) := (
0 => '1',
1 => '0',
2 => '1',
3 => '1',
...
56 => '0',
others => '0'
);

Unexpected function output when function parameter is negated

I have a priority encoding function that returns a vector containing a 1 at the position where the first 1 is found in the input vector. The function works as expected, unless I try to negate the input vector. Here's an example that demonstrates the unexpected behavior:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
entity tb IS
end tb;
architecture run of tb is
constant N : natural := 5;
function get_first_one_in_vec (vec_in: std_logic_vector) return std_logic_vector is
variable ret: std_logic_vector(vec_in'high downto vec_in'low);
begin
ret := (others => '0');
for i in vec_in'low to vec_in'high loop
if vec_in(i)='1' then
ret(i) := '1';
exit;
end if;
end loop;
return ret;
end get_first_one_in_vec;
signal a : std_logic_vector(N-1 downto 0);
signal abar : std_logic_vector(N-1 downto 0);
signal first_a : std_logic_vector(N-1 downto 0);
signal first_nota : std_logic_vector(N-1 downto 0);
signal first_abar : std_logic_vector(N-1 downto 0);
begin
process
begin
a <= "10100";
wait for 10 ns;
a <= "01011";
wait for 10 ns;
wait;
end process;
abar <= not(a);
first_a <= get_first_one_in_vec(a);
first_nota <= get_first_one_in_vec(not(a));
first_abar <= get_first_one_in_vec(abar);
end run;
To my understanding, first_nota should be the same as first_abar. However, my simulator (ModelSim - Intel FPGA Starter Edition 10.5b, rev. 2016.10) thinks otherwise, as you can see here:
What am I missing here?
This works OK:
function get_first_one_in_vec (vec_in: std_logic_vector) return std_logic_vector is
variable ret: std_logic_vector(vec_in'length downto 1);
variable inp: std_logic_vector(vec_in'length downto 1) := vec_in;
begin
ret := (others => '0');
for i in inp'right to inp'left loop
if inp(i)='1' then
ret(i) := '1';
exit;
end if;
end loop;
return ret;
end get_first_one_in_vec;
https://www.edaplayground.com/x/3zP_
Why does yours not work? Well, when you call your function with the not operator* as part of the expression:
first_nota <= get_first_one_in_vec(not a);
the numbering of the input to the function is changed to 1 to by the not operator. Why? Here is the code for the not operator and you can see why:
-------------------------------------------------------------------
-- not
-------------------------------------------------------------------
FUNCTION "not" ( l : std_logic_vector ) RETURN std_logic_vector IS
-- pragma built_in SYN_NOT
-- pragma subpgm_id 204
--synopsys synthesis_off
ALIAS lv : std_logic_vector ( 1 TO l'LENGTH ) IS l;
VARIABLE result : std_logic_vector ( 1 TO l'LENGTH ) := (OTHERS => 'X');
--synopsys synthesis_on
BEGIN
--synopsys synthesis_off
FOR i IN result'RANGE LOOP
result(i) := not_table( lv(i) );
END LOOP;
RETURN result;
--synopsys synthesis_on
END;
---------------------------------------------------------------------
Anyway, this breaks your code (which starts scanning from the other end of the word).
One way of making function agnostic to the ordering of the numbering of its input is to normalise the inputs like this:
variable inp: std_logic_vector(vec_in'length downto 1) := vec_in;
Once you have done this, you're in control. So, instead of loops from 'high downto 'low, we can be more explicit and loop from 'right to 'left:
for i in inp'right to inp'left loop
not is an operator not a function. You don't need the brackets.

How can I replace the syntax "wait on a" in vhdl with equivalent syntax that won't initiate an infinite loop and is synthesizable on quartus?

I am working on a single cycle processor using vhdl. I was trying to solve bugs in the code but eventually we were trapped in two situations in the instruction memory and data memory(in imem & dmem):
there is a part in the code ( “wait on a”) that can’t be synthesized on quarus and also a problem with loops that make the code loop infinitely on quartus
we tried to replace loops and (wait on a) with (process(a)) but also we have a problem that there can’t be a process inside another process.
How can I solve these bugs?
library IEEE;
use IEEE.STD_LOGIC_1164.all; use STD.TEXTIO.all;
use IEEE.STD_LOGIC_arith.all;
entity imem is -- instruction memory
port(a: in STD_LOGIC_VECTOR(31 downto 0);
rd: out STD_LOGIC_VECTOR(31 downto 0));
end;
architecture behave of imem is -- instruction memory
type ramtype is array (63 downto 0) of STD_LOGIC_VECTOR(31 downto 0);
begin
process is
file mem_file: TEXT;
variable L: line;
variable ch: character;
variable i, index, result: integer;
--type ramtype is array (63 downto 0) of STD_LOGIC_VECTOR(31 downto 0);
variable mem: ramtype;
begin
-- initialize memory from file
for i in 0 to 63 loop -- set all contents low
mem(i) := (others => '0');
end loop;
index := 0;
FILE_OPEN(mem_file, "memfile.dat", READ_MODE);
while not endfile(mem_file) loop
readline(mem_file, L);
result := 0;
for i in 1 to 8 loop
read(L, ch);
if '0' <= ch and ch <= '9' then
result := character'pos(ch) - character'pos('0');
elsif 'a' <= ch and ch <= 'f' then
result := character'pos(ch) - character'pos('a') + 10;
elsif 'A' <= ch and ch <= 'F' then
result := character'pos(ch) - character'pos('A') + 10;
else report "Formaterror on line " & integer'image(index)
severity error;
end if;
mem(index)(35-i*4 downto 32-i*4) :=conv_std_logic_vector(result,4);
end loop;
index := index + 1;
end loop;
-- read memory
loop
rd <= mem(conv_integer(unsigned(a(7 downto 2))));
wait on a;
end loop;
end process;
end;
As reported by #Tricky, I overlooked that you're using quartus. As far was we both know, Quartus does not support reading files in initializer functions. The whole package textio for file I/O is not supported / ignored. You need to use the Altera Mega Function primitives from VHDL library altera_mf called altsyncram to represent a RAM or ROM. The PoC-Library has an implementation here.
altsyncram example for a single-port RAM:
library altera_mf;
use altera_mf.all;
mem : altsyncram
generic map (
address_aclr_a => "NONE",
indata_aclr_a => "NONE",
init_file => INIT_FILE,
intended_device_family => getAlteraDeviceName(DEVICE),
lpm_hint => "ENABLE_RUNTIME_MOD = NO",
lpm_type => "altsyncram",
numwords_a => DEPTH,
operation_mode => "SINGLE_PORT",
outdata_aclr_a => "NONE",
outdata_reg_a => "UNREGISTERED",
power_up_uninitialized => "FALSE",
widthad_a => A_BITS,
width_a => D_BITS,
width_byteena_a => 1,
wrcontrol_aclr_a => "NONE"
)
port map (
clocken0 => ce,
wren_a => we,
clock0 => clk,
address_a => a_sl,
data_a => d,
q_a => q
);
Source: https://github.com/VLSI-EDA/PoC/blob/master/src/mem/ocram/altera/ocram_sp_altera.vhdl?ts=2
Original answer:
You need to put your RAM initializing code into a function, which is returning the initial values for your RAM. In the function, you read the external file and convert each line to a memory value.
Here are some snippets to get you onto the right way:
architecture a of e is
type ram_type is array(natural range <>) of std_logic_vector(31 downto 0);
function initialize(
constant file_name : string;
constant size : positive
) return ram_type is
file mem_file : text;
variable result : ram_type(0 to size - 1);
begin
file_open(mem_file, file_name, READ_MODE);
while not endfile(mem_file) loop
-- ... read and convert content
end loop;
file_close(mem_file);
return result;
end function;
signal mem : ram_type := initialize("memfile.dat", 64);
begin
process(a)
begin
rd <= mem(to_integer(unsigned(a(7 downto 2))));
end process;
More hints:
Normally reading an instruction memory (BlockRAM) is a clocked process. Currently you are reading asynchronously on every address change.
A wait on statement is equivalent to a process with a sensitivity list.
You should close opened files.
Don't use package STD_LOGIC_arith, use numeric_std instead.

VHDL generic case statement

I am trying to instantiate a mux with a generic number of case statements. Currently my code looks like this:
In these examples data_array and selector are inputs, data is the output and the width of the mux is 4.
process(all)
begin
case? selector is
when "1---" => data <= data_array(3);
when "01--" => data <= data_array(2);
when "001-" => data <= data_array(1);
when "0001" => data <= data_array(0);
when others => data <= (others => '-');
end case?;
end process;
Is there a way to have a generic number of case statements? Or is there a similar feature that I could use?
I could solve this using code generation to generate the appropriate number of case statements but I was wondering if there is a VHDL(-2008) feature that I could use to solve this.
I have rewritten the mux to use a for loop but unfortunately my implementation tool is not handling this very well. The logic that is inferred is not optimal and quite bad in terms of timing.
In this example GENERIC_WIDTH is the width of the mux.
process(all)
begin
data_v := (others => '0');
for i in 0 to GENERIC_WIDTH-1 loop
if selector(i) then
data <= data_array(i);
end if;
end loop;
end process;
I am targeting a Xilinx device using Vivado 2017.3. Implementation results show that using the case statement yields more efficient logic (in terms of WNS and logic depth) than using the for loop.
It doesn't matter anymore: modern synthesis tools will correctly optimize all logic. I made a comparison between Vivado 2017.3 outputs. The base entity is
library ieee;
use ieee.std_logic_1164.all;
entity MyMux is
generic(
data_width : positive := 32;
data_depth : positive := 4
);
port(
clk : in std_logic;
data_in : in std_logic_vector(data_width-1 downto 0);
selector : in std_logic_vector(data_depth-1 downto 0);
data_out : out std_logic_vector(data_width-1 downto 0)
);
end entity;
Architecture 1:
architecture rtl of MyMux is
subtype data_type is std_logic_vector(data_width-1 downto 0);
type data_array_type is array (0 to data_depth-1) of data_type;
signal data_array : data_array_type := (others => (others => '0'));
begin
read_data : process(clk) begin
if rising_edge(clk) then
for i in data_depth-1 downto 1 loop
data_array(i) <= data_array(i-1);
end loop;
data_array(0) <= data_in;
end if;
end process;
select_output: process(all) begin
case? selector is
when "1---" => data_out <= data_array(3);
when "01--" => data_out <= data_array(2);
when "001-" => data_out <= data_array(1);
when "0001" => data_out <= data_array(0);
when others => data_out <= (others => '-');
end case?;
end process;
end architecture;
Architecture 2:
architecture rtl of MyMux is
subtype data_type is std_logic_vector(data_width-1 downto 0);
type data_array_type is array (0 to data_depth-1) of data_type;
signal data_array : data_array_type := (others => (others => '0'));
begin
read_data : process(clk) begin
if rising_edge(clk) then
for i in data_depth-1 downto 1 loop
data_array(i) <= data_array(i-1);
end loop;
data_array(0) <= data_in;
end if;
end process;
select_output: process(all) begin
data_out <= (others => '-');
for i in 0 to data_depth-1 loop
if selector(i) then
data_out <= data_array(i);
end if;
end loop;
end process;
end architecture;
Architecture 3:
architecture rtl of MyMux is
subtype data_type is std_logic_vector(data_width-1 downto 0);
type data_array_type is array (0 to data_depth-1) of data_type;
signal data_array : data_array_type := (others => (others => '0'));
function my_mux(
selector : std_logic_vector(data_depth-1 downto 0);
data_array : data_array_type) return data_type is
variable data : data_type;
begin
data := (others => '-');
for i in 0 to data_depth-1 loop
if selector(i)='1' then
data := data_array(i);
end if;
end loop;
return data;
end function;
begin
read_data : process(clk) begin
if rising_edge(clk) then
for i in data_depth-1 downto 1 loop
data_array(i) <= data_array(i-1);
end loop;
data_array(0) <= data_in;
end if;
end process;
data_out <= my_mux(selector, data_array);
end architecture;
Output:
Architecture 1: 32 LUT3, 32 LUT6, 128 FDRE
Architecture 2: 32 LUT3, 32 LUT5, 128 FDRE
Architecture 3: 32 LUT3, 32 LUT5, 128 FDRE
So they are all practically the same.
The problem is you case seems to be the non deterministic component: initial placement randomization. In my experience this initial placement is based on some randomizer seed extracted from the hash of the code. The same code will always give the same implementation. But make a very small change in the code, and timing and resource use might be completely different.
You should take note that the logic you describe in you code will implement as a chain of multiplexers. When the GENERIC_WIDTH increases, so will the delay. This is inevitable.

Why won't VHDL left shifter work?

I'm new to VHDL and I'm trying to write a left shifter that takes in a 32 bit value and a 5 bit value. The left shifter then tries to perform a logical left shift of the 32 bit value by moving out the number of bits specified by the 5 bit number on the left and bringing that many zeros on the right. I can't understand why the array notation isn't working. The result of 1 << 1 produces 20000000 instead of 00000002. Can someone explain where I'm going wrong? Here's the code:
SIGNAL lshiftOutput : STD_LOGIC_VECTOR( 31 downto 0 );
COMPONENT Lshift32
Port( a : in STD_LOGIC_VECTOR( 31 downto 0 );
b : in STD_LOGIC_VECTOR( 4 downto 0 );
lshiftOutput : out STD_LOGIC_VECTOR( 31 downto 0 ) );
END COMPONENT;
PROCESS( a, b, opcode, adderOutput, subtractOutput, xorOutput, lshiftOutput, rshiftOutput )
BEGIN
IF opcode = "0000" THEN
result <= x"00000000";
ELSIF opcode = "0001" THEN
result <= adderOutput;
ELSIF opcode = "0010" THEN
result <= subtractOutput;
ELSIF opcode = "0011" THEN
result <= NOT a;
ELSIF opcode = "0100" THEN
result <= a AND b;
ELSIF opcode = "0101" THEN
result <= a OR b;
ELSIF opcode = "0110" THEN
result <= xorOutput;
ELSIF opcode = "0111" THEN
result <= lshiftOutput;
ELSIF opcode = "1000" THEN
result <= rshiftOutput;
END IF;
END PROCESS;
LIBRARY ieee;
USE ieee.std_logic_unsigned.ALL;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY Lshift32 IS
Port( a : in STD_LOGIC_VECTOR ( 31 downto 0 );
b : in STD_LOGIC_VECTOR ( 4 downto 0 );
lshiftOutput : out STD_LOGIC_VECTOR ( 31 downto 0 ) );
END Lshift32;
ARCHITECTURE Lshift32Architecture of Lshift32 IS
BEGIN
PROCESS( a, b )
VARIABLE shiftAmount : INTEGER := 0;
BEGIN
shiftAmount := to_integer( b(4 downto 0) );
-- Shift left
lshiftOutput <= a( 31-shiftAmount downto 0 ) & ( shiftAmount-1 downto 0 => '0' );
END PROCESS;
END Lshift32Architecture;
The test bench for this is:
-- Shift Left -------------------------------------------------------
WAIT FOR 9 ns;
op <= "0111";
-- 1 << 1
input_a <= x"00000001";
input_b <= x"00000001";
WAIT FOR 1 ns;
IF (output /= x"00000002") THEN
ASSERT false REPORT "1 << 1 has incorrect result" severity error;
END IF;
Brian asked that you supply a Minimal, Complete, and Verifiable example, your edited code doesn't do that. And the reason for asking is that it's possible to create an mcve around the portions of your code you originally supplied that does give the right answer:
library ieee; -- added
use ieee.std_logic_1164.all; -- added
use ieee.numeric_std_unsigned.all; -- added
entity lshift32 is
port( a : in std_logic_vector ( 31 downto 0 );
b : in std_logic_vector ( 4 downto 0 );
lshiftoutput : out std_logic_vector ( 31 downto 0 ) );
end entity lshift32;
architecture lshift32architecture of lshift32 is
begin
process( a, b )
variable shiftamount : integer := 0;
begin
shiftamount := to_integer( b(4 downto 0) );
-- shift left
lshiftoutput <= a( 31-shiftamount downto 0 ) & ( shiftamount-1 downto 0 => '0' );
end process;
end architecture lshift32architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std_unsigned.all;
entity lshift32_tb is
end entity;
architecture foo of lshift32_tb is
signal a: std_logic_vector (31 downto 0) := (others => '0');
signal b: std_logic_vector (4 downto 0) := (others => '0');
signal lshiftoutput: std_logic_vector (31 downto 0);
begin
DUT:
entity work.lshift32
port map (
a => a,
b => b,
lshiftoutput => lshiftoutput
);
SIMULIS:
process
begin
wait for 10 ns;
a(0) <= '1'; -- 1
b(0) <= '1'; -- 1
wait for 10 ns;
wait;
end process;
ANALYSIS:
process (lshiftoutput)
variable shiftamount: integer;
begin
if now > 0 ns then
shiftamount := to_integer(b);
report "ShiftAmount = " & integer'image(shiftamount);
report "lshiftOutput = " & to_string(lshiftoutput);
end if;
end process;
end architecture;
And running the above testbench gives:
ghdl -a --std=08 lshift.vhdl
ghdl -e --std=08 lshift32_tb
ghdl -r lshift32_tb
lshift.vhdl:60:13:#10ns:(report note): ShiftAmount = 1
lshift.vhdl:61:13:#10ns:(report note): lshiftOutput = 00000000000000000000000000000010
And that your execution fails says there's either something wrong with your context clause (use clauses) or something wrong with your testbench.
Note that you are using both none standard package std_logic_unsigned and IEEE standard package numeric_std. You really shouldn't mix and match there can be unexpected consequences.
The package numeric_std_unsigned is available with a VHDL implementation compliant with the IEEE Std 1076-2008 standard. If using a previous version of the VHDL standard you can use package numeric_std and type convert b to unsigned as the expression passed to to_integer.
For the testbench supplied with this answer you'd also find that to_stringfor std_logic_vector is not supplied. Without seeing your entire testbench it could well be functional.
If you want to prove the answer supplied testbench works in a non -2008 revision environment:
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
The function can be supplied as an architecture declarative item.

Resources