Record Reflection Use Case - To Std_Logic_Vector

So one of the things I frequently have to do is transform record types to and from std_logic_vector. Vendor-provided IP tools (such as dual-clock FIFOs and IP system generators) tend to not work with anything smarter. So I've got a library of functions I use called pack and unpack for all manner of datatypes, the prototypes of which always look like:

procedure pack(target : inout std_logic_vector; idx : inout integer; nd : in std_logic_vector);
procedure pack(target : inout std_logic_vector; idx : inout integer; nd : in std_ulogic);
procedure unpack(source : in std_logic_vector; idx : inout integer; dat : out std_logic_vector);
procedure unpack(source : in std_logic_vector; idx : inout integer; dat : out std_ulogic);

And then the usage model is:

type t_wide_response is record
  data : std_logic_vector(63 downto 0);
 
  resp : unsigned(15 downto 0); -- Response time, 8 ns LSB
  af : std_logic; -- VME cycle failed arbitration
  dtack : std_logic; -- VME cycle completed with DTACK
  berr : std_logic; -- VME cycle completed with BERR
  retry : std_logic; -- VME cycle completed with RETRY
  bto : std_logic; -- VME cycle completed with bus timeout
 
  seq : t_sequence_id; -- Sequence ID from the request.
end record;
subtype t_wide_response_slv is std_logic_vector(89 downto 0);

function TO_SLV(rec : t_wide_response) return t_wide_response_slv is
  variable slv : t_wide_response_slv := (others => 'U');
  variable idx : integer := 0;
begin
  pack(slv, idx, rec.seq);
  pack(slv, idx, rec.data);
  pack(slv, idx, rec.resp);
  pack(slv, idx, rec.af);
  pack(slv, idx, rec.dtack);
  pack(slv, idx, rec.berr);
  pack(slv, idx, rec.retry);
  pack(slv, idx, rec.bto);
  return slv;
end function TO_SLV;
 
function TO_RESPONSE(slv : t_wide_response_slv) return t_wide_response is
  variable idx : integer := 0;
  variable rec : t_wide_response;
begin
  unpack(slv, idx, rec.seq);
  unpack(slv, idx, rec.data);
  unpack(slv, idx, rec.resp);
  unpack(slv, idx, rec.af);
  unpack(slv, idx, rec.dtack);
  unpack(slv, idx, rec.berr);
  unpack(slv, idx, rec.retry);
  unpack(slv, idx, rec.bto);
  return rec;
end function TO_RESPONSE;

As you can imagine, this doesn't become in the slightest bit repetitive in projects with lots of various types being passed around.

Ideally, it seems like all this horribleness could be replaced by a generic TO_SLV/TO_RECORD pair, each of which enumerates over the record type and calls the appropriate pack/unpack functions for each contained type. Practically, I'm not sure that's doable without the concept of dynamic types. We may be able to convince the simulation vendors to take up that one. But I can't see even the remotest chance of takeup for synthesis, since I found yesterday that the synthesis tool I'm working around has VHDL-2008 support for neither A) the ?? operator (implicit or explicit) or B) std_ulogic_vector.

To elaborate on why I think this may just not be feasible, let's keep the same example and have the compiler flesh it out at analysis time.

package gen_recslv is generic (type t_record; constant slv_len : positive) is
subtype t_slv is std_logic_vector(slv_len-1 downto 0);
...

package wide_responses is new work.gen_recslv generic map(t_record => t_wide_response; slv_len => 90);

gives us

function TO_RECORD(slv : t_slv) return t_record is [wide_responses.t_slv return wide_responses.t_record] 
  variable idx : integer := 0;
  variable rec : t_record;
begin
  standard_functions.unpack(slv, idx, rec.seq)[std_logic_vector, integer, unsigned];
  standard_functions.unpack(slv, idx, rec.data)[std_logic_vector, integer, std_logic_vector];
  standard_functions.unpack(slv, idx, rec.resp)[std_logic_vector, integer, unsigned];
  standard_functions.unpack(slv, idx, rec.af)[std_logic_vector, integer, std_logic];
  standard_functions.unpack(slv, idx, rec.dtack)[std_logic_vector, integer, std_logic];
  standard_functions.unpack(slv, idx, rec.berr)[std_logic_vector, integer, std_logic];
  standard_functions.unpack(slv, idx, rec.retry)[std_logic_vector, integer, std_logic];
  standard_functions.unpack(slv, idx, rec.bto)[std_logic_vector, integer, std_logic];
  return rec;
end function TO_RESPONSE;

All well and good, but what happens when we try to nest this record into another, a t_verywide_response, and instantiate a verywide_responses package? The specific verywide_responses.TO_RECORD can enumerate the fields, but then it hits a field which is a t_wide_response. The appropriate TO_RECORD is wide_responses.TO_RECORD, but verywide_responses has no way of knowing that.



-- Rob Gaddi - 2016-03-23

Comments


I Attachment Action Size Date Who Comment
Unknown file formatvhd standard_functions.vhd manage 12.2 K 2016-03-23 - 23:37 RobGaddi The package with all the pack/unpack functions, just in case anyone needs it.
Topic revision: r1 - 2016-03-24 - 00:01:41 - RobGaddi
 
Copyright © 2008-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback