How to create a subsignal / subvariable from an entity variable in VHDL? - 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.

Related

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: When can ports be used as signals?

Please help me understand when ports can be used as signals in VHDL.
I am asking this question because I am using ports to move data from one component to another in Xilinx ISim, but the data remains undefined at it's destination. My problems could be caused if I am inferring data transfer by wiring port to port as in my first and third examples below without an explicity assignment statement.
I believe this is valid use of a ports from the entity as a signals wired to the ports of an included component.
-- Example 1 - Use ports instead of signals
entity user is
port(
data_bus : inout std_logic_vector(15 downto 0);
address_bus: in std_logic_vector(12 downto 0)
);
end user;
architecture Behavioral of user is
-- Component Port Definitions
component memory
port(
mem_data_bus : inout std_logic_vector(15 downto 0);
mem_address_bus: in std_logic_vector(12 downto 0)
);
end component memory;
begin
-- some logic
-- Instantiate thing
a_memory : memory
port map(
mem_data_bus => data_bus,
mem_address_bus => address_bus
);
end architecture;
I am not sure this is valid. Are extra signals required to wire components together or can the entity ports be used? (I realise there could be a problem joining to inout ports together, but this question is about when ports can be used as signals).
-- Example 2 - connect ports to multiple components
entity user is
port(
data_bus : inout std_logic_vector(15 downto 0);
address_bus: in std_logic_vector(12 downto 0)
);
end entity user;
architecture Behavioral of user is
-- Component Port Definitions
component memory_a
port(
ma_data_bus : inout std_logic_vector(15 downto 0);
ma_address_bus: in std_logic_vector(12 downto 0)
);
end component memory_a;
component memory_b
port(
mb_data_bus : inout std_logic_vector(15 downto 0);
mb_address_bus: in std_logic_vector(12 downto 0)
);
end component memory_b;
begin
-- some logic
-- Instantiate memories
a_memory_a : memory_a
port map(
ma_data_bus => data_bus,
ma_address_bus => address_bus
);
a_memory_b : memory_b
port map(
mb_data_bus => data_bus,
mb_address_bus => address_bus
);
end architecture
If the entity port definition does not include the ports, signals are required and cannot be inferred from ports.
-- Example 3 - Use signals for inteconnection as no suitable ports available
entity user is
end user;
architecture Behavioral of user is
-- Component Port Definitions
component memory_a
port(
data_bus : inout std_logic_vector(15 downto 0);
address_bus: in std_logic_vector(12 downto 0)
);
end component memory_a;
component memory_b
port(
data_bus : inout std_logic_vector(15 downto 0);
address_bus: in std_logic_vector(12 downto 0)
);
end component memory_b;
signal data_bus_sig : std_logic_vector(15 downto 0);
signal address_bus_sig : std_logic_vector(12 downto 0);
begin
-- some logic
-- Instantiate memories
a_memory_a : memory_a
port map(
data_bus => data_bus_sig,
address_bus => address_bus_sig
);
a_memory_b : memory_b
port map(
data_bus => data_bus_sig,
address_bus => address_bus_sig
);
end architecture
This is wrong because neither signals nor entity ports are defined.
-- Example 4 - WRONG? - Try to infer ports
entity user is
end user;
architecture Behavioral of user is
-- Component Port Definitions
component memory_a
port(
data_bus : inout std_logic_vector(15 downto 0);
address_bus: in std_logic_vector(12 downto 0)
);
end component memory_a;
component memory_b
port(
data_bus : inout std_logic_vector(15 downto 0);
address_bus: out std_logic_vector(12 downto 0)
);
end component memory_b;
begin
-- some logic
-- Instantiate memories
a_memory_a : memory_a
port map(
data_bus => data_bus,
address_bus => address_bus
);
a_memory_b : memory_b
port map(
data_bus => data_bus,
address_bus => address_bus
);
end architecture
I will refer to your example codes as 1, 2 3 and 4.
1) Example 1 is correct. This is a viable way to connect port in a hierarchical way.
2) For sure you will have compilation/synthesis errors in particular for the output ports.
In fact you will have multiple drivers (each of the out ports of the instantiated components) impacting on the same signal/port of the top entity. It will be easy to see in a simulation too, since you will see 'X's appear at that port (indicating multiple driver to the same signal). Please note that multiple input ports can be connected to a single driver (e.g. same input port of top entity, same signal, etc...)
3) It is partially correct! You have the same issue as in example 2 with the multiple drivers acting on the same signal.
4) This is definitely wrong!. You have not defined neither ports nor signals to be bonded to
UPDATE after changes in entity:
1) It is still correct, entity port can be used as (implicit) signal in this way. You can imagine the top entity just as a container for the 2 sub-component where you have "soldered" the pin of the components to the pins of the top-entity/container (the soldering material provides the electrical continuity)
2) This might be OK when the inout ports are used as input, but when you try to use then as outputs, there might be issues. There is a heavy dependency on how they component are described. If the components use weak logic values ('L' & 'H') then if you drive strong values ('0' & '1') then it might behave OK. It would be better to use intermediate signal end probably some sort of mux/demux to select/steer the data to/from the proper internal component.
3) From the pure interconnect point of view, this is OK. However, from the functional point of view you have to be sure that there is always on component that is acting as a driver and the other as a receiver. Otherwise you will have either undefined value on the internal signal or 'X' due to multiple drivers. However, for the address signal, no one is driving it, so it will be always 'U' (undifined). You need something (a port in top entity, a process, etc...) this si driving some kind of value on it.
4) As before, this is incorrect. The port of the component are connected to nothing. Please note that VHDL (but the same is valid for verilog) is a description language; you try to describe an actual circuit (like one made of chips on a PCB). Like in a real circuit you need some sort of wire to connect one pin of a chip to another pin in another IC, then also in VHDL/verilog you need an equivalent "object" to enabel the interconnection.Thus, you need to define the object (in this case the signal) and then describe its behavior (in this case bind together 2 ports of 2 components).
I hope this time is a bit clearer

structural vhdl: creating a "main function"

I would like to create a structural VHDL file that implements a "main" function. The "top-level" file would be design and the program that runs the code would be prog. Assuming that fulladd_pack contains the fulladd component, how do I "link" the two VHDL files?
*I also don't get the arguments in main in order for this to work.
-- design.vhdl
library ieee;
use ieee.std_logic_1164.all;
use work.fulladd_pack.all;
ENTITY design IS
port(Cin : IN STD_LOGIC;
X,Y : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
S : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
Cout, Over : OUT STD_LOGIC);
END design;
ARCHITECTURE struct OF design IS
SIGNAL C,temp : STD_LOGIC_VECTOR(1 TO 15);
BEGIN
main: prog PORT MAP(Cin,X,Y,S,C,Cin);
END struct;
-- prog.vhdl
library ieee;
use ieee.std_logic_1164.all;
use work.fulladd_pack.all;
ENTITY prog IS
port(Cin : IN STD_LOGIC;
X,Y : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
S : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
Cout, Over : OUT STD_LOGIC);
END prog;
ARCHITECTURE struct OF prog IS
SIGNAL C,temp : STD_LOGIC_VECTOR(1 TO 15);
BEGIN
instance0: fulladd PORT MAP(Cin,X,Y,S,C,Cin);
output: fulladd PORT MAP(Cin,X,Y,S,C,Cin);
END struct;
You've missed the point. VHDL, as a "programming language", models concurrency, dataflow, and the passage of time. A model is composed of large numbers of elements ('processes') with data ('signals') flowing between them. A built-in kernel in your simulator handles the concurrency and time flow.
At the "top level", you write a testbench, which instantiates the model, and you apply stimulus (by driving signals which are inputs to the model). The stimulus forces data around the model. This carries on until you stop providing stimulus, at which point everthing else (should) stop.
So, no main. Write a testbench. 'Linking' is an internal concept in the simulator; forget it. Just simulate your source files together.

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;

How instanciate a generic entity with an embedded signal?

Iam using a package for state_values:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
package States is
type state_values is (ST0,ST1,ST2,ST3,ST4,ST5,ST6,ST7,ST8,ST9,ST10,ST11,ST12,ST13,ST14,ST15,ST16);
signal pres_state, next_state: state_values;
end States;
This is my component, with a generic entity:
component NextStateLogic
generic (
BLRH : STD_LOGIC_VECTOR (3 downto 0);
pres_state : state_values := ST0;
next_state : state_values := ST0);
end component;
In the code there are several embedded signals to use for comunication between components:
signal LRH_int : STD_LOGIC_VECTOR (3 downto 0);
signal next_state_int : state_values := ST0;
signal pres_state_int : state_values := ST0;
signal Clk1Hz_int : STD_LOGIC;
At the instanciate shows me the next error:
The actual value (Signal 'LRH_int') associated with a generic must be a globally static expression.
Investigating, I cannot connect signals to generics, I can use constanst but this ones are no useful to the propuse of the code.
Is there a way to instanciate the generic component with and another type of embedded signals?
Generics are used for everything that configures a component before the code is synthesized. E.g., you could have a generic that configures the width of your input and ouput signals.
Ports are used for everything that changes dynamically during runtime, e.g., data signals clocks etc.
Therefore it is not sensible to have an entity (or component) with only a generic map, because it would never do anything in hardware. Use a port definition.

Resources