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