structural vhdl: creating a "main function" - vhdl

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.

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

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.

Quartus Prime VHDL component instantiation compile error

I am having an issue when trying to compile the following code:
----------------
----------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity adder_top is
Port ( a_in : in STD_LOGIC_VECTOR (3 downto 0);
b_in : in STD_LOGIC_VECTOR (3 downto 0);
clk : in STD_LOGIC;
clk_en : in STD_LOGIC;
carry_in : in STD_LOGIC;
carry_out : out STD_LOGIC;
c_out : out STD_LOGIC_VECTOR (3 downto 0));
end adder_top;
architecture Behavioral of adder_top is
COMPONENT c_addsub_0
PORT (
A : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
B : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
CLK : IN STD_LOGIC;
C_IN : IN STD_LOGIC;
CE : IN STD_LOGIC;
C_OUT : OUT STD_LOGIC;
S : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)
);
END COMPONENT c_addsub_0;
begin
inst_1 : COMPONENT c_addsub_0
port map
(
A => a_in,
B => b_in,
CLK => clk,
C_IN => carry_in,
CE => clk_en,
C_OUT => carry_out,
S => c_out
);
end Behavioral;
---------------------------
---------------------------
I receive the following error code when trying to compile:
Error (12006): Node instance "inst_1" instantiates undefined entity
"c_addsub_0". Ensure that required library paths are specified
correctly, define the specified entity, or change the instantiation.
If this entity represents Intel FPGA or third-party IP, generate the
synthesis files for the IP.
I am entirely unsure why I am receiving this error. Any help would be greatly appreciated.
The synthesis tool (Quartus) used to analyze and elaborate (a.k.a. compile) your design is complaining that it has not found an entity to bind the component c_addsub_0 with. You need to point the tool, in a tool defined way, to a library that contains the desired entity.
If you intended c_addsub_0 to be a block that you created then maybe it did not analyze into the work library as expected (unexpected syntax errors), or the library path to the work library is not established correctly (unlikely for a synthesis tool). If you wrote c_addsub_0 then it may be easier to use direct entity instantiation -- it saves the hassle of writing the component declaration and keep it in sync with the instance and the entity in another file. For example:
inst_1 : ENTITY work.c_addsub_0(<arch_name>)
port map
(
A => a_in,
B => b_in,
CLK => clk,
C_IN => carry_in,
CE => clk_en,
C_OUT => carry_out,
S => c_out
);
If the c_addsub_0 block is meant to be unbound through elaboration, as a black box until place-and-route, then you need to tell Quartus by decorating the instance with the appropriate syn_black_box attribute.
architecture Behavioral of adder_top is
COMPONENT c_addsub_0
PORT (
A : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
B : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
CLK : IN STD_LOGIC;
C_IN : IN STD_LOGIC;
CE : IN STD_LOGIC;
C_OUT : OUT STD_LOGIC;
S : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)
);
END COMPONENT c_addsub_0;
attribute syn_black_box : boolean;
attribute syn_black_box of c_addsub_0: component is true;
begin
...
It then knows to synthesize a black box representation in the post synthesis netlist for that component. You then need to insure the Quartus back end can find a netlist for the given component in a netlist library path somewhere.
VHDL provides for a variety of ways to create hierarchy with incredibly precise control over binding, signal connections, naming/renaming of blocks and other features which are rarely used in ordinary designs. Unless your synthesis tool only supports one style of instantiation using component declarations or you need a black box, then I would stick with direct entity instantiation.
P.S.: Your use clause use ieee.std_logic_unsigned; should be use synopsys.std_logic_unsigned; -- The IEEE standards body never approved the std_logic_unsigned package. Though, if analyzing with the 1076-2008 standard, it is allowed now to analyze anything you want into the IEEE library. That permits defacto vendor, but not formally standardized, packages to be used without modification of your source code. Only the STD library is now actually a standard. Just be aware that Mentor Graphics and Synopsys versions of this package are different so your code may not achieve the portability that use of the standards based numeric_std package will achieve.

VHDL-2008 continuously force an external name

I'd like to be able to continuously force a signal down in my testbench hierarchy. Here is a simple example illustrating how I've been doing this in my test benches.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity double_inverter is
port(
a : in std_logic;
z : out std_logic
);
end double_inverter;
architecture x of double_inverter is
signal b : std_logic;
begin
b <= not a;
z <= not b;
end architecture x;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity inverter_tb is
end inverter_tb;
architecture y of inverter_tb is
signal z : std_logic;
signal clk : std_logic := '0';
begin
clk <= not clk after 5 ns;
dut : entity work.double_inverter
port map(
a => '0',
z => z
);
continuous_stim : process(clk)
begin
<< signal dut.b : std_logic >> <= force clk;
end process;
end architecture y;
This works in Modelsim 10.4b i.e. signal b in the double_inverter instance will be set by clk and not signal a, but is there a better way to control external name signals?
Thanks for your help.
In some situations you can use is an alias to the external name:
alias dut_b is <<signal dut.b : std_logic >> ;
Since we think of signals being declared in an architecture, our instinct is to put the alias in the architecture. However, in this situation, it is not allowed because the DUT has not been elaborated yet.
You may be allowed to put it in the process - I would have to do some research to check if the language allows this. My concern is that processes do not allow signal declarations, so I am not confident that it will allow aliases to signals in a process - no harm in trying it and letting us know if it worked.
Generally when I am using something like this, I put it in a architecture declarative region of a component that creates the test cases and is instanced by the testbench. To avoid issues with elaboration order, I make sure to instance my DUT first in the testbench and typically the component that generates the test cases last (with the transaction based models in the middle) - VHDL elaborates designs in the order they are instantiated.

" top level design entity is undefined" ... what does it mean?

this is the code and saved it as IR.vhd, while the name of the project is saved as "8051"
when i try to compile a vhdl program in altera it is showing "Error (12007): Top-level design entity "8051" is undefined
" ... what does it mean ?
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity IR is
port(clk,rst,pb1:in std_logic;
irreg:in std_logic_vector(15 downto 0);
ops:out std_logic_vector(2 downto 0);
modes:out std_logic;
loc1:out std_logic_vector(3 downto 0);
loc2ordata:out std_logic_vector(7 downto 0));
end IR;
architecture rtl of IR is
signal ireg: std_logic_vector(15 downto 0);
begin
process (pb1)
begin
if(pb1='0')then --I am going to set up to feed in one instruction at a time
ireg<=irreg; --the instruction is executed when pb1 is pressed
end if;
end process;
ops<=ireg(15 downto 13);
modes<=ireg(12);
loc1<=ireg(11 downto 8);
loc2ordata<=ireg(7 downto 0);
end rtl;
Something I have noticed is that the top level entity name needs to be the same as the file name and module name. So if you called the top level IR, the file probably needs to be IR.v. Now I never capitalize my file names so I don't actually know if capitalization matching is important.

Resources