Using VHDL Record in SystemVerilog Testbench in Modelsim - vhdl

I've done research on this, but the examples that I've found on other web pages have broken links. I'm looking for an example of how to import a custom VHDL record that is contained in a package into a SystemVerilog Testbench.
I'm using modelsim, so I've read that I need to use the -mixedsvvh switch. Do I need to use this switch for both vcom and vlog calls? Also, there's another switch [b | s | v] which when I use s it gives me an error:
** Error: (vcom-1276) Option '-mixedsvvh' was given with a bad argument.
When I use no arguments, I try to run vsim and I get the following message:
-- Importing package c:/Projects/source/work.test_pkg__mti__sv__equiv__implct__pack
** Error: Test_Top_TB.sv(4): 't_Test' is an unknown type.
VHDL Package:
library ieee;
use ieee.std_logic_1164.all;
package test_pkg is
type t_Test is record
DATA1 : std_logic_vector(15 downto 0);
DV1 : std_logic;
DATA2 : std_logic_vector(5 downto 0);
DV2 : std_logic;
end record t_Test;
end package test_pkg;
VHDL Entity/Architecture:
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.test_pkg.all;
entity Test_Top is
port (
i_Clk : in std_logic;
i_Data : in t_Test;
o_Data : out t_Test
);
end entity Test_Top;
architecture RTL of Test_Top is
begin
process (i_Clk) is
begin
if rising_edge(i_Clk) then
o_Data.DATA1 <= i_Data.DATA1;
o_Data.DV1 <= i_Data.DV1;
o_Data.DATA2 <= i_Data.DATA2;
o_Data.DV2 <= i_Data.DV2;
end if;
end process;
end architecture RTL;
SystemVerilog Testbench:
interface Test_IF();
import test_pkg::*;
t_Test Data;
endinterface // Test_IF
module Test_Top_TB ();
import test_pkg::*;
logic r_Clock;
Test_IF hook();
Test_IF hook2();
Test_Top UUT
(.i_Clk(r_Clock),
.i_Data(hook.Data),
.o_Data(hook2.Data)
);
endmodule

Try changing t_Test in your systemverilog testbench to lower case, ie. t_test.

Related

Internal signal type error in Test Bench VHDL

I want use internal signal of tag_mem entity in vivado in Test Bench.
Line with error in TB_tag_mem.vhd:
alias chTagMem is << signal .tag_mem.chTagMem : chTagMem_line >>;
Signal in tag_mem (tag_mem.vhd):
type chTagMem_line is array (natural range <>) of std_logic_vector (TAG_WIDTH downto 0);
signal chTagMem : chTagMem_line(CHAN_CNT - 1 downto 0);
When I run simulation, I see error in elaborate.log:
Starting static elaboration
ERROR: [VRFC 10-3763] type error near 'chtagmem' ; expected type 'chtagmem_line' [C:/Users/Mixen/CBDD/tag_mem/tag_mem.srcs/sim_1/new/TB_tag_mem.vhd:68]
ERROR: [XSIM 43-3321] Static elaboration of top level VHDL design unit tb_tag_mem in library work failed.
How fix this?
Reproduce
TB_tag_mem.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.NUMERIC_STD.all;
entity TB_tag_mem is
-- Port ( );
end TB_tag_mem;
architecture Test of TB_tag_mem is
component tag_mem is
Port (
clk : in STD_LOGIC
);
end component;
-- for check
type chTagMem_line is array (natural range <>) of std_logic_vector (5 downto 0);
alias chTagMem is << signal .tag_mem.chTagMem : chTagMem_line >>;
begin
sim: process begin
report "TEST: Init";
wait;
end process sim;
end Test;
tag_mem.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
entity tag_mem is
Generic (
WIDTH: integer := 5
);
Port (
clk : in STD_LOGIC
);
end tag_mem;
architecture Behavioral of tag_mem is
type chTagMem_line is array (natural range <>) of std_logic_vector (WIDTH downto 0);
signal chTagMem : chTagMem_line(4 downto 0);
begin
end Behavioral;

Creating VHDL Multiplexer with variable width and number of inputs

I am trying to create a bus/dataflow multiplexer with variable width and number of inputs, and use it as an IP Module in block design with Vivado. So far I have successfully managed to create a 2to1 mux with variable width:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity mux is
Generic ( NUM_BITS : integer);
Port (
SEL : in STD_LOGIC;
A : in STD_LOGIC_VECTOR(NUM_BITS-1 downto 0);
B : in STD_LOGIC_VECTOR(NUM_BITS-1 downto 0);
X : out STD_LOGIC_VECTOR(NUM_BITS-1 downto 0));
end mux;
architecture Behavioral of mux is
begin
X <= A when (SEL = '0') else B;
end Behavioral;
This works. I am able to drop this into the Block Design tool in Vivado, and I am able to customize the block and change the value of "NUM_BITS".
Customizable IP Mux in Block Design
I have almost successfully created a variable input mux with fixed width:
use IEEE.STD_LOGIC_1164.ALL;
package my_pkg is
-- Generic ( NUM_BITS : integer);
type inputs is array(natural range<>) of STD_LOGIC_VECTOR(8 downto 0);
end my_pkg;
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL;
use work.my_pkg.all;
entity mux is
Generic ( SEL_WIDTH : integer);
Port (
SEL : in STD_LOGIC_VECTOR(SEL_WIDTH-1 downto 0);
INPUT : in inputs(0 downto 2**SEL_WIDTH-1);
OUTPUT : out STD_LOGIC_VECTOR(8 downto 0));
end mux;
architecture Behavioral of mux is
begin
OUTPUT <= INPUT(to_integer(unsigned(SEL)));
end Behavioral;
However, I am not able to drop this into the block design tool because port type needs to be std_logic_vector in order to be recognized by the block design tool.
Block Design Error
I have seen some other posts addressing similar issues:
Using array of std_logic_vector as a port type, with both ranges using a generic - unable to use the provided examples in block design tool
Use generic parameter as port array length - used this to create the code in second portion
But neither of these helped me achieve what I would like.
I would like to combine these two into one multiplexer with BOTH variable inputs and width.
I am using Xilinx Vivado 2020.1

VHDL enumerator relational operators

I'm currently programming a system in VHDL, and I'm using an enumerator from another package called vnir, which is defined as such:
package vnir is
type row_type_t is (ROW_NONE, ROW_NIR, ROW_BLUE, ROW_RED);
end package vnir;
I've defined my architecture as such
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vnir;
entity imaging_buffer is
port(
clock : in std_logic;
reset_n : in std_logic;
vnir_row_ready : in vnir.row_type_t
);
end entity imaging_buffer;
architecture rtl of imaging_buffer is
signal vnir_row_ready_i : vnir.row_type_t;
begin
vnir_pipeline : process (reset_n, clock) is
begin
if (reset_n = '0') then
vnir_row_ready_i <= vnir.ROW_NONE;
elsif rising_edge(clock) then
if (vnir_row_ready /= vnir.ROW_NONE) then
--do stuff
end if;
end if;
end process vnir_pipeline;
end architecture;
The internal signal vnir_row_ready_i can be assigned to no problem, however the relational operator doesn't seem to work as ModelSim throws this error when I try to compile:
# ** Error: C:/Users/nashg/Documents/iris_project/ex2_iris/vhdl/subsystems/sdram/Imaging Buffer/test.vhd(23): (vcom-1581) No feasible entries for infix operator '/='.
# ** Error: C:/Users/nashg/Documents/iris_project/ex2_iris/vhdl/subsystems/sdram/Imaging Buffer/test.vhd(23): Type error resolving infix expression "/=" as type std.STANDARD.BOOLEAN.
# ** Error: C:/Users/nashg/Documents/iris_project/ex2_iris/vhdl/subsystems/sdram/Imaging Buffer/test.vhd(28): VHDL Compiler exiting
My coworker helped me figure out how to make it work! I think that the /= operator is created in the vnir scope, but not ported over to the entity I'm working on. By writing :use work.vnir."/="; at the beginning of the file it compiles, so the full entity looks like so:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vnir;
use work.vnir."/=";
entity imaging_buffer is
port(
clock : in std_logic;
reset_n : in std_logic;
vnir_row_ready : in vnir.row_type_t
);
end entity imaging_buffer;
architecture rtl of imaging_buffer is
signal vnir_row_ready_i : vnir.row_type_t;
begin
vnir_pipeline : process (reset_n, clock) is
begin
if (reset_n = '0') then
vnir_row_ready_i <= vnir.ROW_NONE;
elsif rising_edge(clock) then
if (vnir_row_ready /= vnir.ROW_NONE) then
--do stuff
end if;
end if;
end process vnir_pipeline;
end architecture;
Alternatively it did work by including use work.vnir.all; and taking out the vnir. before the types, but that wasn't possible with the project I'm working one

Passing generic to generic package to set port in VHDL

I’m looking at a generic package example in eda playground (https://www.edaplayground.com/x/6Mpm) and I’m trying to do something similar. I’m trying to get an integer from the top level through the generic field in the entity, and then pass the generic value on to the generic package to set the size of a part of a record. This record type is then to be used in the port of the entity where the generic came from.
Is this possible or do I have to hard code the number in the package declaration as in the example? Trying to declare the package in the entity gives me error proclaiming that the port can’t see the record type. Declaring the package normally as in the example mean that the package can’t see the generics in the entity.
I have been meaning to use a constant package to circumvent the “problem”, but I’m wondering if it is possible to do this using generics and a generic package without hard coding the numbers. This is so that I don’t have to remember to change the constant package when I’m reusing the module.
Package:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- pps_control_generic_pkg
package pps_control_generic_pkg is
generic(
-- Size of register. Max 32. Default 32
g_reg_size : integer := 32
);
type t_apb3_pif2core is record
rw_config : std_logic_vector(g_register_size-1 downto 0);
rw_config_we : std_logic;
end record;
type t_apb3_core2pif is record
rw_config : std_logic_vector(g_register_size-1 downto 0);
end record;
end package pps_control_generic_pkg;
Code
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Trying to declare this correctly
-----------------------------------------------------------
package pps_control_pkg is new work.pps_control_generic_pkg
generic map(
g_reg_size => g_reg_size
);
use work.pps_control_pkg.all;
-----------------------------------------------------------
entity pps_control_core is
generic(
-- Size of register. Default 32
g_register_size : integer := 32;
);
port(
csi_sys_clk : in std_logic;
rsi_sys_reset : in std_logic;
-- Interface to access register
p2c : in t_apb3_pif2core;
c2p : out t_apb3_core2pif;
pps_in : in std_logic;
pps_out : out std_logic;
pps_en_n : out std_logic
);
end entity;
architecture rtl of pps_control_core is
...
begin
...
end rtl;
An unconstrained composite element of a record type provided with a record constraint works. Credit goes to Tricky for mentioning the solution and user1155120 for typing it out.
library ieee;
use ieee.std_logic_1164.all;
package pps_control_generic_pkg is
type t_apb3_pif2core is record
rw_config : std_logic_vector;
rw_config_we : std_logic;
end record;
type t_apb3_core2pif is record
rw_config : std_logic_vector;
end record;
end package pps_control_generic_pkg;
library ieee;
use ieee.std_logic_1164.all;
use work.pps_control_pkg.all;
entity pps_control_core is
generic(
g_register_size : integer := 32;
);
port(
csi_sys_clk : in std_logic;
rsi_sys_reset : in std_logic;
p2c : in t_apb3_pif2core
(arw_config(g_register_size-1 downto 0));
c2p : out t_apb3_core2pif
(aro_config(g_register_size-1 downto 0));
pps_in : in std_logic; --! External pps signal
pps_out : out std_logic; --! Outputted pulse
pps_en_n : out std_logic --! Enable pps signal to instrument
);
end entity;

Error : Library "IEEE" does not contain primary unit "numeric_std_unsigned"

I'm using Quartus prime edition v15.1 for writing a register file and I need to use the numeric_std_unsigned package. On compiling, there's an error saying
Error (10481): VHDL Use Clause error : design library "IEEE" does not contain primary unit "NUMERIC_STD_unsigned". Verify that the primary unit exists in the library and has been successfully compiled.
How doesn't the IEEE library have the numeric_std_unsigned package? I've searched a lot and found that IEEE actually supports it. And if so, how can I firstly download the package and install it to the compiler or add it to my project?
EDIT
Here's my code:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.numeric_std_unsigned.all;
entity regfile is
port( clk: in STD_LOGIC;
regwrite: in STD_LOGIC;
rs, rt, rd: in STD_LOGIC_VECTOR(1 downto 0);
data_in: in STD_LOGIC_VECTOR(15 downto 0);
rd1, rd2: out STD_LOGIC_VECTOR(15 downto 0));
end;
architecture behave of regfile is
type registerFile is array (3 downto 0) of STD_LOGIC_VECTOR(15 downto 0);
signal registers: registerFile;
begin
process(clk) begin
if rising_edge(clk) then
if regwrite='1' then
registers(to_integer(unsigned(rd))) <= data_in;
end if;
end if;
end process;
process(all)
begin
if (to_integer(rs)=0)
then rd1 <= X"0000";
else rd1 <= registers(to_integer(unsigned(rs)));
end if;
if (to_integer(rt)=0)
then rd2 <= X"0000";
else rd2 <= registers(to_integer(unsigned(rt)));
end if;
end process;
end;
When I use IEEE.numeric_std_unsigned.all the compiler reports the error I posted above.
And when I use IEEE_numeric_std.all the compiler reports
can't determine type of object at to_integer
more than one Use Clause imports a declaration of simple name unsigned -- none of the declarations are directly visible
Once you edited your question to provide a Minimal, Complete, and Verifiable example the error is clearly visible.
Remove the use clause with std_logic_arith, it's incompatible with the unsigned declaration package numeric_std_unsigned uses (referenced from a use clause invoking ieee.numeric_std.all). In it's place use
use ieee.numeric_std.all;
Some of the to_integer function calls found in your regfile architecture have a signature of [STD_ULOGIC_VECTOR return NATURAL].
(STD_ULOGIC_VECTOR is the base type for resolved subtype STD_LOGIC_VECTOR in package std_logic_1164 in VHDL -2008).
Some to_integer conversion function calls (e.g. to_integer(rs)) require package numeric_std_unsigned.
Those depending on package numeric_std (e.g. registers(to_integer(unsigned(rs))) also depend on a visible declaration for type unsigned being the same as the type declaration of the same name being visible in package numeric_std (referenced in a use clause in package numeric_std_unsigned).
In VHDL each declaration is unique even if they have the same name. Which one you are referencing is governed by visibility rules.
Before changing the use clause only the unsigned type declared in the Synopsys package was visible in your entity and architecture pair.
After switching std_logic_arith to numeric_std your code analyzes with a -2008 compliant VHDL implementation:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
-- use IEEE.std_logic_arith.all;
use ieee.numeric_std.all;
use IEEE.numeric_std_unsigned.all;
entity regfile is
port (
clk: in STD_LOGIC;
regwrite: in STD_LOGIC;
rs, rt, rd: in STD_LOGIC_VECTOR(1 downto 0);
data_in: in STD_LOGIC_VECTOR(15 downto 0);
rd1, rd2: out STD_LOGIC_VECTOR(15 downto 0)
);
end entity;
architecture behave of regfile is
type registerFile is array (3 downto 0) of STD_LOGIC_VECTOR(15 downto 0);
signal registers: registerFile;
begin
process (clk)
begin
if rising_edge(clk) then
if regwrite = '1' then
registers(to_integer(unsigned(rd))) <= data_in;
end if;
end if;
end process;
process (all)
begin
if to_integer(rs) = 0 then
rd1 <= X"0000";
else
rd1 <= registers(to_integer(unsigned(rs)));
end if;
if to_integer(rt) = 0 then
rd2 <= X"0000";
else
rd2 <= registers(to_integer(unsigned(rt)));
end if;
end process;
end architecture;
Style changes not withstanding the only change is the use clause.
You could remove the dependency on package numeric_std by changing the to_integer function calls with the signature [UNSIGNED return NATURAL] to [STD_ULOGIC_VECTOR return NATURAL]:
library ieee;
use ieee.std_logic_1164.all;
-- use IEEE.std_logic_arith.all;
-- use ieee.numeric_std.all;
use IEEE.numeric_std_unsigned.all;
entity regfile is
port (
clk: in std_logic;
regwrite: in std_logic;
rs, rt, rd: in std_logic_vector(1 downto 0);
data_in: in std_logic_vector(15 downto 0);
rd1, rd2: out STD_LOGIC_VECTOR(15 downto 0)
);
end entity;
architecture behave of regfile is
type registerFile is array (3 downto 0) of STD_LOGIC_VECTOR(15 downto 0);
signal registers: registerFile;
begin
process (clk)
begin
if rising_edge(clk) then
if regwrite = '1' then
registers(to_integer(rd)) <= data_in;
end if;
end if;
end process;
process (all)
begin
if to_integer(rs) = 0 then
rd1 <= X"0000";
else
rd1 <= registers(to_integer(rs));
end if;
if to_integer(rt) = 0 then
rd2 <= X"0000";
else
rd2 <= registers(to_integer(rt));
end if;
end process;
end architecture;
Note we've gotten rid of the use clause with package numeric_std and dropped some type conversions for generating the indexes for indexed names selecting registers elements for writes to the register file as well as both read ports.
Both these modifications to your code example analyze, elaborate and simulate telling us the indexes work correctly. The second one using only package numeric_std_unsigned enhances readability.
And of course if your VHDL tool is actually missing package numeric_std_unsigned and it isn't cured by re-installation or updating the Quartus tools you could use a -1993 compliant design description:
library ieee;
use ieee.std_logic_1164.all;
-- use IEEE.std_logic_arith.all;
use ieee.numeric_std.all;
-- use IEEE.numeric_std_unsigned.all;
entity regfile is
port (
clk: in std_logic;
regwrite: in std_logic;
rs, rt, rd: in std_logic_vector(1 downto 0);
data_in: in std_logic_vector(15 downto 0);
rd1, rd2: out STD_LOGIC_VECTOR(15 downto 0)
);
end entity;
architecture behave of regfile is
type registerFile is array (3 downto 0) of STD_LOGIC_VECTOR(15 downto 0);
signal registers: registerFile;
begin
process (clk)
begin
if rising_edge(clk) then
if regwrite = '1' then
registers(to_integer(unsigned(rd))) <= data_in;
end if;
end if;
end process;
process (rs, rt) -- (all)
begin
if to_integer(unsigned(rs)) = 0 then
rd1 <= X"0000";
else
rd1 <= registers(to_integer(unsigned(rs)));
end if;
if to_integer(unsigned(rt)) = 0 then
rd2 <= X"0000";
else
rd2 <= registers(to_integer(unsigned(rt)));
end if;
end process;
end architecture;
Where the process sensitivity list is manually specified and all to_integer calls are from package numeric_std, requiring unsigned type conversions for std_logic_vector values.
(And this analyzes, elaborates and simulates).
I assume you mean the unsigned type of the numeric_std package in the ieee library.
library ieee;
use ieee.numeric_std.all;
...
signal foo : unsigned(7 downto 0);
or
library ieee;
use ieee.numric_std;
...
signal bar : numeric_std.unsigned(7 downto 0);
The installation folder of Quartus Prime 15.1 actually contains a file called numeric_std_unsigned_vhdl2008.vhd which defines the package numeric_std_unsigned and its body. But, apparently the synthesizer does not support it.
The Quartus Prime Standard Handbook v15.1.1, Volume 1 gives in Section 16 under "VHDL Synthesis Support" -> "VHDL-2008 Support" a link to this online help page. At the time of writing this answer, the list of supported VHDL'08 features does not reference Section 16.8.5 of the VHDL'08 Standard which defines the package numeric_std_unsigned. There is also no reference to Appendix A.2.4.
The following sub-section in the Quartus manual states further:
The Quartus Prime software includes the standard IEEE libraries and several vendor-specific VHDL libraries.
The IEEE library includes the standard VHDL packages std_logic_1164, numeric_std, numeric_bit, and math_real.
Given that, you must revert back to using the numeric_std package. But, this package defines the type unsigned which is also defined in std_logic_arith. You should not use the non-standard std_logic_arith package from Synopsys anymore.
Thus, you have to use the package numeric_std instead of both numeric_std_unsigned and std_logic_arith.. Then you have to convert all std_logic_vector to unsigned first, before passing them as an argument to the function to_integer, e.g.:
to_integer(unsigned(rs))
instead of
to_integer(rs)

Resources