TWiki
>
P1076 Web
>
Vhdl2019CollectedRequirements
>
EnumAttributes
(2020-02-17,
JimLewis
)
(raw view)
E
dit
A
ttach
---+ Attributes for Enumerated Types %TOC% ---++ Proposal Editing Information * Who Updates: Main.JimLewis, Main.PatrickLehmann, <Add YourName >, ... * Date Proposed: 2012-08-17 * Date Last Updated: 2016-12-29 * Priority: * Complexity: * Focus: Testbench and Synthesis ---++ Requirement Summary Additional attributes for enumerated types ---++ Related and/or Competing Issues: none ---++ Proposal ---+++ Basic Capability It would be appropriate to allow these to apply to objects, however, in the "Basic" part of this proposal, I am only applying the prefix to types and subtypes since this is consistend with LRM 16.2.2. I would like these to apply to: Prefix: Any prefix T that is appropriate for a discrete or physical type or subtype, or an object with a discrete or physical type or subtype, or an alias thereof. However, many of the other attributes in the LRM that operate on subtypes are of the form: Prefix: Any discrete or physical type or subtype T. We need consistency, so I am limiting the current proposal to the existing LRM text. ---++++ T'LENGTH <pre>Kind: function. Prefix: Any discrete or physical type or subtype T. Result type: universal_integer. Result: T'LENGTH = T'POS(T'HIGH) - T'POS(T'LOW) + 1 </pre> ---++++ T'POS_RANGE <pre>Kind: range. Prefix: Any discrete or physical type or subtype T. Result type: Type integer. Result: For an ascending 0 to T'POS(T'RIGHT) </pre> <pre> type state_type is (S0, S1, S2) ; signal state : state_type ; ... state_type'range = S0 to S2 -- see extended proposal state_type'pos_range = 0 to 2 </pre> Do we really need 'pos_range? The proposal adds 'LENGTH and we know that for enumerated types the range is 0 to state_type'LENGTH. Furthermore, the Extended capability adds 'RANGE. For integer based values, 'RANGE and 'POS_RANGE produce the same range. ---+++ Extended capability [[Main.BrentHahoe][<Brent Hayhoe>]] suggested the supporting T'RANGE as follows: <pre>P'RANGE Kind: range. Prefix: Any prefix P that is appropriate for an object with a discrete or physical type or subtype T, or an alias thereof, or a discrete or physical type or subtype T. . . . </pre> If we do this, then we would need to support scalar_object'range, as otherwise, it would be confusing that arrays support array_object'range. However, if we do this, then we also need to add attributes for all objects of a scalar type. <pre> type state_type is (S0, S1, S2) ; signal state : state_type ; ... state_type'range = S0 to S2 state_type'pos_range = 0 to 2 state_type'image(state) ; state'image ; </pre> Similarly for integers: <pre> subtype int10 is integer range 1 to 10 ; signal A : int10 ; signal B : integer range 1 to 10 ; . . . int10'range = 1 to 10 -- subtype A'range = 1 to 10 -- object B'range = 1 to 10 -- object </pre> Note the only reason to do T'Range is for consistency (and there is alot of value to this). We already have O'subtype which does something similar (and more). Also for any discrete type, type'range is the same as using the type name so if this is not expanded to include objects, there is no reason for it. ---++++ Expand where appropriate Type attributes to objects having that type. For example, with T'POS_RANGE, change the prefix to: <pre>Prefix: Any prefix T that is appropriate for a discrete or physical type or subtype, or an object with a discrete or physical type or subtype, or an alias thereof.</pre> We would need to review LRM section 16.2.2 for attributes for which it is appropriate to expand to objects. Some, such as type'val(integer) may be confusing if they are applied to a object name. ---+++ Advanced capability ---++++ T'SERIALIZE(value : T) <pre>Kind: function. Prefix: Converts an enum value into a commonly exchangeable binary representation. Parameter 'value': Value that is to be serialized. Result type: Type STD_LOGIC_VECTOR. Result: Binary representation of value </pre> ---++++ T'DESERIALIZE(value : STD_LOGIC_VECTOR) <pre>Kind: function. Prefix: Converts a binary representation of an enum value into a concrete enum member. Parameter 'value': Value that is to be deserialized. Result type: Type T. Result: Enum member of it's binary representation </pre> ---++ Use Models Serialization and de-serialization of enumerated types into binary representations is a common use case in simulation and synthesis of HDL code. While VHDL does not support type generics to describe generic RAMs, FIFOs or cross-clock synchronizers. A 'serialization' functionality is needed to convert enum values into a common binary representation. Such converted values (e.g. of type STD_LOGIC_VECTOR) can be passed to a FIFO. Later it's also possible to convert the STD_LOGIC_VECTOR value back to an enum value. The knowledge of the required bit count in the resulting bit vector, is a major step in enum value serialization into binary representations. Currently the count of declared enum members can only be retrieved by =T'POS(T'RIGHT)+1= or =T'POS(T'HIGH)+1=. An initial step towards serialization is a VHDL attribute to get the count of enum members. Such an attribute could be named ='LENGTH= - as known from array types - or ='COUNT= to state the difference between array types and scalar types. Some code snippets, which are used by the next examples: <verbatim>type T_STATUS is ( STATUS_IDLE, STATUS_TRANSMITTING, STATUS_COMPLETE, STATUS_ERROR ); function log2(value : NATURAL) return POSITIVE; -- returns log2 of value function str_len(value : STRING) return NATURAL; -- returns the length of a NUL terminated string function str_trim(value : STRING) return STRING; -- returns a trimmed string without trailing NUL characters</verbatim> Use Case 1 - Serializing enum values to STD_LOGIC_VECTOR and vice versa for using with generic VHDL components At the moment it's not possible to store enum vales in a generic FIFO or RAM. Here are several solutions for this scenario: * give up on using enums * implement a FIFO or RAM for each enum type * convert enum values to STD_LOGIC_VECTOR and vice versa * use type generics (see Main.RyanHinton comment in General Comments) The latter solution needs one conversion function per type and direction. <verbatim>function serializeStatus(value : T_STATUS) return STD_LOGIC_VECTOR is begin return std_logic_vector(to_unsigned(T_STATUS'pos(value), log2(T_STATUS'pos(T_STATUS'high) + 1))); end function; function deserializeStatus(slv : STD_LOGIC_VECTOR) return T_STATUS is begin if (to_integer(unsigned(slv)) <= T_STATUS'pos(T_STATUS'high)) then return T_STATUS'val(to_integer(unsigned(slv))); else return STATUS_ERROR; end if; end function;</verbatim> This could be shortened to this, if enum types support ='COUNT=: <verbatim>function serializeStatus(value : T_STATUS) return STD_LOGIC_VECTOR is begin return std_logic_vector(to_unsigned(T_STATUS'pos(value), log2(T_STATUS'count))); end function; function deserializeStatus(slv : STD_LOGIC_VECTOR) return T_STATUS is begin if (to_integer(unsigned(slv)) < T_STATUS'count) then return T_STATUS'val(to_integer(unsigned(slv))); else return STATUS_ERROR; end if; end function;</verbatim> All these function could be spared if enum types support a ='SERIALZE= and a ='DESERIALZE= attribute: <verbatim>signal Status : T_STATUS; signal Debugger_Data : STD_LOGIC_VECTOR(15 downto 0); Debugger_Data(1 downto 0) <= serializeStatus(Status)</verbatim> Or shorter with support for ='serialize=: <verbatim>Debugger_Data(1 downto 0) <= T_STATUS'serialize(Status);</verbatim> Use Case 2 - Exporting/writing enum values and member names into files for external tools Some simulation and synthesis tools support I/O functions to read and write files from the host's file system. While this feature is massively used in simulation environments it's rarely used in synthesis environments. Synthesis tools generate large reports, which include state encodings for enum based FSMs. But it's not common to report other encodings for e.g. enum based signals. There are several solutions to this scenario: * give up on using enums * force a specific enum encoding by using a vendor specific encoding attribute * export enum values and it's internal value (position) into a string representation These string representations can be read back by external tools like waveform viewers or debuggers to show captured signals with it's member name instead of it's binary representation. A simple export format could be: * one member per line * separated by semi-colons Example of a simple format: <verbatim>STATUS_IDLE;STATUS_TRANSMITTING;STATUS_COMPLETE;STATUS_ERROR; procedure str_append(StringBuffer : inout STRING; value : STRING) is constant BufferEnd : POSITIVE := str_len(StringBuffer); begin StringBuffer(BufferEnd + 1 to BufferEnd + str_len(value)) := value; end procedure; function encodeStatus return string is variable StringBuffer : STRING(1 to (64 * T_STATUS'count)) := (others => NUL); begin for member in T_STATUS loop str_append(StringBuffer, (T_STATUS'image(member) & ';'); end loop; return str_trim(StringBuffer); end function;</verbatim> A external script can transform this enum member list into other file formats like ChipScope 's token files (*.tok) or GTKwaves data format filter files. It's even possible to export these file formats directly. An advantage is to generate up-to-date encoding files for external tools without complex synthesis report parsing. Questions * [[Main.BrentHahoe][<Brent Hayhoe>]] 2015-06-30 - Do we really want T'RANGE to return an integer range? Should it not return the enumerated range T'LEFT to T'RIGHT? For example, in Std_logic_1164 we already use the *range* keyword to define subtypes: <sticky><verbatim> ------------------------------------------------------------------- -- common subtypes ------------------------------------------------------------------- subtype X01 is resolved STD_ULOGIC range 'X' to '1'; -- ('X','0','1') subtype X01Z is resolved STD_ULOGIC range 'X' to 'Z'; -- ('X','0','1','Z') subtype UX01 is resolved STD_ULOGIC range 'U' to '1'; -- ('U','X','0','1') subtype UX01Z is resolved STD_ULOGIC range 'U' to 'Z'; -- ('U','X','0','1','Z') </verbatim></sticky> I think that we should match T'range to return the base type range, in the same manner as it is used in defining a subtype. [[Main.BrentHahoe][</Brent Hayhoe>]] * [[Main.JimLewis - 2016-12-30]] - In response to Brent's suggestion to modify 'Range to return the range of the type. For a type, you don't need this as the "the range of a type" is a subtype and you can use the subtype just like you use array_object'range (see my example below). If we expanded these attributes (in a consistent fashion with array attributes) and applied this to an object of a type, then 'Range provides something useful. If we want 'Range on an object, then we need to modify all of the attributes for types so they apply to objects as well - this is not necessarily a bad thing. Hence, I will take the action to rename the attribute I want to 'POS_RANGE. Going further, to support my claim about types/subtypes, try the following: <verbatim> entity for_subtype is end for_subtype ; use std.textio.all ; architecture test of for_subtype is subtype R_T_RANGE is integer range 1 to 10 ; begin process begin for i in R_T_RANGE loop write(std.textio.OUTPUT, integer'image(i) & LF ) ; end loop ; wait ; end process ; end test ; </verbatim> * [[Main.BrentHahoe][<Brent Hayhoe>]] 2015-06-30 - Prefixes should be 'any enumerated type or subtype T' [[Main.BrentHahoe][</Brent Hayhoe>]] * Main.JimLewis 2016-12-30: Yes. Just updated it to something appropriate (borrowing LRM text from other attributes) * Main.PatrickLehmann - 2015-06-26: Use name T'COUNT instead of T'LENGTH: * Main.JimLewis 2016-12-30: No. We need something that is intuitively related to other VHDL attributes and this overloads the existing attribute for arrays. I did rename the RANGE to POS_RANGE to allow for future changes. Perhaps this should be POS_LENGTH? * The extension is trivial, but where and how would this be used? -- Main.ErnstChristen - 2015-01-27 * [[Main.BrentHahoe][<Brent Hayhoe>]] 2015-06-30 - I think 'serialize' and 'deserialize' are application specific and should remain as functions in an (open source?) package. The problem here is not so much language design deficiency as a limitation in synthesis. We could build a FIFO model to handle enumerated types and would work in simulation, but would a synthesis tool be able to map it to Std_Logic. My guess is that it will complain at the compilation stage? [[Main.BrentHahoe][</Brent Hayhoe>]] ---++ General Comments (Main.RyanHinton - 2016-12-29:) I agree that ='range= and ='length= are easy, and I agree with Brent's amendment to ='range=. The risk I see with ='serialize= and ='deserialize= is that your simulator likely won't implement them the same way your synthesizer encodes them. What are you really trying to accomplish? Regarding writing a list of enum values to file, you showed how it's already possible. For working with external tools, it seems like you're going to need a customized format for each tool. (You mentioned the ChipScope =.TOK= format and GTKwaves filter file format.) I don't think these formats should be standardized. With some kind of type [[ArrayTypeGenerics][annotation similar to that being proposed for array type generics]], this procedure could be written once for each desired file format, and instantiated for each desired enumerated type. Regarding RAMs, the synthesis tool we use supports inferring a RAM (which can be used as a FIFO) where the element type is enumerated, or a record, or another array, or whatever. (Haven't tried access types yet....) This is legal in VHDL-87, and handles the case of an inferred FIFO inside an architecture. Our synthesis tool also supports type generics (as far as we've tested...). So we're upgrading our standard FIFO components to take a type generic, use this type for the =DIN= and =DOUT= ports, and create an array type with this type for an element internally for the RAM. If your synthesis tool supports VHDL-2008, this covers the FIFO use case. Is there another use case you have for ='serialize=? ( [[Main.RyanHinton][/Main.RyanHinton]]) ---++ Supporters -- [[Main.BrentHahoe][Brent Hayhoe]] - 2015-06-30 (with the provisos of *range* based on base enumerated type and that *serialize* and *deserialize* attributes are not approved. -- Main.PatrickLehmann - 2015-06-26 _Add your signature here to indicate your support for the proposal_
E
dit
|
A
ttach
|
P
rint version
|
H
istory
: r21
<
r20
<
r19
<
r18
<
r17
|
B
acklinks
|
V
iew topic
|
Ra
w
edit
|
M
ore topic actions
Topic revision: r21 - 2020-02-17 - 15:34:29 -
JimLewis
P1076
Log In
or
Register
P1076 Web
Create New Topic
Index
Search
Changes
Notifications
RSS Feed
Statistics
Preferences
Webs
Main
P1076
Ballots
LCS2016_080
P10761
P1647
P16661
P1685
P1734
P1735
P1778
P1800
P1801
Sandbox
TWiki
VIP
VerilogAMS
Copyright © 2008-2026 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki?
Send feedback