2010-10-21 58 views
1

假设我有依赖于常量,表示记录部件的矢量长度以下类型定义:“序列化” VHDL记录

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_vector s到把它们进入比如说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_vector而不必诉诸手动编写序列化/反序列化代码?对我来说,了解具体的编码并不重要,因为我在内部使用记录,并且最终的输出格式是明确指定的,并将手动实施。

回答

5

你就不能这样写:

d <= pnt.x & pnt.y; 
+0

哦,好点,谢谢!有时我想知道我能忽略多少!逆操作也可以用类似简洁的方式写入? – distributed 2010-10-21 12:10:35

+0

我想你需要两个分配和属性来“解压”记录。尝试像这样:pnt.x <= d(pnt.x'length-1 downto 0); – Philippe 2010-11-15 15:31:17

1

我通常与记录一起在包中定义的转换功能。

在你的情况,是这样的:

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))); 
+0

嗯,这正是我现在的情况。我尽量保持编码/解码功能非常接近类型定义。你的编码/解码代码写得有点不同,有明确的索引,尽管其含义是相同的。您录制的成员越多,线路获得的时间越长。对于拥有10名成员的记录,这变得笨拙。如果您添加或删除成员,您必须更新您的代码,并且非常谨慎,以便您正确地做到这一点。 – distributed 2010-10-21 13:26:45

+0

对于具有较长成员的大记录,我通常明确定义位区域而不是拼接SLV,即: slv(31 downto 16):= pnt.x; slv(15 downto 0):= pnt.y; 这是使用调整大小函数的地方,如果X和Y的长度不是固定的,那么它可以非常方便: slv(31 downto 16):= std_logic_vector(resize(unsigned(pnt.x,16)); – 2010-10-21 14:48:33

1

尽管目前转换记录载体(反之亦然)的没有正式自动化的方式,这是一个非常普遍的要求。你有两个选择:

  • 定义自己的to_vector和from_vector功能为每个记录类型(繁琐
  • 含有上述类型转换自动生成包(难/容易出错

单调乏味且重复的任务激励您编写脚本以生成代码,这表明语言本身存在缺陷。您可以通过在IEEE工作组中使用活动角色影响next version of the VHDL standard来更改此设置。

2

从讨论采取here

一种合理的方式做到这一点,大的交易记录是提前定义范围的时间是这样的:

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; 
1

我准备了一个脚本,它会自动生成VHDL包,用于在用户定义的re线类型和s td_logic_vector类型。

此脚本的来源在alt.sources组中发布为PUBLIC DOMAIN。 你可以看到http://groups.google.com/group/alt.sources/browse_frm/thread/53ea61208013e9d1或寻找主题“脚本生成VHDL包转换记录类型和std_logic_vector” 如果你想从谷歌档案中解压档案,记得选择“show original”选项。否则Python信号源的缺失将被破坏。