Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > VHDL > data type choice

Reply
Thread Tools

data type choice

 
 
alb
Guest
Posts: n/a
 
      08-30-2013
Hi everyone,

I'm trying to define my own set of types in order to have a more
readable code and try to represent my data structures at a higher level.
This code is used for testbench only and I'm using it to define my
packets to be transmitted on my serial link.

Eventually somewhere there is a procedure handling these data types and
'sending' a std_logic signal to a DUT.

<code>
constant WORD_LENGTH : natural := 16;
constant MAX_BUF_LEN : natural := 1024;

-- data word over the link interface are 16 bit wide.
subtype data_word_t is bit_vector (WORD_LENGTH - 1 downto 0);

type buff_t is array (0 to MAX_BUF_LEN - 1) of data_word_t;

type data_buffer_t is record
len : natural; -- length of the data
buf : buff_t; -- data buffer
end record;
</code>

the intent of this gymnastic is to deal with bits and non negative
integers for packet lengths, but I'm facing lots of troubles when I
start to manipulate these datatypes because of conversion.

Since the header of my packets include the length I thought that simply
doing:

<code>
variable data_buffer : data_buffer_t;
variable data_word : data_word_t;
data_word := some_conversion_function(data_buffer.len);
</code>

would have been enough, but it seems to me I'm too stupid to find the
right combination of conversions.

Moreover I start to think that maybe my original choice of types is not
optimal and some people around here can direct me to a better choice of
types.

Should I build a set of functions that allow me to manipulate these types?

Any suggestion is welcome.

Al

--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
 
 
 
Jim Lewis
Guest
Posts: n/a
 
      08-30-2013
Hi Al,
If I were not using std_logic_vector, I would be using integer. I am planning on migrating toward using integers in my testbenches. Especially if we can get larger than 32 bit integers in the next revision of the language. OSVVM likers integers.

If you continue using bit_vector, math operations are in numeric_bit_unsigned and numeric_bit. Conversions to between std_logic family are in std_logic_1164:
function To_bit (s : STD_ULOGIC; xmap : BIT := '0') return BIT;
function To_bitvector (s : STD_ULOGIC_VECTOR; xmap : BIT := '0') return BIT_VECTOR;

function To_StdULogic (b : BIT) return STD_ULOGIC;
function To_StdLogicVector (b : BIT_VECTOR) return STD_LOGIC_VECTOR;

In my testbenches, I like communicating through a single record. Bit_vector does not work with this approach since it does not have a resolution function. Of course, you could write one. I did this for integer, time, and real.

Jim
 
Reply With Quote
 
 
 
 
alb
Guest
Posts: n/a
 
      09-02-2013
On 30/08/2013 18:59, Jim Lewis wrote:
> Hi Al, If I were not using std_logic_vector, I would be using
> integer. I am planning on migrating toward using integers in my
> testbenches. Especially if we can get larger than 32 bit integers in
> the next revision of the language. OSVVM likers integers.


unfortunately I cannot get rid of the slv since this is how the DUT
interface is defined. It seems to me that slv is a common choice with RTL.

I may understand why OSVVM likes integers and I would like to profit of
that as well, but sooner or later you need to face with the conversion
to slv and this is where I hoped for the bv to be more friendly.

>
> If you continue using bit_vector, math operations are in numeric_bit_unsigned and numeric_bit. Conversions to between std_logic family are in std_logic_1164:
> function To_bit (s : STD_ULOGIC; xmap : BIT := '0') return BIT;
> function To_bitvector (s : STD_ULOGIC_VECTOR; xmap : BIT := '0') return BIT_VECTOR;
>
> function To_StdULogic (b : BIT) return STD_ULOGIC;
> function To_StdLogicVector (b : BIT_VECTOR) return STD_LOGIC_VECTOR;
>


thanks for the hint. My choice for bv is that it seems to me well
representing bit fields in the protocol.

What I'm doing is breaking down the packet format to each individual
field, so I can randomly set each field and see how this effects my DUT.
How do you eventually convert the integers into your '16bit word header'
for example?

> In my testbenches, I like communicating through a single record.


I have not yet moved to the single record transaction and therefore keep
using two (one to the server and one from the server). As of now I do
not have a case for that need.

> Bit_vector does not work with this approach since it does not have a
> resolution function. Of course, you could write one. I did this for
> integer, time, and real.


Writing the resolution function shouldn't be complex. I'll postpone this
effort though since I'm not yet convinced I need it
 
Reply With Quote
 
Tricky
Guest
Posts: n/a
 
      09-03-2013
Its not quite clear to me - is this data_buffer_t a single packet, or does it contain multiple packets?

If its the latter, wouldnt it be better to make a single packet type, and then have some sort of controller to convert the packet into your serial data stream, rather than have a big fixed bus in your testbench, that isnt easily seperable into packets (if you wanted to inspect them in modelsim).

What I have done before in a homemade BFM for PCIe over an avalon streamingbus was to create a linked list of packets (acting as my event queue) handled by a protected type, and a wraparound entity controlled the data flow (with random wait times between packets to try and simulate some form of worse case or reality. Meant I could pump thounsands of PCIe packets into my controller, and from the top level all I needed were procedures like send_rd_req(addr) send_wr_req(addr, data), and never worry about overflowing any controllers in the testbench (only in the design).
 
Reply With Quote
 
alb
Guest
Posts: n/a
 
      09-03-2013
On 03/09/2013 11:27, Tricky wrote:
> Its not quite clear to me - is this data_buffer_t a single packet, or
> does it contain multiple packets?


data_buffer_t is a single packet. I intend to break down the fields more
clearly but for the time being you can assume that the packet is just a
sequence of data_word_t types. The 'controller', as you call it, does
the job of converting the sequence into the appropriate bits (I call it
server).

> If its the latter, wouldnt it be better to make a single packet type,
> and then have some sort of controller to convert the packet into your
> serial data stream, rather than have a big fixed bus in your
> testbench, that isnt easily seperable into packets (if you wanted to
> inspect them in modelsim).


this is indeed my intent. The client simply sends a random sequence of
packets, varying randomly the various fields of the packet. Since OSVVM
allows you to do so very easily I intended to profit of this.

The fact is that in the stream of serial data out I need to 'merge'
information coming from data_buffer_t elements and combine them in a
sequence of bits on a std_logic port. This 'merging' is now very awkward
due to the casting (from/to integers, bit and std_logic).

> What I have done before in a homemade BFM for PCIe over an avalon
> streaming bus was to create a linked list of packets (acting as my
> event queue) handled by a protected type, and a wraparound entity
> controlled the data flow (with random wait times between packets to
> try and simulate some form of worse case or reality. Meant I could
> pump thounsands of PCIe packets into my controller, and from the top
> level all I needed were procedures like send_rd_req(addr)
> send_wr_req(addr, data), and never worry about overflowing any
> controllers in the testbench (only in the design).


My issue is not 'overflowing' the controller on the testbench. I simply
need to stick to a selection of datatypes which are coherent with the
number of conversion to and from std_logic.

If I use integers *and* bits than I'm kind of stuck when I want to
combine them, if I use only integers than it is not quite readable when
you need to deal with words which have various fields, if I use only
bits than a length field may appear not so readable (101011110 instead
of 350, with unsigned representation). Assume you have a data word which
is split in some fields like the following:

- add(15 downto 12)
- crc(11)
- ext(10)
- len(9 downto 0)

a second word of length comes if ext is set. A crc flag indicates the
presence of crc at the end of the message. If all the fields are
integers (better be natural in this case) then my word to be sent will
look like this:

data_word = (add * 2**12) + (crc * 2**11) + (ext * 2**10) + len

which I find rather ugly. And again at a certain point I should convert
the data_word integer to a std_logic (passing through an unsigned).


 
Reply With Quote
 
KJ
Guest
Posts: n/a
 
      09-03-2013
On Tuesday, September 3, 2013 6:01:28 AM UTC-4, alb wrote:
> Assume you have a data word which
> is split in some fields like the following:
>
> - add(15 downto 12)
> - crc(11)
> - ext(10)
> - len(9 downto 0)


Then presumably you would have defined a record like this...

type t_packet is record
add: std_ulogic_vector(15 downto 12);
crc: std_ulogic_vector(11 downto 11);
ext: std_ulogic_vector(10 downto 10);
len: std_ulogic_vector(9 downto 0);
end record;

Then I would define functions to convert between records and std_ulogic_vectors like this...
function to_std_ulogic_vector(L: t_packet) return std_ulogic_vector is
variable RetVal: std_ulogic_vector(15 downto 0);
begin
RetVal(L.add'range) := L.add;
RetVal(L.crc'range) := L.crc;
RetVal(L.ext'range) := L.ext;
RetVal(L.len'range) := L.len;
return(RetVal);
end function to_std_ulogic_vector;

function from_std_ulogic_vector(L: std_ulogic_vector) return t_packet;
-- Left as an exercise for the reader, but similar in style with to_std_ulogic_vector


>
> a second word of length comes if ext is set. A crc flag indicates the
> presence of crc at the end of the message. If all the fields are
> integers (better be natural in this case) then my word to be sent will
> look like this:
>
> data_word = (add * 2**12) + (crc * 2**11) + (ext * 2**10) + len
>
> which I find rather ugly. And again at a certain point I should convert
> the data_word integer to a std_logic (passing through an unsigned).


But data_word <= to_std_ulogic_vector(L); looks much better. If you want to convert it to
integer than wrap to_integer(unsigned()) around it.

Kevin Jennings
 
Reply With Quote
 
alb
Guest
Posts: n/a
 
      09-03-2013
Hi KJ,

On 03/09/2013 13:32, KJ wrote:
> On Tuesday, September 3, 2013 6:01:28 AM UTC-4, alb wrote:
>> Assume you have a data word which
>> is split in some fields like the following:
>>
>> - add(15 downto 12)
>> - crc(11)
>> - ext(10)
>> - len(9 downto 0)

>
> Then presumably you would have defined a record like this...
>
> type t_packet is record
> add: std_ulogic_vector(15 downto 12);
> crc: std_ulogic_vector(11 downto 11);
> ext: std_ulogic_vector(10 downto 10);
> len: std_ulogic_vector(9 downto 0);
> end record;


That is more or less where I was aiming to, but I would have preferred
to define the len element as an integer (or even better a natural) instead.
At that point I believe that in to_std_ulogic_vector I could change this:

- RetVal(L.len'range) := L.len;

into something along these lines:

- RetVal(log2(L.len'length) downto 0) := to_unsigned(L.len, ???);

uhm... I'm again lost!

Actually your example triggers another question: why std_ulogic_vector
and not a bit_vector? At the packet definition level I do not really
need the 'Z', 'W', 'L'... values of the type. I may blindly adopt the
std_ulogic (and why not std_logic instead?), I just would like to know
what is important and what might be neglected when deciding what type of
data we choose.

> Then I would define functions to convert between records and std_ulogic_vectors like this...
> function to_std_ulogic_vector(L: t_packet) return std_ulogic_vector is
> variable RetVal: std_ulogic_vector(15 downto 0);
> begin
> RetVal(L.add'range) := L.add;
> RetVal(L.crc'range) := L.crc;
> RetVal(L.ext'range) := L.ext;
> RetVal(L.len'range) := L.len;
> return(RetVal);
> end function to_std_ulogic_vector;
>
> function from_std_ulogic_vector(L: std_ulogic_vector) return t_packet;
> -- Left as an exercise for the reader, but similar in style with to_std_ulogic_vector


I think I got your message, by writing a to/from pair of functions which
hides the nuances of the type casting and formatting I can simply
manipulate my records.

BTW I did not know the 'range attribute would return (15 downto 12) for
L.add, I was convinced it would simply return a generic (3 downto
0)...thanks for the hint.

 
Reply With Quote
 
KJ
Guest
Posts: n/a
 
      09-05-2013
On Tuesday, September 3, 2013 8:33:16 AM UTC-4, alb wrote:
> On 03/09/2013 13:32, KJ wrote:
> > On Tuesday, September 3, 2013 6:01:28 AM UTC-4, alb wrote:
> > Then presumably you would have defined a record like this...
> >
> > type t_packet is record
> > add: std_ulogic_vector(15 downto 12);
> > crc: std_ulogic_vector(11 downto 11);
> > ext: std_ulogic_vector(10 downto 10);
> > len: std_ulogic_vector(9 downto 0);
> > end record;

>
>
> That is more or less where I was aiming to, but I would have preferred
> to define the len element as an integer (or even better a natural) instead.
> At that point I believe that in to_std_ulogic_vector I could change this:
>
> - RetVal(L.len'range) := L.len;
>
> into something along these lines:
>
> - RetVal(log2(L.len'length) downto 0) := to_unsigned(L.len, ???);
>
> uhm... I'm again lost!
>


While you can put other data types in, one of the whole points of this is to
come up with a generic type that can be passsed through any conduit. In this
case, the generic type is 'std_ulogic_vector'. The 'conduit' is anything that
you want that is generic in nature but you need for your application. A couple
examples would be memory or a fifo or even an interconnect interface. You don't
need to write the code for a memory to store your t_packets when you already have
one that is debugged and works for std_logic_vector or std_ulogic_vector. All
you have to do to reuse that working component is convert to a vector. If you
put those to/from vector conversion functions right at the input/output of that
conduit you would typically not need to worry very often about just which bit
in the memory is used to represent a particular field.

Even something simple like 'ext' which you have as a one bit field. Normally, one
would think to first use 'std_logic/std_ulogic' rather than a one bit wide vector
for this field. However, try writing the to/from functions where you change 'ext'
to something else and you'll find yourself having some trouble expressing the
proper bit position. You can do it, but it won't be as clean as what I've shown.
By making it a vector and putting that right in the record you've documented it
precisely and portably.

The only manual check you have here is that you don't double up and assign
the same bit to multiple fields. A big plus is that the to/from conversion
functions get written once and would be put into the same package as the record
so when the bits in that record get packed differently you're editing one file. No
edits are needed when simply changing the bit definitions, only if you add/remove
fields.


> Actually your example triggers another question: why std_ulogic_vector
> and not a bit_vector? At the packet definition level I do not really
> need the 'Z', 'W', 'L'... values of the type.


I like std_ulogic because of the metavalues. You never know where you're going to
reuse something and debugging why some signal is unknown will almost always be
fixing a design error. Using bit_vector you can fool yourself into thinking that
something is designed correctly when you're actually dependent on the simulator's
initialization of that bit_vector which may or may not agree with what the hardware
is actually doing.

Kevin Jennings

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
c++ as choice for long term application choice. miles.jg C++ 16 11-14-2007 03:43 PM
implementing a scheme-like interpreter in Java - data type choice metaperl Java 0 08-22-2007 05:34 PM
The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value. luna ASP .Net 1 02-13-2004 01:15 PM
Can Choice components respond to keyboard input like HTML Choice components? Mickey Segal Java 0 02-02-2004 10:59 PM
Choice of DHCP-server? Is the "IOS-one" a good choice? Fred Cisco 1 12-11-2003 06:25 AM



Advertisments