3

假设我有以下类型定义,它依赖于常量来指示记录成员的向量长度:

type point_t is record
    x: std_logic_vector(X_WIDTH-1 downto 0);
    y: std_logic_vector(Y_WIDTH-1 downto 0); 
end record;

我想将这些类型的记录转换为std_logic_vectors 以将它们放入例如 FIFO 中。目前我正在使用以下代码:

PROCEDURE encodepoint(signal pnt: in point_t;
                      signal d: out std_logic_vector(POINT_ENC_WIDTH-1 downto 0)) is
    variable top: integer := 0;
begin
    top := X_WIDTH-1;
    d(top downto 0) <= pnt.x;

    top := top + Y_WIDTH;
    d(top downto top-X_WIDTH+1) <= sl.y;

    d(d'left downto top+1) <= (others => '0');
end;

这段代码在很多方面都不是最理想的。例如,它要求我始终正确地将 POINT_ENC_WIDTH 设置为一个足够大的值以允许d保存整个序列化记录。它依赖于程序员做非常机械的工作。例如,对于记录的每个成员,例如x,在代码中X_WIDTH出现两次x,一次与下一个成员直接相关,一次与下一个成员相关,y。这很快就会变得乏味。如果我通过添加其他字段来更改记录的定义,我必须同时更新序列化和(非常相似的)反序列化代码,我可能会忘记这一点。当我删除字段时,至少编译器会抱怨。

因此,这引出了我的问题:是否有一种简单、自动化或至少准自动化的方式将 VHDL 记录转换为std_logic_vectors 而无需求助于手动编写的序列化/反序列化代码?知道具体的编码对我来说并不重要,因为我在内部使用记录,并且明确指定了最终输出格式并将手动实现。

4

6 回答 6

6

你不能写这个吗:

d <= pnt.x & pnt.y;
于 2010-10-21T12:07:43.620 回答
3

虽然目前没有将记录转换为向量的官方自动化方法(反之亦然),但这是一个非常普遍的要求。您有 2 个选项:

  • 为每种记录类型定义自己的 to_vector 和 from_vector 函数(乏味
  • 自动生成包含上述类型转换的包(困难/容易出错

激励您编写脚本来生成代码的乏味和重复性任务表明语言本身存在缺陷。您可以通过在 IEEE 工作组中发挥积极作用来改变这一点,并影响VHDL 标准的下一个版本。

于 2011-06-27T09:18:30.940 回答
2

取自这里的讨论

对于大型记录,一种合理的方法是提前定义范围,如下所示:

type t_SPI_DATA_PORT is record
  Data_Size_Minus1: std_ulogic_vector(31 downto 28);
  Done: std_ulogic_vector(27 downto 27);
  Rx_Wait_Timeout: std_ulogic_vector(26 downto 26);
  Rx_Wait_On_Miso: std_ulogic_vector(25 downto 25);
  Sclk_Select: std_ulogic_vector(24 downto 24);
  Reserved: std_ulogic_vector(23 downto 20);
  Hold_Cs: std_ulogic_vector(19 downto 19);
  Cpha: std_ulogic_vector(18 downto 17);
  Cpol: std_ulogic_vector(16 downto 16);
  Data: std_ulogic_vector(15 downto 0);
end record;

然后转换函数如下所示:

function To_Std_ULogic_Vector(L : t_SPI_DATA_PORT) return
  std_ulogic_vector is
    variable RetVal: std_ulogic_vector(31 downto 0);
  begin

    RetVal := (others => '0');
    RetVal(L.Data_Size_Minus1'range) := L.Data_Size_Minus1;
    RetVal(L.Done'range) := L.Done;
    RetVal(L.Rx_Wait_Timeout'range) := L.Rx_Wait_Timeout;
    RetVal(L.Sclk_Select'range) := L.Sclk_Select;
    RetVal(L.Reserved'range) := L.Reserved;
    RetVal(L.Rx_Wait_On_Miso'range) := L.Rx_Wait_On_Miso;
    RetVal(L.Hold_Cs'range) := L.Hold_Cs;
    RetVal(L.Cpha'range) := L.Cpha;
    RetVal(L.Cpol'range) := L.Cpol;
    RetVal(L.Data'range) := L.Data;

    return(RetVal);
end To_Std_ULogic_Vector;

function From_Std_ULogic_Vector(L : std_ulogic_vector) return
  t_SPI_DATA_PORT is
    variable RetVal: t_SPI_DATA_PORT;
    variable Lx: std_ulogic_vector(L'length - 1 downto 0);
  begin
    Lx := L;    
    RetVal.Data_Size_Minus1 := Lx(RetVal.Data_Size_Minus1'range);
    RetVal.Done := Lx(RetVal.Done'range);
    RetVal.Rx_Wait_Timeout := Lx(RetVal.Rx_Wait_Timeout'range);
    RetVal.Sclk_Select := Lx(RetVal.Sclk_Select'range);
    RetVal.Reserved := Lx(RetVal.Reserved'range);
    RetVal.Rx_Wait_On_Miso := Lx(RetVal.Rx_Wait_On_Miso'range);
    RetVal.Hold_Cs := Lx(RetVal.Hold_Cs'range);
    RetVal.Cpha := Lx(RetVal.Cpha'range);
    RetVal.Cpol := Lx(RetVal.Cpol'range);
    RetVal.Data := Lx(RetVal.Data'range);

    return(RetVal);
end From_Std_ULogic_Vector;
于 2012-03-05T18:08:43.950 回答
2

我通常将转换函数与记录一起定义在一个包中。

在您的情况下,类似于:

function point2slv (pnt : point_t) return std_logic_vector is
    variable slv : std_logic_vector(X_WIDTH + Y_WIDTH - 1 downto 0);
begin
    slv :=  pnt.x & pnt.y;
    return slv;
end;

function slv2point (slv : std_logic_vector) return point_t is
    variable pnt : point_t;
begin
    pnt.x     := slv(X_WIDTH + Y_WIDTH - 1 downto Y_WIDTH);
    pnt.y     := slv(Y_WIDTH - 1 downto  0);
    return pnt;
end;

注意:根据您要执行的操作,您可能希望在一侧或另一侧使用预定义的尺寸,以及将填充/剪辑转换为自然长度的函数(即:可能将 X 和 Y 值放入 16或 32 位值)。无符号类型和调整大小功能适用于此:

slv(31 downto 16):=  std_logic_vector(resize(unsigned(pnt.x,16)));
slv(15 downto  0):=  std_logic_vector(resize(unsigned(pnt.7,16)));
于 2010-10-21T13:19:38.893 回答
1

我准备了一个脚本,它会自动生成VHDL用于在用户定义的记录类型和 s 类型之间转换的包td_logic_vector

该脚本的来源PUBLIC DOMAINalt.sources组中发布。您可以查看http://groups.google.com/group/alt.sources/browse_frm/thread/53ea61208013e9d1或查找主题“生成VHDL用于在记录类型和之间转换的包的脚本std_logic_vector”如果您想从谷歌存档,记得选择“ show original”选项。否则Python会损坏源的压痕。

于 2012-03-19T18:19:08.047 回答
0

我又尝试了记录序列化。我相信我的方法更稳健一些。您仍然需要为每种记录类型创建函数,但您不需要提及范围。

假设您需要使用我的包序列化 type_a :

type type_a is record
  a : std_logic_vector(15 downto 0);
  b : std_logic_vector(31 downto 0);
  c : std_logic_vector(7 downto 0);
  d : std_logic_vector(7 downto 0);
end record type_a;

constant type_a_width : integer := 64;

像这样定义两个函数:

use work.SERIALIZE_PKG.all;

function serialize (
     input : type_a)
  return std_logic_vector is
  variable ser : serializer_t(type_a_width-1 downto 0);
  variable r   : std_logic_vector(type_a_width-1 downto 0);
begin  -- function serialize_detectorCacheLine_t
  serialize_init(ser);
  serialize(ser, input.a);
  serialize(ser, input.b);
  serialize(ser, input.c);
  serialize(ser, input.d);
  r := serialize_get(ser);
  return r;
end function serialize;


function deserialize (
     input : std_logic_vector)
  return type_a is
  variable ser : serializer_t(type_a_width-1 downto 0);
  variable r   : type_a;
begin  -- function serialize_detectorCacheLine_t
  ser := serialize_set(input);
  deserialize(ser, r.a);
  deserialize(ser, r.b);
  deserialize(ser, r.c);
  deserialize(ser, r.d);
  return r;
end function deserialize;

然后你可以在这样的代码中使用它:

signal type_a_ser       : std_logic_vector(type_a_width-1 downto 0)       := (others => '0');
signal type_a_in        : type_a;
signal type_a_out       : type_a;
....
type_a_ser       <= serialize(type_a_in);
type_a_out       <= deserialize(type_a_ser);

我在以下位置发布了我的代码和更复杂类型(嵌套记录等)的示例:https ://github.com/gitmodimo/vhdl-serialize

于 2018-10-17T08:47:33.570 回答