2d65aa2a7c60535205fac491618a826a92265809
[DuneNvme.git] / sim / testbench / test020-write.vhd
1 --------------------------------------------------------------------------------
2 --      Test020-write.vhd       Simple nvme interface tests
3 --      T.Barnaby,      Beam Ltd.       2020-05-12
4 --------------------------------------------------------------------------------
5 --
6 --
7 --
8 library ieee ;
9 use ieee.std_logic_1164.all;
10 use ieee.numeric_std.all;
11
12 library work;
13 use work.NvmeStoragePkg.all;
14 use work.NvmeStorageIntPkg.all;
15 use work.TestPkg.all;
16
17 entity Test is
18 end;
19
20 architecture sim of Test is
21
22 --constant BlockSize    : integer := 512;                       --! For simple testing should be 4096
23 constant BlockSize      : integer := 4096;                      --! Proper block size
24
25 component NvmeStorage is
26 generic(
27         Simulate        : boolean       := True;                --! Generate simulation core
28         --ClockPeriod   : time          := 10 ms;               --! Clock period for timers (125 MHz)
29         ClockPeriod     : time          := 8 ns;                        --! Clock period for timers (125 MHz)
30         BlockSize       : integer       := Blocksize
31 );
32 port (
33         clk             : in std_logic;                         --! The interface clock line
34         reset           : in std_logic;                         --! The active high reset line
35
36         -- Control and status interface
37         axilIn          : in AxilToSlaveType;                   --! Axil bus input signals
38         axilOut         : out AxilToMasterType;                 --! Axil bus output signals
39
40         -- From host to NVMe request/reply streams
41         hostSend        : in AxisType;                          --! Host request stream
42         hostSendReady   : out std_logic;                        --! Host request stream ready line
43         hostRecv        : out AxisType;                         --! Host reply stream
44         hostRecvReady   : in std_logic;                         --! Host reply stream ready line
45
46         -- AXIS data stream input
47         dataEnabledOut  : out std_logic;                        --! Indicates that data ingest is enabled
48         dataIn          : in AxisDataStreamType;                --! Raw data input stream
49         dataIn_ready    : out std_logic;                        --! Raw data input ready
50
51         -- NVMe interface
52         nvme_clk_p      : in std_logic;                         --! Nvme external clock +ve
53         nvme_clk_n      : in std_logic;                         --! Nvme external clock -ve
54         nvme_reset_n    : out std_logic;                        --! Nvme reset output to reset NVMe devices
55
56         nvme0_exp_txp   : out std_logic_vector(3 downto 0);     --! Nvme0 PCIe TX plus lanes
57         nvme0_exp_txn   : out std_logic_vector(3 downto 0);     --! Nvme0 PCIe TX minus lanes
58         nvme0_exp_rxp   : in std_logic_vector(3 downto 0);      --! Nvme0 PCIe RX plus lanes
59         nvme0_exp_rxn   : in std_logic_vector(3 downto 0);      --! Nvme0 PCIe RX minus lanes
60
61         nvme1_exp_txp   : out std_logic_vector(3 downto 0);     --! Nvme1 PCIe TX plus lanes
62         nvme1_exp_txn   : out std_logic_vector(3 downto 0);     --! Nvme1 PCIe TX minus lanes
63         nvme1_exp_rxp   : in std_logic_vector(3 downto 0);      --! Nvme1 PCIe RX plus lanes
64         nvme1_exp_rxn   : in std_logic_vector(3 downto 0);      --! Nvme1 PCIe RX minus lanes
65
66
67         -- Debug
68         leds            : out std_logic_vector(5 downto 0)
69 );
70 end component;
71
72 component TestData is
73 generic(
74         BlockSize       : integer := BlockSize                  --! The block size in Bytes.
75 );
76 port (
77         clk             : in std_logic;                         --! The interface clock line
78         reset           : in std_logic;                         --! The active high reset line
79
80         -- Control and status interface
81         enable          : in std_logic;                         --! Enable production of data
82
83         -- AXIS data output
84         dataOut         : out AxisDataStreamType;               --! Output data stream
85         dataOutReady    : in std_logic
86 );
87 end component;
88
89 component PcieStreamMux is
90 port (
91         clk             : in std_logic;                         --! The interface clock line
92         reset           : in std_logic;                         --! The active high reset line
93         
94         stream1In       : inout AxisStreamType := AxisStreamInput;      --! Single multiplexed Input stream
95         stream1Out      : inout AxisStreamType := AxisStreamOutput;     --! Single multiplexed Ouput stream
96
97         stream2In       : inout AxisStreamType := AxisStreamInput;      --! Host Replies input stream
98         stream2Out      : inout AxisStreamType := AxisStreamOutput;     --! Host Requests output stream
99
100         stream3In       : inout AxisStreamType := AxisStreamInput;      --! Nvme Requests input stream
101         stream3Out      : inout AxisStreamType := AxisStreamOutput      --! Nvme replies output stream
102 );
103 end component;
104
105 constant TCQ            : time := 1 ns;
106 constant CHUNK_SIZE     : integer := 32;                        -- The data write chunk size in DWords due to PCIe packet size limitations
107
108 signal clk              : std_logic := '0';
109 signal reset            : std_logic := '0';
110
111 signal axil             : AxilBusType;
112 signal hostSend         : AxisType;
113 signal hostSendReady    : std_logic := '0';
114 signal hostRecv         : AxisType;
115 signal hostRecvReady    : std_logic := '0';
116
117 signal leds             : std_logic_vector(5 downto 0);
118
119 signal hostSend1        : AxisStreamType;
120 signal hostRecv1        : AxisStreamType;
121 signal hostReply        : AxisStreamType := AxisStreamInput;
122 signal hostReq          : AxisStreamType := AxisStreamOutput;
123 signal nvmeReq          : AxisStreamType := AxisStreamInput;
124 signal nvmeReply        : AxisStreamType := AxisStreamOutput;
125
126 signal dataStream       : AxisDataStreamType;
127 signal dataStreamReady  : std_logic := '0';
128
129 type NvmeStateType is (NVME_STATE_IDLE, NVME_STATE_WRITEDATA, NVME_STATE_READHEAD, NVME_STATE_READDATA);
130 signal nvmeState        : NvmeStateType := NVME_STATE_IDLE;
131 signal nvmeRequestHead  : PcieRequestHeadType;
132 signal nvmeRequestHead1 : PcieRequestHeadType;
133 signal nvmeReplyHead    : PcieReplyHeadType;
134 signal nvmeCount        : unsigned(10 downto 0);                        -- DWord data send count
135 signal nvmeChunkCount   : unsigned(10 downto 0);                        -- DWord data send within a chunk count
136 signal nvmeData         : std_logic_vector(127 downto 0);
137 signal nvmeData1        : std_logic_vector(127 downto 0);
138
139 signal sendData         : std_logic := '0';
140
141 begin
142         clock : process
143         begin
144                 wait for 5 ns; clk  <= not clk;
145         end process clock;
146
147         init : process
148         begin
149                 reset   <= '1';
150                 wait for 20 ns;
151                 reset   <= '0';
152                 wait;
153         end process;
154         
155
156         stop : process
157         begin
158                 --wait for 400 ns;
159                 wait for 14000 ns;
160                 assert false report "simulation ended ok" severity failure;
161         end process;
162
163         run : process
164         begin
165                 axil.toSlave <= ((others => '0'), (others => '0'), '0', (others => '0'), (others => '0'), '0', '0', (others => '0'), (others => '0'), '0', '0');
166                 wait until reset = '0';
167
168                 if(False) then
169                         -- Test Read/Write NvmeStorageUnit's registers
170                         wait for 100 ns;
171                         busWrite(clk, axil.toSlave, axil.toMaster, 16#0004#, 16#40000000#);
172                         busWrite(clk, axil.toSlave, axil.toMaster, 16#0204#, 16#48000000#);
173                         busRead(clk, axil.toSlave, axil.toMaster, 16#0000#);
174                         busRead(clk, axil.toSlave, axil.toMaster, 16#0004#);
175                         busRead(clk, axil.toSlave, axil.toMaster, 16#0204#);
176
177                         wait;
178                 end if;
179                 
180                 if(False) then
181                         -- Test Read/Write NvmeWrite registers
182                         wait for 100 ns;
183                         busRead(clk, axil.toSlave, axil.toMaster, 16#0040#);
184                         busRead(clk, axil.toSlave, axil.toMaster, 16#0044#);
185                         busWrite(clk, axil.toSlave, axil.toMaster, 16#0040#, 16#00000004#);
186                         busRead(clk, axil.toSlave, axil.toMaster, 16#0040#);
187
188                         wait;
189                 end if;
190                 
191                 if(False) then
192                         -- Perform local reset
193                         wait for 100 ns;
194                         busWrite(clk, axil.toSlave, axil.toMaster, 4, 16#00000001#);
195                         busRead(clk, axil.toSlave, axil.toMaster, 16#0000#);
196                         busRead(clk, axil.toSlave, axil.toMaster, 16#0008#);
197                         busRead(clk, axil.toSlave, axil.toMaster, 16#0008#);
198                         wait for 200 ns;
199                         busRead(clk, axil.toSlave, axil.toMaster, 16#0008#);
200                 end if;
201                 
202                 if(False) then
203                         -- Start off TestData source and start writing data to Nvme
204                         wait for 100 ns;
205                         sendData <= '1';
206
207                         -- Write to NvmeStorage control register to start NvmeWrite processing
208                         wait for 100 ns;
209                         --busWrite(clk, axil.toSlave, axil.toMaster, 16#0144#, 2);              -- Number of blocks
210                         busWrite(clk, axil.toSlave, axil.toMaster, 16#0144#, 16);               -- Number of blocks
211                         busWrite(clk, axil.toSlave, axil.toMaster, 16#0104#, 16#00000004#);     -- Start
212
213                         wait for 11000 ns;
214                         --busWrite(clk, axil.toSlave, axil.toMaster, 16#0104#, 16#00000000#);   -- Stop
215                         --busWrite(clk, axil.toSlave, axil.toMaster, 16#0104#, 16#00000004#);   -- Start
216                         wait;   
217                 end if;
218                 
219                 if(True) then
220                         -- Start off Reading data from block 8
221                         wait for 100 ns;
222
223                         busWrite(clk, axil.toSlave, axil.toMaster, 16#0188#, 8);                -- Start blocks
224                         busWrite(clk, axil.toSlave, axil.toMaster, 16#018C#, 2);                -- Number blocks
225                         busRead(clk, axil.toSlave, axil.toMaster, 16#0188#);
226
227                         busWrite(clk, axil.toSlave, axil.toMaster, 16#0180#, 16#00000001#);     -- Start
228
229                         wait for 11000 ns;
230                         --busWrite(clk, axil.toSlave, axil.toMaster, 16#0180#, 16#00000000#);   -- Stop
231                         wait;   
232                 end if;
233                 
234                 if(False) then
235                         -- Send command to IO queue to read a block
236                         wait for 100 ns;
237
238                         -- Write to DataQueue
239                         pcieRequestWriteHead(clk, hostReq, 1, 1, 16#02020000#, 16#22#, 16);
240
241                         wait until rising_edge(clk) and (hostReq.ready = '1');
242                         hostReq.data <= zeros(64) & x"00000001" & x"01000002";  -- Namespace 1, From stream1, opcode 2
243                         wait until rising_edge(clk) and (hostReq.ready = '1');
244                         hostReq.data <= zeros(32) & x"01800000" & zeros(64);    -- Data source address to host
245                         wait until rising_edge(clk) and (hostReq.ready = '1');
246                         hostReq.data <= zeros(32) & x"00000000" & zeros(64);    -- Block number
247                         wait until rising_edge(clk) and (hostReq.ready = '1');
248                         hostReq.data <= zeros(96) & to_stl(0, 32);              -- WriteMethod, NumBlocks (0 is 1 block)
249                         hostReq.last <= '1';
250                         wait until rising_edge(clk) and (hostReq.ready = '1');
251                         hostReq.last <= '0';
252                         hostReq.valid <= '0';
253                         
254                         wait;
255                 end if;
256
257                 --wait for 1000 ns;
258                 
259                 -- Perform local reset
260                 --busWrite(clk, axil.toSlave, axil.toMaster, 4, 16#00000001#);
261                 --wait for 1000 ns;
262
263                 -- Set PCIe configuration command register to 0x06
264                 --pcieRequestWrite(clk, hostReq, 1, 10, 4, 16#44#, 1, 16#00100006#);
265                 
266                 -- Read PCIe configuration command register
267                 --pcieRequestRead(clk, hostReq, 1, 8, 4, 16#55#, 1);
268                 
269                 -- Test Mux with Write to Nvmeregister 0
270                 --pcieRequestWrite(clk, hostReq, 1, 1, 16#0000#, 16#22#, 1, 16#40#);
271
272                 -- Write to AdminQueue doorbell register
273                 --pcieRequestWrite(clk, hostReq, 1, 1, 16#1000#, 16#22#, 1, 16#40#);
274
275                 -- Write to AdminQueue
276                 --pcieRequestWrite(clk, hostReq, 1, 1, 16#02000000#, 16#22#, 16, 16#00000010#);
277
278                 -- Write to DataQueue
279                 --pcieRequestWrite(clk, hostReq, 1, 1, 16#02010000#, 16#22#, 16, 16#00000010#);
280
281                 -- Perform NVMe data write
282                 -- Write to DataWriteQueue doorbell register
283                 --pcieRequestWrite(clk, hostReq, 1, 1, 16#1008#, 16#23#, 1, 16#40#);
284                 wait;
285         end process;
286         
287         -- The test data interface
288         testData0 : TestData
289         port map (
290                 clk             => clk,
291                 reset           => reset,
292
293                 enable          => sendData,
294
295                 dataOut         => dataStream,
296                 dataOutReady    => dataStreamReady
297         );      
298
299         axisConnect(hostSend, hostSendReady, hostSend1);
300         axisConnect(hostRecv1, hostRecv, hostrecvReady);
301         
302         hostReply.ready <= '1';
303         
304         NvmeStorage0 : NvmeStorage
305         port map (
306                 clk             => clk,
307                 reset           => reset,
308
309                 axilIn          => axil.toSlave,
310                 axilOut         => axil.toMaster,
311
312                 hostSend        => hostSend,
313                 hostSendReady   => hostSendReady,
314                 hostRecv        => hostRecv,
315                 hostRecvReady   => hostRecvReady,
316                 
317                 dataIn          => dataStream,
318                 dataIn_ready    => dataStreamReady,
319
320                 -- NVMe interface
321                 nvme_clk_p      => '0',
322                 nvme_clk_n      => '0',
323
324                 --nvme0_exp_txp : out std_logic_vector(0 downto 0);
325                 --nvme0_exp_txn : out std_logic_vector(0 downto 0);
326                 nvme0_exp_rxp   => "0000",
327                 nvme0_exp_rxn   => "0000",
328
329                 --nvme1_exp_txp : out std_logic_vector(0 downto 0);
330                 --nvme1_exp_txn : out std_logic_vector(0 downto 0);
331                 nvme1_exp_rxp   => "0000",
332                 nvme1_exp_rxn   => "0000",
333
334                 leds            => leds
335         );
336
337         -- Host to Nvme stream Mux/DeMux
338         pcieStreamMux0 : PcieStreamMux
339         port map (
340                 clk             => clk,
341                 reset           => reset,
342
343                 stream1In       => hostRecv1,
344                 stream1Out      => hostSend1,
345                 
346                 stream2In       => nvmeReply,
347                 stream2Out      => nvmeReq,
348
349                 stream3In       => hostReq,
350                 stream3Out      => hostReply
351         );
352
353
354         nvmeRequestHead <= to_PcieRequestHeadType(nvmeReq.data);
355         nvmeReply.data <= nvmeData(31 downto 0) & to_stl(nvmeReplyHead) when(nvmeState = NVME_STATE_READHEAD)
356                 else nvmeData(31 downto 0) & nvmeData1(127 downto 32);
357         
358         requests : process(clk)
359         begin
360                 if(rising_edge(clk)) then
361                         if(reset = '1') then
362                                 nvmeReq.ready   <= '0';
363                                 nvmeReply.valid <= '0';
364                                 nvmeReply.last  <= '0';
365                                 nvmeReply.keep  <= (others => '1');
366                                 nvmeData        <= (others => '0');
367                                 nvmeState       <= NVME_STATE_IDLE;
368                         else
369                                 case (nvmeState) is
370                                 when NVME_STATE_IDLE =>
371                                         if(nvmeReq.ready = '1' and nvmeReq.valid = '1') then
372                                                 nvmeRequestHead1        <= nvmeRequestHead;
373                                                 nvmeCount               <= nvmeRequestHead.count;
374
375                                                 if(nvmeRequestHead.request = 1) then
376                                                         nvmeState <= NVME_STATE_WRITEDATA;
377                                                 elsif(nvmeRequestHead.request = 0) then
378                                                         nvmeState <= NVME_STATE_READHEAD;
379                                                 end if;
380                                         else
381                                                 nvmeReq.ready <= '1';
382                                         end if;
383
384                                 when NVME_STATE_WRITEDATA =>
385                                         if((nvmeReq.ready = '1') and (nvmeReq.valid = '1') and (nvmeReq.last = '1')) then
386                                                 nvmeState <= NVME_STATE_IDLE;
387                                         end if;
388                                 
389                                 
390                                 when NVME_STATE_READHEAD =>
391                                         nvmeReq.ready                   <= '0';
392                                         nvmeReplyHead.byteCount         <= nvmeCount & "00";
393                                         nvmeReplyHead.address           <= nvmeRequestHead1.address(nvmeReplyHead.address'length - 1 downto 0);
394                                         nvmeReplyHead.error             <= (others => '0');
395                                         nvmeReplyHead.status            <= (others => '0');
396                                         nvmeReplyHead.tag               <= nvmeRequestHead1.tag;
397                                         nvmeReplyHead.requesterId       <= nvmeRequestHead1.requesterId;
398
399                                         if(nvmeCount > CHUNK_SIZE) then
400                                                 nvmeReplyHead.count     <= to_unsigned(PcieMaxPayloadSize, nvmeReplyHead.count'length);
401                                                 nvmeChunkCount          <= to_unsigned(PcieMaxPayloadSize, nvmeReplyHead.count'length);
402                                         else
403                                                 nvmeReplyHead.count     <= nvmeCount;
404                                                 nvmeChunkCount          <= nvmeCount;
405                                         end if;
406                                         
407                                         nvmeData1               <= nvmeData;
408                                         nvmeReply.keep          <= (others => '1');
409                                         nvmeReply.valid         <= '1';
410
411                                         if(nvmeReply.ready = '1' and nvmeReply.valid = '1') then
412                                                 nvmeData        <= std_logic_vector(unsigned(nvmeData) + 1);
413                                                 nvmeState       <= NVME_STATE_READDATA;
414                                         end if;
415
416                                 when NVME_STATE_READDATA =>
417                                         if(nvmeReply.ready = '1' and nvmeReply.valid = '1') then
418                                                 nvmeData1       <= nvmeData;
419                                                 nvmeData        <= std_logic_vector(unsigned(nvmeData) + 1);
420
421                                                 if(nvmeChunkCount = 4) then
422                                                         nvmeReply.last  <= '0';
423                                                         nvmeReply.valid <= '0';
424
425                                                         if(nvmeCount = 4) then
426                                                                 nvmeState       <= NVME_STATE_IDLE;
427                                                         else
428                                                                 nvmeState       <= NVME_STATE_READHEAD;
429                                                         end if;
430
431                                                 elsif(nvmeChunkCount = 8) then
432                                                         nvmeReply.keep <= zeros(4) & ones(12);
433                                                         nvmeReply.last <= '1';
434
435                                                 else
436                                                         nvmeReply.last <= '0';
437                                                 end if;
438                                                 
439                                                 nvmeChunkCount                  <= nvmeChunkCount - 4;
440                                                 nvmeCount                       <= nvmeCount - 4;
441                                                 nvmeRequestHead1.address        <= nvmeRequestHead1.address + 4;
442                                         end if;
443                                 end case;
444                         end if;
445                 end if;
446         end process;
447 end;