How to reuse an entity to work with different components - vhdl

I'm reasonably new to vhdl and wondering what the best way is to manage the following situation / pattern:
Say I have an entity A whose architecture instantiates a component B. I would then like to reuse A but this time instantiate a component C in the place of B. C has a completely different functionality to B. B and C may have different sized ports, however the functionality of A is such that it can handle the different port sizes, using, say, generics and generate statements. Essentially A is like a container for either component B, C or maybe D, E, F etc. It maybe performs some logic/buffering on the inputs and outputs of B, C etc. in a way that is common for all these components.
I have read about configurations and my understanding is that I can instantiate a component in A (call it Z), and then link it's entity to different architectures using configurations. It seems not many people use this feature of vhdl.
Are configurations the right way to go for this situation?
Ideally, I would like all of the parameters in the design to depend ultimately on the architecture chosen for Z so that the architecture dictates the port sizes of the entity its linked to (Z), and in turn the port sizes of Z dictate the parameters of A and finally these parameters dictate the port sizes of A. Is this possible?
(I am using 'parameterisation' in the general sense to mean a way of configuring a design. Generics, packages, 'range attributes etc would all be examples of parameterisation)
A pseudocode example of what I mean is below. The values in capitals should depend on the architecture chosen for Z.
entity A is
port
(
clk : in std_logic;
reset : in std_logic;
inputs : in std_logic_vector(SOME_WIDTH_A_IN - 1 downto 0);
outputs : out std_logic_vector(SOME_WIDTH_A_OUT - 1 downto 0);
);
end A;
architecture A_arch of A is
component Z
port
(
clock : in std_logic;
inputs : std_logic_vector(SOME_WIDTH_Z_IN - 1 downto 0);
ouputs : std_logic_vector(SOME_WIDTH_Z_OUT - 1 downto 0)
);
end component;
begin
for i in 1 to SOME_VALUE generate
-- whatever logic/buffering we want to perform on the inputs
end generate;
for i in 1 to SOME_VALUE generate
-- whatever logic/buffering we want to perform on the outputs
end generate;
instance: Z
port map(
clock => clk,
inputs => --output of logic/buffering above
outputs => -- input of logic/buffering above
);
end A_arch;
I may be thinking about this the wrong way - Essentially I would like to avoid having to copy/paste the 'container' entity A to work with different components B, C etc. What is the best way to do this?

It seems that you want your components B,C,D, etc... to do exactly the same except for different port sizes. The best approach to do this is with GENERIC. Let's say your other entity (let's call it INNER_ENTITY) is configurable n-bit wide double flip flop (can be used to resolve metastability).
Here is the example code for OUTER_ENTITY and INNER_ENTITY:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity OUTER_ENTITY is
port (
CLK : in std_logic;
RST : in std_logic;
PORT_A : in std_logic_vector(6 downto 0);
PORT_B : in std_logic_vector(13 downto 0);
SUM_A_B : out std_logic_vector(13 downto 0)
);
end entity;
architecture RTL_OUTER_ENTITY of OUTER_ENTITY is
signal PORT_A_INNER : std_logic_vector(6 downto 0);
signal PORT_B_INNER : std_logic_vector(13 downto 0);
component INNER_ENTITY
generic (PORT_SIZE : integer);
port (
CLK : in std_logic;
RST : in std_logic;
PORT_IN : in std_logic_vector(PORT_SIZE - 1 downto 0);
PORT_OUT : out std_logic_vector(PORT_SIZE - 1 downto 0);
);
end component INNER_ENTITY;
begin
SUM_A_B <= PORT_A_INNER + PORT_B_INNER;
INNER_7_BIT : INNER_ENTITY
generic map (PORT_SIZE => 7)
port map (
CLK => CLK,
RST => RST,
PORT_IN => PORT_A,
PORT_OUT => PORT_A_INNER
);
INNER_14_BIT : INNER_ENTITY
generic map (PORT_SIZE => 14)
port map (
CLK => CLK,
RST => RST,
PORT_IN => PORT_B,
PORT_OUT => PORT_B_INNER
);
end RTL_OUTER_ENTITY;
entity INNER_ENTITY
generic (PORT_SIZE : integer);
port (
CLK : in std_logic;
RST : in std_logic;
PORT_IN : in std_logic_vector(PORT_SIZE - 1 downto 0);
PORT_OUT : out std_logic_vector(PORT_SIZE - 1 downto 0);
);
end entity;
architecture RTL_INNER_ENTITY of INNER_ENTITY is
signal PORT_X : std_logic_vector(PORT_SIZE - 1 downto 0);
begin
process(CLK, RST)
begin
if RST = '1' then
PORT_OUT <= (OTHERS => '0');
PORT_X <= (OTHERS => '0');
elsif rising_edge(CLK) then
PORT_OUT <= PORT_X;
PORT_X <= PORT_IN;
end if;
end process;
end RTL_INNER_ENTITY;
Please note that I did not compile this code so it might have some minor syntax errors but it should give you an overview to how GENERICs might be used to do what you want.

Related

lattice mackXO3 board output transient

I have a lattice MachXO3L starter kit and I'm having some trouble with inputs, I think. I'm tried reducing the code only to read 4 switches (MachXO3 Starter Kit User’s Guide page 26) and light 4 LEDs according to the state of the switch. The problem is the LEDs seem to be half off. I tried adding 'reveal' and it appears that I'm not getting any change from the switches when I expect change. I set the spreadsheet I set it the same as in the example. I'm still learning VHDL, this is the first time I'm actually trying to connect something to it and the example is on Verilog, so I can't really check what I'm doing wrong. I'm probably missing something basic, but I don't know what.
Top File:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity TOP is
GENERIC(
DATAWIDTH : natural := 4
);
PORT(
-- Input Buffer --
ADCInputBuffer : IN STD_LOGIC_VECTOR (DATAWIDTH-1 downto 0);
OUTPUT : OUT STD_LOGIC_VECTOR (DATAWIDTH-1 downto 0);
ADC_SRT : OUT STD_LOGIC
);
end TOP;
architecture ADReader of TOP is
SIGNAL INTERNAL_CLOCK : STD_LOGIC;
SIGNAL CLOCK : STD_LOGIC;
SIGNAL CLOCK_65 : STD_LOGIC;
-- BUFFER --
signal adcInPut : std_logic_vector(DATAWIDTH-1 downto 0);
---------------------------------------------------
-- Internal Clock. Mach0X3 --
---------------------------------------------------
COMPONENT OSCH is
GENERIC(NOM_FREQ: string := "133.00"); --133.00MHz, or can select other supported frequencies
PORT(
STDBY : IN STD_LOGIC; --'0' OSC output is active, '1' OSC output off
OSC : OUT STD_LOGIC; --the oscillator output
SEDSTDBY : OUT STD_LOGIC --required only for simulation when using standby
);
END COMPONENT;
---------------------------------------------------
-- Internal Clock multiplier. Mach0X3 --
---------------------------------------------------
COMPONENT MASTERCLOCK is
PORT(
CLKI : IN STD_LOGIC; --'0' OSC output is active, '1' OSC output off
CLKOP : OUT STD_LOGIC; --the oscillator output 260MHz
CLKOS : OUT STD_LOGIC --the oscillator output for adc 65Mhz
);
END COMPONENT;
---------------------------------------------------
-- Read data In --
---------------------------------------------------
COMPONENT InputBuffer is
GENERIC(n: natural :=DATAWIDTH );
PORT(
clk : in STD_LOGIC;
CLK65 : IN STD_LOGIC;
En : in STD_LOGIC;
STRT : OUT STD_LOGIC;
Ipin : in STD_LOGIC_VECTOR (n-1 downto 0);
Output : out STD_LOGIC_VECTOR (n-1 downto 0)
);
END COMPONENT;
begin
-- System Clock
OSC: OSCH
GENERIC MAP (NOM_FREQ => "133.0")
PORT MAP (STDBY => '0', OSC => INTERNAL_CLOCK, SEDSTDBY => OPEN);
-- System Clock Multiplied
OSCmain: MASTERCLOCK
PORT MAP (CLKI => INTERNAL_CLOCK, CLKOP => CLOCK, CLKOS => CLOCK_65);
-- Gets data from ONE ADC
ADCIn: InputBuffer
GENERIC MAP (n => DATAWIDTH)
PORT MAP( clk => CLOCK, CLK65 =>CLOCK_65, EN =>'0', Ipin => adcInPut, Output => OUTPUT, STRT => ADC_SRT );
adcInPut <= ADCInputBuffer;
end ADReader;
InputBuffer:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity InputBuffer is
generic(n: natural :=4 );
Port (
clk : in STD_LOGIC;
CLK65 : IN STD_LOGIC;
En : in STD_LOGIC;
STRT : OUT STD_LOGIC;
Ipin : in STD_LOGIC_VECTOR (n-1 downto 0);
Output : out STD_LOGIC_VECTOR (n-1 downto 0)
);
end InputBuffer;
architecture Behavioral of InputBuffer is
signal temp : STD_LOGIC_VECTOR(n-1 downto 0);
SIGNAL CLK2 : STD_LOGIC;
begin
-- invert the signal from the push button switch and route it to the LED
process(clk, En)
begin
if( En = '1') then
temp <= B"0000";
elsif rising_edge(clk) then
temp <= Ipin;
end if;
end process;
Output <= temp;
STRT <= CLK65;
end Behavioral;
this is the setting for MASTERCLOCK generated by lattice diamond:
this is how the pins are setup:
and here is the netlist generated by lattice-diamond:
here I'm just trying to have a static output:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity TOP is
GENERIC(
DATAWIDTH : natural := 4
);
PORT(
OUTPUT : OUT STD_LOGIC_VECTOR (DATAWIDTH-1 downto 0)
);
end TOP;
architecture ADReader of TOP is
begin
OUTPUT <= B"1010";
end ADReader;
Page 15 of the user guide (The link you provided) mentions different LED pins: H11,J13,J11,L12 which you have as ADC input. I think you might have swapped some pins around...

How to create port map that maps a single signal to 1 bit of a std_logic_vector?

I am designing some hardware using VHDL. My design requires the use of a 12-bit ripple counter that will utimately get connected as shown in the schematic screenshot below.
I found an existing entity & architecture for a ripple counter from online that I have decided should be suitable for my design. Here it is, in case it is useful in helping answer my question.
entity ripple_counter is
generic (
n : integer := 12
);
port (
clk : in std_logic;
clear : in std_logic;
dout : out std_logic_vector(n-1 downto 0)
);
end ripple_counter;
architecture behavioral of ripple_counter is
signal clk_i, q_i : std_logic_vector(n-1 downto 0);
begin
clk_i(0) <= clk;
clk_i(n-1 downto 1) <= q_i(n-2 downto 0);
gen_cnt: for i in 0 to n-1 generate
dff: process(clear, clk_i)
begin
if (clear = '1') then
q_i(i) <= '1';
elsif (clk_i(i)'event and clk_i(i) = '1') then
q_i(i) <= not q_i(i);
end if;
end process dff;
end generate;
dout <= not q_i;
end behavioral;
One will see that the ripple counter entity uses a n-bit (12-bit in this case) std_logic_vector for it's output. But, only two of the Q* outputs get connected. The ripple counter's component and port map declarations have been created as follows. Note that u22d_out, u21b_out and, u26_q12_out are all signals that have been defined in the same structural architecture as the ripple counter's component and port map. Also, q10 is an output of the system.
component ripple_counter is
generic (
n : integer := 12
);
port (
clk : in std_logic;
clear : in std_logic;
dout : out std_logic_vector(n-1 downto 0)
);
end component;
u26: ripple_counter port map (
clk => u22d_out,
clear => u21b_out,
dout(11) => u26_q12_out,
dout(9) => q10
);
When I attempt to run my design I get the following errors...
Error: [42972]: "c:/somefilepath/somefilename.vhd", line 493: Incomplete sub-element association for formal dout
Error: [42604]: "c:/somefilepath/somefilename.vhd", line 489: Port and Port Map does not match
Error: [40008]: HDL analysis failed.
Line 493 is the line that reads dout(9) => q10.
Line 489 is the line that reads u26: ripple_counter port map.
I am unsure if this is a syntax error or if it is a functional issue. How can I map specific bits of a vector to a single signal?
As suggested by Brian D in the comments...the port map association was incomplete. Here is an updated version of the port map.
u26: ripple_counter port map (
clk => u22d_out,
clear => u21b_out,
dout(11) => u26_q12_out,
dout(10) => open,
dout(9) => q10,
dout(8 downto 0) => open
);

how to update the output on the rising edge of the clock in structural VHDL code?

I have this very simple 16-bit and gate written in structural form in VHDL:
The files are uploaded here.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity and_16bit is
Port (
A : in std_logic_vector(15 downto 0);
B : in std_logic_vector(15 downto 0);
Clk : in STD_LOGIC;
--Rst : in STD_LOGIC;
C : out std_logic_vector(15 downto 0) );
end and_16bit;
architecture Behavioral of and_16bit is
component and_1bit is
Port (
A : in std_logic;
B : in std_logic;
C : out std_logic );
end component;
signal s : std_logic_vector(15 downto 0);
begin
ands: for i in 15 downto 0 generate
and_1bit_x: and_1bit port map (A => A(i), B => B(i), C => s(i));
end generate;
process(Clk)
begin
if rising_edge(Clk) then
C <= s;
end if;
end process;
end Behavioral;
In order to update the output in the rising edge of the clock, I have defined this "s" signal. I wonder if this is the correct way to update the output in structural VHDL codes? what should I do to scape the unknown output for the first output?
Any comments will be a great help.
It's better to put the sequential process into a submodule and instantiate it in the top-level (and_16bit). Then your top-level will be more structural.
You can have one instance for each bit as you did for and_1bit.
For example, this module is a 1-bit register.
entity dff_1bit is
Port (
D : in std_logic;
Clk : in std_logic;
Q : out std_logic );
end dff_1bit;
architecture Behavioral of dff_1bit is
begin
process(Clk)
begin
if rising_edge(Clk) then
Q <= D;
end if;
end process;
end Behavioral;
Then you can instantiate it in and_16bit, inside the same generate block.
dff_1bit_x: dff_1bit port map (D => s(i), Clk => Clk, Q => C(i));

VHDL output is undifined in simulation but compilation is passed fine

I am a fresh student and the assignment is to build 3 components with testbench and then to arrange them into one structure. All 3 components I have built work great but when I put them together one of the the outputs stays undefined. I tried to trace the signal called dat and it is fine, but probably I am not using correct syntax to assign the dat signal to data_out . The id_led_ind is the second output and it works fine but the data_out is undefined.
Here is the code (i think the problem is in lane 21 - "data_out <= dat")
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity peak_detect is
port(
input : in std_logic_vector (7 downto 0);
data_out : out std_logic_vector (7 downto 0);
reset : in std_logic;
clock : in std_logic;
enable : in std_logic;
id_led_ind : out std_logic);
end peak_detect;
architecture dataflow of peak_detect is
signal a_big_b : std_logic;
signal en : std_logic;
signal dat : std_logic_vector (7 downto 0);
begin
en <= (enable or a_big_b);
data_out <= dat;
end dataflow;
architecture structure of peak_detect is
signal a_big_b : std_logic;
signal en : std_logic;
signal dat : std_logic_vector (7 downto 0);
component comp_8bit is
port(
A : in std_logic_vector (7 downto 0);
B : in std_logic_vector (7 downto 0);
res : out std_logic);
end component;
component dff is
port (
data : in std_logic_vector (7 downto 0);
q : out std_logic_vector (7 downto 0);
clk : in std_logic;
reset : in std_logic;
en : in std_logic);
end component;
component id_sens is
port(
data_in : in std_logic_vector (7 downto 0);
led : out std_logic);
end component;
begin
reg : dff port map (data => input, q => dat, clk => clock, reset => reset, en => enable);
comp : comp_8bit port map (A => input, B => dat, res => a_big_b);
sens : id_sens port map (data_in => dat, led => id_led_ind);
end structure;
There appears to be confusion over having two architectures (dataflow and structure) for the entity peak_detect. The two architectures are mutually exclusive, and the last one analyzed is the default in absence of other configuration specifying one of the architectures directly.
For purposes of evaluating how the components are interconnected and their port mapped connections relate to the port declarations of peak_detect, the first architecture could be commented out (dataflow).
When you disregard the architecture dataflow we find there is no driver for data_out in architecture structure.
You're missing an assignment to data_out using dat as a source in architecture structure, as found in architecture dataflow. Copy or replicate the concurrent signal assignment statement data_out <= dat; into architecture structure.
You can't simply connect data_out to q in the port map of dff because the output of dff is also used as an input to id_sense.
dat is driven by q of dff. That is not how you connect components. port map should be used to connect ports of different components/entities, not signals of any entity to the port of another entity.

VHDL - Writing To Registers

I want to use four push buttons as inputs and three seven-segment LED displays as outputs. Two push buttons should step up and down through the sixteen RAM locations; the other two should increment and decrement the contents of the currently-displayed memory location. One seven segment display should show the current address (0–F), and two others should display the contents of that location in hexadecimal (00–FF). This is my code to attempt to do this (I haven't implemented the display yet):
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity raminfr is
port (
clk : in std_logic;
we : in std_logic;
do : out unsigned(7 downto 0)
);
end raminfr;
architecture rtl of raminfr is
type ram_type is array (0 to 15) of unsigned(7 downto 0);
signal RAM : ram_type;
signal read_a : unsigned(3 downto 0);
signal a : unsigned(3 downto 0);
signal di : unsigned(7 downto 0);
signal clock : std_logic;
signal key : std_logic_vector(3 downto 0);
begin
U1: entity work.lab1 port map (
clock =>clock,
key => key,
register_counter => a,
value_counter => di
);
process (clk)
begin
if rising_edge(clk) then
if we = '1' then
RAM(to_integer(a)) <= di;
end if;
read_a <= a;
end if;
end process;
do <= RAM(to_integer(read_a));
end rtl;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity lab1 is
port(
clock : in std_logic;
key : in std_logic_vector(3 downto 0);
value_counter : buffer unsigned(7 downto 0) ;
register_counter : buffer unsigned(3 downto 0)
);
end lab1;
architecture up_and_down of lab1 is
signal value_in_ram : unsigned(7 downto 0);
signal clk : std_logic;
signal we : std_logic;
begin
U1: entity work.raminfr port map (
do=>value_in_ram,
clk=>clk,
we=>we
);
process(clock, value_counter, register_counter)
begin
if rising_edge(clock) then
if (key(3)='0' and key(2)='0' and key(1)='1' and key(0)='0') then
value_counter <= value_counter + "1";
elsif (key(3)='0' and key(2)='0' and key(1)='0' and key(0)='1') then
value_counter <= value_counter - "1";
elsif (key(3)='1' and key(2)='0' and key(1)='0' and key(0)='0') then
register_counter<= register_counter + "1";
value_counter <= value_in_ram;
elsif (key(3)='0' and key(2)='1' and key(1)='0' and key(0)='0') then
register_counter<= register_counter - "1";
value_counter <= value_in_ram;
end if;
end if;
end process;
end architecture up_and_down;
When I try to compile this, I get the following errors repeating over and over:
Error (12051): Project too complex: hierarchy path is too long
Error (12052): Entity "lab1" is instantiated by entity "raminfr"
Error (12052): Entity "raminfr" is instantiated by entity "lab1"
This is obviously due to the fact that I have port mapped each entity in the other, but I don't know any other way to accomplish what I want to accomplish. Can somebody suggest alternatives?
This is a guess since it's not too clear what you want to do. It seems that the problem is one of design : you have a good idea what the end result should do, but it's not clear how to decompose that into components which interact in the simplest way to accomplish the goal.
I am basing this guess on the fact that the active code in "raminfr" stores and loads data independent of the other stuff that has crept in.
So I am going to suggest that "raminfr" be cleaned up as just a memory component WITHOUT any of the other stuff. It can then be embedded in the "lab1" component which handles keys, and stores and displays values from the correct registers. It can also be reused anywhere else you need a memory.
So let's look at raminfr.
entity raminfr is
port (
clk : in std_logic;
we : in std_logic;
do : out unsigned(7 downto 0)
);
end raminfr;
It has a clock, a write enable input, and a data output. But curiously, no address or data inputs! Now, memory is such a standard "design pattern" that deviation from it is probably ill advised, so let's add them...
entity raminfr is
port (
clk : in std_logic;
we : in std_logic;
addr : in unsigned(3 downto 0);
di : in unsigned(7 downto 0);
do : out unsigned(7 downto 0)
);
end raminfr;
Some variants of the memory pattern have other features; read enables, output enables, separate read and write clocks, etc but this simple one will do here.
You can also use generics to customise its size, modifying its data and address bus widths to match. This makes it much more useful and saves a proliferation of similar but different modules...
Let's clean up the architecture to match.
architecture rtl of raminfr is
type ram_type is array (0 to 15) of unsigned(7 downto 0);
signal RAM : ram_type;
signal read_a : unsigned(3 downto 0);
begin
process (clk)
...
end process;
do <= RAM(to_integer(read_a));
end rtl;
Now we can instantiate it in the "lab1" module, connecting up its new ports
U1: entity work.raminfr port map (
addr => register_counter, -- was "a", typo
di => value_counter,
do => value_in_ram,
clk => clk,
we => we
);
and making any supporting changes to the rest of lab1.
This is not the only reasonable decomposition : you could also make "lab1" a simple component without its own storage and bring out other necessary signals as ports. Then you would need a third "top level" entity whose architecture interconnected lab1 and raminfr.

Resources