Запись "Сериализация" VHDL - PullRequest
3 голосов
/ 21 октября 2010

Предположим, у меня есть следующее определение типа, которое опирается на константы для указания длины вектора членов записи:

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 s без необходимости прибегать к написанию вручную сериализованного / десериализованного кода? Мне не важно знать конкретную кодировку, поскольку я использую записи для внутреннего использования, и окончательный формат вывода четко указан и будет реализован вручную.

Ответы [ 6 ]

5 голосов
/ 21 октября 2010

Не могли бы вы просто написать это:

d <= pnt.x & pnt.y;
2 голосов
/ 05 марта 2012

взято из обсуждения здесь

Один разумный способ сделать это с большими записями - это заранее определить диапазоны следующим образом:

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 голос
/ 19 марта 2012

Я подготовил скрипт, который автоматически генерирует пакет VHDL для преобразований между пользовательским типом записи и типом s td_logic_vector.

Исходники этого скрипта опубликованы как PUBLIC DOMAIN в группе alt.sources. Вы можете посмотреть http://groups.google.com/group/alt.sources/browse_frm/thread/53ea61208013e9d1 или поискать тему "Скрипт для генерации VHDL пакета для преобразования между типом записи и std_logic_vector" Если вы хотите распаковать архив из архива Google, не забудьте выбрать опцию «show original». В противном случае потеря источника Python будет повреждена.

1 голос
/ 27 июня 2011

Хотя в настоящее время нет официального автоматизированного способа преобразования записей в векторы (и наоборот), это очень распространенное требование.У вас есть 2 варианта:

  • Определить свои собственные функции to_vector и from_vector для каждого типа записи ( утомительно )
  • Автогенерация пакетов, содержащих приведенные выше преобразования типов ()сложный / подверженный ошибкам )

Утомительные и повторяющиеся задачи, побуждающие вас написать скрипт для генерации кода, свидетельствуют о недостатке самого языка.Вы можете изменить это, взяв активную роль в рабочей группе IEEE и повлиять на следующую версию стандарта VHDL .

1 голос
/ 21 октября 2010

Обычно я определяю функции преобразования в пакете вместе с записью.

В вашем случае что-то вроде:

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 битовые значения). Тип unsigned и функция изменения размера хорошо работают для этого:

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 голосов
/ 17 октября 2018

Я сделал еще одну попытку сериализации записи.Я считаю, что мой метод немного более надежен.Вам все еще нужно создать функцию для каждого типа записи, но вам не нужно упоминать диапазоны.

Допустим, вам нужно сериализовать 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;

И затем вы можете использовать его в кодеthis:

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

...