Partially constrained vector and arrays in VHDL - vhdl

Is there some way to define an alias, function or subtype in a package to define syntactic sugar around constrained vector declaration?
I often declare port and signals in VHDL as std_logic_vector(N - 1 downto 0). I would like some syntactic sugar around this. something similar to this:
context work.common;
entity X is
generic(
byteSize : integer := 8
);
port(
DataIn : in logic_bus(byteSize);
DataOut : out logic_bus(byteSize)
);
end entity;
architecture X_arch of X is
signal DataSignal : logic_bus(byteSize);
begin
DataOut <= DataSignal;
DataSignal <= DataIn;
end architecture;
I would like to have this syntactic sugar defined all over my project, i.e., avoid defining a subtype in the architecture if possible. I'm very confused with the usage of open, natural range <>, the difference between type and subtype, and what kind of things functions can return.
regarding constraints inference
I would like to stress that I'm looking for a way to abstract away the definition of similar vector constraints.
The proposal to leave my vector completely unconstrained, while a clever workaround, has strings attached to it that I would like to avoid :
It is not compatible with type casting see here.
It doesn't communicate the relationship between ports (for instance it doesn't communicate that DataIn and DataOut are supposed to be the same size)
It risks to allow badly sized bus designs to pass synthesis by mistake (accidental meaning)
For this reasons, my workplace coding style has banned unconstrained types in ports in favor of generics. Thank you for your understanding.

I assume that you want logic_bus(x) to be some kind function/alias/subtype to abstract away std_logic_vector(N-1 downto 0), working around constrained vector declaration.
VHDL have a quite small user base in terms of numbers. So much of what of the language you can use is highly tool dependent. Make sure you have read up on the supported features of vhdl-2008 for your development environment. As a main user of Xilinx UG901 is my go to for Vivado. Even though a feature is supported you might sometime be required to add an keep attribute to make it not be optimized away in synthesis.
Since a few years back Vivado have a quite full support for vhdl-2008
Unbounded arrays have been supported for even longer.
Generic package have just seen the light of day and seems to be a bit different in Mentor and Xilinx interpretation, but you can make it implement.
Generic types is a part of the language, but I have never got it to work the way I needed it to. (I always try to keep to sl and slv in entity)
As I'm not sure about your environment I can only answer for mine.
Full VHDL-2008 support is assumed
Unconstrained slv
Working around constrained vector definition by avoiding it.
entity X is
port(
DataIn : in std_logic_vector;
DataOut : out std_logic_vector
);
end entity;
architecture X_arch of X is
-- guiding DataSignal with to have a relationship with some signal is usally needed
signal DataSignal : std_logic_vector(DataIn'range);
begin
assert DataIn'length = DataOut'length
report "length missmatch of input and output data"
severity ERROR;
DataOut <= DataSignal;
DataSignal <= DataIn;
end architecture;
Asserts will need to be enabled for synthesis, ether for the run or appended to the synthesis strategy. (see ug901, for Xilinx or check vendor docs)
Unconstrained vectors need to be constrained at the top level. Some times a bit flakey in multi layered component designs. Signals are usually a bit iffy about how they get inferred.
Higher dimensional data can also be unconstrained
type slv_2d is array(natural range <>) of std_logic_vector;
-- Constrain multiple dimensions at once
-- (this might still be broken in GHDL, open issue last time i checked)
-- synthesis/implementation in Vivado works
-- simulates in Modelsim/Questa works
signal test_signal : slv_2d(0 to 5)(7 downto 0);
-- constants can de inferred from assignment
constant test_signal : slv_2d := ("001", "010", "011", "100" );
subtype I usually think about as limiting a type further.
-- integer may be any value within -2147483648 to +2147483647.
-- I might have an issue or a design restriction to highlight
-- I usually don't use subtypes
subtype my_range is integer range 0 to 255;
-- Will throw error if outside of range 0 to 255.
variable cnt : my_range := 0;
I really recommend reading ug901 "Supported VHDL-2008 Features" section of the latest release, even if you don't work with Xilinx. Dolus have a few really good writeups on vhdl-2008 that might strike your fancy and will talk about related features to what you are looking for.

Related

Integer output turns to binary in synthesize ISE

I have a VHDL BCD counter whose output is an integer value (digit).
But when I simulate the code in Xilinx ISE it shows the code's waveform in binary value. The code works but the output should be integer but it's not. I have tested this code in Modelsim and the output is correct and it's in integer value. This problem is in code synthesize too and the value is binary.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity bcdcnt is
Port ( clk : in STD_LOGIC;
digit : out INTEGER RANGE 0 TO 9);
end bcdcnt;
architecture Behavioral of bcdcnt is
begin
count: PROCESS(clk)
VARIABLE temp : INTEGER RANGE 0 TO 10;
BEGIN
IF (clk'EVENT AND clk = '1') THEN
temp := temp + 1;
IF (temp = 10) THEN temp := 0;
END IF;
END IF;
digit <= temp;
END PROCESS count;
end Behavioral;
That's what synthesis does.
That's what synthesis MUST do : it translates your high level design to the resources in your FPGA or ASIC, which are binary. So, what's the problem here?
If you need to simulate the post-synth result, the usual approach is to create a wrapper entity that takes the correct port types, and translates between those and the post-synthesis netlist component.
Then, simulation should work with either the original entity, or this wrapper entity, both of which have integer ports.
Better still, you can re-use the same entity, and add the wrapper as a second architecture, thus guaranteeing that it uses the same interface (ports).
(You can even instantiate both the original and post-synth in its wrapper in the testbench, in parallel with a comparator on their outputs, to see they both do the same thing. But note there will be gate-level delays between them; usually you check outputs only on clock edges so these do not matter.)
Another approach is to restrict port types on the top level of the design to binary types like std_logic_vector. This plays nicer with badly designed tools, like ISE where the automatically generated testbench will have binary port types, (I generally edit them back to the correct ones; it's almost easier to write TBs from scratch).
But it restricts you to using an obscure and complex design style instead of higher level abstractions like Integers.
It's bad - really bad - that this approach is taught and encouraged so widely. But it is, and sometimes you'll just have to live with it. (Even in this approach, there's no reason to avoid decent abstractions internal to the FPGA, as long as the synthesis tool understands them).
A third approach - roughly, "trust, but verify" - is to trust that synthesis tools are competently written - which is usually true - and forget about post-synthesis simulation.
Just verify the design thoroughly at the behavioural level in simulation, then synthesise it, and test in live FPGA.
99% of the time (unless you're writing really weird VHDL), synth and P&R have done the right thing, and any differences you see are due to the aforementioned I/O timings (gate delays at the I/O pins). Then model these in the testbench and/or wrapper until you see the same behaviour in both (fix anything that needs fixing, and re-synthesise).
In this approach you only need to bother with the (MUCH slower) post-synth and post-PAR simulations if you need to track down a suspected synthesis tool bug.
This does happen : I've seen two in a quarter century.
Most of the time I just use the third approach.

issue with vhdl structural coding

The code below is a simple vhdl structural architecture, however, the
concurrent assignment to the signal, comb1, is upsetting the simulation
with the outputs (tb_lfsr_out) and comb1 becoming undefined. Please, please help,
thank you, Louise.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity testbench is
end testbench;
architecture behavioural of testbench is
CONSTANT clock_frequency : REAL := 1.0e9;
CONSTANT clock_period : REAL := (1.0/clock_frequency)/2.0;
signal tb_master_clk, comb1: STD_LOGIC := '0';
signal tb_lfsr_out : std_logic_vector(2 DOWNTO 0) := "111";
component dff
port
(
q: out STD_LOGIC;
d, clk: in STD_LOGIC
);
end component;
begin
-- Clock/Start Conversion Generator
tb_master_clk <= (NOT tb_master_clk) AFTER (1 SEC * clock_period);
comb1 <= tb_lfsr_out(0) xor tb_lfsr_out(2);
dff6: dff port map (tb_lfsr_out(2), tb_lfsr_out(1), tb_master_clk);
dff7: dff port map (tb_lfsr_out(1), tb_lfsr_out(0), tb_master_clk);
dff8: dff port map (tb_lfsr_out(0), comb1, tb_master_clk);
end behavioural;
It's just a little more complex than Radix Ciano(1) says. All tb_lfsr_out elements are showing 'U' from Now = 0 ns. The reason why is that all of the D flip flops aren't initialized.
All tb_lfsr_out elements are showing 'U' from Now = 0 ns. The reason why is that all of the D flip flops aren't initialized.
If you reset all the flip flops the result will always be '0' without a '1' to cause a flip in the XOR gate.
Preset the D flip flops (which can come for free in an FPGA implementation):
This was done by simply adding a default value:
q: out std_logic := '1';
(1) Yes it's a minor change, and to all appearances someone changed their user name and if asked I would have changed Radix to Ciano. Making changes simply to cross a threshold is ridiculous.
The entire purpose of this answer was to avoid stepping on the other answerer's rights of authorship and now he's done the very thing. The issue with his answer being that the complimentary property of XOR prevented the LFSR from working when all inputs were '0's or any inputs were metavalues.
And while you're at it no one noticed the error in the waveform now corrected, apparently too self absorbed in playing games with answer edits. (The signals after the label dff8 were actually from dff7).
There's a message here which is in the form of a question. What's the purpose in answering questions on stackoverflow? See Why I no longer contribute to StackOverflow . And note Mr. Richter's reputation has continued to eek upward, including for the example post on goto he cites as likely to induce severe ire. (And the message there is have patience all you petty editors, sooner or later you're 'reputation' will reach self sustaining levels unless the system is altered to prevent it).
Also note the question's author has to date and after an impassioned plea closing his question not show acceptance of nor use for any answer.
In the mean time quit spoiling why I answer questions on VHDL by changing the words I write, although I have to admit the edit voting history was entertaining.

When to use what types

Questions:
Is there a more appropiate "supertype" to signed and unsigned than std_logic_vector (regarding my case)?
Is it ok to define an Input as (subtype of) Integer or is it better to define it as bitvector? (Are there any Issues with the Integer approach)
When should I use resolved or unresolved logic for the Inputs/Outputs off an Entity?
Resolved for Bus drivers (because of the "high Z drivers") otherwise unresolved?
Always resolved so a bus can be driven/used as input (this seems wrong, because when would I use unresolved then?)
Actual Case:
I am declaring an entity and am wondering for the right types for the inputs and outputs.
Lets assume I am constructing a dynamic width equal. It compares the first n Bits of two Inputs for equality.
The entity definition would be:
entity comparisonDynWidth is
generic(
width : positive;
min_width : positive;
-- when the tools suport vhdl2008 enough
-- reason for both signed/unsigned => std_logic inputs
--function compareFunc (x: in std_logic_vector; y: in std_logic_vector) return std_logic
);
port (
left, right : in std_logic_vector(width-1 downto 0);
widthControl: in natural range 0 to width-min_width;
result : out std_logic / std_ulogic ??
);
I chose std_logic_vector as Input since I want it to look the ports like a generic less than comparator as well, for which signedness matters and which can have signed and unsigned inputs.
since it is easier for me to define the width as an integer I did so.
Is there a more appropiate "supertype" to signed and unsigned than
std_logic_vector (regarding my case)?
Not sure what you mean, but you have no choice - signed and unsigned are defined in the standard.
Is it ok to define an Input as (subtype of) Integer or is it better to
define it as bitvector? (Are there any Issues with the Integer
approach)
Integers will flag errors if you go outside their range. vectors (signed and unsigned) will wrap around. Which is "correct" depends on what you want and how you feel about coding explicit wrap-around if you want it with integers.
When should I use resolved or unresolved logic for the Inputs/Outputs
off an Entity?
If you stick to:
only using resolved types for the top level IO ports (i.e. the actual pins of the device)
using unresolved types internally
you will be able catch errors involving multiple drivers on a signal with a detailed error-message at elaboration-time. This can be preferable to chasing down Xs in your waveforms at simulation-time.
There are no internal tri-state buses internally to most technologies these days, so you can't have multiple drivers, so there's no need for resolved signals inside the device. IO pins (almost?) always have tri-stateble drivers, so the use of a resolved type is appropriate, and the driving of a 'Z' can be used to infer that behaviour.
std_logic_vector is a good choice in your case (and in most cases in an entity, as it represents hardware situation best... e.g. with use of 'U' and 'Z' and so on)
the use of integer in an entity is ok as long as it is not the top-level entity. in top level entities, the exclusive use of std_logic(_vector) is recommended.
most tools report multi-driver situations anyway... the use of resolved types is therefore ok.

What does this VHDL code do?

I am working on a project but whatever I do I can’t understand what this code does. Since I am not familiar with VHDL, it’s really hard for me to understand the purpose of this code.
library iee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use work.my_package.all;
Entity multiplier is
generic (size: integer :=4);
Port (a,b : in unsigned( size-1 downto 0);
y : out unsigned( size-1 downto 0));
End multiplier ;
ARCHITECTURE behavior of multiplier is
Begin
y<= mult(a,b);
End behavior;
You have an entity which describes the interface of your design. In this case inputs a and b as well as output y. These are all 4-bit values.
The architecture contains the implementation of what you're trying to do (the body if you will). In this case it's simply a multiplication of a and b, which is assigned to y. And (should you be confused) no, the <= does not stand for "smaller than or equal to" but it's an assignment.
It takes two 4 bit inputs and produces a 4 bit product on the output. This is a little weird as the input size is equal to the output so if you multiply together 2 big numbers you get an overflow.
just look for the ARCHITECTURE section and you can see that you do multiplying of two integers a and b which are defined in the Entity section.
the ARCHITECTURE section always describes how you system behaves!

adding '1' to LOGIC_VECTOR in VHDL

I'm trying to add '1' to an N-Length STD_LOGIC_VECTOR in VHDL
This is the very first time I'm using VHDL so I'm not at all sure how to add this 1 without bulding a Full-Adder which seems kinda of redundent
We are not allowed to use any more liberaries then then one in the code.
LIBRARY IEEE ;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY cnt IS
GENERIC (n: natural :=3);
PORT( clk: IN std_logic; -- clock
rst: IN std_logic; -- reset
cntNum: IN std_logic_vector(n-1 DOWNTO 0); -- # of counting cycles
cntOut: OUT std_logic_vector(n-1 DOWNTO 0) -- count result
);
END cnt;
architecture CntBhvArc OF cnt IS
signal counta : std_logic_vector(n-1 DOWNTO 0);
begin
process (clk, rst)
begin
if rst='1' then
counta<="0";
elsif (clk'event) and (clk='0') then
counta<= counta+'1';
end if;
cntOut<=counta;
end process;
END CntBhvArc
Also... can anyone point to a VHDL totrial for someone who has very little experince in programing?
Thanks
You should not use library IEEE.STD_LOGIC_UNSIGNED.ALL
This library is deprecated (see VHDL FAQ); use ieee.numeric_std.all instead.
To answer your last point - don't think of it as programming. HDL stands for "hardware description language". You're describing hardware, always keep it in mind when writing your code :)
I've also written at length about not using STD_LOGIC_UNSIGNED, but using NUMERIC_STD instead. If this is homework and you're being taught to use STD_LOGIC_UNSIGNED, then I despair of the educational establishments. It's been years since that made sense.
VHDL is strongly-typed, so if count is representing a number (and with a name like that, it better had be :), use either a signed or unsigned vector, or an integer. Integers don't wrap around in simulation unless you make them (if you add 1 to them when they are at their max value, the simulator will terminate). The vector types do. Sometimes you want one behaviour, sometimes the other.
Finally, I just noted this:
elsif (clk'event) and (clk='0') then
which is better written as:
elsif falling_edge(clk) then
again, this has been so for about a decade or two. Were you intending to use the falling edge - rising edge is more usual.
You need to cast the std_logic_vector to an unsigned value so you can add one, then cast it back so you can assign it to your output.
This looks like a homework assignment, so I'll leave you to figure out exactly how to do the implementation.

Resources