问题
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