VHDL create enumerated "bit" values for std_ulogic_vector - vhdl

I have a group of 19 bits with each bit having a specific meaning ( a group of flags ). I would like to label each of these bits so they are identified within the simulator with their label.
These bits are read over a communications interface, and when I get them, they are in std_logic_vector value something like this:
signal myflags : std_ulogic_vector(18 downto 0);
I am new to VHDL, but I think the proper procedure for this is to create an enumerated type, but I am not exactly sure how to do this. I have created enumerated types for state machine signals, but the enumeration of each state "label" is just the next numeric value (0,1,2,3, etc). This is not what I want to do. Instead, I want each bit specifically enumerated (or at least a label assigned to each bit).
Really, this would not even come up as an issue if ModelSim would allow me to change the displayed value for a bit. The example below shows my desire to change the Display Name from (31), bit 31 in a std_ulogic_vector value, to "power_good". Any advice would be appreciated.

Related

What does don't cares and null do in VHDL?

What does setting a value to don't cares actually mean and do in VHDL? Also what's the difference between setting the values to don't care vs setting it to null?
Here's a snippet from the lab I'm doing:
with selector select
mux_data_selected <= Channel_1_registered_data when '0';
Channel_2_registered_data when '1';
(others => '-') when others;
The type of the elements of mux_data_selected is probably std_ulogic or one of the like. To answer your last question, there is no null value in these types, so you cannot assign (others => null).
null is a void instruction that does nothing and that is sometimes used to indicate that there is nothing to be done in a branch of the control flow and that it is intentional.
It is also a pointer value (access types). Finally we sometimes talk about null arrays but it means that the array has an empty range, like 1 to 0, for instance. If your vector has a non-null range you cannot assign it a null array value, this would cause an error.
The - don't care value is one of the 9 values of the std_ulogic enumerated type. As its name says it is for cases where you do not care about the value. Either because you know this situation will never happen in real life or because when the situation happens you do not use the signal.
A smart enough logic synthesizer can use this indication to implement any actual '0' or '1' value that improves one metric (speed, area, power...) While if you code, e.g., '0' the synthesizer is forced to obey, which could lead to a speed, area or power waste.
As noted by #user16145658 the '-' value is also treated as a match anything wildcard by VHDL2008 STD_MATCH functions and predefined matching relational operators (?=, ?/=, ?<, ?<=, ?>, and ?>=). So you can use it also for soft comparisons.

Signal association after port mapping-VHDL

I am working in a TOP file of a project in VHDL. I have a problem-question concerning the port mapping.
Below, is a part of the code that I am trying to implement and afterwards the description of the context.
generate_microfib:
for i in 0 to 5 generate
fib: microfib
Port Map (
InL => SignalNumber(num(i)*2 + i), --Input Left
OutR => SignalNumber(num(i)*2 + i+1) --Output Right
);
end generate generate_microfib;
The code above creates multiple components of microfib. The microfib, has an input and an output port. What I want to do is connect the left input of the current created component with the right output of the previous created one.
My initial thought was to do it inside the port mapping, but VHDL doesn't give many options for calculations in the for..generate statement. So, I decided to do it in two steps. Meaning that, I first create the desired components and afterwards do the connections (by setting the desired signals equal).
So, my question is: Is it possible to do the connections in a function for example, by setting:
SignalNumber(i)=SignalNumber(i-1)?
I know that the '<=' operator is accepted and not the '=' but I want to show you that my goal is to make those two signals equal and not assign the value of the one to the other.
When I've done things like this, I've used an array-type signal to act as an intermediate placeholder. Then, within the generate loop, you can connect the ports to the indexed locations on the array signal.
So you could try something like this, using std_ulogic as an example port type:
architecture rtl of entity is:
constant N_DEVICES : integer := 5;
signal port_connector : std_ulogic vector(N_DEVICES downto 0);
begin
-- Concurrent statements
generate_microfib : for i in N_DEVICES-1 downto 0 generate
fib : microfib
port map (
InL => port_connector(i+1)
OutR => port_connector(i)
)
end generate generate_microfib;
-- Other stuff
end architecture rtl;
Then, port_connector(N_DEVICES) acts as the input to the chain, and port_connector(0) acts as the output from the chain.
This isn't a function, but it is (relatively) clean and avoids too much of a headache with the generate statement. Functions in VHDL, though, are meant to produce calculated values, not circuit connections, so I would recommend against trying for that anyhow.

VHDL - Why does using the length attribute directly on a function produce a warning?

I have a VHDL function that returns a std_logic_vector representation of a record and I want the length of that std_logic_vector. I am able to use the length attribute directly on the function. Why does this produce a warning in ModelSim? Am I inviting subtle problems? Googling the warning text did not turn up anything I understood to be helpful.
my_function_returns_slv(my_record)'length;
** Warning: ../src/my.vhd(line#): (vcom-1515) Prefix of predefined attribute "length" is function
call "my_function_returns_slv"
I've written the function to assemble the output by concatenating std_logic_vector representations of the record elements. The length of the record is fixed at compile time, but I do not want to hard code the length. I need the length to create signals for using the function output. So I can't just call 'length on the output of the function (ex: call 'length on a signal holding the function output) because it is not possible to declare an unconstrained signal to hold the output. I could write a similar function to calculate the length of the std_logic_vector, but that would add some significant code, especially for the number of records I have. Should I accept the ModelSim warning and carry on? Should I deal with the extra code from writing functions to assemble the bit width of my records? Is there a better solution altogether?
Helpful record pack/unpack subprograms I am making use of:
http://www.eda-twiki.org/twiki/pub/P1076/RecordReflectionToSlv/standard_functions.vhd
Thanks!
Using the 'length attribute directly on a function can be seen as just taking another part of the function result than the primary output, thus from a conceptual point of view there should be nothing wrong with that.
So I would accept the ModelSim warning, but also take it as an indication that the tool is worried about the construction, so I would check that my other tools, e.g. synthesis tools and code checkers, accept this use of an attribute directly on a function call.
Appears that you can avoid the ModelSim warning by making a function like:
function len(slv : std_logic_vector) return natural is
begin
return slv'length;
end function;
and then this won't result in a ModelSim warning:
signal MY_LEN : natural := len(slv_not(CONST));
So being able to avoid the warning using such encapsulation confirms that the warning is a little flaky in the first place.
"I need the length to create signals for using the function output. So I can't just call 'length on the output of the function (ex: call 'length on a signal holding the function output) because it is not possible to declare an unconstrained signal to hold the output."
A fun work around for sizing signals is:
constant MY_CONST : std_logic_vector := my_function_returns_slv(my_record) ;
signal MySig : std_logic_vector(MY_CONST'range) := MY_CONST ;
We have an LCS for VHDL-2017 that allows signals to be unconstrained and get their constraints from the initialization.

VHDL: Mapping a slice of an output to a signal

I want to map the lower bit (bit0) of a 32 bit output port to a signal and leave the upper bits unconnected (OPEN). Is there a way to treat this mapping as an aggregate?
I've tried the following to no avail:
port map (
some_output => ( 0 => sig_1, others => OPEN)
);
The below is not a valid answer, since it does not adhere to the VHDL standard. This "answer" is however kept here, and not deleted, since it shows what construction to avoid for tool compliance, since some tools apparently accept this non-standard compliant VHDL code.
Example of port mapping without association of all scalar subelement, which is accepted by Altera Quartus II and Mentor ModelSim in some cases, but is also likely to result in warning or error:
port map(
some_output(0) => sig_1,
-- some_output others are simply not included in port mapping
So, as David Koontzs point out in the comment, the VHDL standard (IEEE Std 1076-2008) section "6.5.7 Association lists" describes:
... every scalar subelement of the explicitly declared interface object shall be associated exactly once with an actual (or subelement thereof) in the same association list, and all such associations shall appear in a contiguous sequence within that association list. Each association element that associates a slice or subelement (or slice thereof) of an interface object shall identify the formal with a locally static name.
So it is not valid to only associate some of the scalar subelements, since the standard says "every scalar subelement", and open can't be used for the remaining scalar subelements, since the standard says "Each association element that associates a slice ... of an interface object shall identify the formal with a locally static name.".
Another solution is this:
signal my_vector : STD_LOGIC_VECTOR(3 downto 0);
signal my_vector_float : STD_LOGIC_VECTOR(3 downto 0);
port map (
[...]
some_output(3 downto 0) => my_vector,
some_output(7 downto 4) => my_vector_float,
[...]
);
You can now setup some report filter rules to silence all warning concerning *_float signals.

Can custom types be used in port declaration?

I am preparing for an exam by going through some old ones. One of the questions is:
Write the synthesizable behavioral VHDL code that implements the synchronous FSM in fig...
The FSM has one input, called request, that is of enumeration type with values (r1, r2, r3)...
That makes me want to write this code:
entity fsm is
port ( clk : in std_logic;
request : in my_enum_type
);
end fsm;
And somewhere have a:
type my_enum_type is (r1, r2, r3);
somewhere (I have tried right befor the port declaration and right after the architecture declaration).
But I can't seem to get that to work.
Can I have custom types as inputs or outputs like that?
Yes you can, and I regard it as best practice - it means least work, best understanding, easiest maintenance, and cleanest design.
The trick is to declare the types common to your whole design in a package (I usually call it "Common" :-) and add use work.Common.all before the entity declaration AND in every customer of that entity. More specialised components can have appropriate names, of course!
For example:
package Common is -- untested...
type my_enum_type is (r1, r2, r3);
-- (optional) useful tools
function to_slv (e : my_enum_type) return std_logic_vector;
function to_enum (s : std_logic_vector(my_enum'length downto 0))
return my_enum_type;
end Common;
package body Common is
-- subprogram bodies here
end Common;
Now when you add a value to the enumeration, you ONLY modify "Common" and rebuild the design, while those who follow conventional guidelines are still trying to identify every port and signal where they have to increase the range of their "std_logic_vector" by 1.
Works really well for bus interfaces too, where a record in each direction hides all the individual bus and handshaking signals.
You WILL have to fight brain-dead tools like Xilinx "automatic testbench generator" which will helpfully translate ALL your port types - integer or boolean as well as custom - into std_logic(_vector) and then fail to compile. Just translate them back again.
You can still make a case that at the very top level, all the external FPGA pins should still be std_logic based. And if you ever need to simulate a post-synthesis version of your design, then you will either need to live with std_logic_vector ports, or add a simple wrapper to convert from one form to the other.

Resources