How to write a record to memory and get it back in VHDL?

感情迁移 提交于 2020-01-17 07:21:48

问题


In VHDL pseudo-code what I would like to achieve is:

type tTest is record
    A : std_logic_vector(3 downto 0);
    B : std_logic_vector(7 downto 0);
    C : std_logic_vector(0 downto 0);
end record tTest;
. . . 
signal sTestIn       : tTest;
signal sMemWrData    : std_logic_vector(fRecordLen(tTest)-1 downto 0);
signal sMemRdData    : std_logic_vector(fRecordLen(tTest)-1 downto 0);
signal sTestOut      : tTest;
. . .
sMemWrData <= fRecordToVector(sTestIn);
-- At some point sMemRdData gets the data in sMemWrData...
sTestOut <= fVectorToRecord(sMemRdData);

fRecordLen is an imaginary function that returns the aggregate length of record directly from the type and fRecordToVector and fVectorToRecord are hopefully self explanatory. The target is synthesizable code that doesn't produce any extra logic. I post my current solution as an answer to further clarify the operation. However this is extremely awkward method and I don't consider it as a feasible solution due to the amount of boiler plate code.

I am aware of record introspection proposal but not holding my breath and even the proposed method seems very cumbersome.

I've given up hope for a fully general solution, so some concessions are more than acceptable. For example, allow only std_logic_vectors in the record and use several function/procedure calls. However, it would be great to avoid any boiler-plate code that must be hand or external script-adjusted per-record basis.

Also, if any Verilog/SystemVerilog wrappers exist that can input/output the record directly and achieve the same, pointers are extremely welcome.


回答1:


One way to translate data from a vector (a linear array) to a record would be through the use of an aggregate.

library ieee;
use ieee.std_logic_1164.all;

package TestPck is
    subtype A is std_logic_vector (12 downto 9);
    subtype B is std_logic_vector  (8 downto 1);
    subtype C is std_logic_vector  (0 downto 0);
    constant ABC_len: natural := A'length + B'length + C'length;
    type tTest is record
        A:  std_logic_vector (A'RANGE);
        B:  std_logic_vector (B'RANGE);
        C:  std_logic_vector (C'RANGE);
    end record tTest;
    type tTests is array (natural range <>) of tTest;
end package TestPck;

library ieee;
use ieee.std_logic_1164.all;
use work.TestPck.all;

entity tb is
end entity tb;

architecture sim of tb is
    signal sTestIn:        tTest;
    signal sMemWrData:     std_logic_vector(ABC_len - 1 downto 0);
    signal sMemRdData:     std_logic_vector(ABC_len - 1 downto 0);
    signal sTestOut:       tTest;
    constant tests:        tTests (0 to 1) :=  
             (0 => (x"E", x"A7", "1"), 1 => (x"7", x"AC", "0"));
begin
    sMemWrData <= sTestIn.A & sTestIn.B & sTestIn.C;
    sMemRdData <= sMemWrData after 5 ns;
    sTestOut <= 
        tTest'(sMemRdData(A'range), sMemRdData(B'range), SMemRdData(C'range));
process is
    begin
        wait for 10 ns;
        sTestIn <= tests(0);
        wait for 10 ns;
        sTestIn <= tests(1);
        wait for 10 ns;
        wait;
    end process;
end architecture sim;

The qualified expression defines the aggregate as a value of tTest record with positional association which is assigned to the record type sTestOut.

And this gives:

So you can use concatenation for assembling a vector value (or an aggregate in -2008) and use an aggregate as a qualified expression to transfer sMemRdData to sTestOut.

If you have no plans to declare an object of an A, B or C subtype you can declare them as integer subtypes:

library ieee;
use ieee.std_logic_1164.all;

package TestPck is
    subtype A is natural range 12 downto 9;
    subtype B is natural range  8 downto 1;
    subtype C is natural range  0 downto 0;
    constant ABC_len: natural := A'left + 1;
    type tTest is record
        A:  std_logic_vector (A);
        B:  std_logic_vector (B);
        C:  std_logic_vector (C);
    end record tTest;
    type tTests is array (natural range <>) of tTest;
end package TestPck;

library ieee;
use ieee.std_logic_1164.all;
use work.TestPck.all;

entity tb is
end entity tb;

architecture sim of tb is
    signal sTestIn:        tTest;
    signal sMemWrData:     std_logic_vector(ABC_len - 1 downto 0);
    signal sMemRdData:     std_logic_vector(ABC_len - 1 downto 0);
    signal sTestOut:       tTest;
    constant tests:        tTests (0 to 1) :=  
             (0 => (x"E", x"A7", "1"), 1 => (x"7", x"AC", "0"));
begin
    sMemWrData <= sTestIn.A & sTestIn.B & sTestIn.C;
    sMemRdData <= sMemWrData after 5 ns;
    sTestOut <= 
        tTest'(sMemRdData(A), sMemRdData(B), SMemRdData(C));
process is
    begin
        wait for 10 ns;
        sTestIn <= tests(0);
        wait for 10 ns;
        sTestIn <= tests(1);
        wait for 10 ns;
        wait;
    end process;
end architecture sim;

This may be a little easier to read. It'll produce the same waveform above.




回答2:


This a one way to achieve what is requested. The shortcomings/improvement ideas are in the comments.

library ieee;
use ieee.std_logic_1164.all;
package TestPck is
    type tTest is record
        A : std_logic_vector(3 downto 0);
        B : std_logic_vector(7 downto 0);
        C : std_logic_vector(0 downto 0);
    end record tTest;
    procedure pSliceToFrom (
        signal vec_to   : out   std_logic_vector;
        signal vec_from : in    std_logic_vector;
        position        : inout integer
    );
end package TestPck;

package body TestPck is
  procedure pSliceToFrom (
    signal vec_to   : out   std_logic_vector;
    signal vec_from : in    std_logic_vector;
    position        : inout integer
    ) is
  begin
    vec_to   <= vec_from(position-1 downto position-vec_to'length);
    position := position-vec_to'length;
  end pSliceToFrom;
end package body TestPck;

library ieee;
use ieee.std_logic_1164.all;
use work.TestPck.all;

entity tb is
end entity tb;

architecture sim of tb is
  signal sTestIn       : tTest;
  -- How to create this constant in the package, 
  -- i.e. without needing the signal?
  constant cTestLength : integer := sTestIn.A'length + sTestIn.B'length + sTestIn.C'length;
  signal sMemWrData    : std_logic_vector(cTestLength-1 downto 0);
  signal sMemRdData    : std_logic_vector(cTestLength-1 downto 0);
  signal sTestOut      : tTest;
begin
  -- How to make this without needing to know what 
  -- is inside tTest?
  sMemWrData <= sTestIn.A & sTestIn.B & sTestIn.C;
  -- Memory, Fifo, communication link, doesn't matter...
  sMemRdData <= sMemWrData after 5 ns;
  -- How to get the data back without needing this
  -- process (and the procedure)?
  slice_data_to_item : process (all) is
    variable vPosition : integer := 0;
  begin
    vPosition := cTestLength;
    pSliceToFrom(sTestOut.A, sMemRdData, vPosition);
    pSliceToFrom(sTestOut.B, sMemRdData, vPosition);
    pSliceToFrom(sTestOut.C, sMemRdData, vPosition);
  end process slice_data_to_item;

process is
    begin
        wait for 10 ns;
        sTestIn <= (x"E", x"A7", "1");
        wait for 10 ns;
        sTestIn <= (x"7", x"AC", "0");
        wait;
    end process;
end architecture sim;


来源:https://stackoverflow.com/questions/42745104/how-to-write-a-record-to-memory-and-get-it-back-in-vhdl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!