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