VHDL trivia?

Hi folks!

A bit of VHDL trivia.

What I want is the reverse of:

one_hot_gen: for i in 0 to 15 generate begin one_hot(i)

Reply to
Philip Herzog
Loading thread data ...

how about a big case statement ?

case OneHot is when X"0001" => Address Address Address Address Address Address Address Address Address Address Address Address Address Address Address Address

Reply to
jan.kindt

Gets too big if the width grows, and doesn't work with generic widths... :(

- Philip

--
Democracy: Three wolves and a sheep voting on what's
for dinner.
Reply to
Philip Herzog

Hi Philip, Perhaps comp.lang.vhdl might be a better place to ask? HTH., Syms.

Reply to
Symon

What about:

process(one_hot) variable temp : integer range 0 to 15; begin for k in one_hot'range loop if one_hot(k) = '1' then temp

Reply to
Dave

Hi,

Shown below is a HDFS binary to onehot convertor which can generate VHDL or Verilog designs for any width input.

The first one generates a case statement - it's the one I would use if I were writing the code in VHDL and I'd assume it would produce the best implementation. The second one generates a structural implementation using multiplexors and or gates. I wouldn't even consider writing this by hand. However, for a 16 bit onehot input, the case statement version requires 39 luts, while the structural version needs just 12 luts. The difference lies in how the two versions deal with invalid inputs, though I was very surprised at just how big that difference was.

Cheers,

Andy

formatting link

compile:

case statement version, 56 bit one hot input vector, verilog out

structural version, 16 bit one hot input vector, vhdl out

(* binary to one hot circuit, VHDL/Verilog generator and simulator *)

#light open DigitalLogic open Numeric.Ops open Signal

(* convert one hot vector to binary. Behavioural implementation using a case statement. If the one hot vector is invalid (zero or more than one bit is set) then the output is set to zero *) let onehot_to_binary_b onehot = let owidth = width onehot let bwidth = Util.clog2 (owidth-1) let binary = b_wire0 bwidth let match_case n m = [ for i in 0 .. n-1 -> if (n-i-1)=m then "1" else "0" ] |> String.concat "" behave [ b_switch onehot [ for i in { 0 .. owidth-1 } -> b_case (constb (match_case owidth i)) [ binary $== consti bwidth i ] ] ]; binary.q

(* convert one hot vector to binary. Structural implementation using multiplexors. Behaviour is undefined if the one hot vector is invalid - at a rough guess, 0 in 0 out, otherwise the highest set bit is chosen *) let onehot_to_binary_s onehot = let owidth = width onehot in let bwidth = Util.clog2 (owidth-1) in let rec split_and_mux onehot value = match width onehot with | 1 -> consti bwidth value, onehot | n when n>0 ->

let hi,lo = split onehot let (hi,hictrl),(lo,loctrl) = split_and_mux hi (value + width lo), split_and_mux lo value hictrl.mux2(hi, lo), (hictrl ||| loctrl) | _ -> failwith "split_and_mux error" fst (split_and_mux onehot 0)

let argv = #if INTERACTIVE fsi.CommandLineArgs #else Sys.argv #endif

let gen_onehot_to_binary core_type hdl onehot_bits = (* build circuit *) let onehot = input "onehot" onehot_bits let onehot_to_binary = match core_type with | "behave" -> onehot_to_binary_b | "struct" -> onehot_to_binary_s | _ -> failwith "Invalid core type" let write,ext = match hdl with | "vhdl" -> Vhdl.write, ".vhd" | "verilog" -> Verilog.write, ".v" | _ -> failwith "Invalid hdl type" let circuit = [ (onehot_to_binary onehot).output "binary" ] |>

Circuit.create (* write hdl *) Circuit.write_file write "" ("onehot_to_binary_" ^ core_type ^ "_" ^ string_of_int onehot_bits) ext circuit (* simulate *) let sim,data = (Simulator.create circuit).record sim.reset let binary n m = [ for i in 0 .. n-1 -> if (n-i-1)=m then "1" else "0" ] |> String.concat "" for i=0 to onehot_bits-1 do sim.[onehot].b

Reply to
evilkidder

How about

addr_p: process (one_hot) begin address '0'); for i in 1 to 15 loop if one_hot(i) = '1' then address

Reply to
Duane Clark

That, and Dave's similar suggestion, have the feature (drawback? benefit?) that each lower-priority bit must check that all higher-priority bits are zero before asserting its value on to the output. This is typically rather extravagant, and it's unnecessary if you are confident that the one-hot code is indeed one-hot (or, more likely, you don't care what happens if it isn't).

This form will give you much more compact hardware (just a few OR gates) at the expense of being somewhat less clear. And if there is more than one bit of the input "one-hot" code set, it will generate a silly result.

onehot_to_binary: process (onehot) is variable OH: std_logic_vector (one_hot'length-1 downto 0); variable result: unsigned(address'range); begin -- Paranoia: Normalize the onehot vector -- so that you don't care how the original -- was defined. Leftmost bit is number N-1, -- rightmost bit is number 0. OH := onehot; -- start the OR-tree result := (others => '0'); -- build the OR-tree for i in OH'range loop if OH(i) = '1' then result := result OR to_unsigned(i, result'length); end if; end loop; -- copy result to your output signal address onehot'length report "Address not big enough to fit onehot value" severity failure; sounds good to me.

--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
 Click to see the full signature
Reply to
Jonathan Bromley

See my response to Duane Clark, later in the thread, for a direct answer.

HOWEVER... two fairly serious nitpicks with your decoder design.

1) Break the bad habit of using nasty obsolete flaky arithmetic packages, and switch to NUMERIC_STD. Then your CONV_INTEGER function (to integer? from integer) becomes TO_INTEGER, and correctly requires "address" to be UNSIGNED. 2) The generate loop is unnecessarily obscure, and will simulate more slowly than is necessary. Instead, consider a procedural loop:

-- assumes Address is declared "unsigned" process (address) begin one_hot '0'); for i in one_hot'range loop if address = i then one_hot(i)

Reply to
Jonathan Bromley

The short answer is shown in the VHDL functions below (for an 8 state one hot encoding). Left as an exercise is extension to other bit widths. You'll find that this structure will most likely always result in the minimal synthesized logic representation.

function Encode_OneHots(L: std_ulogic_vector) return std_ulogic_vector is variable RetVal: std_ulogic_vector(2 downto 0); begin RetVal(0) := L(1) xor L(3) xor L(5) xor L(7); RetVal(1) := L(2) xor L(3) xor L(6) xor L(7); RetVal(2) := L(4) xor L(5) xor L(6) xor L(7);

RetVal(0) := L(1) or L(3) or L(5) or L(7); RetVal(1) := L(2) or L(3) or L(6) or L(7); RetVal(2) := L(4) or L(5) or L(6) or L(7);

return(RetVal); end function Encode_OneHots;

function Decode_OneHots(L: std_ulogic_vector) return std_ulogic_vector is variable RetVal: std_ulogic_vector(7 downto 0); begin RetVal := (others => '0'); RetVal(to_integer(unsigned(L))) := '1'; return(RetVal);

The somewhat longer answer is that darn near every time people talk about one-hot encoding it is usually in the context of state machines or enumerated types. In that scenario, one can convert enumerations to/from vectors with the functions shown below. When used in pairs in the correct fashion, the pair results in 0 logic gates synthesized.

type My_Type is (s0, s1, s2, s3, s4, s5, s6, s7);

function To_Std_ULogic_Vector(L: My_Type) return std_ulogic_vector is variable RetVal: std_ulogic_vector(2 downto 0); -- '2' should be log2(My_Type'length) - 1 begin RetVal := std_ulogic_vector(to_unsigned(My_Type'pos(L), RetVal'length)); return(RetVal); end function To_Std_ULogic_Vector;

function From_Std_ULogic_Vector(L: std_ulogic_vector) return My_Type is variable RetVal: My_Type; begin RetVal := My_Type'val(to_integer(unsigned(L))); return(RetVal); end function From_Std_ULogic_Vector;

For an even deeper understanding of the problem about why working directly with one hots and reversing the decoding is probably not the best approach in the first place, read the side discussion on exactly this topic that starts at link below. That thread will also get into showing why any solution that involves if/elsif/end if; or a case statement will result in a lot of extra logic being generated (as Andy seems to have rediscovered on his last post to your thread).

formatting link

That whole thread is quite long, posts #81-90 cover the gist of what you're asking about (the link above is to #81). 90-100 or so go off on another tangent and there are even more tangents in there as well.

KJ

Reply to
KJ

Jonathan, thanks for tips like that - I'm still looking for a good _current_ reference guide on VHDL (I own the "Designers guide to VHDL

2nd edition", but although it's often recommended, I'm not quite satisfied with it) where you would find stuff like that.

Thanks (also to the others who suggested that), seems that i filed that under "not synthesizable" a few years ago when that was still the fact.

- Philip

--
Have you ever parked your motorcycle in a hotel room?
(+3)
Reply to
Philip Herzog

You could do a similar thing with a generate loop containing a "when" statement - what's the advantage (or downside) to using a process?

- Philip

--
Have you ever parked your motorcycle in a hotel room?
(+3)
Reply to
Philip Herzog

Multiple passes around a generate loop give rise to multiple processes, and therefore to multiple drivers if you try to drive the same signal (even conditionally) from the generate loop's body. A process, on the other hand, constructs only one driver for each signal that it writes; so you can write a signal many times within a process - starting with a "most likely" default, and then progressively mopping-up various special cases in various conditionals - and you still get only one driver. Your "software-like" description has implicitly defined the transfer function of the process.

In fact, I actually *don't* think I could "do a similar thing" with generate... and conditional signal assignment, unless it were to apply hi-Z values when the condition is false.

--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
 Click to see the full signature
Reply to
Jonathan Bromley

Thanks again, Jonathan.

- Philip

--
Have you ever parked your motorcycle in a hotel room?
(+3)
Reply to
Philip Herzog

I'd like to dispute that point.

(** convert one hot vector to binary. "Or" based implementation. Two versions are possible, with the or's composed linearly, or as a tree. *) let one_hot_to_binary_a arity onehot = let owidth = width onehot in let bwidth = clog2 (owidth-1) in if arity r ||| onehot.[i].mux2(consti bwidth i, 0), i

+1) (zero bwidth, 1) [ 1 .. owidth-1 ]) else tree arity (fun x -> reduce_1 (|||) x) [ for i in 0 .. owidth-1 -> onehot.[i].mux2(consti bwidth i, 0) ]

(* The or-tree version with an arity of 4 produces the smallest circuit, so that's the default. Just or'ing everything together without a tree structure (arity No, I don't like it either. I like it better than

Obscure, maybe, but not necessarily without value ;-)

Cheers,

Andy.

Reply to
evilkidder

|-----------------------------------------------------------------------| |"Jonathan Bromley wrote: | |> 1) Break the bad habit of using nasty obsolete flaky | |> arithmetic packages, and switch to NUMERIC_STD. | | | |Jonathan, thanks for tips like that - I'm still looking for a good | |_current_ reference guide on VHDL (I own the "Designers guide to VHDL | |2nd edition", but although it's often recommended, I'm not quite | |satisfied with it) where you would find stuff like that. | | | |[..]" | |-----------------------------------------------------------------------|

The standard packages are documented in recent versions of P1076 (the VHDL Language Reference Manual). Read it, really. Many people who specialize in VHDL but do not care about VHDL seem to have not bothered to read the standard.

Reply to
Colin Paul Gloster

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.