How to read data from rom_type in VHDL? - vhdl

How can I read data from rom_type?
entity my_rom is
port(
addr: in std_logic_vector(3 downto 0);
data: out std_logic_vector(0 to 7)
);
end my_rom;
architecture a of my_rom is
type rom_type is array (0 to 7) of std_logic_vector(0 to 7);
constant R1_ROM: rom_type :=
(
-- data
);
begin
data <= R1_rom(conv_integer(addr));
end a;

You are using conv_integer, which is not part of raw VHDL... it's in a library. However, you don't want to use it - it's from a non-standard library.
Instead use ieee.numeric_std.all; is what you need before your entity. Then use to_integer(unsigned(addr)) to index the ROM. Better still, pass the address in as an unsigned vector, or even directly as an integer.
Try to get out of the habit of using std_logic_vector (which is just a bag of bits) to represent numbers, and use the well-defined numerical types.
Or use Verilog, which doesn't care :)
Myself, I prefer VHDL's strong-typing to keep me from daft foot-shooting...

Related

Can you make an array of types in VHDL?

Vivado Simulation cannot support unconstrained types which have a signed component to them.
i.e.
type A is array (natural range <>) of signed;
I have been using this in a design where type A is used in port declarations as I wish to have a parallel design which I control through a generic as well as the current stage word length e.g.
port (
inputdata : A(0 to number_of_parallel_generic-1)(stage_wordlength_generic-1 downto 0)
);
As I use the type A with many variations of the generics controling them e.g. 4 wide arrays with 16 wordlengths and other variations (often controled by a for generate loop)
for i in 0 to length_of_generate_statement-1 generate
signal example_signal : A(0 to 3)(stage_wordlength_generic + i - 1 downto 0);
begin
<functional code>
end generate;
This sort of code would allow me to gain bit growth from sequential sections of my archetecture - e.g. from an addition.
Now... getting to the question at hand.
One way I could get round this rather than initiating a signal with a forever changing generate statement could actually be in the creation of an "array of types".
Lend me your eyes this is written in a not quite vhdl way but hopefully you can see what Im trying to do.
type my_arr_of_types is array(0 to length_of_array-1) of type;
for i in 0 to length_of_array-1 generate
my_arr_of_types(i) <= <type declaration with some dependance on i>;
end generate;
Hopefully you can see what I am trying to do.
This would allow you to then call an element of the my_arr_of_types which itself is a type to then assign to a signal/variable.
i.e.
signal my_sig : my_arr_of_types(n);
*Where n is any valid index of the array.
Obviously this is not allowed in VHDL or any simulation tool. But can anyone see a potential solution to my problem?
Remember I use most of these types on port statements so any solution has to fit within the limitations of the port declarations.
Using two dimensional arrays as a solution:
Package
library ieee;
use ieee.numeric_std.all;
package utilities is
type T_SLM is array(natural range <>, natural range <>) of std_logic;
end package;
Entity
Now you can use this type in a port declaration together with two generic parameters. As sizes are now known in the architecture, you can create your used defined type of signed values and you can use either generate statements or a function to convert from the T_SLM to myArray type.
library ieee;
use ieee.numeric_std.all;
library myLib;
use myLib.utilities.all;
entity foo is
generic (
number_of_parallel : natural;
stage_wordlength : natural
);
port (
Input : T_SLM(0 to number_of_parallel - 1, stage_wordlength - 1 downto 0)
);
end entity;
architecture a of foo is
type myArray is array (natural range <>) of signed(Input'range(2));
function convert(matrix : T_SLM) return myArray is
variable result : myArray(matrix'range(1));
begin
for i in matrix'range(1) loop
for k in matrix'range(2) loop
result(i)(j) := matrix(i, j);
end loop;
end loop;
return result;
end function;
signal InputData1 : myArray(Input'range(1));
signal InputData2 : myArray(Input'range(1));
begin
genInput: for i in Input'range(1) generate
genInput: for j in Input'range(2) generate
InputData1(i)(j) <= Input(i, j);
end generate;
end generate;
InputData2 <= convert(Input);
end architecture;
Many helper functions like this have been implemented in the PoC Library in package PoC.vectors.

How to create a subsignal / subvariable from an entity variable in VHDL?

I am currently implementing a MIPS processor in VHDL. The system component (which glues together the ALU, register file, control unit, etc.) has the follow entity description:
entity system is
port (
reset : in std_logic;
sys_clk : in std_logic;
instruction : in std_logic_vector(15 downto 0);
sys_mem_dump : in std_logic := '0'
);
end system;
In the architecture section of this system, I am trying to create "subvariables" of the instruction variable, corresponding to the opcode and registers in use.
architecture Behavioral of system is
instruction_opcode : std_logic_vector(3 downto 0) := instruction(15 downto 12);
instruction_rd : std_logic_vector(3 downto 0) := instruction(11 downto 8); -- destination register
instruction_rs : std_logic_vector(3 downto 0) := instruction(7 downto 4); -- source register
instruction_rt : std_logic_vector(3 downto 0) := instruction(3 downto 0); -- target register
-- a bunch of signals
begin
-- a bunch of port maps
end Behavioral
I've tried signal, variable, shared_variable, and constant, but these result in the register file's addresses not being initialized when I port map one of these variables to it. I've also tried putting these variables in the system entity port, but that also doesn't work. I don't want to split the instruction variable in the system entity port into those four variables either.
agree with paebles: you seem to lack basic VHDL knowledge and should look for this in your book.
You should at least know this method:
architecture Behavioral of system is
signal instruction_opcode : std_logic_vector(3 downto 0);
begin
instruction_opcode <= instruction(15 downto 12);
end architecture;
But you can in fact use aliases:
architecture Behavioral of system is
alias instruction_opcode : std_logic_vector(3 downto 0) is instruction(15 downto 12);
begin
end architecture;
A common thread reflecting your comment
#Paebbels Is it simply not possible to do this in VHDL? I have looked at the synario manual and some other websites, and none of the data object types match this use case.
is that the references you have used are inadequate.
In addition to intermediary signals and object aliases described in JH Bonarius' answer there is a method using index ranges declared as subtypes:
library ieee;
use ieee.std_logic_1164.all;
entity field is
port (
fourbitfield: in std_logic_vector (3 downto 0)
);
end entity;
architecture foo of field is
begin
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity system is
port (
reset: in std_logic;
sys_clk: in std_logic;
instruction: in std_logic_vector(15 downto 0);
sys_mem_dump: in std_logic := '0'
);
end entity system;
architecture foo of system is
subtype opcode is integer range 15 downto 12;
subtype rd is integer range 11 downto 8;
subtype rs is integer range 7 downto 4;
subtype rt is integer range 3 downto 0;
begin
U1:
entity work.field port map (instruction(opcode));
U2:
entity work.field port map (instruction(rd));
U3:
entity work.field port map (instruction(rs));
U4:
entity work.field port map (instruction(rt));
end architecture;
This analyzes, elaborates and simulates (Not actually doing anything while proving a lack of bounds errors).
An entity is an independent design unit and naturally allows abstraction (port names are associated with actual signals in a port map during elaboration of a component instantiation). All other forms of names or using intermediary objects are forms of abstraction intended for readability and are dictated by style.
In the above instruction(opcode) and it's like are slice names (IEEE Std 1076-2008 8.5 Slice names) providing a discrete range in the form of a integer subtype. You could likewise use slice names with discrete ranges (e.g. 15 downto 12) as actuals in association lists directly without declaring subtypes:
U1:
entity work.field port map (fourbitfield => instruction(15 downto 12));
Using named association between formal port and actual signals shown here can preclude the need for further abstraction. Dictating abstraction impinges on style not required by the VHDL standard.
Your idea of sub signals or variables aligns with slice names in VHDL as easily as the use of intermediary signals. Aliases are simply other names for named entities (including object slices).
Which additional abstraction method if any you use might depend on the sophistication level of anticipated readers.
If someone were to search the vhdl tag on Stackoverflow thoroughly you'd find examples of all three of these methods. A wile reader could edit your question to align with VHDL syntax and submit it as a duplicate.

How can I index into a vhdl std_logic_vector?

I have the following declarations:
signal count:STD_LOGIC_VECTOR (3 downto 0);
signal txbuff:STD_LOGIC_VECTOR (7 downto 0);
dout is a std_logic output
I am using IEEE.NUMERIC_STD.ALL;
I want to use the vector count as an index into txbuff. Among the many things I've tried is the following:
count<=std_logic_vector(unsigned(count)-1);
dout<=txbuff(unsigned(count));
but I get the following error:
Line 99. Wrong index type for txbuff.
You need an integer as the index type. (Or with other arrays, you can use any discrete type, such as as enumeration).
Other answers have showed you how to get there using type conversion functions : I'll ask instead, why not make "count" an integer, like natural range 0 to 15 in the first place? It'll synthesise just the same, and make for cleaner simpler code.
We actually want to convert the number to an integer, not an unsigned or signed.
To do this, we can use to_integer as defined in numeric_std. Here's an example:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
entity conv_test is Port (
data_in : in std_logic_vector(7 downto 0);
data_sel : in std_logic_vector(2 downto 0);
data_out : out std_logic
);
end conv_test;
architecture Behavioral of conv_test is
begin
data_out <= data_out(to_integer(unsigned(data_sel)));
end Behavioral;
You need to convert to integer using the to_integer function. Check the parameterised MUX:
architecture RTL of MUX is
begin
-----------------------------------------------------------------------
-- MUX_RTL
-----------------------------------------------------------------------
-- Implements a multiplexer
-----------------------------------------------------------------------
MUX_RTL: process(DATA_IN, ADDR_IN)
variable ADDR_IN_INT : integer range 0 to 2**ADDR_WIDTH-1; -- holds the integer value of the address
begin
ADDR_IN_INT := to_integer(unsigned(ADDR_IN));
DATA_OUT <= DATA_IN(ADDR_IN_INT);
end process MUX_RTL;
end architecture RTL;

VHDL: How to declare a variable width generic [duplicate]

This question already has answers here:
How to use generic parameters that depend on other generic parameters for entities?
(2 answers)
Closed 6 years ago.
I want to create a VHDL entity with a one generic that changes the width of another generic.
entity lfsr_n is
generic (
WIDTH : integer := 32; -- counter width
POLYNOMIAL : std_logic_vector (WIDTH-1 downto 0) := "1000_0000_0000_0000_0000_0000_0110_0010"
);
Unfortunately, it seems I can't reference an earlier defined generic later in the generic list. Active-HDL gives the following errors:
Error: COMP96_0300: modules/m3_test_load/lfsr_n.vhd : (26, 45): Cannot reference "WIDTH" until the interface list is complete.
Error: COMP96_0077: modules/m3_test_load/lfsr_n.vhd : (26, 66): Undefined type of expression. Expected type 'STD_LOGIC_VECTOR'.
One workaround would be to make POLYNOMIAL a port. But it properly should be a generic since since the value is constant at elaboration time. I know that if I apply a constant to the port, it will synthesize the way I want and optimize the constants values into the module, but I'd like to find someway to make it a generic. Any suggestions how to do this?
If you want the POLYNOMIAL parameter to remain a generic you can specify it as an unconstrained array. You can also dispense with the WIDTH parameter by replacing all references by POLYNOMIAL'range, POLYNOMIAL'length-1 downto 0, or POLYNOMIAL'length as needed.
entity lfsr_n is
generic (
POLYNOMIAL : std_logic_vector := X"FFAA55BB"
);
port (
-- Vector with copied range (defaults to ascending from 0)
state : out std_logic_vector(POLYNOMIAL'range);
-- Vector with forced descending range
state2 : out std_logic_vector(POLYNOMIAL'length-1 downto 0)
);
end entity;
Unconstrained arrays are a powerful feature that help simplify code by implicitly controlling widths rather than needing a dedicated generic parameter. When used effectively they reduce the number of hard-coded array sizes in your source resulting in naturally resizable logic. You can freely change the POLYNOMIAL generic to another value with a different length and the rest of your logic should adapt without any additional effort.
There's an entity declarative part following any generic and any port declaration:
library ieee;
use ieee.std_logic_1164.all;
entity lfsr_n is
generic (
WIDTH: integer := 32 -- counter width
);
port (
foo: integer
);
constant POLYNOMIAL: std_logic_vector (WIDTH-1 downto 0)
:= B"1000_0000_0000_0000_0000_0000_0110_0010";
end entity;
architecture foo of lfsr_n is
begin
end architecture;
This analyzes and elaborates showing the generic is properly used.
You could also note that the literal you assign to the std_logic_vector doesn't adapt to changing WIDTH. I would have thought these '1's stand for tap off locations and you'd expect these could change from one LFSR length to another.
You could convey the 'WIDTH' in the polynomial constant:
library ieee;
use ieee.std_logic_1164.all;
entity lfsr_n is
generic (
-- WIDTH: integer := 32; -- counter width
POLYNOMIAL: std_logic_vector :=
B"1000_0000_0000_0000_0000_0000_0110_0010"
);
port (
foo: integer
);
-- constant POLYNOMIAL: std_logic_vector (WIDTH-1 downto 0)
-- := B"1000_0000_0000_0000_0000_0000_0110_0010";
end entity;
architecture foo of lfsr_n is
signal shft_register: std_logic_vector (0 to POLYNOMIAL'LENGTH-1);
begin
end architecture;
Or:
architecture foo of lfsr_n is
-- signal shft_register: std_logic_vector (0 to POLYNOMIAL'LENGTH-1);
-- or
signal shift_register: std_logic_vector(POLYNOMIAL'RANGE);

Use a generic to determine (de)mux size in VHDL?

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,
...
...

Resources