As part of my description, within a wrapper component I generate N number of rom components. These roms are initialized from a text file containing the rom image. I pass the name of the file with which I wish to initialize each component as a generic parameter.
A hopefully sufficient excerpt of the description is as follows:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
package lnx1_types is
type lnx1_cs is array (integer range <>) of std_logic_vector(7 downto 0);
constant rom_count: integer := 9;
end package lnx1_types;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use STD.textio.all; -- For reading ucode roms from filesystem
use ieee.std_logic_textio.all;
use work.lnx1_types.all;
entity lnx1_uc_rom is
generic ( file_name : string := "" );
port ( uc_addr : in std_logic_vector(7 downto 0);
uc_q : out std_logic_vector(7 downto 0) );
end entity lnx1_uc_rom;
architecture dataflow of lnx1_uc_rom is
type lnx1_rom is array (0 to 2 ** 8 - 1) of std_logic_vector(7 downto 0);
impure function lnx1_load_rom(file_name : in string)
return lnx1_rom
is
file curr_rom_file: text;
variable curr_il : line;
variable curr_hx : std_logic_vector(7 downto 0);
variable rom : lnx1_rom;
variable good : boolean := TRUE;
begin
file_open (curr_rom_file, file_name, READ_MODE);
for i in rom'range(1) loop
if not endfile(curr_rom_file) then
readline(curr_rom_file, curr_il); -- Read line
read(curr_il, curr_hx, good); -- Read hex code
rom(i) := curr_hx;
end if;
end loop;
return rom;
end function lnx1_load_rom;
signal rom: lnx1_rom := lnx1_load_rom(file_name);
begin
uc_q <= rom(to_integer(unsigned(uc_addr)));
end architecture dataflow;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use work.lnx1_types.all;
entity lnx1_uc is
port ( uc_addr : in std_logic_vector(7 downto 0);
cs_q : out lnx1_cs(rom_count - 1 downto 0)
);
end entity lnx1_uc;
architecture dataflow of lnx1_uc is
component lnx1_uc_rom is
generic ( file_name : string := "" );
port ( uc_addr : in std_logic_vector(7 downto 0);
uc_q : out std_logic_vector(7 downto 0) );
end component lnx1_uc_rom;
type lnx1_rom_names is array (integer range <>) of string;
constant rom_path: lnx1_rom_names := (
0 => "r0.hex",
1 => "r1.hex",
2 => "r2.hex",
3 => "r3.hex",
4 => "r4.hex",
5 => "r5.hex",
6 => "r6.hex",
7 => "r7.hex",
8 => "r8.hex"
);
begin
ucgen: for i in rom_path'range(1) generate
rom0: lnx1_uc_rom
generic map ( rom_path(i) )
port map (
uc_addr => uc_addr,
uc_q => cs_q(i)
);
end generate ucgen;
end architecture dataflow;
entity intro_main is
end intro_main;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use work.lnx1_types.all;
architecture testbench_lnx1_uc of intro_main is
component lnx1_uc is
port ( uc_addr : in std_logic_vector(7 downto 0);
cs_q : out lnx1_cs(rom_count - 1 downto 0)
);
end component lnx1_uc;
signal uc_addr: std_logic_vector(7 downto 0);
signal cs_q: lnx1_cs(rom_count - 1 downto 0);
begin
uc0: lnx1_uc
port map (
uc_addr => uc_addr,
cs_q => cs_q
);
main: process
variable index: integer range 0 to 255 := 0;
begin
uc_addr <= std_logic_vector(to_unsigned(index, uc_addr'length(1)));
wait for 5 ns;
index := index + 1;
end process main;
end architecture testbench_lnx1_uc;
Although the description synthesis is without errors, attempt at simulation fails with the following message:
[VRFC 10-322] array element type cannot be unconstrained ["...":1080]
[XSIM 43-3321] Static elaboration of top level VHDL design unit intro_main in library work failed.
line 1080 is referring to
type lnx1_rom_names is array (integer range <>) of string;
I accordingly made the following change:
- type lnx1_rom_names is array (integer range <>) of string;
+ type lnx1_rom_names is array (integer range <>) of string(0 to 32);
Now, by definition, lnx_rom_names no longer has an unconstrained element type. However, not only does this change not remove the previous simulation error, it also introduces some very curious errors during synthesis:
[Synth 8-3302] unable to open file 'r0.hexr1.hexr2.hexr3.hexr4.hexr5.' in 'r' mode ["...":1026]
This implies that during the first iteration of the generate loop, rom_path(i) indeed points to the first item, however there is no delimitation of elements at all - simply, the entire linear segment of data beginning at that point is passed, in a string(0 to 32);.
As I write this, I realize that I have two questions, the latter borne out of trying to answer the first:
Why does the unconstrained element type error persist?
Why is the aforementioned array behavior present, namely the passing of a linear block of data of the array, rather than the actual array member?
I suspect the answer in the latter may be due to VHDL simply not initializing the spare slots left in the string(0 to 32), and thus the next element being allocated immediately afterwards; However, I would not believe VHDL to contain such broken functionality.
As user1155120 pointed out in the comments, the issue was due to incorrect length of the array element type, and had I actually tried to simulate first, I would've been greeted by some very helpful error messages:
Thus, changing the line
type lnx1_rom_names is array (integer range <>) of string(1 to 32);
to
type lnx1_rom_names is array (integer range <>) of string(1 to 6);
Removed all errors and simulation produced the expected result.
Also, strings must have a natural index range, so string(0 to n) is invalid, and should be string(1 to n); all following code has been amended accordingly.
Since I invested (or perhaps wasted) so much time into this problem, I thought it would be a waste not to at-least document my findings regarding string concatenation.
During synthesis Vivado decides to concatenate as many sequential array elements as would fit in the mis-sized array element when trying to pass an array element as an argument to, in this case, a generic map member:
...
type lnx1_rom_names is array (integer range <>) of string(1 to 32);
constant rom_path: lnx1_rom_names := (
0 => "r0.hex",
1 => "r1.hex",
2 => "r2.hex",
3 => "r3.hex",
4 => "r4.hex",
5 => "r5.hex",
6 => "r6.hex",
7 => "r7.hex",
8 => "r8.hex",
);
begin
ucgen: for i in rom_path'range generate
rom0: lnx1_romblk
generic map (
file_name => rom_path(i) -- << rom_path(i) evalues to "r0.hexr1.hexr2.hex ... "
) port map (
addr => uc_addr,
data => cs_q(i)
);
end generate ucgen;
...
I fiddled around with the description some more, and discovered that to replicate the concatenation behavior, the total number of characters present in the array of strings must be greater than the string length of a single array element, i.e.:
type lnx1_rom_names is array (integer range <>) of string(1 to 32);
constant rom_path: lnx1_rom_names := (
0 => "r0.hex",
1 => "r1.hex",
2 => "r2.hex",
3 => "r3.hex",
4 => "r4.hex",
5 => "r5.hex"
);
will fail with [Synth 8-3302] unable to open file 'r0.hexr1.hexr2.hexr3.hexr4.hexr5.' in 'r' mode ["D:/...":48]
however
constant rom_path: lnx1_rom_names := (
0 => "r0.hex",
1 => "r1.hex",
2 => "r2.hex",
3 => "r3.hex",
4 => "r4.hex"
);
will not cause that error to appear.
Comparison of log during synthesis/simulation (images):
With concatenation error
Without concatenation error
For reference, below is the description I used. It is slightly different from the OP as I've already had time to work on it and didn't use version control, but still demonstrates the problem.
The top level entity and architecture are at the bottom and should be renamed if appropriate.
Sample r0.hex file: Click here
The contents are not important, simply duplicate and rename to r1, r2... etc.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
package lnx1_types is
type lnx1_cs is array (integer range <>) of std_logic_vector(7 downto 0);
constant rom_count: integer := 2;
end package lnx1_types;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use STD.textio.all; -- For reading ucode roms from filesystem
use ieee.std_logic_textio.all;
use work.lnx1_types.all;
entity lnx1_romblk is
generic ( file_name : string := "";
awidth : integer := 8;
dwidth : integer := 8 );
port ( addr : in std_logic_vector(AWIDTH-1 downto 0);
data : out std_logic_vector(DWIDTH-1 downto 0) );
end entity lnx1_romblk;
architecture dataflow of lnx1_romblk is
type lnx1_rom is array (0 to 2 ** AWIDTH - 1) of std_logic_vector(DWIDTH-1 downto 0);
impure function lnx1_load_rom(file_name : in string)
return lnx1_rom
is
file curr_rom_file: text;
variable curr_il : line;
variable curr_hx : std_logic_vector(DWIDTH-1 downto 0);
variable rom : lnx1_rom;
variable good : boolean := TRUE;
begin
-- If no filename passed, initailize with 0
if file_name = "" then
for i in rom'range loop
rom(i) := (others => '0');
end loop;
return rom;
end if;
file_open (curr_rom_file, file_name, READ_MODE);
for i in rom'range loop
if not endfile(curr_rom_file) then
readline(curr_rom_file, curr_il); -- Read line
read(curr_il, curr_hx, good); -- Read binary value
rom(i) := curr_hx;
end if;
end loop;
return rom;
end function lnx1_load_rom;
signal rom: lnx1_rom := lnx1_load_rom(file_name);
begin
data <= rom(to_integer(unsigned(addr)));
end architecture dataflow;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use work.lnx1_types.all;
entity lnx1_uc is
port ( uc_addr : in std_logic_vector(7 downto 0);
cs_q : out lnx1_cs(rom_count - 1 downto 0)
);
end entity lnx1_uc;
architecture dataflow of lnx1_uc is
component lnx1_romblk is -- Needs testbench
generic ( file_name : string := "";
awidth : integer := 8;
dwidth : integer := 8 );
port ( addr : in std_logic_vector(awidth-1 downto 0);
data : out std_logic_vector(dwidth-1 downto 0) );
end component lnx1_romblk;
type lnx1_rom_names is array (integer range <>) of string(1 to 32);
constant rom_path: lnx1_rom_names := (
0 => "r0.hex",
1 => "r1.hex",
2 => "r2.hex",
3 => "r3.hex",
4 => "r4.hex"
-- 5 => "r5.hex" -- Uncomment this line to generate the error.
-- 6 => "r6.hex",
-- 7 => "r7.hex",
-- 8 => "r8.hex",
);
begin
ucgen: for i in rom_path'range generate
rom0: lnx1_romblk
generic map (
file_name => rom_path(i)
) port map (
addr => uc_addr,
data => cs_q(i)
);
end generate ucgen;
end architecture dataflow;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
use work.lnx1_types.all;
-- Here should go the top level entity declaration; I initially created
-- the project with the name "intro_main", so change to whatever is your case.
entity intro_main is
end entity intro_main;
architecture top_level of intro_main is
component lnx1_uc is
port ( uc_addr : in std_logic_vector(7 downto 0);
cs_q : out lnx1_cs(rom_count - 1 downto 0)
);
end component lnx1_uc;
signal uc_addr : std_logic_vector(7 downto 0);
signal cs_q : lnx1_cs(rom_count - 1 downto 0);
begin
uc0: lnx1_uc port map ( uc_addr, cs_q );
end architecture;
Related
I get trouble to get my code that is a correct VHDL (2008 release of language) code correctly analyzed by dc_shell.
The case structure below that is valid 2008 generates an error
gen1: case myInt generate
when 0 =>
...
when 1 =>
...
when 2 =>
...
end generate;
I did not find in any part of the Synopsys design compiler documentation where it is described and if it supported or not.
Error:
106: gencfg: case nb_elem generate
^^^^
[Failure] Syntax error : received 'case'
while expecting 'postponed'
or '(' or 'assert' or 'block' or 'component'
or 'configuration' or 'entity' or 'for' or 'if'
or 'process' or 'with' or IDENTIFIER or STRING LITERAL
*** Presto compilation was unsuccessful. ***
VHDL Snippet is simple as that:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity demo is
generic (
nbelem : positive range 1 to 6:= 6;
regwid : positive := 14
);
port (
data : in std_logic_vector(regwid-1 downto 0);
app_clk : in std_logic_vector(nbelem-1 downto 0);
clk_out : out std_logic
);
end demo;
architecture rtl of demo is
constant selwid : integer := integer(ceil(log2(real(nbelem))));
constant tied_up : std_logic := '1';
constant tied_low : std_logic := '0';
signal sel : std_logic_vector(selwid-1 downto 0);
begin -- architecture rtl
-- selectors mapping
-- NOTE: case style is vhdl08
gen0: block
begin
gencfg: case nbelem generate
when 5|6 =>
sel <= data(15 downto 13);
when 4|3 =>
sel <= data(12 downto 11);
when 2 =>
sel <= data(9 downto 9);
when 1 =>
sel <= (others => tied_low);
end generate gencfg;
end block gen0;
p0: process(all) is -- vhdl'08 syntax
variable sel_v : integer;
begin -- process p0_b
sel_v := to_integer(unsigned(sel));
if (sel_v < nbelem and sel_v > 0) then
clk_out <= app_clk(sel_v);
else
clk_out <= app_clk(0);
end if;
end process p0;
end architecture rtl;
In fact vhdl'08 is set by default so there is no specific option.
And there is already a case opened at Synopsys for that. But they do not provide any date for the support.
The work around is to get back to vhdl'87 syntax.
I am experimenting to synthesise some VHDL 2008 code in Vivado 2016.3 (the same situation is in 2016.4)
The idea is to be able to have unconstrained array in record and at the same time have unconstrained array of these records.
Relevant code:
(axi_pkg.vhd)
-- axi_pkg.vhd
-- Author: Bruno Kremel (CERN BE-RF-FB)
-- Date: 2016-01-23
-- Description: AXI4 Package
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.misc_pkg.all;
package axi_pkg is
type axis_in is record
tdata : std_logic_vector;
tvalid : std_logic;
tlast : std_logic;
tuser : std_logic_vector;
end record;
type axis_out is record
tready : std_logic;
end record;
type axis_in_vector is array (natural range <>) of axis_in;
type axis_out_vector is array (natural range <>) of axis_out;
end package;
(axis_reg.vhd)
-- axis_reg.vhd
-- Author: Bruno Kremel (CERN BE-RF-FB)
-- Date: 2016-11-22
-- Description: AXI4 Stream register
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.misc_pkg.all;
use work.axi_pkg.all;
entity axis_reg is
generic (
DATA_TYPE : string := "signed"
);
port (
aresetn : in std_logic;
aclk : in std_logic;
-- Input stream
in_axis_in : in axis_in;
in_axis_out : out axis_out;
-- Output stream
out_axis_in : out axis_in;
out_axis_out : in axis_out
);
end entity axis_reg;
architecture basic of axis_reg is
constant OUT_DATA_W :natural := out_axis_in.tdata'length;
constant IN_DATA_W :natural := in_axis_in.tdata'length;
signal in_tdata_conv : std_logic_vector(OUT_DATA_W-1 downto 0);
signal in_tuser_conv : std_logic_vector(OUT_DATA_W/8-1 downto 0);
signal in_tdata_shd : std_logic_vector(IN_DATA_W-1 downto 0);
signal in_tuser_shd : std_logic_vector(IN_DATA_W/8-1 downto 0);
begin
gen_signed: if DATA_TYPE = "signed" generate
in_tdata_conv <= std_logic_vector(resize(signed(in_tdata_shd), OUT_DATA_W));
in_tuser_conv <= std_logic_vector(resize(signed(in_tuser_shd), OUT_DATA_W/8));
end generate;
gen_unsigned: if DATA_TYPE = "unsigned" generate
in_tdata_conv <= std_logic_vector(resize(unsigned(in_tdata_shd), OUT_DATA_W));
in_tuser_conv <= std_logic_vector(resize(unsigned(in_tuser_shd), OUT_DATA_W/8));
end generate;
reg_ctrl_inst : entity work.axis_reg_ctrl
port map (
aresetn => aresetn,
aclk => aclk,
next_tdata => in_tdata_conv,
next_tuser => in_tuser_conv,
next_update => open,
in_tvalid => in_axis_in.tvalid,
in_tready => in_axis_out.tready,
in_tlast => in_axis_in.tlast,
out_tdata => out_axis_in.tdata,
out_tvalid => out_axis_in.tvalid,
out_tready => out_axis_out.tready,
out_tlast => out_axis_in.tlast,
out_tuser => out_axis_in.tuser
);
end architecture;
(test_entity.vhd)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.axi_pkg.all;
entity test_entity is
port (
aresetn : std_logic;
aclk : std_logic;
-- Input stream
in_axis_in : in axis_in_vector;
in_axis_out : out axis_out_vector;
-- Output stream
out_axis_in : out axis_in_vector;
out_axis_out : in axis_out_vector
);
end entity;
architecture test of test_entity is
begin
gen_reg : for i in 0 to in_axis_in'length-1 generate
begin
reg_i : entity work.axis_reg
generic map (
DATA_TYPE => "signed"
)
port map (aresetn => aresetn,
aclk => aclk,
in_axis_in => in_axis_in(i),
in_axis_out => in_axis_out(i),
out_axis_in => out_axis_in(i),
out_axis_out => out_axis_out(i));
end generate;
end architecture;
And finally test_entity_top.vhd which basically constraints the sizes for synthesis:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.axi_pkg.all;
entity test_entity_top is
end entity;
architecture test of test_entity_top is
constant SIZE : natural := 10;
constant DATA_W : natural := 16;
signal test_axis_in : axis_in(tdata(DATA_W-1 downto 0),
tuser(DATA_W/8-1 downto 0));
signal test_axis_out : axis_out;
signal in_axis_in : axis_in_vector(SIZE-1 downto 0)(tdata(DATA_W-1 downto 0),
tuser(DATA_W/8-1 downto 0));
signal in_axis_out : axis_out_vector(SIZE-1 downto 0);
signal out_axis_in : axis_in_vector(SIZE-1 downto 0)(tdata(DATA_W-1 downto 0),
tuser(DATA_W/8-1 downto 0));
signal out_axis_out : axis_out_vector(SIZE-1 downto 0);
signal aresetn : std_logic;
signal aclk : std_logic;
begin
tst : entity work.test_entity
port map (aresetn => aresetn,
aclk => aclk,
in_axis_in => in_axis_in,
in_axis_out => in_axis_out,
out_axis_in => out_axis_in,
out_axis_out => out_axis_out
);
end architecture;
This all nicely compiles in ModelSim. But Vivado is reluctant to sythesise it... With this error:
ERROR: [Synth 8-2190] illegal syntax for subtype indication [/home/bkremel/test_vivado/test_entity_top.vhd:15]
ERROR: [Synth 8-2235] indexed name prefix type axis_in_vector expects 1 dimensions [/home/bkremel/test_vivado/test_entity_top.vhd:15]
ERROR: [Synth 8-2190] illegal syntax for subtype indication [/home/bkremel/test_vivado/test_entity_top.vhd:18]
ERROR: [Synth 8-2235] indexed name prefix type axis_in_vector expects 1 dimensions [/home/bkremel/test_vivado/test_entity_top.vhd:18]
ERROR: [Synth 8-1031] in_axis_in is not declared [/home/bkremel/test_vivado/test_entity_top.vhd:28]
ERROR: [Synth 8-1031] out_axis_in is not declared [/home/bkremel/test_vivado/test_entity_top.vhd:30]
ERROR: [Synth 8-1568] actual of formal out port out_axis_in cannot be an expression [/home/bkremel/test_vivado/test_entity_top.vhd:30]
INFO: [Synth 8-2810] unit test ignored due to previous errors [/home/bkremel/test_vivado/test_entity_top.vhd:9]
Which indicate it does actually accept the syntax of record constraint:
signal test_axis_in : axis_in(tdata(DATA_W-1 downto 0),
tuser(DATA_W/8-1 downto 0));
While it does not like:
signal in_axis_in : axis_in_vector(SIZE-1 downto 0)(tdata(DATA_W-1 downto 0),
tuser(DATA_W/8-1 downto 0));
What would you suggest to use intead of unconstrained arrays and records?
The thing is that my design quite often changes the bit size of the stream.. So using generic packages would be quite inelegant (especially this register is nice example when in one file you have the bus with different sizes of data bus)
So far I have used one dimensional slv without records with manual indexing using functions/procedures, but that is quite messy to maintain...
I also add edaplayground example of relevant code https://www.edaplayground.com/x/eiC (to demonstrate that it works in simulator)...
Edit:
What is interesting is, that it actually synthesise if I do following:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.axi_pkg.all;
entity test_entity_top is
end entity;
architecture test of test_entity_top is
constant SIZE : natural := 4;
constant DATA_W : natural := 16;
subtype axis_in_constr is axis_in(tdata(DATA_W-1 downto 0),
tuser(DATA_W/8-1 downto 0));
subtype axis_out_constr is axis_out;
signal ch0, ch1, ch2, ch3 : axis_in_constr;
signal out0, out1, out2, out3 : axis_in_constr;
signal in_axis_in : axis_in_vector := (ch0, ch1, ch2, ch3);
signal out_axis_in : axis_in_vector := (out0, out1, out2, out3);
signal in_axis_out : axis_out_vector(SIZE-1 downto 0);
signal out_axis_out : axis_out_vector(SIZE-1 downto 0);
signal aresetn : std_logic;
signal aclk : std_logic;
begin
tst : entity work.test_entity
port map (aresetn => aresetn,
aclk => aclk,
in_axis_in => in_axis_in,
in_axis_out => in_axis_out,
out_axis_in => out_axis_in,
out_axis_out => out_axis_out
);
end architecture;
So that means that the array of records with unconstrained array is actually supported, but the direct constraint syntax is not.
Any ideas how to define it less elaboratively? Although it's not big deal to define top-level like this.. Still I would not mind to avoid it, it looks a bit hacky...
Thanks
Bruno
With Xilinx SR we had come to working example of desired behaviour, so I post it here as it works in Vivado as well as ModelSim/Edaplayground.
-- axi_pkg.vhd
-- Author: Bruno Kremel (CERN BE-RF-FB)
-- Date: 2016-01-23
-- Description: AXI4 Package
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package axi_pkg is
type axis_downstream is record
tdata : std_logic_vector;
tvalid : std_logic;
tlast : std_logic;
tuser : std_logic_vector;
end record;
type axis_upstream is record
tready : std_logic;
end record;
type axis_downstream_vector is array (natural range <>) of axis_downstream;
type axis_upstream_vector is array (natural range <>) of axis_upstream;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.axi_pkg.all;
entity test_entity_top is
end entity;
architecture test of test_entity_top is
constant SIZE : natural := 4;
constant DATA_W : natural := 16;
signal axis_downstream : axis_downstream_vector(SIZE-1 downto 0)(tdata(DATA_W-1 downto 0),
tuser(DATA_W/8-1 downto 0));
signal axis_upstream : axis_upstream_vector(SIZE-1 downto 0);
begin
assert axis_downstream'length = SIZE
report "SIZE is not correct"
severity failure;
assert axis_downstream(0).tdata'length = DATA_W
report "TDATA width is not correct"
severity failure;
assert axis_downstream(0).tuser'length = (DATA_W/8)
report "TUSER width is not correct"
severity failure;
end architecture;
The problem is that not all files were marked as 2008 in Vivado (my fault). But I post this minimal example so that it nicely fit the question.
Also Edaplayground link: https://www.edaplayground.com/x/3sKr
My vhdl code is as follows:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity pc is
port( inp : in std_logic_vector(31 downto 0);
oup : out std_logic_vector(31 downto 0));
end pc ;
architecture behv of pc is
signal programcounter : std_logic_vector(31 downto 0);
begin
process(inp)
begin
programcounter<=inp;
oup<=programcounter;
end process;
end behv;
library ieee;
use ieee.std_logic_1164.all;
entity ins_memory is
port( inp1 : in std_logic_vector(31 downto 0);
oup1 : out std_logic_vector (4 downto 0));
end ins_memory;
architecture behv1 of ins_memory is
type ROM_Array is array (0 to 14)
of std_logic_vector(4 downto 0);
constant Content: ROM_Array := (
0 => "00001",
-- Suppose ROM has
1 => "00010",
-- prestored value
2 => "00011",
-- like this table
3 => "00100",
--
4 => "00101",
--
5 => "00110",
--
6 => "00111",
--
7 => "01000",
--
8 => "01001",
--
9 => "01010",
--
10 => "01011",
--
11 => "01100",
--
12 => "01101",
--
13 => "01110",
--
14 => "01111",
--
OTHERS => "11111"
--
);
component pc is
port( inp : in std_logic_vector(31 downto 0);
oup : out std_logic_vector(31 downto 0));
end component ;
begin
D1: pc port map(inp1);
process(inp1)
begin
oup1<= Content (to_integer(inp1));
end process;
end behv1;
Here basically, I am trying to instantiate pc in entity ins_memory which is a ROM
The error I am getting is :
oup1<= Content (to_integer(inp1)); The symbol
'TO_INTEGER' does not have a visible declaration.
so, How can I solve this error?
There are two entity/architecture declarations, but only the first uses std_logic_arith/unsigned packages, thus these are not known to the second. So add it before ins_memory the entity:
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
Next, the to_integer is from the numeric_std package. The std_logic_vector to integer convert in the std_logic_unsigned package is named conv_integer, so update the oup1 assign to:
oup1<= Content (conv_integer(inp1));
Btw, you can get ridge of the component declaration if you instantiate the pc entity directly with:
D1 : entity work.pc port map(inp1);
Another btw., consider using the VHDL standard numeric_std package instead of the proprietary Synopsys std_logic_arith/unsigned packages.
I have a problem in my VHDL code. The function integer'image doesn't work properly. In the top of the project I call an entity (region_engine) with two "generate", this is the code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_misc.all;
use ieee.numeric_std.all;
use std.textio.all;
.....
ENGINE_ROW:
for i in 1 to sqrt_REGIONS_NUMBER generate
begin
ENGINES_COL:
for j in 1 to sqrt_REGIONS_NUMBER generate
begin
ENGINE_REGION_inst: entity work.region_engine
PORT MAP
( CLOCK => CLOCK,
RESET => RESET,
HITDATA => hitdata_region(4*(i-1)+j-1),
DV => data_valid((i-1)*sqrt_REGIONS_NUMBER + j-1),
BUSY_MAX => busy_red,
CLKEN => CLKEN_ACC,
number_i => (i-1),
number_j => (j-1),
ECS_BUS => ECS
);
end generate ENGINES_COL;
end generate ENGINE_ROW;
I pass the index i and j through number_i, number_j defined as integer. Here the code of
region_engine :
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_misc.all;
use ieee.numeric_std.all;
use std.textio.all;
entity region_engine is
port
(
CLOCK : in std_logic;
RESET : in std_logic;
HITDATA : in std_logic_vector(DATA_ENGINE-1 +4 downto 0);
DV : in std_logic;
BUSY_MAX : in std_logic;
CLKEN : in std_logic; ---forse non serve
number_i : in integer;
number_j : in integer;
ECS_BUS : in std_logic_vector(31 downto 0)
);
end entity region_engine;
....
ENGINEs_row :
for k in 0 to 3 generate
begin
ENGINEs_col:
for m in 0 to 3 generate
constant romfile_weight : string := "E:\Work\LHCb_Tesi\enginetoy_IT_test_allweight\lut_engine\peso_it\weight_engine_" & integer'image(16*number + k) & ".hex";
constant romfile_intersect : string := "E:\Work\LHCb_Tesi\enginetoy_IT_test_allweight\lut_engine\intersection_it_256\intersect_engine_" & integer'image(4*number_i + k) & "_" & integer'image((4*number_j + m)) &".hex";
begin
engine_inst : entity work.engine
GENERIC MAP
(
ENGINE_WEIGHT_FILE => romfile_weight,
ENGINE_INTERSECT_FILE => romfile_intersect
)
PORT MAP
(
CLOCK => CLOCK,
RESET => RESET,
HITDATA => c2(4*k + m)(DATA_ENGINE -1 downto 0),--HITDATA(i)(DATA_ENGINE -1 downto 0),--
ACC_RESET => acc_rst,--ed, --EE_delay,
ACC_EN => g,--e,--
ECS_DATA => ECS_BUS(DATA_ENGINE -1 downto 0),
INTERSECT_ADD => address(4*k +m),
WRITE_EN => w_en,--(i),
ACC_ENG => acc_16_eng(4*k + m)
);
end generate ENGINEs_col;
end generate ENGINEs_row;
I would like to pass to entity engine a file called intersect_engine_x_y.hex. Because of the previously range of indexes, the value
4*number_i + k and 4*number_j +m
should has a range from 0 to 15. But if I try to simulate the code with modelsim-altera these values don't match with the ones that I expect, in particulary the value 4*number_i - 4*number_j are put to zero.
Instead if I put in the string just number_i, number_j, as follow
constant romfile_intersect : string := "E:\Work\LHCb_Tesi\enginetoy_IT_test_allweight\lut_engine\intersection_it_256\intersect_engine_" & integer'image(number_i) & "_" & integer'image((number_j)) &".hex";
I read in modelsim this string:
"E:\Work\LHCb_Tesi\enginetoy_IT_test_allweight\lut_engine\intersection_it_256\intersect_engine_-2147483648_-2147483648.hex"
I don't know the reason for this behaviour, is it possible some trouble with the function integer'image?
Thanks for the help.
The index values i and j should be passed to region_engine through generics,
and not ports, so change the entity to:
entity region_engine is
generic (
NUMBER_I : integer;
NUMBER_J : integer);
port (
CLOCK : in std_logic;
RESET : in std_logic;
DV : in std_logic;
BUSY_MAX : in std_logic;
CLKEN : in std_logic; -- Force non serve
ECS_BUS : in std_logic_vector(31 downto 0));
end entity region_engine;
The generate should be changed accordingly to:
ENGINE_ROW :
for i in 1 to sqrt_REGIONS_NUMBER generate
begin
ENGINES_COL :
for j in 1 to sqrt_REGIONS_NUMBER generate
begin
ENGINE_REGION_inst : entity work.region_engine
generic map (
NUMBER_I => (i-1),
NUMBER_J => (j-1))
port map (
CLOCK => CLOCK,
RESET => RESET,
HITDATA => hitdata_region(4*(i-1)+j-1),
DV => data_valid((i-1)*sqrt_REGIONS_NUMBER + j-1),
BUSY_MAX => busy_red,
CLKEN => CLKEN_ACC,
ECS_BUS => ECS);
end generate ENGINES_COL;
end generate ENGINE_ROW;
The reason you see the value -2147483648 used for number_i in the other case,
is that the number_i is uninitialized at the time of use, as a result of the
VHDL execution model, thus having the lowest integer value (integer'low),
which is -2**31. So integer'image gives the expected result.
Btw. using both the standard IEEE package numeric_std and the non-standard
packages (actually Synopsys proprietary) std_logic_arith is very likely to
cause problems since e.g. unsigned is declared in both. So you may consider
removing all the std_logic_arith, and only using numeric_std.
I want to use a generic 'p' to define how many outputs a demux will have. Input and all outputs are 1 bit. The outputs, control, and input can be something simple like:
signal control : std_logic_vector(log 2 p downto 0); -- I can use a generic for the log2..
signal input : std_logic;
signal outputs : std_logic_vector(p-1 downto 0);
But what would the mux implementation code be? Is it even possible?
No generics required:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity demux is
port(
control : in unsigned;
input : in std_logic;
outputs : out std_logic_vector
);
end entity demux;
architecture rtl of demux is
-- Check size of input vectors
assert 2**control'length = outputs'length
report "outputs length must be 2**control length"
severity failure;
-- actually do the demuxing - this will cause feedback latches to be inferred
outputs(to_integer(unsigned(control)) <= input;
end architecture;
(Untested, just typed in off the top of my head...)
This will infer latches though - is that what you want?
You need to feed log_p as generic and compute p as you go.
library ieee;
use ieee.std_logic_1164.all;
entity demux is
generic (
log_p: integer);
port(
control : in std_logic_vector(log_p downto 0);
input :in std_logic;
outputs : out std_logic_vector(2**log_p - 1 downto 0)
);
end entity demux;
You need to pass both the number of outputs and the size of the control array as generics, unless you are always using powers of two.
Outside of your (de)mux module (ie: when you instantiate), you can use code to calculate the number of bits for the control bus. I have a function in a common package I use to initialize various configuration constants and generics that get passed to code similar to your (de)mux application:
-- Calculate the number of bits required to represent a given value
function NumBits(val : integer) return integer is
variable result : integer;
begin
if val=0 then
result := 0;
else
result := natural(ceil(log2(real(val))));
end if;
return result;
end;
...which allows you to do things like:
constant NumOut : integer := 17;
signal CtrlBus : std_logic_vector(NumBits(NumOut)-1 downto 0);
my_mux : demux
generic map (
NumOut => NumOut,
NumCtrl => NumBits(NumOut) )
port map (
control => CtrlBus,
...
...