Documentation changes.
[DuneNvme.git] / src / NvmeStorageUnit.vhd
1 --------------------------------------------------------------------------------
2 -- NvmeStorageUnit.vhd Nvme storage access module
3 -------------------------------------------------------------------------------
4 --!
5 --! @class      NvmeStorageUnit
6 --! @author     Terry Barnaby (terry.barnaby@beam.ltd.uk)
7 --! @date       2020-05-12
8 --! @version    0.5.1
9 --!
10 --! @brief
11 --! This is the main Nvme control module for a single Nvme device.
12 --!
13 --! @details
14 --! This module manages a single Nvme device. It is controlled via a simple regsiter access interface
15 --! and an optional bi-directional PCIe packet stream.
16 --! An AXI4 data stream, blocked into BlockSize Bytes using the "last" signal, is written sequentially
17 --! to the Nvme device. The DataChunkStart and DataChunkSize registers define the starting block number
18 --! and the number of blocks to write.
19 --! See the NvmeStorageManual for more details.
20 --!
21 --! @copyright GNU GPL License
22 --! Copyright (c) Beam Ltd, All rights reserved. <br>
23 --! This code is free software: you can redistribute it and/or modify
24 --! it under the terms of the GNU General Public License as published by
25 --! the Free Software Foundation, either version 3 of the License, or
26 --! (at your option) any later version.
27 --! This program is distributed in the hope that it will be useful,
28 --! but WITHOUT ANY WARRANTY; without even the implied warranty of
29 --! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30 --! GNU General Public License for more details. <br>
31 --! You should have received a copy of the GNU General Public License
32 --! along with this code. If not, see <https://www.gnu.org/licenses/>.
33 --!
34 library ieee;
35 use ieee.std_logic_1164.all;
36 use ieee.numeric_std.all;
37
38 library unisim;
39 use unisim.vcomponents.all;
40
41 library work;
42 use work.NvmeStoragePkg.all;
43 use work.NvmeStorageIntPkg.all;
44
45 entity NvmeStorageUnit is
46 generic(
47         Simulate        : boolean       := False;               --! Generate simulation core
48         Platform        : string        := "Ultrascale";        --! The underlying target platform
49         ClockPeriod     : time          := 4 ns;                --! Clock period for timers (250 MHz)
50         BlockSize       : integer       := NvmeStorageBlockSize;        --! System block size
51         PcieCore        : integer       := 0;                   --! The Pcie hardblock block to use
52         UseConfigure    : boolean       := False                --! The module configures the Nvme's on reset
53 );
54 port (
55         clk             : in std_logic;                         --! The interface clock line
56         reset           : in std_logic;                         --! The active high reset line
57
58         -- Control and status interface
59         regWrite        : in std_logic;                         --! Enable write to register
60         regAddress      : in unsigned(5 downto 0);              --! Register to read/write
61         regDataIn       : in std_logic_vector(31 downto 0);     --! Register write data
62         regDataOut      : out std_logic_vector(31 downto 0);    --! Register contents
63
64         -- From host to NVMe request/reply streams
65         hostSend        : inout AxisStreamType := AxisStreamInput;      --! Host request stream
66         hostRecv        : inout AxisStreamType := AxisStreamOutput;     --! Host reply stream
67
68         -- AXIS data stream input
69         dataEnabledOut  : out std_logic;                        --! Indicates that data ingest is enabled
70         dataIn          : inout AxisStreamType := AxisStreamInput;      --! Raw data to save stream
71
72         -- NVMe interface
73         nvme_clk        : in std_logic;                         --! Nvme external clock
74         nvme_clk_gt     : in std_logic;                         --! Nvme external GT clock
75         nvme_reset_n    : out std_logic;                        --! Nvme reset output to reset NVMe devices
76
77         nvme_exp_txp    : out std_logic_vector(3 downto 0);     --! nvme PCIe TX plus lanes
78         nvme_exp_txn    : out std_logic_vector(3 downto 0);     --! nvme PCIe TX minus lanes
79         nvme_exp_rxp    : in std_logic_vector(3 downto 0);      --! nvme PCIe RX plus lanes
80         nvme_exp_rxn    : in std_logic_vector(3 downto 0);      --! nvme PCIe RX minus lanes
81
82         -- Debug
83         leds            : out std_logic_vector(2 downto 0)
84 );
85 end;
86
87 architecture Behavioral of NvmeStorageUnit is
88
89 constant TCQ            : time := 1 ns;
90 constant NumStreams     : integer := 8;
91 constant ResetCycles    : integer := (100 ms / ClockPeriod);
92
93 component RegAccessClockConvertor is
94 port (
95         clk1            : in std_logic;                         --! The interface clock line
96         reset1          : in std_logic;                         --! The active high reset line
97         
98         regWrite1       : in std_logic;                         --! Enable write to register
99         regAddress1     : in unsigned(5 downto 0);              --! Register to read/write
100         regDataIn1      : in std_logic_vector(31 downto 0);     --! Register write data
101         regDataOut1     : out std_logic_vector(31 downto 0);    --! Register contents
102
103         clk2            : in std_logic;                         --! The interface clock line
104         reset2          : in std_logic;                         --! The active high reset line
105
106         regWrite2       : out std_logic;                                --! Enable write to register
107         regAddress2     : out unsigned(5 downto 0);             --! Register to read/write
108         regDataIn2      : out std_logic_vector(31 downto 0);    --! Register write data
109         regDataOut2     : in std_logic_vector(31 downto 0)      --! Register contents
110 );
111 end component;
112
113 component AxisClockConverter is
114 generic(
115         Simulate        : boolean       := Simulate
116 );
117 port (
118         clkRx           : in std_logic;
119         resetRx         : in std_logic;
120         streamRx        : inout AxisStreamType := AxisStreamInput;                        
121
122         clkTx           : in std_logic;
123         resetTx         : in std_logic;
124         streamTx        : inout AxisStreamType := AxisStreamOutput
125 );
126 end component;
127
128 --! The PCIe Gen3 hardblock to communicate with the NVMe device
129 component Pcie_nvme0
130 port (
131         pci_exp_txn : out std_logic_vector ( 3 downto 0 );
132         pci_exp_txp : out std_logic_vector ( 3 downto 0 );
133         pci_exp_rxn : in std_logic_vector ( 3 downto 0 );
134         pci_exp_rxp : in std_logic_vector ( 3 downto 0 );
135         user_clk : out std_logic;
136         user_reset : out std_logic;
137         user_lnk_up : out std_logic;
138         s_axis_rq_tdata : in std_logic_vector ( 127 downto 0 );
139         s_axis_rq_tkeep : in std_logic_vector ( 3 downto 0 );
140         s_axis_rq_tlast : in std_logic;
141         s_axis_rq_tready : out std_logic_vector ( 3 downto 0 );
142         s_axis_rq_tuser : in std_logic_vector ( 59 downto 0 );
143         s_axis_rq_tvalid : in std_logic;
144         m_axis_rc_tdata : out std_logic_vector ( 127 downto 0 );
145         m_axis_rc_tkeep : out std_logic_vector ( 3 downto 0 );
146         m_axis_rc_tlast : out std_logic;
147         m_axis_rc_tready : in std_logic;
148         m_axis_rc_tuser : out std_logic_vector ( 74 downto 0 );
149         m_axis_rc_tvalid : out std_logic;
150         m_axis_cq_tdata : out std_logic_vector ( 127 downto 0 );
151         m_axis_cq_tkeep : out std_logic_vector ( 3 downto 0 );
152         m_axis_cq_tlast : out std_logic;
153         m_axis_cq_tready : in std_logic;
154         m_axis_cq_tuser : out std_logic_vector ( 84 downto 0 );
155         m_axis_cq_tvalid : out std_logic;
156         s_axis_cc_tdata : in std_logic_vector ( 127 downto 0 );
157         s_axis_cc_tkeep : in std_logic_vector ( 3 downto 0 );
158         s_axis_cc_tlast : in std_logic;
159         s_axis_cc_tready : out std_logic_vector ( 3 downto 0 );
160         s_axis_cc_tuser : in std_logic_vector ( 32 downto 0 );
161         s_axis_cc_tvalid : in std_logic;
162         cfg_interrupt_int : in std_logic_vector ( 3 downto 0 );
163         cfg_interrupt_pending : in std_logic_vector ( 3 downto 0 );
164         cfg_interrupt_sent : out std_logic;
165         sys_clk : in std_logic;
166         sys_clk_gt : in std_logic;
167         sys_reset : in std_logic;
168         int_qpll1lock_out : out std_logic_vector ( 0 to 0 );
169         int_qpll1outrefclk_out : out std_logic_vector ( 0 to 0 );
170         int_qpll1outclk_out : out std_logic_vector ( 0 to 0 );
171         phy_rdy_out : out std_logic
172 );
173 end component;
174
175 component Pcie_nvme1
176 port (
177         pci_exp_txn : out std_logic_vector ( 3 downto 0 );
178         pci_exp_txp : out std_logic_vector ( 3 downto 0 );
179         pci_exp_rxn : in std_logic_vector ( 3 downto 0 );
180         pci_exp_rxp : in std_logic_vector ( 3 downto 0 );
181         user_clk : out std_logic;
182         user_reset : out std_logic;
183         user_lnk_up : out std_logic;
184         s_axis_rq_tdata : in std_logic_vector ( 127 downto 0 );
185         s_axis_rq_tkeep : in std_logic_vector ( 3 downto 0 );
186         s_axis_rq_tlast : in std_logic;
187         s_axis_rq_tready : out std_logic_vector ( 3 downto 0 );
188         s_axis_rq_tuser : in std_logic_vector ( 59 downto 0 );
189         s_axis_rq_tvalid : in std_logic;
190         m_axis_rc_tdata : out std_logic_vector ( 127 downto 0 );
191         m_axis_rc_tkeep : out std_logic_vector ( 3 downto 0 );
192         m_axis_rc_tlast : out std_logic;
193         m_axis_rc_tready : in std_logic;
194         m_axis_rc_tuser : out std_logic_vector ( 74 downto 0 );
195         m_axis_rc_tvalid : out std_logic;
196         m_axis_cq_tdata : out std_logic_vector ( 127 downto 0 );
197         m_axis_cq_tkeep : out std_logic_vector ( 3 downto 0 );
198         m_axis_cq_tlast : out std_logic;
199         m_axis_cq_tready : in std_logic;
200         m_axis_cq_tuser : out std_logic_vector ( 84 downto 0 );
201         m_axis_cq_tvalid : out std_logic;
202         s_axis_cc_tdata : in std_logic_vector ( 127 downto 0 );
203         s_axis_cc_tkeep : in std_logic_vector ( 3 downto 0 );
204         s_axis_cc_tlast : in std_logic;
205         s_axis_cc_tready : out std_logic_vector ( 3 downto 0 );
206         s_axis_cc_tuser : in std_logic_vector ( 32 downto 0 );
207         s_axis_cc_tvalid : in std_logic;
208         cfg_interrupt_int : in std_logic_vector ( 3 downto 0 );
209         cfg_interrupt_pending : in std_logic_vector ( 3 downto 0 );
210         cfg_interrupt_sent : out std_logic;
211         sys_clk : in std_logic;
212         sys_clk_gt : in std_logic;
213         sys_reset : in std_logic;
214         int_qpll1lock_out : out std_logic_vector ( 0 to 0 );
215         int_qpll1outrefclk_out : out std_logic_vector ( 0 to 0 );
216         int_qpll1outclk_out : out std_logic_vector ( 0 to 0 );
217         phy_rdy_out : out std_logic
218 );
219 end component;
220
221 component StreamSwitch is
222 generic(
223         NumStreams      : integer       := NumStreams           --! The number of stream
224 );
225 port (
226         clk             : in std_logic;                         --! The interface clock line
227         reset           : in std_logic;                         --! The active high reset line
228         
229         streamIn        : inout AxisStreamArrayType(0 to NumStreams-1) := (others => AxisStreamInput);  --! Input stream
230         streamOut       : inout AxisStreamArrayType(0 to NumStreams-1) := (others => AxisStreamOutput)  --! Output stream
231 );
232 end component;
233
234 component NvmeQueues is
235 generic(
236         NumQueueEntries : integer       := NvmeQueueNum;        --! The number of entries per queue
237         Simulate        : boolean       := False
238 );
239 port (
240         clk             : in std_logic;                         --! The interface clock line
241         reset           : in std_logic;                         --! The active high reset line
242         
243         streamIn        : inout AxisStreamType := AxisStreamInput;      --! Request queue entries
244         streamOut       : inout AxisStreamType := AxisStreamOutput      --! replies and requests
245 );
246 end component;
247
248 component NvmeConfig is
249 generic(
250         ClockPeriod     : time := ClockPeriod                   --! Clock period for timers (125 MHz)
251 );
252 port (
253         clk             : in std_logic;                         --! The interface clock line
254         reset           : in std_logic;                         --! The active high reset line
255
256         configStart     : in std_logic;                         --! Start the initialisation (1 clk cycle only)
257         configComplete  : out std_logic;                        --! Initialisation is complete
258
259         -- From host to NVMe request/reply streams
260         streamOut       : inout AxisStreamType := AxisStreamOutput;     --! Nvme request stream
261         streamIn        : inout AxisStreamType := AxisStreamInput       --! Nvme reply stream
262 );
263 end component;
264
265 component PcieStreamMux is
266 port (
267         clk             : in std_logic;                         --! The interface clock line
268         reset           : in std_logic;                         --! The active high reset line
269         
270         stream1In       : inout AxisStreamType := AxisStreamInput;      --! Single multiplexed Input stream
271         stream1Out      : inout AxisStreamType := AxisStreamOutput;     --! Single multiplexed Ouput stream
272
273         stream2Out      : inout AxisStreamType := AxisStreamOutput;     --! Host Requests output stream
274         stream2In       : inout AxisStreamType := AxisStreamInput;      --! Host Replies input stream
275
276         stream3In       : inout AxisStreamType := AxisStreamInput;      --! Nvme Requests input stream
277         stream3Out      : inout AxisStreamType := AxisStreamOutput      --! Nvme replies output stream
278 );
279 end component;
280
281 component NvmeSim is
282 generic(
283         Simulate        : boolean := True;
284         BlockSize       : integer := BlockSize                  --! System block size
285 );
286 port (
287         clk             : in std_logic;
288         reset           : in std_logic;
289
290         -- AXIS Interface to PCIE
291         hostReq         : inout AxisStreamType := AxisStreamInput;
292         hostReply       : inout AxisStreamType := AxisStreamOutput;                        
293         
294         -- From Nvme reqeuest and reply stream
295         nvmeReq         : inout AxisStreamType := AxisStreamOutput;
296         nvmeReply       : inout AxisStreamType := AxisStreamInput
297 );
298 end component;
299
300 component NvmeWrite is
301 generic(
302         Simulate        : boolean := Simulate;                  --! Generate simulation core
303         ClockPeriod     : time := ClockPeriod;                  --! The clocks period
304         BlockSize       : integer := BlockSize                  --! System block size
305 );
306 port (
307         clk             : in std_logic;                         --! The interface clock line
308         reset           : in std_logic;                         --! The active high reset line
309
310         enable          : in std_logic;                         --! Enable the data writing process
311         dataIn          : inout AxisStreamType := AxisStreamInput;      --! Raw data to save stream
312
313         -- To Nvme Request/reply streams
314         requestOut      : inout AxisStreamType := AxisStreamOutput;     --! To Nvme request stream (3)
315         replyIn         : inout AxisStreamType := AxisStreamInput;      --! from Nvme reply stream
316
317         -- From Nvme Request/reply streams
318         memReqIn        : inout AxisStreamType := AxisStreamInput;      --! From Nvme request stream (4)
319         memReplyOut     : inout AxisStreamType := AxisStreamOutput;     --! To Nvme reply stream
320         
321         regWrite        : in std_logic;                         --! Enable write to register
322         regAddress      : in unsigned(3 downto 0);              --! Register to read/write
323         regDataIn       : in std_logic_vector(31 downto 0);     --! Register write data
324         regDataOut      : out std_logic_vector(31 downto 0)     --! Register contents
325 );
326 end component;
327
328 component NvmeRead is
329 generic(
330         Simulate        : boolean := False;                     --! Generate simulation core
331         BlockSize       : integer := NvmeStorageBlockSize       --! System block size
332 );
333 port (
334         clk             : in std_logic;                         --! The interface clock line
335         reset           : in std_logic;                         --! The active high reset line
336
337         -- To Nvme Request/reply streams
338         requestOut      : inout AxisStreamType := AxisStreamOutput;     --! To Nvme request stream (3)
339         replyIn         : inout AxisStreamType := AxisStreamInput;      --! from Nvme reply stream
340
341         regWrite        : in std_logic;                         --! Enable write to register
342         regAddress      : in unsigned(3 downto 0);              --! Register to read/write
343         regDataIn       : in std_logic_vector(31 downto 0);     --! Register write data
344         regDataOut      : out std_logic_vector(31 downto 0)     --! Register contents
345 );
346 end component;
347
348 signal reset_local              : std_logic := '0';
349 signal reset_local_active       : std_logic := '0';
350 signal reset_local_counter      : integer range 0 to ResetCycles := 0;
351
352 -- Streams
353 signal streamSend               : AxisStreamArrayType(0 to NumStreams-1);
354 signal streamRecv               : AxisStreamArrayType(0 to NumStreams-1);
355
356 alias nvmeSend                  is streamSend(0);
357 alias nvmeRecv                  is streamRecv(0);
358 alias hostSend1                 is streamSend(1);
359 alias hostRecv1                 is streamRecv(1);
360 alias queueSend                 is streamSend(2);
361 alias queueRecv                 is streamRecv(2);
362 alias configSend                is streamSend(3);
363 alias configRecv                is streamRecv(3);
364 alias writeSend                 is streamSend(4);
365 alias writeRecv                 is streamRecv(4);
366 alias writeMemSend              is streamSend(5);
367 alias writeMemRecv              is streamRecv(5);
368 alias readSend                  is streamSend(6);
369 alias readRecv                  is streamRecv(6);
370
371 signal dataIn1                  : AxisStreamType;
372 signal streamNone               : AxisStreamType := AxisStreamOutput;
373 signal streamSink               : AxisStreamType := AxisStreamSink;
374
375 -- Nvme PCIe interface
376 signal hostReq                  : AxisStreamType;
377 signal hostReq_ready            : std_logic_vector(3 downto 0);
378 signal hostReq_morethan1        : std_logic;
379 signal hostReq_user             : std_logic_vector(59 downto 0);
380
381 signal hostReply                : AxisStreamType;
382
383 signal nvmeReq                  : AxisStreamType;
384
385 signal nvmeReply                : AxisStreamType;
386 signal nvmeReply_ready          : std_logic_vector(3 downto 0);
387 signal nvmeReply_user           : std_logic_vector(32 downto 0);
388
389 -- Register interface
390 constant RegWidth               : integer := 32;
391 subtype RegDataType             is std_logic_vector(RegWidth-1 downto 0);
392
393 type StateType                  is (STATE_START, STATE_IDLE, STATE_WRITE, STATE_READ1, STATE_READ2);
394 signal state                    : StateType := STATE_START;
395
396 signal regWrite1                : std_logic;                            --! Enable write to register
397 signal regAddress1              : unsigned(5 downto 0) := (others => '0');      --! Register to read/write
398 signal regDataIn1               : std_logic_vector(31 downto 0);        --! Register write data
399 signal regDataOut0              : std_logic_vector(31 downto 0);        --! Register contents
400 signal regDataOut1              : std_logic_vector(31 downto 0);        --! Register contents
401
402 signal reg_id                   : RegDataType := x"56010200";
403 signal reg_control              : RegDataType := (others => '0');
404 signal reg_status               : RegDataType := (others => '0');
405 signal reg_totalBlocks          : RegDataType := to_stl(NvmeTotalBlocks, RegWidth);
406 signal reg_blocksLost           : RegDataType := (others => '0');
407 signal reg_nvmeWrite            : RegDataType := (others => '0');
408 signal reg_nvmeRead             : RegDataType := (others => '0');
409 signal nvmeWrite_write          : std_logic := '0';
410 signal nvmeRead_write           : std_logic := '0';
411
412 -- Nvme configuration signals
413 signal configStart              : std_logic := 'U';
414 signal configStartDone          : std_logic := 'U';
415 signal configComplete           : std_logic := 'U';
416
417 -- Nvme data write signals
418 signal writeEnable              : std_logic := 'U';
419
420
421 -- Pcie_nvme signals
422 signal nvme_reset_local_n       : std_logic := '0';
423 signal nvme_user_clk            : std_logic := 'U';
424 signal nvme_user_reset          : std_logic := 'U';
425
426 signal cfg_mgmt_addr                    : std_logic_vector(18 downto 0);
427 signal cfg_mgmt_write                   : std_logic;
428 signal cfg_mgmt_write_data              : std_logic_vector(31 downto 0);
429 signal cfg_mgmt_read                    : std_logic;
430 signal cfg_mgmt_read_data               : std_logic_vector(31 downto 0);
431 signal cfg_mgmt_read_write_done         : std_logic;
432 signal cfg_mgmt_type1_cfg_reg_access    : std_logic;
433
434 signal dummy1                   : AxisStreamType := AxisStreamInput;
435 signal dummy2                   : AxisStreamType := AxisStreamOutput;
436 signal dummy3                   : AxisStreamType := AxisStreamOutput;
437
438
439 begin
440         -- Register access over clock domain crossing
441         regClockConvertor : RegAccessClockConvertor
442         port map (
443                 clk1            => clk,
444                 reset1          => reset,
445
446                 regWrite1       => regWrite,
447                 regAddress1     => regAddress,
448                 regDataIn1      => regDataIn,
449                 regDataOut1     => regDataOut0,
450
451                 --clk2          => clk,                         --! **** Needs to operate from Nvme clock
452                 --reset2        => reset,
453                 clk2            => nvme_user_clk,
454                 reset2          => nvme_user_reset,
455
456                 regWrite2       => regWrite1,
457                 regAddress2     => regAddress1,
458                 regDataIn2      => regDataIn1,
459                 regDataOut2     => regDataOut1
460         );
461
462         -- Host request packets across clock domain crossing
463         axisClockConverter0 :  AxisClockConverter
464         port map (
465                 clkRx           => clk,
466                 resetRx         => reset,
467                 streamRx        => hostSend,
468
469                 clkTx           => nvme_user_clk,
470                 resetTx         => nvme_user_reset,
471                 streamTx        => hostSend1
472         );
473
474         -- Host reply packets across clock domain crossing
475         axisClockConverter1 :  AxisClockConverter
476         port map (
477                 clkRx           => nvme_user_clk,
478                 resetRx         => nvme_user_reset,
479                 streamRx        => hostRecv1,
480
481                 clkTx           => clk,
482                 resetTx         => reset,
483                 streamTx        => hostRecv
484         );
485         
486         -- Data stream across clock domain crossing
487         axisClockConverter2 :  AxisClockConverter
488         port map (
489                 clkRx           => clk,
490                 resetRx         => reset,
491                 streamRx        => dataIn,
492
493                 clkTx           => nvme_user_clk,
494                 resetTx         => nvme_user_reset,
495                 streamTx        => dataIn1
496         );
497
498         -- Register access
499         regDataOut1 <= reg_id when(regAddress1 = 0) else
500                         reg_control when(regAddress1 = 1) else
501                         reg_status when(regAddress1 = 2) else
502                         reg_totalBlocks when(regAddress1 = 3) else
503                         reg_blocksLost when(regAddress1 = 4) else
504                         reg_nvmeWrite when((regAddress1 >= 16) and (regAddress1 < 32)) else
505                         reg_nvmeRead when((regAddress1 >= 32) and (regAddress1 < 48)) else
506                         x"FFFFFFFF";
507
508         regDataOut <= zeros(31) & reset_local_active when(reset_local_active = '1') else regDataOut0;
509         nvmeWrite_write <= regWrite1 when((regAddress1 >= 16) and (regAddress1 < 32)) else '0';
510         nvmeRead_write <= regWrite1 when((regAddress1 >= 32) and (regAddress1 < 48)) else '0';
511         
512         -- Status register bits
513         reg_status(0)           <= '0';
514         reg_status(1)           <= configComplete;
515         reg_status(2)           <= '0';
516         reg_status(3)           <= '0';                                         -- **** Needs setting
517         reg_status(31 downto 4) <= (others => '0');
518         
519         -- Perform reset of Nvme subsystem. This implements a 100ms reset suitable for the Nvme Pcie reset.
520         -- Local state machines and external Nvme devices use this reset_local signal.
521         reset_local             <= reset or reset_local_active;
522         nvme_reset_local_n      <= not reset_local;
523         nvme_reset_n            <= nvme_reset_local_n;
524         
525         -- Process reset
526         process(clk)
527         begin
528                 if(rising_edge(clk)) then
529                         if(reset = '1') then
530                                 reset_local_active <= '0';
531                         else
532                                 if((regWrite = '1') and (regAddress = 1)) then
533                                         if(regDataIn(0) = '1') then
534                                                 reset_local_counter     <= ResetCycles;
535                                                 reset_local_active      <= '1';
536                                         end if;
537                                 end if;
538                                 
539                                 if(reset_local_active = '1') then
540                                         if(reset_local_counter = 0) then
541                                                 reset_local_active      <= '0';
542                                         else
543                                                 reset_local_counter <= reset_local_counter - 1;
544                                         end if;
545                                 end if;
546                         end if;
547                 end if;
548         end process;
549
550         -- Process register access
551         process(nvme_user_clk)
552         begin
553                 if(rising_edge(nvme_user_clk)) then
554                         if(nvme_user_reset = '1') then
555                                 reg_control     <= (others => '0');
556                         else
557                                 if(regWrite1 = '1') then
558                                         if(regAddress1 = 1) then
559                                                 reg_control <= regDataIn1;
560                                         end if;
561                                 end if;
562                         end if;
563                 end if;
564         end process; 
565         
566         -- Host to Nvme stream Mux/DeMux
567         pcieStreamMux0 : PcieStreamMux
568         port map (
569                 clk             => nvme_user_clk,
570                 reset           => nvme_user_reset,
571
572                 stream1In       => nvmeRecv,
573                 stream1Out      => nvmeSend,
574
575                 stream2Out      => hostReq,
576                 stream2In       => hostReply,
577                 
578                 stream3In       => nvmeReq,
579                 stream3Out      => nvmeReply
580         );
581
582         sim: if (Simulate = True) generate
583         nvme_user_clk   <= clk;
584         nvme_user_reset <= reset_local;
585
586         nvmeSim0 : NvmeSim
587         port map (
588                 clk             => nvme_user_clk,
589                 reset           => nvme_user_reset,
590
591                 hostReq         => hostReq,
592                 hostReply       => hostReply,
593
594                 nvmeReq         => nvmeReq,
595                 nvmeReply       => nvmeReply
596         );
597         end generate;
598         
599         synth: if (Simulate = False) generate
600
601         genpci0: if(PcieCore = 0) generate
602         --! The PCIe to NVMe interface
603         pcie_nvme_0 : Pcie_nvme0
604         port map (
605                 sys_clk                 => nvme_clk,
606                 sys_clk_gt              => nvme_clk_gt,
607                 sys_reset               => nvme_reset_local_n,
608                 phy_rdy_out             => leds(0),
609
610                 pci_exp_txn             => nvme_exp_txn,
611                 pci_exp_txp             => nvme_exp_txp,
612                 pci_exp_rxn             => nvme_exp_rxn,
613                 pci_exp_rxp             => nvme_exp_rxp,
614
615                 user_clk                => nvme_user_clk,
616                 user_reset              => nvme_user_reset,
617                 user_lnk_up             => leds(1),
618
619                 s_axis_rq_tdata         => hostReq.data,
620                 s_axis_rq_tkeep         => hostReq.keep,
621                 s_axis_rq_tlast         => hostReq.last,
622                 s_axis_rq_tready        => hostReq_ready,
623                 s_axis_rq_tuser         => hostReq_user,
624                 s_axis_rq_tvalid        => hostReq.valid,
625                 
626                 m_axis_rc_tdata         => hostReply.data,
627                 m_axis_rc_tkeep         => hostReply.keep,
628                 m_axis_rc_tlast         => hostReply.last,
629                 m_axis_rc_tready        => hostReply.ready,
630                 --m_axis_rc_tuser       => hostReply_user,
631                 m_axis_rc_tvalid        => hostReply.valid,
632                 
633                 m_axis_cq_tdata         => nvmeReq.data,
634                 m_axis_cq_tkeep         => nvmeReq.keep,
635                 m_axis_cq_tlast         => nvmeReq.last,
636                 m_axis_cq_tready        => nvmeReq.ready,
637                 --m_axis_cq_tuser       => nvmeReq_user,
638                 m_axis_cq_tvalid        => nvmeReq.valid,
639                 
640                 s_axis_cc_tdata         => nvmeReply.data,
641                 s_axis_cc_tkeep         => nvmeReply.keep,
642                 s_axis_cc_tlast         => nvmeReply.last,
643                 s_axis_cc_tready        => nvmeReply_ready,
644                 s_axis_cc_tuser         => nvmeReply_user,
645                 s_axis_cc_tvalid        => nvmeReply.valid,
646
647                 cfg_interrupt_int       => "0000",
648                 cfg_interrupt_pending   => "0000"
649                 --cfg_interrupt_sent    => --cfg_interrupt_sent,
650         );
651         end generate;
652         
653         genpci1: if(PcieCore = 1) generate
654         --! The PCIe to NVMe interface
655         pcie_nvme_1 : Pcie_nvme1
656         port map (
657                 sys_clk                 => nvme_clk,
658                 sys_clk_gt              => nvme_clk_gt,
659                 sys_reset               => nvme_reset_local_n,
660                 phy_rdy_out             => leds(0),
661
662                 pci_exp_txn             => nvme_exp_txn,
663                 pci_exp_txp             => nvme_exp_txp,
664                 pci_exp_rxn             => nvme_exp_rxn,
665                 pci_exp_rxp             => nvme_exp_rxp,
666
667                 user_clk                => nvme_user_clk,
668                 user_reset              => nvme_user_reset,
669                 user_lnk_up             => leds(1),
670
671                 s_axis_rq_tdata         => hostReq.data,
672                 s_axis_rq_tkeep         => hostReq.keep,
673                 s_axis_rq_tlast         => hostReq.last,
674                 s_axis_rq_tready        => hostReq_ready,
675                 s_axis_rq_tuser         => hostReq_user,
676                 s_axis_rq_tvalid        => hostReq.valid,
677                 
678                 m_axis_rc_tdata         => hostReply.data,
679                 m_axis_rc_tkeep         => hostReply.keep,
680                 m_axis_rc_tlast         => hostReply.last,
681                 m_axis_rc_tready        => hostReply.ready,
682                 --m_axis_rc_tuser       => hostReply_user,
683                 m_axis_rc_tvalid        => hostReply.valid,
684                 
685                 m_axis_cq_tdata         => nvmeReq.data,
686                 m_axis_cq_tkeep         => nvmeReq.keep,
687                 m_axis_cq_tlast         => nvmeReq.last,
688                 m_axis_cq_tready        => nvmeReq.ready,
689                 --m_axis_cq_tuser       => nvmeReq_user,
690                 m_axis_cq_tvalid        => nvmeReq.valid,
691                 
692                 s_axis_cc_tdata         => nvmeReply.data,
693                 s_axis_cc_tkeep         => nvmeReply.keep,
694                 s_axis_cc_tlast         => nvmeReply.last,
695                 s_axis_cc_tready        => nvmeReply_ready,
696                 s_axis_cc_tuser         => nvmeReply_user,
697                 s_axis_cc_tvalid        => nvmeReply.valid,
698
699                 cfg_interrupt_int       => "0000",
700                 cfg_interrupt_pending   => "0000"
701                 --cfg_interrupt_sent    => --cfg_interrupt_sent,
702         );
703         end generate;
704         
705         
706         -- Interface between Axis streams and PCIe Gen3 streams
707         hostReq.ready <= hostReq_ready(0);
708
709         -- The last_be bits in hostReq_user should be 0 when reading/writing less than 2 words due to the daft PCIe Gen3 core.
710         -- This code peeks at the PCIe TLP headers numDwords field and sets the be bits appropriately. Only valid in the first
711         -- beat of the 128bit wide data stream packet.
712         -- Warning: This may not be valid for message and atomic packets.
713         --hostReq_morethan1 <= reg_control(31);
714         hostReq_morethan1 <= '1' when(unsigned(hostReq.data(74 downto 64)) > 1) else '0';
715         hostReq_user <= x"00000000" & "0000" & "00000000" & "0" & "00" & "0" & "0" & "000" & "1111" & "1111" when(hostReq_morethan1 = '1')
716                 else x"00000000" & "0000" & "00000000" & "0" & "00" & "0" & "0" & "000" & "0000" & "1111";
717
718         nvmeReply.ready <= nvmeReply_ready(0) and nvmeReply_ready(1) and nvmeReply_ready(2) and nvmeReply_ready(3);
719         nvmeReply_user <= (others => '0');
720         
721         cfg_mgmt_addr <= (others => '0');
722         cfg_mgmt_write <= '0';
723         cfg_mgmt_write_data <= (others => '0');
724         cfg_mgmt_read <= '0';
725         cfg_mgmt_type1_cfg_reg_access <= '0';
726         
727
728         leds(2) <= '0';
729         end generate;
730         
731         -- Raw Host to Nvme communications
732         gen02: if false generate
733                 axisConnect(nvmeRecv, hostSend1);
734                 axisConnect(hostRecv1, nvmeSend);
735         end generate;
736         
737         -- Full switched communications
738         gen03: if true generate
739         set1: for i in 7 to 7 generate
740                 streamSend(i).valid     <= '0';
741                 streamRecv(i).ready     <= '1';
742         end generate;
743
744         streamSwitch0 : StreamSwitch
745         port map (
746                 clk             => nvme_user_clk,
747                 reset           => nvme_user_reset,
748
749                 streamIn        => streamSend,
750                 streamOut       => streamRecv
751         );
752         
753         nvmeQueues0: NvmeQueues
754         port map (
755                 clk             => nvme_user_clk,
756                 reset           => nvme_user_reset,
757
758                 streamIn        => queueRecv,
759                 streamOut       => queueSend
760         );
761
762         nvmeConfig0: NvmeConfig
763         port map (
764                 clk             => nvme_user_clk,
765                 reset           => nvme_user_reset,
766
767                 configStart     => configStart,
768                 configComplete  => configComplete,
769
770                 streamOut       => configSend,
771                 streamIn        => configRecv
772         );
773
774         -- Start config after reset
775         process(nvme_user_clk)
776         begin
777                 if(rising_edge(nvme_user_clk)) then
778                         if(nvme_user_reset = '1') then
779                                 configStart     <= '0';
780                                 configStartDone <= '0';
781                         else
782                                 if(UseConfigure and (configStartDone = '0')) then
783                                         configStart     <= '1';         -- Start the Nvme configuration
784                                         configStartDone <= '1';
785                                 elsif((configStartDone = '0') and (configComplete = '0') and (reg_control(1) = '1')) then
786                                         configStart     <= '1';         -- Start the Nvme configuration
787                                         configStartDone <= '1';
788                                 else
789                                         configStart     <= '0';
790                                 end if;
791                         end if;
792                 end if;
793         end process;
794         
795         -- The Data write processing
796         writeEnable     <= reg_control(2);
797         dataEnabledOut  <= writeEnable;
798         
799         nvmeWrite0: NvmeWrite
800         port map (
801                 clk             => nvme_user_clk,
802                 reset           => nvme_user_reset,
803
804                 enable          => writeEnable,
805                 dataIn          => dataIn1,
806
807                 requestOut      => writeSend,
808                 replyIn         => writeRecv,
809
810                 memReqIn        => writeMemRecv,
811                 memReplyOut     => writeMemSend,
812
813                 regWrite        => nvmeWrite_write,
814                 regAddress      => regAddress1(3 downto 0),
815                 regDataIn       => regDataIn1,
816                 regDataOut      => reg_nvmeWrite
817         );
818
819         -- The Data read processing
820         nvmeRead0: NvmeRead
821         port map (
822                 clk             => nvme_user_clk,
823                 reset           => nvme_user_reset,
824
825                 requestOut      => readSend,
826                 replyIn         => readRecv,
827
828                 regWrite        => nvmeRead_write,
829                 regAddress      => regAddress1(3 downto 0),
830                 regDataIn       => regDataIn1,
831                 regDataOut      => reg_nvmeRead
832         );
833
834         end generate;
835 end;