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