Types of bits

Discussion in 'VHDL' started by MikeWhy, May 20, 2012.

  1. MikeWhy

    MikeWhy Guest

    I'm tired, frustrated, and frankly, maybe don't entirely know what I'm
    doing. But what exactly does the type system do for you aside from beat you
    over the head constantly?

    Set that aside for the moment...

    I wrote a recursive function to flatten an array of arrays of bits. It
    synthesizes fine. It should; it's only a bunch of wires. Simulation in ISIM,
    though, is heavily skewed and offset, apparently trying to simulate some
    perceived logic delays.


    subtype byte_t is std_logic_vector(7 downto 0);
    type byte_array_t is array (natural range <>) of byte_t;

    function flatten (foo : byte_array_t) return std_logic_vector;

    ----------------------------
    function flatten (foo : byte_array_t) return std_logic_vector is
    begin
    if (foo'length = 1) then
    return foo(foo'low);
    elsif (foo'ascending) then
    return foo(foo'low) & flatten(foo(foo'low+1 to foo'high));
    else
    return foo(foo'high) & flatten(foo(foo'high-1 downto foo'low));
    end if;
    end function;
    ----------------------------

    I have a matched set for 7-bit and 6-bit words, too. I think I can cut &
    paste a few more variants without imploding. It was the simulation that was
    the last straw.

    It's a bunch of bits. Everything's a bunch of bits. Why oh why can't we have
    tools that understand bits?

    What am I doing wrong?
    MikeWhy, May 20, 2012
    #1
    1. Advertising

  2. MikeWhy

    Tricky Guest

    On Sunday, May 20, 2012 1:55:59 PM UTC+1, MikeWhy wrote:
    > I'm tired, frustrated, and frankly, maybe don't entirely know what I'm
    > doing. But what exactly does the type system do for you aside from beat you
    > over the head constantly?
    >
    > Set that aside for the moment...
    >
    > I wrote a recursive function to flatten an array of arrays of bits. It
    > synthesizes fine. It should; it's only a bunch of wires. Simulation in ISIM,
    > though, is heavily skewed and offset, apparently trying to simulate some
    > perceived logic delays.
    >
    >
    > subtype byte_t is std_logic_vector(7 downto 0);
    > type byte_array_t is array (natural range <>) of byte_t;
    >
    > function flatten (foo : byte_array_t) return std_logic_vector;
    >
    > ----------------------------
    > function flatten (foo : byte_array_t) return std_logic_vector is
    > begin
    > if (foo'length = 1) then
    > return foo(foo'low);
    > elsif (foo'ascending) then
    > return foo(foo'low) & flatten(foo(foo'low+1 to foo'high));
    > else
    > return foo(foo'high) & flatten(foo(foo'high-1 downto foo'low));
    > end if;
    > end function;
    > ----------------------------
    >
    > I have a matched set for 7-bit and 6-bit words, too. I think I can cut &
    > paste a few more variants without imploding. It was the simulation that was
    > the last straw.
    >
    > It's a bunch of bits. Everything's a bunch of bits. Why oh why can't we have
    > tools that understand bits?
    >
    > What am I doing wrong?


    I think the questions is why do you need to flatten it? whats wrong with just having ports of byte_array_t? Thats why we have the type system (so they you use the types as much as possible).

    What exactly are the problems in ISIM? There should be no logic (delta) delays, because you're just assigning one large array.

    or why not simply use a for loop, rather than recursive functions?
    Tricky, May 20, 2012
    #2
    1. Advertising

  3. MikeWhy

    MikeWhy Guest

    "Tricky" <> wrote in message
    news:...
    > On Sunday, May 20, 2012 1:55:59 PM UTC+1, MikeWhy wrote:
    >> I'm tired, frustrated, and frankly, maybe don't entirely know what I'm
    >> doing. But what exactly does the type system do for you aside from beat
    >> you
    >> over the head constantly?
    >>
    >> Set that aside for the moment...
    >>
    >> I wrote a recursive function to flatten an array of arrays of bits. It
    >> synthesizes fine. It should; it's only a bunch of wires. Simulation in
    >> ISIM,
    >> though, is heavily skewed and offset, apparently trying to simulate some
    >> perceived logic delays.
    >>
    >>
    >> subtype byte_t is std_logic_vector(7 downto 0);
    >> type byte_array_t is array (natural range <>) of byte_t;
    >>
    >> function flatten (foo : byte_array_t) return std_logic_vector;
    >>
    >> ----------------------------
    >> function flatten (foo : byte_array_t) return std_logic_vector
    >> is
    >> begin
    >> if (foo'length = 1) then
    >> return foo(foo'low);
    >> elsif (foo'ascending) then
    >> return foo(foo'low) & flatten(foo(foo'low+1 to foo'high));
    >> else
    >> return foo(foo'high) & flatten(foo(foo'high-1 downto
    >> foo'low));
    >> end if;
    >> end function;
    >> ----------------------------
    >>
    >> I have a matched set for 7-bit and 6-bit words, too. I think I can cut &
    >> paste a few more variants without imploding. It was the simulation that
    >> was
    >> the last straw.
    >>
    >> It's a bunch of bits. Everything's a bunch of bits. Why oh why can't we
    >> have
    >> tools that understand bits?
    >>
    >> What am I doing wrong?

    >
    > I think the questions is why do you need to flatten it? whats wrong with
    > just having ports of byte_array_t? Thats why we have the type system (so
    > they you use the types as much as possible).


    A fair enough question. It's being written into a 64-bit wide FIFO. They
    came in as 7-bit words, hence the initial lumped treatment.

    >
    > What exactly are the problems in ISIM? There should be no logic (delta)
    > delays, because you're just assigning one large array.


    The ISIM thing was self-inflicted. A clocked process got hold of the wrong
    clock. Things are happily aligned on clock edges again. ;)

    That's the last time I'll name signals for instantiation ports. I'm sure
    rd_clk and wr_clk were meaningful enough in their original context. They
    lacked the semantic descriptiveness to grab my attention here.

    > or why not simply use a for loop, rather than recursive functions?


    As in:

    for i in foo'range loop
    -- descending
    tmp(dumb_goofy_calc(i) downto other_goofy_calc(i)) := foo(i);
    end loop;
    return tmp;

    Recursing on concatenation saved me a burst blood vessel, from having to
    write yet another pair of dumb_goofy_calc(i) functions. I fear I'll bleed
    from the eyes if I try to write just one more.

    I'd love to hear a better way, preferably without constant reinvention or
    even copy/paste. Recursion is the closest I've come. Just change the formal
    arg type.

    ===========
    All that aside, I write software by day. The above type of wire jiggling is
    almost akin to C++ template meta programming. It's a compile time thing, not
    run-time. C++ has variadic templates, which can do some big magic in the
    right hands. Even simple template parameters for the actual type will make
    this a non-issue. Just write it once, and let it synthesize with the actual
    type passed. That's the key. I find myself continually rewriting noisy,
    tedious things like the above, rather than solving the problem at hand. A
    good language supports its intended use. I don't see that in the type
    system's stubborness.

    I'm thinking the type system saved me once or twice from trying to shove,
    say, 8 bits into some other shaped signal. Meanwhile, I've about wore out
    this keyboard with noisy constructs like
    std_logic_vector(to_unsigned(.....)). I joke that my copy and paste keys
    will break off one day, but the truth is the developing repetitive stress
    injury in those fingers will preclude that.

    I've been building software with various languages for 24 years. I can think
    of only one language so mean spiritedly aggressive about confounding your
    wishes.

    And that was the other, implicit question. A mature perspective will
    obviously have come to terms with the little niggles above. What's the
    magic, the secret to its understanding? Surely it can't be the type system
    that is VHDL's strength.
    MikeWhy, May 20, 2012
    #3
  4. MikeWhy

    Tricky Guest


    >
    > And that was the other, implicit question. A mature perspective will
    > obviously have come to terms with the little niggles above. What's the
    > magic, the secret to its understanding? Surely it can't be the type system
    > that is VHDL's strength.


    IMHO, if you're constantly having to do type conversions, you're doing it wrong. It is intended that you keep signals in the same type for as long as possible. My question is if you have an integer, why are you even making ita std_logic_vector? The only reason I ever convert integers is when I input them into some IP block that only has slv ports, and I dont use them veryoften. Now compilers are very good at handling all types, and even at the top level, as long as you have a bit type, it doesnt complain about mappingthe ports.
    Tricky, May 21, 2012
    #4
  5. MikeWhy

    Andy Guest

    First, about VHDL typing. The first design where you have to do
    unsigned arithmetic in some places, signed in others, and fixed point
    or even floating point (of both signed and unsigned representations)
    in yet others, you'll thank your lucky stars that VHDL has strong
    types. Ditto for big endian and little endian byte vectors, with
    overloaded conversions to unsigned/SLV. No strong types, no
    overloading. Records, arrays, records of arrays, arrays of records:
    all these things make keeping a complex design in focus so much
    easier, and assist & enforce the coding practices that help make your
    design understandable, reviewable and maintainable.

    Hints that help me a lot:

    Once inside the top level (external pin interface) I use unsigned
    almost everywhere instead of std_logic_vector ("unsigned" is less
    typing, and it does more).

    I usually define a "subtype slv is std_logic_vector;" as an
    abbreviation to reduce typing as well ("slv(to_unsigned())"). Note,
    there is a new package in numeric_std for vhdl-2008 that defines
    arithmetic operators that assume an unsigned interpretation of SLV.

    If it works within integer's ~32 bit (signed) range limits in most
    tools, I use subtypes of integer/natural instead.

    Rather than have conditionals handle different range direction/start/
    end on unconstrained arguments, I normalize the argument's range on a
    variable up front, then use the variable instead of the argument:
    variable narg : unsigned(arg'length - 1 downto 0) := arg; --
    normalized arg


    Andy
    Andy, May 21, 2012
    #5
  6. MikeWhy

    Rob Gaddi Guest

    On Sun, 20 May 2012 15:32:37 -0500
    "MikeWhy" <> wrote:

    >
    > And that was the other, implicit question. A mature perspective will
    > obviously have come to terms with the little niggles above. What's the
    > magic, the secret to its understanding? Surely it can't be the type system
    > that is VHDL's strength.
    >


    VHDL's type system has very strong opinions about how it intends to be
    used. Once you've wrapped your head around it, it actively and
    aggressively keeps the barrel of the gun away from your foot.

    My general rule is that a std_logic_vector only gets used to represent
    things that are fundamentally not of a known numeric type (bitmasks,
    Johnson counters, bus data that will have different interpretations
    based on which register it's addressing, etc.) Otherwise it's an
    integer if it can be, a unsigned/signed if it has to be.

    Likewise, anywhere booleans can be used instead of std_logic makes the
    world that much better of a place.

    The only other place to be using sl/slv is when you have to shim in or
    out of someone else's IP. It's to my mind the biggest reason to avoid
    using CoreGens, Megafunctions, and their ilk.

    Other folks have asked you why you aren't just keeping your data in the
    byte array form, but I'd ask the other question: Why try to keep your
    data as a byte array rather than a wide data element like a
    std_logic_vector(63 downto 0)? If you need it to have byte division
    boundaries at different places at different times, then only break it
    up where and as you need to. If you're thinking of it as "just a
    collection of wires", then make it just a collection of wires.

    --
    Rob Gaddi, Highland Technology -- www.highlandtechnology.com
    Email address domain is currently out of order. See above to fix.
    Rob Gaddi, May 21, 2012
    #6
  7. MikeWhy

    MikeWhy Guest

    "Rob Gaddi" <> wrote in message
    news:...
    > On Sun, 20 May 2012 15:32:37 -0500
    > "MikeWhy" <> wrote:
    >
    >>
    >> And that was the other, implicit question. A mature perspective will
    >> obviously have come to terms with the little niggles above. What's the
    >> magic, the secret to its understanding? Surely it can't be the type
    >> system
    >> that is VHDL's strength.
    >>

    >
    > VHDL's type system has very strong opinions about how it intends to be
    > used. Once you've wrapped your head around it, it actively and
    > aggressively keeps the barrel of the gun away from your foot.
    >
    > My general rule is that a std_logic_vector only gets used to represent
    > things that are fundamentally not of a known numeric type (bitmasks,
    > Johnson counters, bus data that will have different interpretations
    > based on which register it's addressing, etc.) Otherwise it's an
    > integer if it can be, a unsigned/signed if it has to be.
    >
    > Likewise, anywhere booleans can be used instead of std_logic makes the
    > world that much better of a place.
    >
    > The only other place to be using sl/slv is when you have to shim in or
    > out of someone else's IP. It's to my mind the biggest reason to avoid
    > using CoreGens, Megafunctions, and their ilk.


    I appreciate the thoughtful responses. All have been very helpful.

    I get it about polarized and segmented "plugs" in physical wiring. That
    there's a ribbon cable in between makes them all the more valuable, not
    less. I totally get that.

    Part of my problem was an innate sense that this "doesn't belong". It wasn't
    entirely a language issue. It was a consequence of where I partitioned the
    modules. Fine. Restrucuturing that was easy. It now reflects some sense of
    order.

    Near the boundaries, I really want LocalLink interfaces, not the constituent
    signals. Internally, I want modules to pass around their own private types.
    Cool. That really helps clean up the module boundaries. That wrong clock
    problem was a big indicator of poor partitioning.

    So, I really want to standardize interfaces between modules. Say, a
    LocalLink port, rather than exposing the constituent signals. One module has
    a LocalLink_out port. Another module has a LocalLink_in port. In between,
    they connect with a LocalLink_x signal. I think that works... I just need 3
    record types.

    Any smooshing, smushing, and reshaping into SLV can be rather well
    contained, if it's needed at all. I like that. They're neatly contained in
    the module that. If they're needed.

    What if I wanted a LocalLink of MyPrivateDataType? Record types have to be
    fully constrained, and don't support generics. Does the concept stop here?
    Do I need to manually rewrap each such type in its own type? I think I'll
    just pass the data part separate from the LocalLink signals. I wish the
    language supported more...

    C++ generics are rather more round and whole in this sense. "template
    <typename data_t> class LocalLink;", and "LocalLink<MyDataType>" connotes
    exactly that. It doesn't seem worthwhile to create a VHDL module to just
    marry the two together, so I expect I'll pass data separate from the control
    sigs.

    > Other folks have asked you why you aren't just keeping your data in the
    > byte array form, but I'd ask the other question: Why try to keep your
    > data as a byte array rather than a wide data element like a
    > std_logic_vector(63 downto 0)? If you need it to have byte division
    > boundaries at different places at different times, then only break it
    > up where and as you need to. If you're thinking of it as "just a
    > collection of wires", then make it just a collection of wires.


    Where do you draw the line between useful abstraction and unnecessary noise?

    The wire protocol is byte oriented. The low 7 bits is data; the high bit
    signifies if it is the last byte of this particular data word. The 7 bits of
    data word are successively shifted into an accumulator until the high bit is
    set. The value can be up to 56 bits wide, or 8 such 7-bit words. The value
    lives in a 56 bit SLV (or, maybe more reasonably, an unsigned). Early in its
    life, it suited me to treat the 56-bit accumulator as an array of 8 7-bit
    words. Is this a useful abstraction? Or is it noise?

    Internally, it kicks around the 56-bit value, along with the word count and
    sign bit, which are needed elsewhere but not easily extracted from the
    stored value. These are then wrapped and tagged with a 4-bit ID to signify
    that it contains this type of value; other value types coexist. The 64-bit
    mess gets flattened into a fifo, and then reconstituted when it comes out
    the other end.

    Since it passes through a phase when it is an SLV, is the abstraction
    useful? Or just noise?

    Similarly, the word width, 56, is largely set in stone by long industry
    practice and also published standards. Is that data word an "slv(55 downto
    0)", or is it really "unsigned(FF_VALUE_WIDTH-1 downto 0)"? Is this a useful
    abtraction? Or is it noise?
    MikeWhy, May 21, 2012
    #7
  8. MikeWhy

    MikeWhy Guest

    "MikeWhy" <> wrote in message
    news:jpe43u$mlg$...
    > So, I really want to standardize interfaces between modules. Say, a
    > LocalLink port, rather than exposing the constituent signals. One module
    > has a LocalLink_out port. Another module has a LocalLink_in port. In
    > between, they connect with a LocalLink_x signal. I think that works... I
    > just need 3 record types.


    It turns out I don't know how to do this. The in/out'ness is specified for
    the port, not in the record field.

    Can this be done? The ports look like this:

    entity foo_ll is
    Port (
    rst : in STD_LOGIC;
    ------------------
    clk_src : in STD_LOGIC;
    src_rdy_in_n : in STD_LOGIC;
    dst_rdy_out_n : out STD_LOGIC;
    din : in STD_LOGIC_VECTOR (7 downto 0);
    sof_in_n : in STD_LOGIC;
    eof_in_n : in STD_LOGIC;
    ------------------
    clk_dst : in STD_LOGIC;
    src_rdy_out_n : out STD_LOGIC;
    dst_rdy_in_n : in STD_LOGIC;
    dout : out STD_LOGIC_VECTOR (7 downto 0);
    sof_out_n : out STD_LOGIC;
    eof_out_n : out STD_LOGIC
    ------------------
    );
    end entity foo_ll;
    ------------------------------
    For the concept to be useful, it needs to look like this:

    entity foo2_ll is
    Port (
    rst : in STD_LOGIC;
    ------------------
    in_ll : XXXX locallink_in;
    out_ll : XXXX locallink_out;
    d_in : in data_t;
    d_out : out data_t;
    );
    end entity foo2_ll;
    --------------------------------
    Instantiation and connectivity:

    signal from_ll, to_ll : locallink_sig;
    signal data_in, data_out : data_t;

    afoo2 : entity work.foo2_ll
    port map (
    rst => rst,
    in_ll => in_ll,
    out_ll => out_ll,
    d_in => data_in;
    d_out => data_out;
    );

    ------
    I don't know how to do this. Can it be done at all? What's the point of a
    type system that doesn't support useful abstraction?
    MikeWhy, May 21, 2012
    #8
  9. MikeWhy

    Rob Gaddi Guest

    On Mon, 21 May 2012 15:01:06 -0500
    "MikeWhy" <> wrote:

    > "MikeWhy" <> wrote in message
    > news:jpe43u$mlg$...
    > > So, I really want to standardize interfaces between modules. Say, a
    > > LocalLink port, rather than exposing the constituent signals. One module
    > > has a LocalLink_out port. Another module has a LocalLink_in port. In
    > > between, they connect with a LocalLink_x signal. I think that works... I
    > > just need 3 record types.

    >
    > It turns out I don't know how to do this. The in/out'ness is specified for
    > the port, not in the record field.
    >
    > Can this be done? The ports look like this:
    >
    > entity foo_ll is
    > Port (
    > rst : in STD_LOGIC;
    > ------------------
    > clk_src : in STD_LOGIC;
    > src_rdy_in_n : in STD_LOGIC;
    > dst_rdy_out_n : out STD_LOGIC;
    > din : in STD_LOGIC_VECTOR (7 downto 0);
    > sof_in_n : in STD_LOGIC;
    > eof_in_n : in STD_LOGIC;
    > ------------------
    > clk_dst : in STD_LOGIC;
    > src_rdy_out_n : out STD_LOGIC;
    > dst_rdy_in_n : in STD_LOGIC;
    > dout : out STD_LOGIC_VECTOR (7 downto 0);
    > sof_out_n : out STD_LOGIC;
    > eof_out_n : out STD_LOGIC
    > ------------------
    > );
    > end entity foo_ll;
    > ------------------------------
    > For the concept to be useful, it needs to look like this:
    >
    > entity foo2_ll is
    > Port (
    > rst : in STD_LOGIC;
    > ------------------
    > in_ll : XXXX locallink_in;
    > out_ll : XXXX locallink_out;
    > d_in : in data_t;
    > d_out : out data_t;
    > );
    > end entity foo2_ll;
    > --------------------------------
    > Instantiation and connectivity:
    >
    > signal from_ll, to_ll : locallink_sig;
    > signal data_in, data_out : data_t;
    >
    > afoo2 : entity work.foo2_ll
    > port map (
    > rst => rst,
    > in_ll => in_ll,
    > out_ll => out_ll,
    > d_in => data_in;
    > d_out => data_out;
    > );
    >
    > ------
    > I don't know how to do this. Can it be done at all? What's the point of a
    > type system that doesn't support useful abstraction?
    >
    >


    When I design WISHBONE systems, I wind up with the following mess o'
    stuff in a file called pkg_global.vhd:

    constant WB_DATA_WIDTH : positive := 32;
    constant WB_ADDR_WIDTH : positive := 15;
    constant WB_SEL_SIZE : positive := 8;
    constant WB_SEL_WIDTH : positive := WB_DATA_WIDTH / WB_SEL_SIZE;

    subtype t_wb_data is std_logic_vector(WB_DATA_WIDTH-1 downto 0);
    subtype t_wb_addr is unsigned(WB_ADDR_WIDTH-1 downto 0);
    subtype t_wb_sel is std_logic_vector(WB_SEL_WIDTH-1 downto 0);

    type t_wb_mosi is record
    DAT : t_wb_data;
    ADDR : t_wb_addr;
    SEL : t_wb_sel;
    WE : std_logic;
    STB : std_logic;
    CYC : std_logic;
    end record;

    type t_wb_miso is record
    DAT : t_wb_data;
    ACK : std_logic;
    BERR : std_logic;
    end record;

    Each slave has a MOSI port coming in and a MISO port coming out. Each
    master has a MISO port coming in and a MOSI port coming out.

    --
    Rob Gaddi, Highland Technology -- www.highlandtechnology.com
    Email address domain is currently out of order. See above to fix.
    Rob Gaddi, May 21, 2012
    #9
  10. MikeWhy

    MikeWhy Guest

    "Rob Gaddi" <> wrote in message
    news:...
    > Each slave has a MOSI port coming in and a MISO port coming out. Each
    > master has a MISO port coming in and a MOSI port coming out.


    That'll work. Thanks. Separate them on signal direction, rather than
    conceptual grouping. (It's still not entirely optimal, but certainly
    pragmatic and far better than what I have.)
    MikeWhy, May 22, 2012
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. GGG
    Replies:
    10
    Views:
    12,511
    Donar
    Jul 6, 2006
  2. sarmin kho
    Replies:
    2
    Views:
    816
    A. Lloyd Flanagan
    Jun 15, 2004
  3. Miki Tebeka
    Replies:
    1
    Views:
    432
    Marcin 'Qrczak' Kowalczyk
    Jun 14, 2004
  4. sergey

    "casting" bits to bits?

    sergey, Nov 8, 2006, in forum: VHDL
    Replies:
    1
    Views:
    690
    sergey
    Nov 8, 2006
  5. Tomás

    Value Bits Vs Object Bits

    Tomás, Jun 2, 2006, in forum: C Programming
    Replies:
    13
    Views:
    534
    Hallvard B Furuseth
    Jul 1, 2006
Loading...

Share This Page