├── .gitignore ├── LICENSE.md ├── Makefile ├── README.md ├── cfg └── program_screamer.cfg ├── docs └── system_design.md ├── ip ├── fifo_32_32_bram │ └── fifo_32_32_bram.xci ├── fifo_36_36_prim │ └── fifo_36_36_prim.xci ├── fifo_pcie_tlp_r32_w64_4096_bram │ └── fifo_pcie_tlp_r32_w64_4096_bram.xci ├── fifo_pcie_tlp_r64_w32_4096_bram │ └── fifo_pcie_tlp_r64_w32_4096_bram.xci ├── ila_0 │ └── ila_0.xci ├── pcie_7x_0 │ └── pcie_7x_0.xci ├── pcie_ila │ └── pcie_ila.xci └── pcie_tlp_ila │ └── pcie_tlp_ila.xci ├── src ├── constrs │ └── screamer_m2.xdc ├── design │ ├── tlp_streamer_ft601.vhd │ ├── tlp_streamer_loopback.vhd │ ├── tlp_streamer_pcie.vhd │ ├── tlp_streamer_pcie_cfg.vhd │ ├── tlp_streamer_pcie_tlp.vhd │ ├── tlp_streamer_records.vhd │ ├── tlp_streamer_reset.vhd │ ├── tlp_streamer_rx_dispatch.vhd │ ├── tlp_streamer_top.vhd │ └── tlp_streamer_tx_arbiter.vhd └── sim │ ├── tlp_streamer_usb_rx_sim.vhd │ └── tlp_usb_rx_sim_behav.wcfg ├── vivado_build.tcl └── vivado_generate_project.tcl /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.jou 3 | *.str 4 | *.cache 5 | *.xpr 6 | *.hw 7 | tlp-streamer 8 | *.tmp 9 | .Xil 10 | ip/pcie* 11 | !ip/pcie*/*.xci 12 | *.ila 13 | *.diff 14 | *.old 15 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | ## Xilinx IP 4 | 5 | The completed solution contains Xilinx proprietary IP cores licensed under the Xilinx CORE LICENSE AGREEMENT. This project as-is published on Github contains no Xilinx proprietary IP. The end user that have downloaded the no-charge Vivado WebPACK from Xilinx will have the proper licenses and will be able to re-generate Xilinx proprietary IP cores by running the build detailed above. 6 | 7 | ## src/constrs/screamer_m2.xdc 8 | 9 | Copyright 2021 Ulf Frisk 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | 17 | ## All other published Source Files 18 | 19 | TLP Streamer - FPGA 20 | Copyright (C) 2021-2022 MikeM64 21 | 22 | This program is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU General Public License as published by 24 | the Free Software Foundation, version 3. 25 | 26 | This program is distributed in the hope that it will be useful, 27 | but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | GNU General Public License for more details. 30 | 31 | You should have received a copy of the GNU General Public License 32 | along with this program. If not, see . 33 | 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | tlp-streamer/tlp-streamer.runs/impl_1/tlp_streamer.bit: 2 | vivado -mode tcl -source vivado_build.tcl -notrace tlp-streamer/tlp-streamer.xpr 3 | 4 | install: tlp-streamer/tlp-streamer.runs/impl_1/tlp_streamer.bit 5 | openocd -f cfg/program_screamer.cfg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TLP Streamer 2 | ## Overview 3 | This project is a PCIe TLP Streamer intended to support device emulation from an attached host computer. 4 | 5 | Please refer to [system_design.md](docs/system_design.md) for details of the design. 6 | 7 | The current board target is the [Screamer M.2](https://shop.lambdaconcept.com/home/43-screamer-m2.html) from LambdaConcept. 8 | 9 | ## Progress 10 | - [x] - FT601 RX/TX Loopback 11 | - [x] - Host Packet RX Dispatch 12 | - [x] - FPGA Packet TX Arbitration 13 | - [x] - PCIe Link Up 14 | - [x] - PCIe configuration space R/W 15 | - [ ] - PCIe TLP Handling 16 | + [x] - TLP RX 17 | + [ ] - TLP TX (in progress) 18 | - [ ] - Host software 19 | 20 | # Thanks 21 | 22 | - [PCILeech](https://github.com/ufrisk/pcileech) 23 | - [NetTLP](https://github.com/nettlp) 24 | 25 | -------------------------------------------------------------------------------- /cfg/program_screamer.cfg: -------------------------------------------------------------------------------- 1 | adapter driver ftdi 2 | transport select jtag 3 | ftdi vid_pid 0x0403 0x6011 4 | ftdi channel 0 5 | ftdi layout_init 0x0098 0x008b 6 | reset_config none 7 | 8 | source [find cpld/xilinx-xc7.cfg] 9 | source [find cpld/jtagspi.cfg] 10 | adapter speed 10000 11 | 12 | init 13 | xc7_program xc7.tap 14 | pld load 0 ./tlp-streamer/tlp-streamer.runs/impl_1/tlp_streamer.bit 15 | shutdown 16 | -------------------------------------------------------------------------------- /docs/system_design.md: -------------------------------------------------------------------------------- 1 | # PCIe TLP Streamer 2 | 3 | ## Architecture 4 | 5 | ### HW: 6 | PCIe (Target) <=> FPGA <=> FT601 <= (USB3) => Host Computer 7 | 8 | ### SW: 9 | FT601 Driver <=> Server Process <= (UDP Socket) => Client 10 | 11 | ## Functionality 12 | 13 | Client could be any PCIe emulator: 14 | - NVMe 15 | - Ethernet 16 | - Etc... 17 | 18 | ## Requirements 19 | - MUST be able to handle both regular and config TLPs 20 | - MUST have counters available for debugging and statistics (USB Packet RX/TX, PCIe TLP RX/TX, etc...) 21 | - MAY be hot-restart capable to change VID/PID/device class from the client software (dependent on FPGA support) 22 | 23 | ## Design 24 | ### Clock Domains 25 | There are three clock domains for the design logic (except for the internals of Xilinx IP): 26 | 1) ft601_clk 27 | - This clock is driven by the FT601 and is used to clock incoming/outgoing data towards the host 28 | - Drives the RX/TX FIFOs 29 | 2) sys_clk 30 | - This is the external 100MHz clock 31 | - Drives the majority of the internal logic 32 | 3) pcie_user_clk 33 | - User clock output from the PCIe IP 34 | - Used to clock all data reads/writes related to the PCIe IP 35 | 36 | ### USB to FPGA Design 37 | The FT601 supports both synchronous single-channel and multi-channel operation. Maximum of 8 channels - 4 IN and 4 OUT. 38 | 39 | Does it make sense to use the multi-channel feature here? One per PCIe data, PCIe config, board config/mgmt. 40 | 41 | Pros: 42 | - Don't need to decode part of the user packet in HW to determine where the data is supposed to go 43 | 44 | Cons: 45 | - More complex software to manage where to send the packet 46 | - More complex bus interactions with the FT601 47 | 48 | Neutral: 49 | - More FIFO resources needed to buffer the three channels (turns out that an RX buffer for each channel is still needed to quickly drain the FT601 FIFO buffer) 50 | 51 | Questions: 52 | - Is the screamer wired up for multichannel FIFO? 53 | - Are the FT601 GPIOs writeable from the FPGA or are they hardwired to a specific config? 54 | - Is it cheaper to decode part of the user packet to determine where to send it or cheaper to implement multi-channel FIFOs? 55 | 56 | **It probably doesn't make sense when starting out to go multi-channel. The design should be modular enough to go multi-channel if required.** 57 | 58 | ### FPGA Design 59 | #### USB Loopback 60 | FT601 => FPGA => FT601 is implemented in order to verify the USB comms channel. 61 | 62 | ##### USB Packet RX 63 | The 245 bus mode on the FT601 has the following read state machine. All FT601 signals change on the negative clock edge and should be clocked on the positive edge. 64 | 65 | 1. `BUS_IDLE` 66 | - The default state of the bus 67 | - This will transition to either `RX_READY` or `TX_READY` depending on which signal is asserted by the FT601. `BUS_IDLE` will also check the state of the RX/TX FIFO to make sure there's either space to receive or data to transfer. 68 | 2. `RX_READY` 69 | - Wait state before asserting `FT601_OE` 70 | 3. `RX_START` 71 | - Asserts `FT601_OE` 72 | - Wait state before asserting `FT601_RD` 73 | 4. `RX_WORD_1` 74 | - Asserts `FT601_OE` and `FT601_RD` 75 | - Wait state before clocking valid data into the RX fifo 76 | 5. `RX_WORD_2` 77 | - Same as `RX_WORD_1`, but clocks valid data into the RX FIFO 78 | - Seems like the FT601 will keep valid data on the bus for an extra cycle, so we only want to clock one copy 79 | - Moves to `RX_COMPLETE` when either there is no more data from the FT601 or 80 | the RX FIFO is full 81 | 6. `RX_COMPLETE` 82 | - Delay state to de-assert `FT601_OE` and `FT601_RD` before going back to `BUS_IDLE` 83 | 84 | ##### USB Packet TX 85 | Similar to the USB Packet RX state machine, this control the TX process 86 | 87 | 1. `TX_READY` 88 | - Wait state before asserting `FT601_WR` 89 | 2. `TX_WORD` 90 | - Transmits a word on the FT601 bus 91 | 3. `TX_COMPLETE` 92 | - Wait state before going back to `BUS_IDLE` 93 | 94 | The controller for FT601 transfers is implemented in `tlp_streamer_ft601.vhd` and provides two FIFOs (one RX from host and one TX to host) as an interface to the rest of the FPGA design. 95 | 96 | #### Host-to-FPGA communications 97 | Packets sent/received by the FPGA are encoded in network order (Big-endian) for ease of communication with the PCIe core. The host is responsible for translating the packet before sending it. 98 | 99 | Each packet MUST have the following header prepended to any data: 100 | 101 | ``` 102 | typedef enum tsh_msg_type_et { 103 | /** Loopback the packet back to the host */ 104 | TSH_MSG_LOOPBACK = 0, 105 | /** PCIe Configuration Space packet */ 106 | TSH_MSG_PCIE_CONFIG, 107 | } __attribute__ ((packed)); 108 | 109 | /* 110 | * NOTE: The header must ALWAYS be size which is a multiple of a uint32_t to 111 | * allow for easy decoding on the FPGA. 112 | */ 113 | struct tlp_streamer_header { 114 | /** @enum tsh_msg_type_et */ 115 | uint8_t tsh_msg_type; 116 | /** Padding */ 117 | uint8_t tsh_reserved_1; 118 | /** Number of DWORDs in the packet, including the header */ 119 | uint16_t tsh_msg_len; 120 | /** Host-defined sequence number, for debugging */ 121 | uint16_t tsh_seq_num; 122 | /** Padding */ 123 | uint8_t tsh_reserved_2[2]; 124 | } __attribute__((packed)); 125 | ``` 126 | 127 | #### Host Packet Processing 128 | 1) Parse header 129 | - Determine which component deals with the request 130 | 2) Dispatch request 131 | - Write header + packet into component FIFO 132 | 133 | #### PCIe Configuration Space Requests 134 | First step in bringing up a PCIe device is respnding to configuration space requests. Refer to "User-Implemented Configuration Space" on page 119 of PG054. 135 | 136 | Most of this is handled by the IP hard block in the FPGA. For NVMe emulation, 137 | BAR0 and BAR1 are of interest. BAR2 is an optional register for NVMe (see 2.1.12 in the NVMe 1.4c specification.) BAR0/1 need to be exposed to the host PC in order to generate TLP requests for the correct memory addresses. 138 | 139 | Per the 7-series FPGA documentation, only PCI config space addresses 0xA8 -> 0xFF are able to be handled by user logic. This means that the host software MUST request BAR addresses during its initialization process by querying the configuration interface. 140 | 141 | The following structure is used to contain configuration space requests from the host. 142 | 143 | ``` 144 | enum tlp_streamer_write_options { 145 | /** PCIe config space read */ 146 | TSWO_READ = (0 << 0), 147 | /** PCIe config space write */ 148 | TSWO_WRITE = (1 << 0), 149 | /** 150 | * Write enable to treat any Read Only bit in the current write 151 | * as RW, not including bits set by attributes, reserved bits and 152 | * status bits. 153 | */ 154 | TSWO_WRITE_READONLY = (1 << 1), 155 | /** 156 | * Indicates the current write operation should treat any RW1C bit as 157 | * RW. Normally a RW1C bit is cleared by writing 1 to it and can normally 158 | * only be set by internal core conditions. During a configuration write 159 | * with this flag set, for every bit in tspcc_cfg_reg_data that is 1, a 160 | * corresponding RW1C configuration register bit is set to 1. A value of 161 | * 0 during this operation has no effect and non-RW1C bits are 162 | * unaffected regardless of the data in tspcc_cfg_reg_data. 163 | */ 164 | TSWO_WRITE_RW1C = (1 << 2), 165 | } 166 | 167 | struct tlp_streamer_pcie_cfg_cmd { 168 | /** 169 | * Configuration register to read from, see page 109+ from pg054. 170 | * Only 10 bits are used. 171 | */ 172 | uint16_t tspcc_cfg_reg_addr; 173 | /** Read vs. write */ 174 | uint8_t tspcc_cfg_write; 175 | /** Which bytes are valid during a cfg_reg write. 4-bits used. */ 176 | uint8_t tspcc_cfg_reg_be; 177 | /** Data returned from the register, or data to write to the register */ 178 | uint32_t tspcc_cfg_reg_data; 179 | }; 180 | ``` 181 | 182 | For example, a request to read BAR0 would be sent as: 183 | ``` 184 | { 185 | .tspcc_cfg_reg_addr = 0x04, 186 | .tspcc_cfg_write = 0, 187 | /* tspcc_cfg_reg_data and tspcf_cfg_reg_be may be uninitialized */ 188 | } 189 | ``` 190 | 191 | And the FPGA would respond: 192 | ``` 193 | { 194 | .tspcc_cfg_reg_addr = 0x4, 195 | .tspcc_cfg_write = 0, 196 | .tspcc_cfg_reg_data = 0xdeadbeef, 197 | .tspcc_cfg_reg_be = 0xf, 198 | } 199 | ``` 200 | 201 | #### PCIe TLP Management 202 | This block manages regular TLP transfers to and from the PCIe IP. It needs to pull data and feed the FIFO in front of the FT601. 203 | 204 | #### FPGA Configuration Block 205 | This block manages configuration of the FPGA device. It manages the following features: 206 | - FPGA hot reset for PCIe reconfiguration 207 | - USB loopback enable/disable 208 | - PCIe attributes that may be changed dynamically 209 | 210 | Q: Should all other requests be stopped during a config change? 211 | Q: Should the in-flight requests be handled first without starting any new ones? 212 | 213 | # Notes on manual testing 214 | ## How to trigger rescan after upgrading the bitstream 215 | 0) Flash new bitstream to the card 216 | 217 | 1) Get the PCI slot from `lspci`: 218 | ``` 219 | $ lspci -d 13a8:7021 220 | 0b:00.0 Serial controller: Exar Corp. Device 7021 221 | ``` 222 | 223 | 2) Remove the device (as root): 224 | ``` 225 | $ echo 1 > /sys/bus/pci/devices/0000\:0b\:00.0/remove 226 | ``` 227 | 228 | 3) Re-scan the PCI bus (as root): 229 | ``` 230 | $ echo 1 > /sys/bus/pci/rescan 231 | ``` 232 | 233 | ## Enabling MMIO for MRd/MWr TLP Generation 234 | 0) Get the PCI slot from `lspci`: 235 | ``` 236 | $ lspci -d 13a8:7021 237 | 0b:00.0 Serial controller: Exar Corp. Device 7021 238 | ``` 239 | 240 | 1) Enable MMIO for the slot (as root): 241 | ``` 242 | $ setpci -s 0b:00.0 COMMAND=0x2 243 | ``` 244 | 245 | 2) Verify the `BAR` is enabled 246 | - There should not be `[virtual]` or `[disabled]` in the output of lspci 247 | 248 | Working output: 249 | ``` 250 | $ lspci -d 13a8:7021 -v | grep "Memory at" 251 | Memory at fcc00000 (32-bit, non-prefetchable) [size=2K] 252 | ``` 253 | 254 | Non-working output: 255 | ``` 256 | $ lspci -d 13a8:7021 -v | grep "Memory at" 257 | Memory at fcc00000 (32-bit, non-prefetchable) [disabled] [size=2K] 258 | ``` 259 | 260 | ## Trigger a MRd/MWr TLP 261 | 0) Get the PCI slot from `lspci`: 262 | ``` 263 | $ lspci -d 13a8:7021 264 | 0b:00.0 Serial controller: Exar Corp. Device 7021 265 | ``` 266 | 267 | 1) Find the sysfs path to the PCIe device 268 | ``` 269 | $ find /sys/devices -name '0000:0b:00.0' | grep -v iommu 270 | /sys/devices/pci0000:00/0000:00:03.2/0000:0b:00.0 271 | ``` 272 | 273 | 2) Trigger a MRd TLP (as root) 274 | - Requires pcimem - https://github.com/billfarrow/pcimem 275 | - If the kernel has loaded a driver for the PCIe device, it may need to be unloaded first 276 | - The `resource0` file corresponds to `BAR0`, adjust as necessary for the appropriate `BAR` address. 277 | ``` 278 | $ ./pcimem /sys/devices/pci0000\:00/0000\:00\:03.2/0000\:0b\:00.0/resource0 0 w 279 | /sys/devices/pci0000:00/0000:00:03.2/0000:0b:00.0/resource0 opened. 280 | Target offset is 0x0, page size is 4096 281 | mmap(0, 4096, 0x3, 0x1, 3, 0x0) 282 | PCI Memory mapped to address 0x7fe58be8c000. 283 | 0x0000: 0xFFFFFFFF 284 | ``` 285 | -------------------------------------------------------------------------------- /src/constrs/screamer_m2.xdc: -------------------------------------------------------------------------------- 1 | set_property PACKAGE_PIN L18 [get_ports {ft601_be_io[0]}] 2 | set_property PACKAGE_PIN M17 [get_ports {ft601_be_io[1]}] 3 | set_property PACKAGE_PIN N18 [get_ports {ft601_be_io[2]}] 4 | set_property PACKAGE_PIN N17 [get_ports {ft601_be_io[3]}] 5 | set_property PACKAGE_PIN B9 [get_ports {ft601_data_io[0]}] 6 | set_property PACKAGE_PIN A9 [get_ports {ft601_data_io[1]}] 7 | set_property PACKAGE_PIN C9 [get_ports {ft601_data_io[2]}] 8 | set_property PACKAGE_PIN A10 [get_ports {ft601_data_io[3]}] 9 | set_property PACKAGE_PIN B10 [get_ports {ft601_data_io[4]}] 10 | set_property PACKAGE_PIN B11 [get_ports {ft601_data_io[5]}] 11 | set_property PACKAGE_PIN A12 [get_ports {ft601_data_io[6]}] 12 | set_property PACKAGE_PIN B12 [get_ports {ft601_data_io[7]}] 13 | set_property PACKAGE_PIN A13 [get_ports {ft601_data_io[8]}] 14 | set_property PACKAGE_PIN A14 [get_ports {ft601_data_io[9]}] 15 | set_property PACKAGE_PIN B14 [get_ports {ft601_data_io[10]}] 16 | set_property PACKAGE_PIN A15 [get_ports {ft601_data_io[11]}] 17 | set_property PACKAGE_PIN B15 [get_ports {ft601_data_io[12]}] 18 | set_property PACKAGE_PIN B16 [get_ports {ft601_data_io[13]}] 19 | set_property PACKAGE_PIN A17 [get_ports {ft601_data_io[14]}] 20 | set_property PACKAGE_PIN B17 [get_ports {ft601_data_io[15]}] 21 | set_property PACKAGE_PIN C17 [get_ports {ft601_data_io[16]}] 22 | set_property PACKAGE_PIN C18 [get_ports {ft601_data_io[17]}] 23 | set_property PACKAGE_PIN D18 [get_ports {ft601_data_io[18]}] 24 | set_property PACKAGE_PIN E17 [get_ports {ft601_data_io[19]}] 25 | set_property PACKAGE_PIN E18 [get_ports {ft601_data_io[20]}] 26 | set_property PACKAGE_PIN E16 [get_ports {ft601_data_io[21]}] 27 | set_property PACKAGE_PIN F18 [get_ports {ft601_data_io[22]}] 28 | set_property PACKAGE_PIN F17 [get_ports {ft601_data_io[23]}] 29 | set_property PACKAGE_PIN G17 [get_ports {ft601_data_io[24]}] 30 | set_property PACKAGE_PIN H18 [get_ports {ft601_data_io[25]}] 31 | set_property PACKAGE_PIN D13 [get_ports {ft601_data_io[26]}] 32 | set_property PACKAGE_PIN C14 [get_ports {ft601_data_io[27]}] 33 | set_property PACKAGE_PIN D14 [get_ports {ft601_data_io[28]}] 34 | set_property PACKAGE_PIN D15 [get_ports {ft601_data_io[29]}] 35 | set_property PACKAGE_PIN C16 [get_ports {ft601_data_io[30]}] 36 | set_property PACKAGE_PIN D16 [get_ports {ft601_data_io[31]}] 37 | set_property PACKAGE_PIN T15 [get_ports ft601_oe_n_o] 38 | set_property PACKAGE_PIN R16 [get_ports ft601_rd_n_o] 39 | set_property PACKAGE_PIN R18 [get_ports ft601_rxf_n_i] 40 | set_property PACKAGE_PIN R17 [get_ports ft601_siwu_n_o] 41 | set_property PACKAGE_PIN P18 [get_ports ft601_txe_n_i] 42 | set_property PACKAGE_PIN T18 [get_ports ft601_wr_n_o] 43 | set_property PACKAGE_PIN U15 [get_ports ft601_rst_n_o] 44 | set_property IOSTANDARD LVCMOS33 [get_ports ft601_rxf_n_i] 45 | set_property IOSTANDARD LVCMOS33 [get_ports ft601_txe_n_i] 46 | set_property IOSTANDARD LVCMOS33 [get_ports ft601_rst_n_o] 47 | set_property IOSTANDARD LVCMOS33 [get_ports ft601_oe_n_o] 48 | set_property IOSTANDARD LVCMOS33 [get_ports ft601_rd_n_o] 49 | set_property IOSTANDARD LVCMOS33 [get_ports ft601_wr_n_o] 50 | set_property IOSTANDARD LVCMOS33 [get_ports ft601_siwu_n_o] 51 | set_property IOSTANDARD LVCMOS33 [get_ports {{ft601_be_io[*]} {ft601_data_io[*]}}] 52 | set_property SLEW FAST [get_ports {{ft601_be_io[*]} {ft601_data_io[*]}}] 53 | set_property SLEW FAST [get_ports ft601_siwu_n_o] 54 | set_property SLEW FAST [get_ports ft601_wr_n_o] 55 | set_property SLEW FAST [get_ports ft601_rd_n_o] 56 | set_property SLEW FAST [get_ports ft601_oe_n_o] 57 | set_property SLEW FAST [get_ports ft601_rst_n_o] 58 | 59 | # LEDs are active high 60 | set_property PACKAGE_PIN V17 [get_ports user_led_ld1] 61 | set_property PACKAGE_PIN U17 [get_ports user_led_ld2] 62 | set_property IOSTANDARD LVCMOS33 [get_ports user_led_ld1] 63 | set_property IOSTANDARD LVCMOS33 [get_ports user_led_ld2] 64 | 65 | # SYSCLK 66 | set_property PACKAGE_PIN R2 [get_ports sys_clk] 67 | set_property IOSTANDARD LVCMOS33 [get_ports sys_clk] 68 | create_clock -period 10.000 -name net_clk -waveform {0.000 5.000} [get_ports sys_clk] 69 | 70 | # FT601 CLK 71 | set_property IOSTANDARD LVCMOS33 [get_ports ft601_clk_i] 72 | set_property PACKAGE_PIN E13 [get_ports ft601_clk_i] 73 | create_clock -period 10.000 -name net_ft601_clk_i -waveform {0.000 5.000} [get_ports ft601_clk_i] 74 | 75 | # Delay constraints are from FT601 Data sheet pg. 17 76 | set_input_delay -clock [get_clocks net_ft601_clk_i] -min 3.000 [get_ports {{ft601_data_io[*]} {ft601_be_io[*]}}] 77 | set_input_delay -clock [get_clocks net_ft601_clk_i] -max 3.500 [get_ports {{ft601_data_io[*]} {ft601_be_io[*]}}] 78 | set_output_delay -clock [get_clocks net_ft601_clk_i] -min 4.800 [get_ports {{ft601_data_io[*]} {ft601_be_io[*]}}] 79 | set_output_delay -clock [get_clocks net_ft601_clk_i] -max 1.000 [get_ports {{ft601_data_io[*]} {ft601_be_io[*]}}] 80 | 81 | set_input_delay -clock [get_clocks net_ft601_clk_i] -min 3.000 [get_ports {ft601_rxf_n_i ft601_txe_n_i}] 82 | set_input_delay -clock [get_clocks net_ft601_clk_i] -max 3.500 [get_ports {ft601_rxf_n_i ft601_txe_n_i}] 83 | 84 | set_output_delay -clock [get_clocks net_ft601_clk_i] -min 4.800 [get_ports {ft601_wr_n_o ft601_rd_n_o ft601_oe_n_o ft601_rst_n_o ft601_siwu_n_o}] 85 | set_output_delay -clock [get_clocks net_ft601_clk_i] -max 1.000 [get_ports {ft601_wr_n_o ft601_rd_n_o ft601_oe_n_o ft601_rst_n_o ft601_siwu_n_o}] 86 | 87 | # Constrain the LEDs to clean up the timing report 88 | set_output_delay -clock [get_clocks net_ft601_clk_i] -max 0.000 [get_ports {user_led_ld1 user_led_ld2}] 89 | set_output_delay -clock [get_clocks net_ft601_clk_i] -min 10.000 [get_ports {user_led_ld1 user_led_ld2}] 90 | 91 | # Exclude the reset hold counter from timing analysis as it only exists to 92 | # generate a reset signal during initial power-on. 93 | set_false_path -from [get_pins {comp_tlp_streamer_reset/reset_hold_count64_s_reg[*]/C}] 94 | set_false_path -to [get_ports {user_led_ld1 user_led_ld2}] 95 | 96 | # Force external signal registers to be in the IO Block for timing closure 97 | # Forcing the following three to IOB makes the design come within 1 net of timing closure 98 | set_property IOB TRUE [get_cells comp_tlp_streamer_ft601/ft601_rd_n_o_reg*] 99 | set_property IOB TRUE [get_cells comp_tlp_streamer_ft601/ft601_oe_n_o_reg*] 100 | set_property IOB TRUE [get_cells comp_tlp_streamer_ft601/ft601_wr_n_o_reg*] 101 | set_multicycle_path -from [get_pins comp_tlp_streamer_ft601/ft601_wr_n_s_2_reg*/C] -to [get_ports {{ft601_be_io[*]} {ft601_data_io[*]}}] 2 102 | 103 | #set_multicycle_path 2 -from [get_pins i_pcileech_com/i_pcileech_ft601/oe_reg/C] -to [get_ports {{ft601_be_io[*]} {ft601_data_io[*]}}] 104 | #set_multicycle_path 2 -from [get_clocks net_ft601_clk_i] -to [get_ports {{ft601_be_io[*]} {ft601_data_io[*]}}] 105 | #set_multicycle_path 2 -from [get_clocks net_ft601_clk_i] -to [get_ports ft601_oe_n_o] 106 | #set_multicycle_path 2 -from [get_clocks net_ft601_clk_i] -to [get_ports ft601_rd_n_o] 107 | #set_false_path -from [get_pins {i_pcileech_fifo/_pcie_core_config_reg[*]/C}] 108 | #set_false_path -from [get_pins i_pcileech_pcie_a7/i_pcie_7x_0/inst/inst/user_lnk_up_int_reg/C] -to [get_pins {i_pcileech_fifo/_cmd_tx_din_reg[16]/D}] 109 | #set_false_path -from [get_pins i_pcileech_pcie_a7/i_pcie_7x_0/inst/inst/user_reset_out_reg/C] 110 | 111 | #PCIe signals 112 | #set_property PACKAGE_PIN K1 [get_ports pcie_present] 113 | set_property PACKAGE_PIN M1 [get_ports pcie_perst_n_i] 114 | set_property PACKAGE_PIN L2 [get_ports pcie_wake_n_o] 115 | #set_property IOSTANDARD LVCMOS33 [get_ports pcie_present] 116 | set_property IOSTANDARD LVCMOS33 [get_ports pcie_perst_n_i] 117 | set_property IOSTANDARD LVCMOS33 [get_ports pcie_wake_n_o] 118 | 119 | #set_property LOC GTPE2_CHANNEL_X0Y2 [get_cells {comp_tlp_streamer_pcie/comp_pcie_7x_0/U0/inst/gt_top_i/pipe_wrapper_i/pipe_lane[0].gt_wrapper_i/gtp_channel.gtpe2_channel_i}] 120 | set_property LOC GTPE2_CHANNEL_X0Y0 [get_cells {comp_tlp_streamer_pcie/comp_pcie_7x_0/U0/inst/gt_top_i/pipe_wrapper_i/pipe_lane[0].gt_wrapper_i/gtp_channel.gtpe2_channel_i}] 121 | set_property PACKAGE_PIN E3 [get_ports {pcie_rxn_i[0]}] 122 | set_property PACKAGE_PIN E4 [get_ports {pcie_rxp_i[0]}] 123 | set_property PACKAGE_PIN H1 [get_ports {pcie_txn_o[0]}] 124 | set_property PACKAGE_PIN H2 [get_ports {pcie_txp_o[0]}] 125 | 126 | #set_property PACKAGE_PIN A3 [get_ports {pcie_rxn_i[1]}] 127 | #set_property PACKAGE_PIN A4 [get_ports {pcie_rxp_i[1]}] 128 | #set_property PACKAGE_PIN F1 [get_ports {pcie_txn_o[1]}] 129 | #set_property PACKAGE_PIN F2 [get_ports {pcie_txp_o[1]}] 130 | 131 | #set_property PACKAGE_PIN C3 [get_ports {pcie_rxn_i[2]}] 132 | #set_property PACKAGE_PIN C4 [get_ports {pcie_rxp_i[2]}] 133 | #set_property PACKAGE_PIN D1 [get_ports {pcie_txn_o[2]}] 134 | #set_property PACKAGE_PIN D2 [get_ports {pcie_txp_o[2]}] 135 | 136 | #set_property PACKAGE_PIN G3 [get_ports {pcie_rxn_i[3]}] 137 | #set_property PACKAGE_PIN G4 [get_ports {pcie_rxp_i[3]}] 138 | #set_property PACKAGE_PIN B1 [get_ports {pcie_txn_o[3]}] 139 | #set_property PACKAGE_PIN B2 [get_ports {pcie_txp_o[3]}] 140 | 141 | set_property PACKAGE_PIN D6 [get_ports pcie_clk_p_i] 142 | set_property PACKAGE_PIN D5 [get_ports pcie_clk_n_i] 143 | 144 | #set_property LOC GTPE2_COMMON_X0Y0 [get_cells {comp_tlp_streamer_pcie/ibufds_gte2_pcie_clk}] 145 | create_clock -period 10.000 -name pcie_ref_clk [get_nets pcie_clk_p_i] 146 | 147 | set_property CFGBVS Vcco [current_design] 148 | set_property CONFIG_VOLTAGE 3.3 [current_design] 149 | set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] 150 | set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] 151 | set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design] 152 | set_property BITSTREAM.CONFIG.CONFIGRATE 66 [current_design] 153 | 154 | set_operating_conditions -airflow 0 155 | set_operating_conditions -board_layers 4to7 156 | set_operating_conditions -board small 157 | set_operating_conditions -heatsink none 158 | set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub] 159 | set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub] 160 | set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub] 161 | connect_debug_port dbg_hub/clk [get_nets ft601_clk_i_IBUF_BUFG] 162 | -------------------------------------------------------------------------------- /src/design/tlp_streamer_ft601.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - FT601 Interface 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | entity tlp_streamer_ft601 is 12 | port ( 13 | sys_clk_i : in std_logic; 14 | sys_reset_i : in std_logic; 15 | ft601_clk_i : in std_logic; 16 | ft601_be_io : inout std_logic_vector(3 downto 0); 17 | ft601_data_io : inout std_logic_vector(31 downto 0); 18 | ft601_oe_n_o : out std_logic; 19 | ft601_rxf_n_i : in std_logic; 20 | ft601_rd_n_o : out std_logic; 21 | ft601_rst_n_o : out std_logic; 22 | ft601_txe_n_i : in std_logic; 23 | ft601_wr_n_o : out std_logic; 24 | ft601_siwu_n_o : out std_logic; 25 | ft601_rx_fifo_rd_en_i : in std_logic; 26 | ft601_rx_fifo_rd_empty_o : out std_logic; 27 | ft601_rx_fifo_rd_valid_o : out std_logic; 28 | ft601_rx_fifo_rd_data_o : out std_logic_vector(35 downto 0); 29 | ft601_tx_fifo_wr_en_i : in std_logic; 30 | ft601_tx_fifo_wr_full_o : out std_logic; 31 | ft601_tx_fifo_wr_data_i : in std_logic_vector(35 downto 0)); 32 | end entity tlp_streamer_ft601; 33 | 34 | architecture RTL of tlp_streamer_ft601 is 35 | 36 | component fifo_36_36_prim IS 37 | PORT ( 38 | rst : IN STD_LOGIC; 39 | wr_clk : IN STD_LOGIC; 40 | rd_clk : IN STD_LOGIC; 41 | din : IN STD_LOGIC_VECTOR(35 DOWNTO 0); 42 | wr_en : IN STD_LOGIC; 43 | rd_en : IN STD_LOGIC; 44 | dout : OUT STD_LOGIC_VECTOR(35 DOWNTO 0); 45 | full : OUT STD_LOGIC; 46 | empty : OUT STD_LOGIC; 47 | valid : OUT STD_LOGIC); 48 | END component fifo_36_36_prim; 49 | 50 | --component ila_0 IS 51 | -- PORT ( 52 | -- clk : IN STD_LOGIC; 53 | -- probe0 : IN STD_LOGIC_VECTOR(12 DOWNTO 0); 54 | -- probe1 : IN STD_LOGIC_VECTOR(12 DOWNTO 0); 55 | -- probe2 : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 56 | -- probe3 : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 57 | -- probe4 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 58 | -- probe5 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 59 | -- probe6 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 60 | -- probe7 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 61 | -- probe8 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 62 | -- probe9 : IN STD_LOGIC_VECTOR(15 DOWNTO 0); 63 | -- probe10 : IN STD_LOGIC_VECTOR(3 DOWNTO 0); 64 | -- probe11 : IN STD_LOGIC_VECTOR(9 DOWNTO 0); 65 | -- probe12 : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 66 | -- probe13 : IN STD_LOGIC_VECTOR(0 DOWNTO 0) 67 | --); 68 | --end component ila_0; 69 | 70 | type ft601_bus_state is (BUS_IDLE, 71 | RX_READY, RX_START, RX_WORD_1, RX_WORD_2, RX_COMPLETE, 72 | TX_READY, TX_WORD, TX_COMPLETE); 73 | signal current_bus_state, next_bus_state: ft601_bus_state; 74 | 75 | signal ft601_be_rd_i: std_logic_vector(3 downto 0); 76 | signal ft601_data_rd_i: std_logic_vector(31 downto 0); 77 | 78 | signal ft601_be_wr_o: std_logic_vector(3 downto 0); 79 | signal ft601_data_wr_o: std_logic_vector(31 downto 0); 80 | 81 | attribute IOB : string; 82 | attribute IOB of ft601_be_wr_o : signal is "TRUE"; 83 | attribute IOB of ft601_data_wr_o : signal is "TRUE"; 84 | 85 | signal ft601_oe_n_s: std_logic; 86 | signal ft601_rd_n_s: std_logic; 87 | signal ft601_wr_n_s_1: std_logic; 88 | signal ft601_wr_n_s_2: std_logic; 89 | 90 | signal fifo_rx_wr_data_s: std_logic_vector(35 downto 0); 91 | signal fifo_rx_wr_en_s: std_logic; 92 | signal fifo_rx_wr_full_s: std_logic; 93 | 94 | signal fifo_tx_rd_data_s: std_logic_vector(35 downto 0); 95 | signal fifo_tx_rd_en_s: std_logic; 96 | signal fifo_tx_rd_empty_s: std_logic; 97 | signal fifo_tx_rd_valid_s: std_logic; 98 | 99 | signal ft601_rx_fifo_rd_valid_s: std_logic; 100 | 101 | begin 102 | 103 | ft601_rx_usb_fifo: fifo_36_36_prim 104 | port map ( 105 | rst => sys_reset_i, 106 | wr_clk => ft601_clk_i, 107 | rd_clk => sys_clk_i, 108 | din => fifo_rx_wr_data_s, 109 | wr_en => fifo_rx_wr_en_s, 110 | rd_en => ft601_rx_fifo_rd_en_i, 111 | dout => ft601_rx_fifo_rd_data_o, 112 | full => fifo_rx_wr_full_s, 113 | empty => ft601_rx_fifo_rd_empty_o, 114 | valid => ft601_rx_fifo_rd_valid_s); 115 | 116 | ft601_tx_usb_fifo: fifo_36_36_prim 117 | port map ( 118 | rst => sys_reset_i, 119 | wr_clk => sys_clk_i, 120 | rd_clk => ft601_clk_i, 121 | din => ft601_tx_fifo_wr_data_i, 122 | wr_en => ft601_tx_fifo_wr_en_i, 123 | rd_en => fifo_tx_rd_en_s, 124 | dout => fifo_tx_rd_data_s, 125 | full => ft601_tx_fifo_wr_full_o, 126 | empty => fifo_tx_rd_empty_s, 127 | valid => fifo_tx_rd_valid_s); 128 | 129 | --comp_pcie_cfg_ila: ila_0 130 | -- PORT map ( 131 | -- clk => ft601_clk_i, 132 | -- probe0 => (others => '0'), 133 | -- probe1 => (others => '0'), 134 | -- probe2 => fifo_tx_rd_data_s(31 downto 0), 135 | -- probe3 => fifo_rx_wr_data_s(31 downto 0), 136 | -- probe4(0) => fifo_tx_rd_en_s, 137 | -- probe5(0) => fifo_rx_wr_en_s, 138 | -- probe6(0) => ft601_txe_n_i, 139 | -- probe7(0) => fifo_tx_rd_empty_s, 140 | -- probe8 => (others => '0'), 141 | -- probe9 => (others => '0'), 142 | -- probe10 => (others => '0'), 143 | -- probe11 => (others => '0'), 144 | -- probe12 => (others => '0'), 145 | -- probe13(0) => ft601_rxf_n_i 146 | --); 147 | 148 | 149 | bus_read_write: process(ft601_wr_n_s_2, ft601_be_wr_o, ft601_data_wr_o, 150 | ft601_be_io, ft601_data_io) 151 | begin 152 | 153 | if (ft601_wr_n_s_2 = '1') then 154 | ft601_be_io <= "ZZZZ"; 155 | ft601_data_io <= "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; 156 | else 157 | ft601_be_io <= ft601_be_wr_o; 158 | ft601_data_io <= ft601_data_wr_o; 159 | end if; 160 | ft601_be_rd_i <= ft601_be_io; 161 | ft601_data_rd_i <= ft601_data_io; 162 | 163 | end process bus_read_write; 164 | 165 | ft601_clock_process: process(ft601_clk_i, ft601_be_rd_i, 166 | ft601_data_rd_i, next_bus_state, 167 | ft601_oe_n_s, ft601_rx_fifo_rd_valid_s, 168 | ft601_rd_n_s, fifo_tx_rd_data_s, 169 | ft601_wr_n_s_1, ft601_wr_n_s_2) 170 | begin 171 | 172 | -- SIWU_N is listed as reserved in the FT601 datasheet. 173 | -- It *is* listed in the following datasheet: 174 | -- https://www.ftdichip.com/Support/Documents/AppNotes/AN_165_Establishing_Synchronous_245_FIFO_Communications_using_a_Morph-IC-II.pdf 175 | -- SI/WU == Send Immediate / Wake Up, assert this signal to send any TX data 176 | -- to the USB host immediately or to wake the host up from suspend. 177 | ft601_siwu_n_o <= '0'; 178 | ft601_rx_fifo_rd_valid_o <= ft601_rx_fifo_rd_valid_s; 179 | fifo_rx_wr_data_s <= ft601_be_rd_i & ft601_data_rd_i; 180 | 181 | if (rising_edge(ft601_clk_i)) then 182 | ft601_oe_n_o <= ft601_oe_n_s; 183 | ft601_wr_n_s_2 <= ft601_wr_n_s_1; 184 | ft601_rd_n_o <= ft601_rd_n_s; 185 | ft601_wr_n_o <= ft601_wr_n_s_1; 186 | ft601_be_wr_o <= fifo_tx_rd_data_s(35 downto 32); 187 | ft601_data_wr_o <= fifo_tx_rd_data_s(31 downto 0); 188 | end if; 189 | 190 | end process ft601_clock_process; 191 | 192 | ft601_fsm_state_process: process(ft601_clk_i, next_bus_state, sys_reset_i) 193 | begin 194 | 195 | ft601_rst_n_o <= not sys_reset_i; 196 | 197 | if (sys_reset_i = '1') then 198 | current_bus_state <= BUS_IDLE; 199 | elsif (rising_edge(ft601_clk_i)) then 200 | current_bus_state <= next_bus_state; 201 | end if; 202 | 203 | end process ft601_fsm_state_process; 204 | 205 | ft601_fsm_data_output_process: process(current_bus_state, ft601_rxf_n_i, 206 | fifo_tx_rd_valid_s) 207 | begin 208 | 209 | -- Assume the FPGA is not taking control of the FT601 bus 210 | ft601_oe_n_s <= '1'; 211 | ft601_rd_n_s <= '1'; 212 | ft601_wr_n_s_1 <= '1'; 213 | fifo_rx_wr_en_s <= '0'; 214 | fifo_tx_rd_en_s <= '0'; 215 | 216 | case current_bus_state is 217 | when RX_START => 218 | ft601_oe_n_s <= '0'; 219 | when RX_WORD_1 => 220 | -- Insert a delay state to ensure the RX FIFO only 221 | -- starts clocking valid data 222 | ft601_oe_n_s <= '0'; 223 | ft601_rd_n_s <= '0'; 224 | when RX_WORD_2 => 225 | -- Insert a delay state to ensure the RX FIFO only 226 | -- starts clocking valid data 227 | ft601_oe_n_s <= '0'; 228 | ft601_rd_n_s <= '0'; 229 | fifo_rx_wr_en_s <= not ft601_rxf_n_i; 230 | when RX_COMPLETE => 231 | ft601_oe_n_s <= '1'; 232 | ft601_rd_n_s <= '1'; 233 | when TX_WORD => 234 | fifo_tx_rd_en_s <= '1'; 235 | ft601_wr_n_s_1 <= not fifo_tx_rd_valid_s; 236 | when others => 237 | end case; 238 | 239 | end process ft601_fsm_data_output_process; 240 | 241 | ft601_fsm_state_select_process: process(current_bus_state, ft601_txe_n_i, ft601_rxf_n_i, 242 | fifo_rx_wr_full_s, fifo_tx_rd_empty_s, fifo_tx_rd_data_s) 243 | 244 | variable ft601_words_to_write_v: integer; 245 | 246 | begin 247 | -- Assume the state does not change by default 248 | next_bus_state <= current_bus_state; 249 | ft601_words_to_write_v := 0; 250 | 251 | case current_bus_state is 252 | when BUS_IDLE => 253 | if (ft601_txe_n_i = '0' and fifo_tx_rd_empty_s = '0') then 254 | next_bus_state <= TX_READY; 255 | elsif (ft601_rxf_n_i = '0' and fifo_rx_wr_full_s = '0') then 256 | next_bus_state <= RX_READY; 257 | end if; 258 | when RX_READY => 259 | next_bus_state <= RX_START; 260 | when RX_START => 261 | next_bus_state <= RX_WORD_1; 262 | when RX_WORD_1 => 263 | next_bus_state <= RX_WORD_2; 264 | when RX_WORD_2 => 265 | if (ft601_rxf_n_i = '1') then 266 | next_bus_state <= RX_COMPLETE; 267 | end if; 268 | when RX_COMPLETE => 269 | next_bus_state <= BUS_IDLE; 270 | when TX_READY => 271 | next_bus_state <= TX_WORD; 272 | ft601_words_to_write_v := to_integer(unsigned(fifo_tx_rd_data_s(23 downto 16) & fifo_tx_rd_data_s(31 downto 24))); 273 | when TX_WORD => 274 | ft601_words_to_write_v := ft601_words_to_write_v - 1; 275 | if (ft601_txe_n_i = '1' or fifo_tx_rd_empty_s = '1' or ft601_words_to_write_v = 0) then 276 | next_bus_state <= TX_COMPLETE; 277 | end if; 278 | when TX_COMPLETE => 279 | next_bus_state <= BUS_IDLE; 280 | end case; 281 | 282 | end process ft601_fsm_state_select_process; 283 | 284 | 285 | end architecture RTL; -------------------------------------------------------------------------------- /src/design/tlp_streamer_loopback.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - Host Packet Loopback Module 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | use work.tlp_streamer_records.all; 12 | 13 | entity tlp_streamer_loopback is 14 | port( 15 | sys_clk_i : in std_logic; 16 | sys_reset_i : in std_logic; 17 | -- Input from dispatch 18 | dispatch_i : in dispatch_producer_r; 19 | dispatch_o : out dispatch_consumer_r; 20 | -- Output to TX 21 | arbiter_i : in arbiter_producer_r; 22 | arbiter_o : out arbiter_consumer_r); 23 | end entity tlp_streamer_loopback; 24 | 25 | architecture RTL of tlp_streamer_loopback is 26 | 27 | component fifo_36_36_prim IS 28 | PORT ( 29 | rst : IN STD_LOGIC; 30 | wr_clk : IN STD_LOGIC; 31 | rd_clk : IN STD_LOGIC; 32 | din : IN STD_LOGIC_VECTOR(35 DOWNTO 0); 33 | wr_en : IN STD_LOGIC; 34 | rd_en : IN STD_LOGIC; 35 | dout : OUT STD_LOGIC_VECTOR(35 DOWNTO 0); 36 | full : OUT STD_LOGIC; 37 | empty : OUT STD_LOGIC; 38 | valid : OUT STD_LOGIC); 39 | END component fifo_36_36_prim; 40 | 41 | signal loopback_wr_en_s: std_logic; 42 | 43 | begin 44 | 45 | loopback_fifo: fifo_36_36_prim 46 | port map ( 47 | rst => sys_reset_i, 48 | wr_clk => sys_clk_i, 49 | rd_clk => sys_clk_i, 50 | din => dispatch_i.dispatch_wr_data, 51 | wr_en => loopback_wr_en_s, 52 | rd_en => arbiter_i.arbiter_rd_en, 53 | dout => arbiter_o.arbiter_rd_data, 54 | full => dispatch_o.dispatch_wr_full, 55 | empty => arbiter_o.arbiter_rd_empty, 56 | valid => arbiter_o.arbiter_rd_valid); 57 | 58 | loopback_wr_en_s <= dispatch_i.dispatch_wr_en and dispatch_i.dispatch_valid; 59 | 60 | end architecture RTL; 61 | -------------------------------------------------------------------------------- /src/design/tlp_streamer_pcie.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - PCIe Interface 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | library UNISIM; 12 | use UNISIM.vcomponents.all; 13 | 14 | use work.tlp_streamer_records.all; 15 | 16 | entity tlp_streamer_pcie is 17 | port ( 18 | user_led_ld2 : out std_logic; 19 | sys_clk_i : in std_logic; 20 | sys_reset_i : in std_logic; 21 | pcie_clk_p_i : in std_logic; 22 | pcie_clk_n_i : in std_logic; 23 | pcie_perst_n_i : in std_logic; 24 | pcie_wake_n_o : out std_logic; 25 | pcie_txp_o : out std_logic_vector(0 downto 0); 26 | pcie_txn_o : out std_logic_vector(0 downto 0); 27 | pcie_rxp_i : in std_logic_vector(0 downto 0); 28 | pcie_rxn_i : in std_logic_vector(0 downto 0); 29 | --pcie_usr_clk_o : out std_logic; 30 | --pcie_usr_rst_o : out std_logic; 31 | pcie_usr_link_up_o : out std_logic; 32 | -- Host Packet RX/TX management 33 | pcie_cfg_dispatch_i : in dispatch_producer_r; 34 | pcie_cfg_dispatch_o : out dispatch_consumer_r; 35 | pcie_cfg_arbiter_i : in arbiter_producer_r; 36 | pcie_cfg_arbiter_o : out arbiter_consumer_r; 37 | pcie_tlp_dispatch_i : in dispatch_producer_r; 38 | pcie_tlp_dispatch_o : out dispatch_consumer_r; 39 | pcie_tlp_arbiter_i : in arbiter_producer_r; 40 | pcie_tlp_arbiter_o : out arbiter_consumer_r); 41 | --pcie_usr_app_rdy : out std_logic; 42 | --pcie_s_axi_tx_tready_o : out std_logic; 43 | --pcie_s_axi_tx_tdata_i : in std_logic_vector(63 downto 0); 44 | --pcie_s_axi_tx_tkeep_i : in std_logic_vector(7 downto 0); 45 | --pcie_s_axi_tx_tlast_i : in std_logic; 46 | --pcie_s_axi_tx_tvalid_i : in std_logic; 47 | --pcie_s_axi_tx_tuser_i : in std_logic_vector(3 downto 0); 48 | --pcie_m_axi_rx_tdata_o : out std_logic_vector(63 downto 0); 49 | --pcie_m_axi_rx_tkeep_o : out std_logic_vector(7 downto 0); 50 | --pcie_m_axi_rx_tlast_o : out std_logic; 51 | --pcie_m_axi_rx_tvalid_o : out std_logic; 52 | --pcie_m_axi_rx_tready_i : in std_logic; 53 | --pcie_m_axi_rx_tuser_o : out std_logic_vector(21 downto 0); 54 | end entity tlp_streamer_pcie; 55 | 56 | architecture RTL of tlp_streamer_pcie is 57 | 58 | component pcie_7x_0 IS 59 | PORT ( 60 | pci_exp_txp : OUT STD_LOGIC_VECTOR(0 DOWNTO 0); 61 | pci_exp_txn : OUT STD_LOGIC_VECTOR(0 DOWNTO 0); 62 | pci_exp_rxp : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 63 | pci_exp_rxn : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 64 | user_clk_out : OUT STD_LOGIC; 65 | user_reset_out : OUT STD_LOGIC; 66 | user_lnk_up : OUT STD_LOGIC; 67 | user_app_rdy : OUT STD_LOGIC; 68 | s_axis_tx_tready : OUT STD_LOGIC; 69 | s_axis_tx_tdata : IN STD_LOGIC_VECTOR(63 DOWNTO 0); 70 | s_axis_tx_tkeep : IN STD_LOGIC_VECTOR(7 DOWNTO 0); 71 | s_axis_tx_tlast : IN STD_LOGIC; 72 | s_axis_tx_tvalid : IN STD_LOGIC; 73 | s_axis_tx_tuser : IN STD_LOGIC_VECTOR(3 DOWNTO 0); 74 | m_axis_rx_tdata : OUT STD_LOGIC_VECTOR(63 DOWNTO 0); 75 | m_axis_rx_tkeep : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); 76 | m_axis_rx_tlast : OUT STD_LOGIC; 77 | m_axis_rx_tvalid : OUT STD_LOGIC; 78 | m_axis_rx_tready : IN STD_LOGIC; 79 | m_axis_rx_tuser : OUT STD_LOGIC_VECTOR(21 DOWNTO 0); 80 | -- PCIe configuration management port 81 | cfg_mgmt_do : OUT STD_LOGIC_VECTOR(31 DOWNTO 0); 82 | cfg_mgmt_rd_wr_done : OUT STD_LOGIC; 83 | cfg_mgmt_di : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 84 | cfg_mgmt_byte_en : IN STD_LOGIC_VECTOR(3 DOWNTO 0); 85 | cfg_mgmt_dwaddr : IN STD_LOGIC_VECTOR(9 DOWNTO 0); 86 | cfg_mgmt_wr_en : IN STD_LOGIC; 87 | cfg_mgmt_rd_en : IN STD_LOGIC; 88 | cfg_mgmt_wr_readonly : IN STD_LOGIC; 89 | cfg_mgmt_wr_rw1c_as_rw : IN STD_LOGIC; 90 | cfg_interrupt : IN STD_LOGIC; 91 | cfg_interrupt_rdy : OUT STD_LOGIC; 92 | cfg_interrupt_assert : IN STD_LOGIC; 93 | cfg_interrupt_di : IN STD_LOGIC_VECTOR(7 DOWNTO 0); 94 | cfg_interrupt_do : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); 95 | cfg_interrupt_mmenable : OUT STD_LOGIC_VECTOR(2 DOWNTO 0); 96 | cfg_interrupt_msienable : OUT STD_LOGIC; 97 | cfg_interrupt_msixenable : OUT STD_LOGIC; 98 | cfg_interrupt_msixfm : OUT STD_LOGIC; 99 | cfg_interrupt_stat : IN STD_LOGIC; 100 | cfg_pciecap_interrupt_msgnum : IN STD_LOGIC_VECTOR(4 DOWNTO 0); 101 | pl_directed_link_change : IN STD_LOGIC_VECTOR(1 DOWNTO 0); 102 | pl_directed_link_width : IN STD_LOGIC_VECTOR(1 DOWNTO 0); 103 | pl_directed_link_speed : IN STD_LOGIC; 104 | pl_directed_link_auton : IN STD_LOGIC; 105 | pl_upstream_prefer_deemph : IN STD_LOGIC; 106 | pl_sel_lnk_rate : OUT STD_LOGIC; -- 107 | pl_sel_lnk_width : OUT STD_LOGIC_VECTOR(1 DOWNTO 0); 108 | pl_ltssm_state : OUT STD_LOGIC_VECTOR(5 DOWNTO 0); 109 | pl_lane_reversal_mode : OUT STD_LOGIC_VECTOR(1 DOWNTO 0); 110 | pl_phy_lnk_up : OUT STD_LOGIC; 111 | pl_tx_pm_state : OUT STD_LOGIC_VECTOR(2 DOWNTO 0); 112 | pl_rx_pm_state : OUT STD_LOGIC_VECTOR(1 DOWNTO 0); 113 | pl_link_upcfg_cap : OUT STD_LOGIC; 114 | pl_link_gen2_cap : OUT STD_LOGIC; 115 | pl_link_partner_gen2_supported : OUT STD_LOGIC; 116 | pl_initial_link_width : OUT STD_LOGIC_VECTOR(2 DOWNTO 0); -- 117 | pl_directed_change_done : OUT STD_LOGIC; 118 | pl_received_hot_rst : OUT STD_LOGIC; 119 | pl_transmit_hot_rst : IN STD_LOGIC; 120 | pl_downstream_deemph_source : IN STD_LOGIC; 121 | sys_clk : IN STD_LOGIC; 122 | sys_rst_n : IN STD_LOGIC 123 | ); 124 | END component pcie_7x_0; 125 | 126 | component tlp_streamer_pcie_cfg is 127 | port ( 128 | sys_clk_i : in std_logic; 129 | pcie_clk_i : in std_logic; 130 | sys_reset_i : in std_logic; 131 | -- PCIe Configuration Port from PCIe IP 132 | pcie_cfg_mgmt_producer_i : in pcie_cfg_mgmt_port_producer_r; 133 | pcie_cfg_mgmt_consumer_o : out pcie_cfg_mgmt_port_consumer_r; 134 | -- Input Requests from the host to handle 135 | dispatch_i : in dispatch_producer_r; 136 | dispatch_o : out dispatch_consumer_r; 137 | -- Output Packets towards the host 138 | arbiter_i : in arbiter_producer_r; 139 | arbiter_o : out arbiter_consumer_r); 140 | end component tlp_streamer_pcie_cfg; 141 | 142 | component tlp_streamer_pcie_tlp is 143 | port ( 144 | sys_clk_i : in std_logic; 145 | pcie_clk_i : in std_logic; 146 | pcie_rst_i : in std_logic; 147 | -- Host Packet RX/TX management 148 | dispatch_i : in dispatch_producer_r; 149 | dispatch_o : out dispatch_consumer_r; 150 | arbiter_i : in arbiter_producer_r; 151 | arbiter_o : out arbiter_consumer_r; 152 | -- PCIe Core TLP Interface 153 | pcie_tlp_tx_producer_i : in pcie_tlp_tx_port_producer_r; 154 | pcie_tlp_tx_consumer_o : out pcie_tlp_tx_port_consumer_r; 155 | pcie_tlp_rx_producer_i : in pcie_tlp_rx_port_producer_r; 156 | pcie_tlp_rx_consumer_o : out pcie_tlp_rx_port_consumer_r); 157 | end component tlp_streamer_pcie_tlp; 158 | 159 | signal pcie_rst_n_s: std_logic; 160 | signal pcie_clk_s: std_logic; 161 | 162 | -- Temporary signal until more behaviour is implemented/exposed to other components. 163 | signal user_clk_s, user_lnk_up_s, user_reset_s, user_app_rdy_s: std_logic; 164 | 165 | signal cfg_interrupt_s, cfg_interrupt_rdy_s, cfg_interrupt_assert_s, 166 | cfg_interrupt_msienable_s, cfg_interrupt_msixenable_s, 167 | cfg_interrupt_msixfm_s, cfg_interrupt_stat_s: std_logic := '0'; 168 | signal cfg_interrupt_di_s, cfg_interrupt_do_s: std_logic_vector(7 downto 0) := "00000000"; 169 | signal cfg_interrupt_mmenable_s: std_logic_vector(2 downto 0) := "000"; 170 | signal cfg_pciecap_interrupt_msgnum_s: std_logic_vector(4 downto 0) := "00000"; 171 | 172 | signal pl_directed_link_change_s, pl_directed_link_width_s: std_logic_vector(1 downto 0) := "00"; 173 | signal pl_directed_link_speed_s, pl_directed_link_auton_s, pl_upstream_prefer_deemph_s, 174 | pl_sel_lnk_rate_s, pl_phy_lnk_up_s, pl_link_upcfg_cap_s, pl_link_gen2_cap_s, 175 | pl_link_partner_gen2_supported_s, pl_directed_change_done_s, pl_received_hot_rst_s, 176 | pl_transmit_hot_rst_s, pl_downstream_deemph_source_s: std_logic := '0'; 177 | signal pl_sel_lnk_width_s, pl_lane_reversal_mode_s, pl_rx_pm_state_s: std_logic_vector(1 downto 0) := "00"; 178 | signal pl_ltssm_state_s: std_logic_vector(5 downto 0) := "000000"; 179 | signal pl_tx_pm_state_s, pl_initial_link_width_s: std_logic_vector(2 downto 0) := "000"; 180 | 181 | signal pcie_clk_blink_64_s: unsigned(63 downto 0) := (others => '0'); 182 | 183 | -- Configuration management interface 184 | signal pcie_cfg_mgmt_producer_s: pcie_cfg_mgmt_port_producer_r; 185 | signal pcie_cfg_mgmt_consumer_s: pcie_cfg_mgmt_port_consumer_r; 186 | 187 | -- TLP RX/TX Interface 188 | signal pcie_tlp_tx_producer_s: pcie_tlp_tx_port_producer_r; 189 | signal pcie_tlp_tx_consumer_s: pcie_tlp_tx_port_consumer_r; 190 | signal pcie_tlp_rx_producer_s: pcie_tlp_rx_port_producer_r; 191 | signal pcie_tlp_rx_consumer_s: pcie_tlp_rx_port_consumer_r; 192 | 193 | begin 194 | 195 | -- Refer to https://www.xilinx.com/support/documentation/user_guides/ug482_7Series_GTP_Transceivers.pdf 196 | -- Page 24 for IBUFDS_GTE2 configuration options 197 | ibufds_gte2_pcie_clk : IBUFDS_GTE2 198 | generic map ( 199 | CLKCM_CFG => TRUE, 200 | CLKRCV_TRST => TRUE, 201 | CLKSWING_CFG => "11" 202 | ) 203 | port map ( 204 | O => pcie_clk_s, 205 | ODIV2 => open, 206 | CEB => '0', 207 | I => pcie_clk_p_i, 208 | IB => pcie_clk_n_i 209 | ); 210 | 211 | comp_tlp_streamer_pcie_cfg: tlp_streamer_pcie_cfg 212 | port map ( 213 | sys_clk_i => sys_clk_i, 214 | pcie_clk_i => user_clk_s, 215 | sys_reset_i => user_reset_s, 216 | -- PCIe Configuration Port from PCIe IP 217 | pcie_cfg_mgmt_producer_i => pcie_cfg_mgmt_producer_s, 218 | pcie_cfg_mgmt_consumer_o => pcie_cfg_mgmt_consumer_s, 219 | -- Input Requests from the host to handle 220 | dispatch_i => pcie_cfg_dispatch_i, 221 | dispatch_o => pcie_cfg_dispatch_o, 222 | -- Output Packets towards the host 223 | arbiter_i => pcie_cfg_arbiter_i, 224 | arbiter_o => pcie_cfg_arbiter_o); 225 | 226 | comp_tlp_streamer_pcie_tlp: tlp_streamer_pcie_tlp 227 | port map( 228 | sys_clk_i => sys_clk_i, 229 | pcie_clk_i => user_clk_s, 230 | pcie_rst_i => user_reset_s, 231 | -- Host Packet RX/TX management 232 | dispatch_i => pcie_tlp_dispatch_i, 233 | dispatch_o => pcie_tlp_dispatch_o, 234 | arbiter_i => pcie_tlp_arbiter_i, 235 | arbiter_o => pcie_tlp_arbiter_o, 236 | -- PCIe Core TLP Interface 237 | pcie_tlp_tx_producer_i => pcie_tlp_tx_producer_s, 238 | pcie_tlp_tx_consumer_o => pcie_tlp_tx_consumer_s, 239 | pcie_tlp_rx_producer_i => pcie_tlp_rx_producer_s, 240 | pcie_tlp_rx_consumer_o => pcie_tlp_rx_consumer_s); 241 | 242 | comp_pcie_7x_0: pcie_7x_0 243 | port map( 244 | pci_exp_txp => pcie_txp_o, 245 | pci_exp_txn => pcie_txn_o, 246 | pci_exp_rxp => pcie_rxp_i, 247 | pci_exp_rxn => pcie_rxn_i, 248 | user_clk_out => user_clk_s, 249 | user_reset_out => user_reset_s, 250 | user_lnk_up => user_lnk_up_s, 251 | user_app_rdy => user_app_rdy_s, 252 | s_axis_tx_tready => pcie_tlp_tx_producer_s.tlp_axis_tx_tready, 253 | s_axis_tx_tdata => pcie_tlp_tx_consumer_s.tlp_axis_tx_tdata, 254 | s_axis_tx_tkeep => pcie_tlp_tx_consumer_s.tlp_axis_tx_tkeep, 255 | s_axis_tx_tlast => pcie_tlp_tx_consumer_s.tlp_axis_tx_tlast, 256 | s_axis_tx_tvalid => pcie_tlp_tx_consumer_s.tlp_axis_tx_tvalid, 257 | s_axis_tx_tuser => pcie_tlp_tx_consumer_s.tlp_axis_tx_tuser, 258 | m_axis_rx_tdata => pcie_tlp_rx_producer_s.tlp_axis_rx_tdata, 259 | m_axis_rx_tkeep => pcie_tlp_rx_producer_s.tlp_axis_rx_tkeep, 260 | m_axis_rx_tlast => pcie_tlp_rx_producer_s.tlp_axis_rx_tlast, 261 | m_axis_rx_tvalid => pcie_tlp_rx_producer_s.tlp_axis_rx_tvalid, 262 | m_axis_rx_tready => pcie_tlp_rx_consumer_s.tlp_axis_rx_tready, 263 | m_axis_rx_tuser => pcie_tlp_rx_producer_s.tlp_axis_rx_tuser, 264 | -- Configuration space management port 265 | cfg_mgmt_do => pcie_cfg_mgmt_producer_s.cfg_mgmt_do, 266 | cfg_mgmt_rd_wr_done => pcie_cfg_mgmt_producer_s.cfg_mgmt_rd_wr_done, 267 | cfg_mgmt_di => pcie_cfg_mgmt_consumer_s.cfg_mgmt_di, 268 | cfg_mgmt_byte_en => pcie_cfg_mgmt_consumer_s.cfg_mgmt_byte_en, 269 | cfg_mgmt_dwaddr => pcie_cfg_mgmt_consumer_s.cfg_mgmt_dwaddr, 270 | cfg_mgmt_wr_en => pcie_cfg_mgmt_consumer_s.cfg_mgmt_wr_en, 271 | cfg_mgmt_rd_en => pcie_cfg_mgmt_consumer_s.cfg_mgmt_rd_en, 272 | cfg_mgmt_wr_readonly => pcie_cfg_mgmt_consumer_s.cfg_mgmt_wr_readonly, 273 | cfg_mgmt_wr_rw1c_as_rw => pcie_cfg_mgmt_consumer_s.cfg_mgmt_wr_rw1c_as_rw, 274 | cfg_interrupt => cfg_interrupt_s, 275 | cfg_interrupt_rdy => cfg_interrupt_rdy_s, 276 | cfg_interrupt_assert => cfg_interrupt_assert_s, 277 | cfg_interrupt_di => cfg_interrupt_di_s, 278 | cfg_interrupt_do => cfg_interrupt_do_s, 279 | cfg_interrupt_mmenable => cfg_interrupt_mmenable_s, 280 | cfg_interrupt_msienable => cfg_interrupt_msienable_s, 281 | cfg_interrupt_msixenable => cfg_interrupt_msixenable_s, 282 | cfg_interrupt_msixfm => cfg_interrupt_msixfm_s, 283 | cfg_interrupt_stat => cfg_interrupt_stat_s, 284 | cfg_pciecap_interrupt_msgnum => cfg_pciecap_interrupt_msgnum_s, 285 | pl_directed_link_change => pl_directed_link_change_s, 286 | pl_directed_link_width => pl_directed_link_width_s, 287 | pl_directed_link_speed => pl_directed_link_speed_s, 288 | pl_directed_link_auton => pl_directed_link_auton_s, 289 | pl_upstream_prefer_deemph => pl_upstream_prefer_deemph_s, 290 | pl_sel_lnk_rate => pl_sel_lnk_rate_s, 291 | pl_sel_lnk_width => pl_sel_lnk_width_s, 292 | pl_ltssm_state => pl_ltssm_state_s, 293 | pl_lane_reversal_mode => pl_lane_reversal_mode_s, 294 | pl_phy_lnk_up => pl_phy_lnk_up_s, 295 | pl_tx_pm_state => pl_tx_pm_state_s, 296 | pl_rx_pm_state => pl_rx_pm_state_s, 297 | pl_link_upcfg_cap => pl_link_upcfg_cap_s, 298 | pl_link_gen2_cap => pl_link_gen2_cap_s, 299 | pl_link_partner_gen2_supported => pl_link_partner_gen2_supported_s, 300 | pl_initial_link_width => pl_initial_link_width_s, 301 | pl_directed_change_done => pl_directed_change_done_s, 302 | pl_received_hot_rst => pl_received_hot_rst_s, 303 | pl_transmit_hot_rst => pl_transmit_hot_rst_s, 304 | pl_downstream_deemph_source => pl_downstream_deemph_source_s, 305 | sys_clk => pcie_clk_s, 306 | sys_rst_n => pcie_rst_n_s 307 | ); 308 | 309 | pcie_reset_process: process(sys_reset_i, pcie_perst_n_i, user_lnk_up_s) 310 | begin 311 | 312 | pcie_wake_n_o <= '1'; 313 | pcie_rst_n_s <= not (sys_reset_i or not pcie_perst_n_i); 314 | pcie_usr_link_up_o <= user_lnk_up_s; 315 | 316 | end process pcie_reset_process; 317 | 318 | blink_debug_process: process(pcie_clk_s, pcie_clk_blink_64_s) 319 | begin 320 | user_led_ld2 <= pcie_clk_blink_64_s(25); 321 | 322 | if (rising_edge(pcie_clk_s)) then 323 | pcie_clk_blink_64_s <= pcie_clk_blink_64_s + 1; 324 | end if; 325 | 326 | end process blink_debug_process; 327 | 328 | end architecture RTL; -------------------------------------------------------------------------------- /src/design/tlp_streamer_pcie_cfg.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - PCIe Configuration Space Request Management 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | use work.tlp_streamer_records.all; 12 | 13 | entity tlp_streamer_pcie_cfg is 14 | port ( 15 | sys_clk_i : in std_logic; 16 | pcie_clk_i : in std_logic; 17 | sys_reset_i : in std_logic; 18 | -- PCIe Configuration Port from PCIe IP 19 | pcie_cfg_mgmt_producer_i : in pcie_cfg_mgmt_port_producer_r; 20 | pcie_cfg_mgmt_consumer_o : out pcie_cfg_mgmt_port_consumer_r; 21 | -- Input Requests from the host to handle 22 | dispatch_i : in dispatch_producer_r; 23 | dispatch_o : out dispatch_consumer_r; 24 | -- Output Packets towards the host 25 | arbiter_i : in arbiter_producer_r; 26 | arbiter_o : out arbiter_consumer_r); 27 | end entity tlp_streamer_pcie_cfg; 28 | 29 | architecture RTL of tlp_streamer_pcie_cfg is 30 | 31 | component fifo_32_32_bram IS 32 | port ( 33 | rst : IN STD_LOGIC; 34 | wr_clk : IN STD_LOGIC; 35 | rd_clk : IN STD_LOGIC; 36 | din : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 37 | wr_en : IN STD_LOGIC; 38 | rd_en : IN STD_LOGIC; 39 | dout : OUT STD_LOGIC_VECTOR(31 DOWNTO 0); 40 | full : OUT STD_LOGIC; 41 | empty : OUT STD_LOGIC; 42 | valid : OUT STD_LOGIC; 43 | wr_rst_busy : OUT STD_LOGIC; 44 | rd_rst_busy : OUT STD_LOGIC 45 | ); 46 | end component fifo_32_32_bram; 47 | 48 | type pcie_cfg_req_state is (PCIE_CFG_IDLE, PCIE_CFG_AWAIT_HEADER, PCIE_CFG_PARSE_HEADER_1, 49 | PCIE_CFG_PARSE_HEADER_2, PCIE_CFG_PARSE_CMD_1, PCIE_CFG_PARSE_CMD_2, 50 | PCIE_CFG_READ_1, PCIE_CFG_READ_2, PCIE_CFG_WRITE_1, PCIE_CFG_WRITE_2, 51 | PCIE_CFG_TX_PACKET_1, PCIE_CFG_TX_PACKET_2, PCIE_CFG_TX_PACKET_3, 52 | PCIE_CFG_TX_PACKET_4, PCIE_CFG_COMPLETE); 53 | 54 | signal current_pcie_cfg_req_state, next_pcie_cfg_req_state: pcie_cfg_req_state; 55 | 56 | -- RX/TX FIFO Signals 57 | signal pcie_cfg_fifo_rx_wr_en_s: std_logic; 58 | signal pcie_cfg_fifo_rx_rd_en_s, pcie_cfg_fifo_rx_rd_empty_s, pcie_cfg_fifo_rx_rd_valid_s: std_logic; 59 | signal pcie_cfg_fifo_rx_rd_data_s: std_logic_vector(31 downto 0); 60 | 61 | signal pcie_cfg_fifo_tx_wr_en_s, next_pcie_cfg_fifo_tx_wr_en_s, pcie_cfg_fifo_tx_wr_full_s: std_logic; 62 | signal pcie_cfg_fifo_tx_wr_data_s, next_pcie_cfg_fifo_tx_wr_data_s, pcie_cfg_fifo_tx_rd_data_s: std_logic_vector(31 downto 0); 63 | 64 | -- Current packet signals 65 | signal pcie_cfg_req_seq_id_s, next_pcie_cfg_req_seq_id_s: std_logic_vector(15 downto 0); 66 | signal pcie_cfg_cmd_write_be_s, next_pcie_cfg_cmd_write_be_s: std_logic_vector(3 downto 0); 67 | signal pcie_cfg_cmd_write_s, next_pcie_cfg_cmd_write_s: std_logic; 68 | signal pcie_cfg_cmd_write_readonly_s, next_pcie_cfg_cmd_write_readonly_s: std_logic; 69 | signal pcie_cfg_cmd_write_rw1c_as_rw_s, next_pcie_cfg_cmd_write_rw1c_as_rw_s: std_logic; 70 | signal pcie_cfg_cmd_addr_s, next_pcie_cfg_cmd_addr_s: std_logic_vector(9 downto 0); 71 | signal pcie_cfg_cmd_data_s, next_pcie_cfg_cmd_data_s: std_logic_vector(31 downto 0); 72 | 73 | begin 74 | 75 | comp_pcie_cfg_rx_fifo: fifo_32_32_bram 76 | port map ( 77 | rst => sys_reset_i, 78 | wr_clk => sys_clk_i, 79 | rd_clk => pcie_clk_i, 80 | din => dispatch_i.dispatch_wr_data(31 downto 0), 81 | wr_en => pcie_cfg_fifo_rx_wr_en_s, 82 | rd_en => pcie_cfg_fifo_rx_rd_en_s, 83 | dout => pcie_cfg_fifo_rx_rd_data_s, 84 | full => dispatch_o.dispatch_wr_full, 85 | empty => pcie_cfg_fifo_rx_rd_empty_s, 86 | valid => pcie_cfg_fifo_rx_rd_valid_s, 87 | wr_rst_busy => open, 88 | rd_rst_busy => open); 89 | 90 | comp_pcie_cfg_tx_fifo: fifo_32_32_bram 91 | port map ( 92 | rst => sys_reset_i, 93 | wr_clk => pcie_clk_i, 94 | rd_clk => sys_clk_i, 95 | din => pcie_cfg_fifo_tx_wr_data_s, 96 | wr_en => pcie_cfg_fifo_tx_wr_en_s, 97 | rd_en => arbiter_i.arbiter_rd_en, 98 | dout => pcie_cfg_fifo_tx_rd_data_s, 99 | full => pcie_cfg_fifo_tx_wr_full_s, 100 | empty => arbiter_o.arbiter_rd_empty, 101 | valid => arbiter_o.arbiter_rd_valid, 102 | wr_rst_busy => open, 103 | rd_rst_busy => open); 104 | 105 | pcie_cfg_rx_tx_async_process: process(dispatch_i, pcie_cfg_fifo_tx_rd_data_s) 106 | begin 107 | 108 | pcie_cfg_fifo_rx_wr_en_s <= dispatch_i.dispatch_wr_en and 109 | dispatch_i.dispatch_valid; 110 | -- The extra 1's here correspond to the byte_enable portion of the 111 | -- data sent to the FT601 112 | arbiter_o.arbiter_rd_data <= "1111" & pcie_cfg_fifo_tx_rd_data_s; 113 | 114 | end process pcie_cfg_rx_tx_async_process; 115 | 116 | pcie_cfg_fsm_state_process: process(pcie_clk_i, sys_reset_i, next_pcie_cfg_req_state, current_pcie_cfg_req_state, 117 | next_pcie_cfg_req_seq_id_s, next_pcie_cfg_cmd_write_be_s, 118 | next_pcie_cfg_cmd_write_s, next_pcie_cfg_cmd_addr_s, 119 | next_pcie_cfg_cmd_data_s, next_pcie_cfg_fifo_tx_wr_data_s, 120 | next_pcie_cfg_cmd_write_readonly_s, next_pcie_cfg_cmd_write_rw1c_as_rw_s) 121 | begin 122 | 123 | if (sys_reset_i = '1') then 124 | current_pcie_cfg_req_state <= PCIE_CFG_IDLE; 125 | pcie_cfg_req_seq_id_s <= (others => '0'); 126 | pcie_cfg_cmd_write_be_s <= (others => '0'); 127 | pcie_cfg_cmd_write_s <= '0'; 128 | pcie_cfg_cmd_addr_s <= (others => '0'); 129 | pcie_cfg_cmd_data_s <= (others => '0'); 130 | pcie_cfg_fifo_tx_wr_data_s <= (others => '0'); 131 | pcie_cfg_fifo_tx_wr_en_s <= '0'; 132 | elsif (rising_edge(pcie_clk_i)) then 133 | current_pcie_cfg_req_state <= next_pcie_cfg_req_state; 134 | 135 | pcie_cfg_req_seq_id_s <= next_pcie_cfg_req_seq_id_s; 136 | pcie_cfg_cmd_write_be_s <= next_pcie_cfg_cmd_write_be_s; 137 | pcie_cfg_cmd_write_s <= next_pcie_cfg_cmd_write_s; 138 | pcie_cfg_cmd_write_readonly_s <= next_pcie_cfg_cmd_write_readonly_s; 139 | pcie_cfg_cmd_write_rw1c_as_rw_s <= next_pcie_cfg_cmd_write_rw1c_as_rw_s; 140 | pcie_cfg_cmd_addr_s <= next_pcie_cfg_cmd_addr_s; 141 | pcie_cfg_cmd_data_s <= next_pcie_cfg_cmd_data_s; 142 | 143 | pcie_cfg_fifo_tx_wr_data_s <= next_pcie_cfg_fifo_tx_wr_data_s; 144 | pcie_cfg_fifo_tx_wr_en_s <= next_pcie_cfg_fifo_tx_wr_en_s; 145 | end if; 146 | 147 | end process pcie_cfg_fsm_state_process; 148 | 149 | pcie_cfg_fsm_data_output_process: process(current_pcie_cfg_req_state, pcie_cfg_req_seq_id_s, 150 | pcie_cfg_cmd_write_be_s, pcie_cfg_cmd_write_s, 151 | pcie_cfg_cmd_addr_s, pcie_cfg_cmd_data_s, 152 | pcie_cfg_fifo_rx_rd_data_s, pcie_cfg_mgmt_producer_i, 153 | pcie_cfg_fifo_tx_wr_data_s, pcie_cfg_cmd_write_readonly_s, 154 | pcie_cfg_cmd_write_rw1c_as_rw_s) 155 | begin 156 | 157 | pcie_cfg_fifo_rx_rd_en_s <= '0'; 158 | next_pcie_cfg_fifo_tx_wr_en_s <= '0'; 159 | 160 | next_pcie_cfg_req_seq_id_s <= pcie_cfg_req_seq_id_s; 161 | next_pcie_cfg_cmd_write_be_s <= pcie_cfg_cmd_write_be_s; 162 | next_pcie_cfg_cmd_write_s <= pcie_cfg_cmd_write_s; 163 | next_pcie_cfg_cmd_write_readonly_s <= pcie_cfg_cmd_write_readonly_s; 164 | next_pcie_cfg_cmd_write_rw1c_as_rw_s <= pcie_cfg_cmd_write_rw1c_as_rw_s; 165 | next_pcie_cfg_cmd_addr_s <= pcie_cfg_cmd_addr_s; 166 | next_pcie_cfg_cmd_data_s <= pcie_cfg_cmd_data_s; 167 | next_pcie_cfg_fifo_tx_wr_data_s <= pcie_cfg_fifo_tx_wr_data_s; 168 | 169 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_di <= (others => '0'); 170 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_byte_en <= (others => '0'); 171 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_dwaddr <= (others => '0'); 172 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_en <= '0'; 173 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_rd_en <= '0'; 174 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_readonly <= '0'; 175 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_rw1c_as_rw <= '0'; 176 | 177 | case current_pcie_cfg_req_state is 178 | when PCIE_CFG_IDLE => 179 | when PCIE_CFG_AWAIT_HEADER => 180 | pcie_cfg_fifo_rx_rd_en_s <= '1'; 181 | when PCIE_CFG_PARSE_HEADER_1 => 182 | -- First valid header word will be here 183 | -- tsh_msg_type and tsh_msg_len are not used by this component and ignored. 184 | pcie_cfg_fifo_rx_rd_en_s <= '1'; 185 | when PCIE_CFG_PARSE_HEADER_2 => 186 | next_pcie_cfg_req_seq_id_s <= pcie_cfg_fifo_rx_rd_data_s(15 downto 0) ; 187 | pcie_cfg_fifo_rx_rd_en_s <= '1'; 188 | when PCIE_CFG_PARSE_CMD_1 => 189 | -- struct tlp_streamer_pcie_cfg_cmd is always fully 190 | -- parsed to simplify the decoding pipeline 191 | pcie_cfg_fifo_rx_rd_en_s <= '1'; 192 | next_pcie_cfg_cmd_addr_s <= pcie_cfg_fifo_rx_rd_data_s(9 downto 0); 193 | next_pcie_cfg_cmd_write_s <= pcie_cfg_fifo_rx_rd_data_s(16); 194 | next_pcie_cfg_cmd_write_readonly_s <= pcie_cfg_fifo_rx_rd_data_s(17); 195 | next_pcie_cfg_cmd_write_rw1c_as_rw_s <= pcie_cfg_fifo_rx_rd_data_s(18); 196 | next_pcie_cfg_cmd_write_be_s <= pcie_cfg_fifo_rx_rd_data_s(27 downto 24); 197 | when PCIE_CFG_PARSE_CMD_2 => 198 | next_pcie_cfg_cmd_data_s <= pcie_cfg_fifo_rx_rd_data_s; 199 | when PCIE_CFG_READ_1 => 200 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_rd_en <= '1'; 201 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_dwaddr <= pcie_cfg_cmd_addr_s; 202 | when PCIE_CFG_READ_2 => 203 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_rd_en <= '1'; 204 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_dwaddr <= pcie_cfg_cmd_addr_s; 205 | next_pcie_cfg_cmd_data_s <= pcie_cfg_mgmt_producer_i.cfg_mgmt_do; 206 | when PCIE_CFG_WRITE_1 => 207 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_en <= '1'; 208 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_readonly <= pcie_cfg_cmd_write_readonly_s; 209 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_rw1c_as_rw <= pcie_cfg_cmd_write_rw1c_as_rw_s; 210 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_dwaddr <= pcie_cfg_cmd_addr_s; 211 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_di <= pcie_cfg_cmd_data_s; 212 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_byte_en <= pcie_cfg_cmd_write_be_s; 213 | when PCIE_CFG_WRITE_2 => 214 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_en <= '1'; 215 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_readonly <= pcie_cfg_cmd_write_readonly_s; 216 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_wr_rw1c_as_rw <= pcie_cfg_cmd_write_rw1c_as_rw_s; 217 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_dwaddr <= pcie_cfg_cmd_addr_s; 218 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_di <= pcie_cfg_cmd_data_s; 219 | pcie_cfg_mgmt_consumer_o.cfg_mgmt_byte_en <= pcie_cfg_cmd_write_be_s; 220 | when PCIE_CFG_TX_PACKET_1 => 221 | next_pcie_cfg_fifo_tx_wr_en_s <= '1'; 222 | next_pcie_cfg_fifo_tx_wr_data_s <= "0000010000000000" & "00000000" & "00000001"; 223 | when PCIE_CFG_TX_PACKET_2 => 224 | next_pcie_cfg_fifo_tx_wr_en_s <= '1'; 225 | next_pcie_cfg_fifo_tx_wr_data_s <= "0000000000000000" & pcie_cfg_req_seq_id_s; 226 | when PCIE_CFG_TX_PACKET_3 => 227 | next_pcie_cfg_fifo_tx_wr_en_s <= '1'; 228 | next_pcie_cfg_fifo_tx_wr_data_s <= "0000" & pcie_cfg_cmd_write_be_s & "00000" & 229 | pcie_cfg_cmd_write_rw1c_as_rw_s & pcie_cfg_cmd_write_readonly_s & 230 | pcie_cfg_cmd_write_s & "000000" & pcie_cfg_cmd_addr_s; 231 | when PCIE_CFG_TX_PACKET_4 => 232 | next_pcie_cfg_fifo_tx_wr_en_s <= '1'; 233 | next_pcie_cfg_fifo_tx_wr_data_s <= pcie_cfg_cmd_data_s; 234 | when PCIE_CFG_COMPLETE => 235 | next_pcie_cfg_req_seq_id_s <= (others => '0'); 236 | next_pcie_cfg_cmd_write_be_s <= (others => '0'); 237 | next_pcie_cfg_cmd_write_s <= '0'; 238 | next_pcie_cfg_cmd_write_readonly_s <= '0'; 239 | next_pcie_cfg_cmd_write_rw1c_as_rw_s <= '0'; 240 | next_pcie_cfg_cmd_addr_s <= (others => '0'); 241 | next_pcie_cfg_cmd_data_s <= (others => '0'); 242 | end case; 243 | 244 | end process pcie_cfg_fsm_data_output_process; 245 | 246 | pcie_cfg_fsm_state_select_process: process(current_pcie_cfg_req_state, pcie_cfg_fifo_rx_rd_empty_s, 247 | pcie_cfg_cmd_write_s, pcie_cfg_mgmt_producer_i) 248 | begin 249 | 250 | next_pcie_cfg_req_state <= current_pcie_cfg_req_state; 251 | 252 | case current_pcie_cfg_req_state is 253 | when PCIE_CFG_IDLE => 254 | if (pcie_cfg_fifo_rx_rd_empty_s = '0') then 255 | next_pcie_cfg_req_state <= PCIE_CFG_AWAIT_HEADER; 256 | end if; 257 | when PCIE_CFG_AWAIT_HEADER => 258 | next_pcie_cfg_req_state <= PCIE_CFG_PARSE_HEADER_1; 259 | when PCIE_CFG_PARSE_HEADER_1 => 260 | next_pcie_cfg_req_state <= PCIE_CFG_PARSE_HEADER_2; 261 | when PCIE_CFG_PARSE_HEADER_2 => 262 | next_pcie_cfg_req_state <= PCIE_CFG_PARSE_CMD_1; 263 | when PCIE_CFG_PARSE_CMD_1 => 264 | next_pcie_cfg_req_state <= PCIE_CFG_PARSE_CMD_2; 265 | when PCIE_CFG_PARSE_CMD_2 => 266 | if (pcie_cfg_cmd_write_s = '0') then 267 | next_pcie_cfg_req_state <= PCIE_CFG_READ_1; 268 | else 269 | next_pcie_cfg_req_state <= PCIE_CFG_WRITE_1; 270 | end if; 271 | when PCIE_CFG_READ_1 => 272 | next_pcie_cfg_req_state <= PCIE_CFG_READ_2; 273 | when PCIE_CFG_READ_2 => 274 | if (pcie_cfg_mgmt_producer_i.cfg_mgmt_rd_wr_done = '1') then 275 | next_pcie_cfg_req_state <= PCIE_CFG_TX_PACKET_1; 276 | end if; 277 | when PCIE_CFG_WRITE_1 => 278 | next_pcie_cfg_req_state <= PCIE_CFG_WRITE_2; 279 | when PCIE_CFG_WRITE_2 => 280 | if (pcie_cfg_mgmt_producer_i.cfg_mgmt_rd_wr_done = '1') then 281 | next_pcie_cfg_req_state <= PCIE_CFG_TX_PACKET_1; 282 | end if; 283 | when PCIE_CFG_TX_PACKET_1 => 284 | next_pcie_cfg_req_state <= PCIE_CFG_TX_PACKET_2; 285 | when PCIE_CFG_TX_PACKET_2 => 286 | next_pcie_cfg_req_state <= PCIE_CFG_TX_PACKET_3; 287 | when PCIE_CFG_TX_PACKET_3 => 288 | next_pcie_cfg_req_state <= PCIE_CFG_TX_PACKET_4; 289 | when PCIE_CFG_TX_PACKET_4 => 290 | next_pcie_cfg_req_state <= PCIE_CFG_COMPLETE; 291 | when PCIE_CFG_COMPLETE => 292 | next_pcie_cfg_req_state <= PCIE_CFG_IDLE; 293 | end case; 294 | 295 | end process pcie_cfg_fsm_state_select_process; 296 | 297 | end architecture RTL; -------------------------------------------------------------------------------- /src/design/tlp_streamer_pcie_tlp.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - PCIe TLP Interface 3 | -- 4 | -- (c) MikeM64 - 2022 5 | -- 6 | 7 | -- From this component's perspective, all references to TX are for Host -> PCIe direction 8 | -- and all RX references are PCIe -> Host 9 | 10 | library IEEE; 11 | use IEEE.std_logic_1164.all; 12 | use IEEE.numeric_std.all; 13 | 14 | use work.tlp_streamer_records.all; 15 | 16 | entity tlp_streamer_pcie_tlp is 17 | port ( 18 | sys_clk_i : in std_logic; 19 | pcie_clk_i : in std_logic; 20 | pcie_rst_i : in std_logic; 21 | -- Host Packet RX/TX management 22 | dispatch_i : in dispatch_producer_r; 23 | dispatch_o : out dispatch_consumer_r; 24 | arbiter_i : in arbiter_producer_r; 25 | arbiter_o : out arbiter_consumer_r; 26 | -- PCIe Core TLP Interface 27 | pcie_tlp_tx_producer_i : in pcie_tlp_tx_port_producer_r; 28 | pcie_tlp_tx_consumer_o : out pcie_tlp_tx_port_consumer_r; 29 | pcie_tlp_rx_producer_i : in pcie_tlp_rx_port_producer_r; 30 | pcie_tlp_rx_consumer_o : out pcie_tlp_rx_port_consumer_r); 31 | end entity tlp_streamer_pcie_tlp; 32 | 33 | architecture RTL of tlp_streamer_pcie_tlp is 34 | 35 | component fifo_pcie_tlp_r64_w32_4096_bram IS 36 | port ( 37 | rst : IN STD_LOGIC; 38 | wr_clk : IN STD_LOGIC; 39 | rd_clk : IN STD_LOGIC; 40 | din : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 41 | wr_en : IN STD_LOGIC; 42 | rd_en : IN STD_LOGIC; 43 | dout : OUT STD_LOGIC_VECTOR(63 DOWNTO 0); 44 | full : OUT STD_LOGIC; 45 | empty : OUT STD_LOGIC; 46 | valid : OUT STD_LOGIC; 47 | wr_rst_busy : OUT STD_LOGIC; 48 | rd_rst_busy : OUT STD_LOGIC 49 | ); 50 | end component fifo_pcie_tlp_r64_w32_4096_bram; 51 | 52 | component fifo_pcie_tlp_r32_w64_4096_bram IS 53 | port ( 54 | rst : IN STD_LOGIC; 55 | wr_clk : IN STD_LOGIC; 56 | rd_clk : IN STD_LOGIC; 57 | din : IN STD_LOGIC_VECTOR(63 DOWNTO 0); 58 | wr_en : IN STD_LOGIC; 59 | rd_en : IN STD_LOGIC; 60 | dout : OUT STD_LOGIC_VECTOR(31 DOWNTO 0); 61 | full : OUT STD_LOGIC; 62 | empty : OUT STD_LOGIC; 63 | valid : OUT STD_LOGIC; 64 | wr_rst_busy : OUT STD_LOGIC; 65 | rd_rst_busy : OUT STD_LOGIC 66 | ); 67 | end component fifo_pcie_tlp_r32_w64_4096_bram; 68 | 69 | component pcie_tlp_ila IS 70 | port ( 71 | clk : IN STD_LOGIC; 72 | probe0 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 73 | probe1 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 74 | probe2 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 75 | probe3 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 76 | probe4 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 77 | probe5 : IN STD_LOGIC_VECTOR(2 DOWNTO 0); 78 | probe6 : IN STD_LOGIC_VECTOR(63 DOWNTO 0); 79 | probe7 : IN STD_LOGIC_VECTOR(63 DOWNTO 0); 80 | probe8 : IN STD_LOGIC_VECTOR(63 DOWNTO 0) 81 | ); 82 | end component pcie_tlp_ila; 83 | 84 | -- TX FSM Signals and types 85 | type pcie_tlp_tx_req_state is (PCIE_TLP_TX_IDLE, PCIE_TLP_TX_PACKET_START, PCIE_TLP_TX_PACKET_PARSE_HEADER, 86 | PCIE_TLP_TX_PACKET); 87 | 88 | signal current_pcie_tlp_tx_req_state, next_pcie_tlp_tx_req_state: pcie_tlp_tx_req_state; 89 | 90 | signal pcie_tlp_fifo_tx_wr_en_s, next_pcie_tlp_fifo_tx_wr_en_s: std_logic; 91 | signal pcie_tlp_fifo_tx_rd_en_s: std_logic; 92 | signal pcie_tlp_fifo_tx_rd_data_s, ila_pcie_tlp_data: std_logic_vector(63 downto 0); 93 | signal pcie_tlp_fifo_tx_rd_empty_s: std_logic; 94 | signal pcie_tlp_fifo_tx_rd_valid_s: std_logic; 95 | 96 | -- This is the number of qwords to read from the TX FIFO when transmitting 97 | -- packets towards the PCIe core 98 | -- 514 is (1024 DW Max TLP Payload + 4 DW Max TLP Header == 1028 DW == 514 QW) 99 | signal pcie_tlp_tx_qwords_to_read, next_pcie_tlp_tx_qwords_to_read: integer range 0 to 514; 100 | 101 | 102 | -- RX FSM Signals and types 103 | type pcie_tlp_rx_req_state is (PCIE_TLP_AWAIT_RX, PCIE_TLP_RX_WRITE_HEADER, PCIE_TLP_RX_WRITE_TLP); 104 | 105 | signal current_pcie_tlp_rx_req_state, next_pcie_tlp_rx_req_state: pcie_tlp_rx_req_state; 106 | signal ila_current_tlp_state: std_logic_vector(2 downto 0); 107 | signal ila_current_tlp_tx_state: std_logic_vector(2 downto 0); 108 | signal ila_tx_tlast: std_logic; 109 | 110 | signal pcie_tlp_fifo_rx_wr_data_s, next_pcie_tlp_fifo_rx_wr_data_s: std_logic_vector(63 downto 0); 111 | -- Buffer to allow time for the header to be added to the RX FIFO ahead of the RXd TLP 112 | signal pcie_tlp_rx_buffer_s_1, pcie_tlp_rx_buffer_s_2: std_logic_vector(63 downto 0); 113 | signal pcie_tlp_rx_buffer_valid_s_1, pcie_tlp_rx_buffer_valid_s_2: std_logic; 114 | signal pcie_tlp_fifo_rx_wr_en_s, next_pcie_tlp_fifo_rx_wr_en_s: std_logic; 115 | signal pcie_tlp_fifo_rx_rd_data_s: std_logic_vector(31 downto 0); 116 | signal pcie_tlp_fifo_rx_rd_en_s, next_pcie_tlp_fifo_rx_rd_en_s: std_logic; 117 | signal pcie_tlp_fifo_rx_wr_full_s: std_logic; 118 | 119 | signal ila_tx_next_qwords_to_read: std_logic_vector(63 downto 0); 120 | 121 | begin 122 | 123 | comp_pcie_tlp_tx_fifo: fifo_pcie_tlp_r64_w32_4096_bram 124 | port map( 125 | rst => pcie_rst_i, 126 | wr_clk => sys_clk_i, 127 | rd_clk => pcie_clk_i, 128 | din => dispatch_i.dispatch_wr_data(31 downto 0), 129 | wr_en => pcie_tlp_fifo_tx_wr_en_s, 130 | rd_en => pcie_tlp_fifo_tx_rd_en_s, 131 | dout(63 downto 32) => pcie_tlp_fifo_tx_rd_data_s(31 downto 0), 132 | dout(31 downto 0) => pcie_tlp_fifo_tx_rd_data_s(63 downto 32), 133 | full => dispatch_o.dispatch_wr_full, 134 | empty => pcie_tlp_fifo_tx_rd_empty_s, 135 | valid => pcie_tlp_fifo_tx_rd_valid_s, 136 | wr_rst_busy => open, 137 | rd_rst_busy => open); 138 | 139 | comp_pcie_tlp_rx_fifo: fifo_pcie_tlp_r32_w64_4096_bram 140 | port map( 141 | rst => pcie_rst_i, 142 | wr_clk => pcie_clk_i, 143 | rd_clk => sys_clk_i, 144 | din => pcie_tlp_fifo_rx_wr_data_s, 145 | wr_en => pcie_tlp_fifo_rx_wr_en_s, 146 | rd_en => arbiter_i.arbiter_rd_en, 147 | dout(31 downto 24) => pcie_tlp_fifo_rx_rd_data_s(7 downto 0), 148 | dout(23 downto 16) => pcie_tlp_fifo_rx_rd_data_s(15 downto 8), 149 | dout(15 downto 8) => pcie_tlp_fifo_rx_rd_data_s(23 downto 16), 150 | dout(7 downto 0) => pcie_tlp_fifo_rx_rd_data_s(31 downto 24), 151 | full => pcie_tlp_fifo_rx_wr_full_s, 152 | empty => arbiter_o.arbiter_rd_empty, 153 | valid => arbiter_o.arbiter_rd_valid, 154 | wr_rst_busy => open, 155 | rd_rst_busy => open); 156 | 157 | --comp_pcie_tlp_rx_ila: pcie_tlp_ila 158 | -- port map( 159 | -- clk => pcie_clk_i, 160 | -- probe0(0) => pcie_tlp_rx_producer_i.tlp_axis_rx_tvalid, 161 | -- probe1(0) => pcie_tlp_rx_producer_i.tlp_axis_rx_tlast, 162 | -- probe2(0) => pcie_tlp_rx_buffer_valid_s_1, 163 | -- probe3(0) => pcie_tlp_rx_buffer_valid_s_2, 164 | -- probe4(0) => pcie_tlp_fifo_rx_wr_en_s, 165 | -- probe5 => ila_current_tlp_state, 166 | -- probe6 => pcie_tlp_rx_buffer_s_1, 167 | -- probe7 => pcie_tlp_rx_buffer_s_2, 168 | -- probe8 => pcie_tlp_fifo_rx_wr_data_s); 169 | 170 | comp_pcie_tlp_tx_ila: pcie_tlp_ila 171 | port map( 172 | clk => pcie_clk_i, 173 | probe0(0) => '0', 174 | probe1(0) => '0', 175 | probe2(0) => pcie_tlp_fifo_tx_rd_valid_s, 176 | probe3(0) => ila_tx_tlast, 177 | probe4(0) => pcie_tlp_fifo_tx_rd_en_s, 178 | probe5 => ila_current_tlp_tx_state, 179 | probe6 => ila_pcie_tlp_data, 180 | probe7 => ila_tx_next_qwords_to_read, 181 | probe8 => pcie_tlp_fifo_tx_rd_data_s); 182 | 183 | pcie_tlp_rx_tx_async_process: process(dispatch_i, pcie_tlp_fifo_rx_rd_data_s) 184 | begin 185 | 186 | pcie_tlp_fifo_tx_wr_en_s <= dispatch_i.dispatch_wr_en and 187 | dispatch_i.dispatch_valid; 188 | -- The extra 1's here correspond to the byte_enable portion of the 189 | -- data sent to the FT601 190 | arbiter_o.arbiter_rd_data <= "1111" & pcie_tlp_fifo_rx_rd_data_s; 191 | 192 | end process pcie_tlp_rx_tx_async_process; 193 | 194 | pcie_tlp_tx_fsm_clock_process: process(pcie_clk_i, pcie_rst_i, next_pcie_tlp_tx_req_state, 195 | next_pcie_tlp_tx_qwords_to_read) 196 | begin 197 | 198 | if (pcie_rst_i = '1') then 199 | current_pcie_tlp_tx_req_state <= PCIE_TLP_TX_IDLE; 200 | pcie_tlp_tx_qwords_to_read <= 0; 201 | ila_tx_next_qwords_to_read <= (others => '0'); 202 | elsif (rising_edge(pcie_clk_i)) then 203 | current_pcie_tlp_tx_req_state <= next_pcie_tlp_tx_req_state; 204 | pcie_tlp_tx_qwords_to_read <= next_pcie_tlp_tx_qwords_to_read; 205 | ila_tx_next_qwords_to_read <= std_logic_vector(to_unsigned(next_pcie_tlp_tx_qwords_to_read, 64)); 206 | ila_current_tlp_tx_state <= std_logic_vector(to_unsigned(pcie_tlp_tx_req_state'POS(next_pcie_tlp_tx_req_state), 3)); 207 | end if; 208 | 209 | end process pcie_tlp_tx_fsm_clock_process; 210 | 211 | pcie_tlp_tx_fsm_data_output_process: process(current_pcie_tlp_tx_req_state, 212 | pcie_tlp_tx_qwords_to_read, pcie_tlp_fifo_tx_rd_data_s, 213 | pcie_tlp_fifo_tx_rd_valid_s) 214 | variable pcie_tlp_tx_packet_len_v: integer range 0 to 65535; 215 | 216 | begin 217 | 218 | pcie_tlp_fifo_tx_rd_en_s <= '0'; 219 | next_pcie_tlp_tx_qwords_to_read <= pcie_tlp_tx_qwords_to_read; 220 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tdata <= (others => '0'); 221 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tuser <= (others => '0'); 222 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tkeep <= (others => '0'); 223 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tlast <= '0'; 224 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tvalid <= '0'; 225 | ila_pcie_tlp_data <= (others => '0'); 226 | ila_tx_tlast <= '0'; 227 | 228 | case current_pcie_tlp_tx_req_state is 229 | when PCIE_TLP_TX_IDLE => 230 | next_pcie_tlp_tx_qwords_to_read <= 0; 231 | when PCIE_TLP_TX_PACKET_START => 232 | pcie_tlp_fifo_tx_rd_en_s <= '1'; 233 | next_pcie_tlp_tx_qwords_to_read <= 0; 234 | when PCIE_TLP_TX_PACKET_PARSE_HEADER => 235 | -- The first double-word out of the FIFO is the tlp_streamer header. 236 | -- Use the length to know when to stop transmitting towards the 237 | -- PCIe core 238 | -- -2: -1 to not count the TLP streamer header, 239 | -- -1 as this read of the header also counts towards the data left 240 | next_pcie_tlp_tx_qwords_to_read <= (to_integer(unsigned(pcie_tlp_fifo_tx_rd_data_s(23 downto 16) & 241 | pcie_tlp_fifo_tx_rd_data_s(31 downto 24))) / 2) - 2; 242 | pcie_tlp_tx_packet_len_v := to_integer(unsigned(pcie_tlp_fifo_tx_rd_data_s(23 downto 16) & 243 | pcie_tlp_fifo_tx_rd_data_s(31 downto 24))); 244 | pcie_tlp_fifo_tx_rd_en_s <= '1'; 245 | when PCIE_TLP_TX_PACKET => 246 | pcie_tlp_fifo_tx_rd_en_s <= '1'; 247 | -- Information from the host is transmitted in network-order, so swap 248 | -- it here to align with the PCIe IP. 249 | ila_pcie_tlp_data <= pcie_tlp_fifo_tx_rd_data_s(39 downto 32) & 250 | pcie_tlp_fifo_tx_rd_data_s(47 downto 40) & 251 | pcie_tlp_fifo_tx_rd_data_s(55 downto 48) & 252 | pcie_tlp_fifo_tx_rd_data_s(63 downto 56) & 253 | pcie_tlp_fifo_tx_rd_data_s(7 downto 0) & 254 | pcie_tlp_fifo_tx_rd_data_s(15 downto 8) & 255 | pcie_tlp_fifo_tx_rd_data_s(23 downto 16) & 256 | pcie_tlp_fifo_tx_rd_data_s(31 downto 24); 257 | 258 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tdata <= pcie_tlp_fifo_tx_rd_data_s(39 downto 32) & 259 | pcie_tlp_fifo_tx_rd_data_s(47 downto 40) & 260 | pcie_tlp_fifo_tx_rd_data_s(55 downto 48) & 261 | pcie_tlp_fifo_tx_rd_data_s(63 downto 56) & 262 | pcie_tlp_fifo_tx_rd_data_s(7 downto 0) & 263 | pcie_tlp_fifo_tx_rd_data_s(15 downto 8) & 264 | pcie_tlp_fifo_tx_rd_data_s(23 downto 16) & 265 | pcie_tlp_fifo_tx_rd_data_s(31 downto 24); 266 | -- TODO: Fix this for return data that is not an odd DW count 267 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tkeep <= (others => '1'); 268 | if (pcie_tlp_tx_qwords_to_read = 0) then 269 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tlast <= '1'; 270 | ila_tx_tlast <= '1'; 271 | end if; 272 | pcie_tlp_tx_consumer_o.tlp_axis_tx_tvalid <= pcie_tlp_fifo_tx_rd_valid_s; 273 | next_pcie_tlp_tx_qwords_to_read <= pcie_tlp_tx_qwords_to_read - 1; 274 | end case; 275 | 276 | end process pcie_tlp_tx_fsm_data_output_process; 277 | 278 | pcie_tlp_tx_fsm_state_select_process: process(current_pcie_tlp_tx_req_state, pcie_tlp_fifo_tx_rd_empty_s, 279 | pcie_tlp_tx_producer_i, pcie_tlp_tx_qwords_to_read) 280 | begin 281 | 282 | next_pcie_tlp_tx_req_state <= current_pcie_tlp_tx_req_state; 283 | 284 | case current_pcie_tlp_tx_req_state is 285 | when PCIE_TLP_TX_IDLE => 286 | if (pcie_tlp_fifo_tx_rd_empty_s = '0' and 287 | pcie_tlp_tx_producer_i.tlp_axis_tx_tready = '1') then 288 | next_pcie_tlp_tx_req_state <= PCIE_TLP_TX_PACKET_START; 289 | end if; 290 | when PCIE_TLP_TX_PACKET_START => 291 | next_pcie_tlp_tx_req_state <= PCIE_TLP_TX_PACKET_PARSE_HEADER; 292 | when PCIE_TLP_TX_PACKET_PARSE_HEADER => 293 | next_pcie_tlp_tx_req_state <= PCIE_TLP_TX_PACKET; 294 | when PCIE_TLP_TX_PACKET => 295 | if (pcie_tlp_tx_qwords_to_read = 0) then 296 | next_pcie_tlp_tx_req_state <= PCIE_TLP_TX_IDLE; 297 | end if; 298 | end case; 299 | 300 | end process pcie_tlp_tx_fsm_state_select_process; 301 | 302 | pcie_tlp_rx_clock_process: process(pcie_clk_i, pcie_rst_i, next_pcie_tlp_rx_req_state, 303 | next_pcie_tlp_fifo_rx_wr_data_s, next_pcie_tlp_fifo_rx_wr_en_s, 304 | pcie_tlp_rx_producer_i) 305 | begin 306 | 307 | if (pcie_rst_i = '1') then 308 | current_pcie_tlp_rx_req_state <= PCIE_TLP_AWAIT_RX; 309 | pcie_tlp_fifo_rx_wr_data_s <= (others => '0'); 310 | pcie_tlp_fifo_rx_wr_en_s <= '0'; 311 | elsif (rising_edge(pcie_clk_i)) then 312 | current_pcie_tlp_rx_req_state <= next_pcie_tlp_rx_req_state; 313 | ila_current_tlp_state <= std_logic_vector(to_unsigned(pcie_tlp_rx_req_state'POS(next_pcie_tlp_rx_req_state), 3)); 314 | pcie_tlp_fifo_rx_wr_data_s <= next_pcie_tlp_fifo_rx_wr_data_s; 315 | pcie_tlp_fifo_rx_wr_en_s <= next_pcie_tlp_fifo_rx_wr_en_s; 316 | 317 | pcie_tlp_rx_buffer_s_1 <= pcie_tlp_rx_producer_i.tlp_axis_rx_tdata; 318 | pcie_tlp_rx_buffer_s_2 <= pcie_tlp_rx_buffer_s_1; 319 | 320 | pcie_tlp_rx_buffer_valid_s_1 <= pcie_tlp_rx_producer_i.tlp_axis_rx_tvalid; 321 | pcie_tlp_rx_buffer_valid_s_2 <= pcie_tlp_rx_buffer_valid_s_1; 322 | end if; 323 | 324 | end process pcie_tlp_rx_clock_process; 325 | 326 | pcie_tlp_rx_fsm_data_output_process: process(current_pcie_tlp_rx_req_state, pcie_tlp_fifo_rx_wr_full_s, 327 | pcie_tlp_rx_buffer_s_1, pcie_tlp_rx_buffer_s_2, pcie_tlp_rx_producer_i, 328 | pcie_tlp_rx_buffer_valid_s_2) 329 | 330 | variable pcie_tlp_rx_packet_len_v: integer range 0 to 65535; 331 | variable pcie_tlp_hdr_len_v: integer range 3 to 4; 332 | 333 | begin 334 | 335 | pcie_tlp_rx_consumer_o.tlp_axis_rx_tready <= not pcie_tlp_fifo_rx_wr_full_s; 336 | next_pcie_tlp_fifo_rx_wr_en_s <= '0'; 337 | -- Need to word-swap the AXI interface so that the correct word is sent 338 | -- out on the wire first. Refer to page 47 of pg054. 339 | next_pcie_tlp_fifo_rx_wr_data_s <= pcie_tlp_rx_buffer_s_2(31 downto 0) & 340 | pcie_tlp_rx_buffer_s_2(63 downto 32); 341 | 342 | case current_pcie_tlp_rx_req_state is 343 | when PCIE_TLP_AWAIT_RX => 344 | when PCIE_TLP_RX_WRITE_HEADER => 345 | next_pcie_tlp_fifo_rx_wr_en_s <= '1'; 346 | -- Setup the tlp_streamer header length based on the TLP 347 | -- format and length contained in the first QW read. 348 | if (pcie_tlp_rx_buffer_s_1(29) = '1') then 349 | pcie_tlp_hdr_len_v := 4; 350 | else 351 | pcie_tlp_hdr_len_v := 3; 352 | end if; 353 | if (pcie_tlp_rx_buffer_s_1(30) = '1') then 354 | -- This TLP has data attached to it 355 | if (pcie_tlp_rx_buffer_s_1(9 downto 0) = "0000000000") then 356 | pcie_tlp_rx_packet_len_v := 2 + 4 + 1024; 357 | else 358 | pcie_tlp_rx_packet_len_v := 2 + pcie_tlp_hdr_len_v + to_integer(unsigned(pcie_tlp_rx_buffer_s_1(9 downto 0))); 359 | if (pcie_tlp_rx_packet_len_v mod 2 = 1) then 360 | -- If it's an odd packet length overall, add one more DW to align 361 | -- the TXd packet with a QW natural boundary. 362 | pcie_tlp_rx_packet_len_v := pcie_tlp_rx_packet_len_v + 1; 363 | end if; 364 | end if; 365 | else 366 | -- TLPs are always assumed to have a 4-byte header in the FPGA 367 | -- to easily align with natural QW/FIFO write boundaries. 368 | -- The host will ignore the additional bytes when it processes the TLP. 369 | pcie_tlp_rx_packet_len_v := 2 + 4; 370 | end if; 371 | -- The length is stored in network-order when going over the wire 372 | next_pcie_tlp_fifo_rx_wr_data_s <= "0000000000000010" & -- tsh_msg_type == 2 373 | std_logic_vector(to_unsigned(pcie_tlp_rx_packet_len_v, 16)) & 374 | "0000000000000000" & -- tsh_rsvd_2 == 0 375 | "0000000000000000"; -- tsh_seq_id 376 | when PCIE_TLP_RX_WRITE_TLP => 377 | next_pcie_tlp_fifo_rx_wr_en_s <= pcie_tlp_rx_buffer_valid_s_2; 378 | end case; 379 | 380 | end process pcie_tlp_rx_fsm_data_output_process; 381 | 382 | pcie_tlp_rx_fsm_state_select_process: process(current_pcie_tlp_rx_req_state, pcie_tlp_rx_producer_i, 383 | pcie_tlp_rx_buffer_valid_s_2) 384 | begin 385 | 386 | next_pcie_tlp_rx_req_state <= current_pcie_tlp_rx_req_state; 387 | 388 | case current_pcie_tlp_rx_req_state is 389 | when PCIE_TLP_AWAIT_RX => 390 | if (pcie_tlp_rx_producer_i.tlp_axis_rx_tvalid = '1') then 391 | next_pcie_tlp_rx_req_state <= PCIE_TLP_RX_WRITE_HEADER; 392 | end if; 393 | when PCIE_TLP_RX_WRITE_HEADER => 394 | next_pcie_tlp_rx_req_state <= PCIE_TLP_RX_WRITE_TLP; 395 | when PCIE_TLP_RX_WRITE_TLP => 396 | if (pcie_tlp_rx_producer_i.tlp_axis_rx_tlast = '1' or 397 | (pcie_tlp_rx_producer_i.tlp_axis_rx_tvalid = '0' and pcie_tlp_rx_buffer_valid_s_2 = '0')) then 398 | next_pcie_tlp_rx_req_state <= PCIE_TLP_AWAIT_RX; 399 | end if; 400 | end case; 401 | 402 | end process pcie_tlp_rx_fsm_state_select_process; 403 | 404 | 405 | end architecture RTL; 406 | -------------------------------------------------------------------------------- /src/design/tlp_streamer_records.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer Records - Record Package 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | 10 | package tlp_streamer_records is 11 | 12 | -- 13 | -- Signals produced by the dispatch queue 14 | -- 15 | type dispatch_producer_r is record 16 | dispatch_wr_en : std_logic; 17 | dispatch_valid : std_logic; 18 | dispatch_empty : std_logic; 19 | dispatch_wr_data : std_logic_vector(35 downto 0); 20 | end record dispatch_producer_r; 21 | 22 | -- 23 | -- Signals consumed by the dispatch queue 24 | -- 25 | type dispatch_consumer_r is record 26 | dispatch_wr_full : std_logic; 27 | end record dispatch_consumer_r; 28 | 29 | -- Array versions of the above records 30 | type dispatch_producer_r_array is array (integer range <>) of dispatch_producer_r; 31 | type dispatch_consumer_r_array is array (integer range <>) of dispatch_consumer_r; 32 | 33 | -- 34 | -- Signals produced by the TX arbitrator 35 | -- 36 | type arbiter_producer_r is record 37 | arbiter_rd_en : std_logic; 38 | arbiter_wr_full : std_logic; 39 | end record arbiter_producer_r; 40 | 41 | -- 42 | -- Signals consumed by the TX arbitrator 43 | -- 44 | type arbiter_consumer_r is record 45 | arbiter_rd_data : std_logic_vector(35 downto 0); 46 | arbiter_rd_empty : std_logic; 47 | arbiter_rd_valid : std_logic; 48 | end record arbiter_consumer_r; 49 | 50 | type arbiter_producer_r_array is array (integer range <>) of arbiter_producer_r; 51 | type arbiter_consumer_r_array is array (integer range <>) of arbiter_consumer_r; 52 | 53 | type pcie_cfg_mgmt_port_producer_r is record 54 | cfg_mgmt_do : STD_LOGIC_VECTOR(31 DOWNTO 0); 55 | cfg_mgmt_rd_wr_done : STD_LOGIC; 56 | end record pcie_cfg_mgmt_port_producer_r; 57 | 58 | type pcie_cfg_mgmt_port_consumer_r is record 59 | cfg_mgmt_di : STD_LOGIC_VECTOR(31 DOWNTO 0); 60 | cfg_mgmt_byte_en : STD_LOGIC_VECTOR(3 DOWNTO 0); 61 | cfg_mgmt_dwaddr : STD_LOGIC_VECTOR(9 DOWNTO 0); 62 | cfg_mgmt_wr_en : STD_LOGIC; 63 | cfg_mgmt_rd_en : STD_LOGIC; 64 | cfg_mgmt_wr_readonly : STD_LOGIC; 65 | cfg_mgmt_wr_rw1c_as_rw : STD_LOGIC; 66 | end record pcie_cfg_mgmt_port_consumer_r; 67 | 68 | type pcie_tlp_tx_port_producer_r is record 69 | tlp_axis_tx_tready : std_logic; 70 | end record pcie_tlp_tx_port_producer_r; 71 | 72 | type pcie_tlp_tx_port_consumer_r is record 73 | tlp_axis_tx_tdata : std_logic_vector(63 downto 0); 74 | tlp_axis_tx_tkeep : std_logic_vector(7 downto 0); 75 | tlp_axis_tx_tlast : std_logic; 76 | tlp_axis_tx_tvalid : std_logic; 77 | tlp_axis_tx_tuser : std_logic_vector(3 downto 0); 78 | end record pcie_tlp_tx_port_consumer_r; 79 | 80 | type pcie_tlp_rx_port_producer_r is record 81 | tlp_axis_rx_tdata : std_logic_vector(63 downto 0); 82 | tlp_axis_rx_tkeep : std_logic_vector(7 downto 0); 83 | tlp_axis_rx_tlast : std_logic; 84 | tlp_axis_rx_tvalid : std_logic; 85 | tlp_axis_rx_tuser : std_logic_vector(21 downto 0); 86 | end record pcie_tlp_rx_port_producer_r; 87 | 88 | type pcie_tlp_rx_port_consumer_r is record 89 | tlp_axis_rx_tready : std_logic; 90 | end record pcie_tlp_rx_port_consumer_r; 91 | 92 | end package tlp_streamer_records; 93 | -------------------------------------------------------------------------------- /src/design/tlp_streamer_reset.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - Reset generator 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | entity tlp_streamer_reset is 12 | port( 13 | sys_clk_i : in std_logic; 14 | sys_reset_o : out std_logic); 15 | end entity tlp_streamer_reset; 16 | 17 | architecture RTL of tlp_streamer_reset is 18 | 19 | signal reset_hold_count64_s: unsigned(63 downto 0) := (others => '0'); 20 | signal reset_s: std_logic; 21 | 22 | begin 23 | 24 | reset_process: process(sys_clk_i, reset_hold_count64_s, reset_s) 25 | begin 26 | sys_reset_o <= reset_s; 27 | 28 | -- Self-generate a 1500ns reset pulse 29 | if (reset_hold_count64_s < to_unsigned(150, 64)) then 30 | reset_s <= '1'; 31 | else 32 | reset_s <= '0'; 33 | end if; 34 | 35 | if (rising_edge(sys_clk_i)) then 36 | reset_hold_count64_s <= reset_hold_count64_s + 1; 37 | end if; 38 | 39 | end process reset_process; 40 | 41 | end architecture RTL; 42 | -------------------------------------------------------------------------------- /src/design/tlp_streamer_rx_dispatch.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - Host Packet RX Dispatch Module 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | use work.tlp_streamer_records.all; 12 | 13 | entity tlp_streamer_rx_dispatch is 14 | generic (NUM_OUTPUT_QUEUES : integer); 15 | port( 16 | sys_clk_i : in std_logic; 17 | sys_reset_i : in std_logic; 18 | -- Input FIFO to dispatch 19 | fifo_rd_en_o : out std_logic; 20 | fifo_rd_empty_i : in std_logic; 21 | fifo_rd_valid_i : in std_logic; 22 | fifo_rd_data_i : in std_logic_vector(35 downto 0); 23 | -- Output FIFOs to dispatch to 24 | dispatch_o_arr : out dispatch_producer_r_array(NUM_OUTPUT_QUEUES-1 downto 0); 25 | dispatch_i_arr : in dispatch_consumer_r_array(NUM_OUTPUT_QUEUES-1 downto 0)); 26 | 27 | end entity tlp_streamer_rx_dispatch; 28 | 29 | architecture RTL of tlp_streamer_rx_dispatch is 30 | 31 | --component ila_0 IS 32 | --PORT ( 33 | --clk : IN STD_LOGIC; 34 | --probe0 : IN STD_LOGIC_VECTOR(12 DOWNTO 0); 35 | -- probe1 : IN STD_LOGIC_VECTOR(12 DOWNTO 0); 36 | -- probe2 : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 37 | -- probe3 : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 38 | -- probe4 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 39 | -- probe5 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 40 | -- probe6 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 41 | -- probe7 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 42 | -- probe8 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 43 | -- probe9 : IN STD_LOGIC_VECTOR(15 DOWNTO 0); 44 | -- probe10 : IN STD_LOGIC_VECTOR(3 DOWNTO 0); 45 | -- probe11 : IN STD_LOGIC_VECTOR(9 DOWNTO 0); 46 | -- probe12 : IN STD_LOGIC_VECTOR(31 DOWNTO 0); 47 | -- probe13 : IN STD_LOGIC_VECTOR(0 DOWNTO 0) 48 | --); 49 | --END component ila_0; 50 | 51 | type dispatch_state is (DISPATCH_IDLE, DISPATCH_AWAIT_HEADER, DISPATCH_READ_HEADER, 52 | DISPATCH_WRITE_HEADER, DISPATCH_WRITE_PACKET, DISPATCH_COMPLETE); 53 | 54 | signal current_dispatch_state_s, next_dispatch_state_s: dispatch_state; 55 | signal dispatch_words_to_write, next_dispatch_words_to_write: integer range 0 to 65535; 56 | signal dispatch_output_queue, next_dispatch_output_queue: integer range 0 to 255; 57 | 58 | -- A two-cycle delay for output data is required in order to first parse the 59 | -- packet header (which denotes the appropriate output queue) and then 60 | -- to continue writing the data to the output queue after it has been clocked 61 | signal dispatch_rd_en_s, dispatch_rd_empty_s, dispatch_rd_valid_s_1, dispatch_rd_valid_s_2, dispatch_wr_en_s: std_logic; 62 | signal dispatch_data_s_1, dispatch_data_s_2: std_logic_vector(35 downto 0); 63 | 64 | --signal ila_dispatch_state: std_logic_vector(5 downto 0); 65 | --signal ila_words_to_write: std_logic_vector(15 downto 0); 66 | --signal ila_dispatch_output_queue: std_logic_vector(7 downto 0); 67 | 68 | begin 69 | 70 | --comp_rx_dispatch_ila: ila_0 71 | --port map ( 72 | -- clk => sys_clk_i, 73 | -- probe0(12 downto 6) => (others => '0'), 74 | -- probe0(5 downto 0) => ila_dispatch_state, 75 | -- probe1 => (others => '0'), 76 | -- probe2(31 downto 16) => (others => '0'), 77 | -- probe2(15 downto 0) => ila_words_to_write, 78 | -- probe3 => fifo_rd_data_i(31 downto 0), 79 | -- probe4(0) => dispatch_wr_en_s, 80 | -- probe5(0) => dispatch_rd_valid_s_2, 81 | -- probe6(0) => fifo_rd_valid_i, 82 | -- probe7(0) => '0', 83 | -- probe8(0) => '0', 84 | -- probe9 => (others => '0'), 85 | -- probe10 => (others => '0'), 86 | -- probe11(9 downto 8) => (others => '0'), 87 | -- probe11(7 downto 0) => ila_dispatch_output_queue, 88 | -- probe12 => dispatch_data_s_2(31 downto 0), 89 | -- probe13(0) => '0'); 90 | 91 | dispatch_fsm_state_process: process(sys_clk_i, next_dispatch_state_s, sys_reset_i, dispatch_data_s_1, 92 | dispatch_rd_valid_s_1, dispatch_rd_empty_s, dispatch_wr_en_s, 93 | dispatch_data_s_2) 94 | begin 95 | if (sys_reset_i = '1') then 96 | current_dispatch_state_s <= DISPATCH_IDLE; 97 | for i in 0 to NUM_OUTPUT_QUEUES-1 loop 98 | dispatch_o_arr(i).dispatch_wr_data <= (others => '0'); 99 | dispatch_o_arr(i).dispatch_valid <= '0'; 100 | dispatch_o_arr(i).dispatch_empty <= '1'; 101 | dispatch_o_arr(i).dispatch_wr_en <= '0'; 102 | end loop; 103 | elsif (rising_edge(sys_clk_i)) then 104 | current_dispatch_state_s <= next_dispatch_state_s; 105 | 106 | -- ila_dispatch_state <= std_logic_vector(to_unsigned(dispatch_state'POS(next_dispatch_state_s), 6)); 107 | -- ila_dispatch_output_queue <= std_logic_vector(to_unsigned(next_dispatch_output_queue, 8)); 108 | -- ila_words_to_write <= std_logic_vector(to_unsigned(next_dispatch_words_to_write, 16)); 109 | 110 | dispatch_output_queue <= next_dispatch_output_queue; 111 | dispatch_words_to_write <= next_dispatch_words_to_write; 112 | 113 | dispatch_rd_empty_s <= fifo_rd_empty_i; 114 | dispatch_rd_valid_s_1 <= fifo_rd_valid_i; 115 | dispatch_data_s_1 <= fifo_rd_data_i; 116 | 117 | dispatch_data_s_2 <= dispatch_data_s_1; 118 | dispatch_rd_valid_s_2 <= dispatch_rd_valid_s_1; 119 | 120 | fifo_rd_en_o <= dispatch_rd_en_s; 121 | 122 | for i in 0 to NUM_OUTPUT_QUEUES-1 loop 123 | if (i = next_dispatch_output_queue) then 124 | dispatch_o_arr(i).dispatch_wr_data <= dispatch_data_s_2; 125 | dispatch_o_arr(i).dispatch_valid <= dispatch_rd_valid_s_2; 126 | dispatch_o_arr(i).dispatch_empty <= dispatch_rd_empty_s; 127 | dispatch_o_arr(i).dispatch_wr_en <= dispatch_wr_en_s; 128 | else 129 | -- Only the selected output will receive valid data. 130 | -- All other outputs will receive placeholder data. 131 | dispatch_o_arr(i).dispatch_wr_data <= (others => '0'); 132 | dispatch_o_arr(i).dispatch_valid <= '0'; 133 | dispatch_o_arr(i).dispatch_empty <= '1'; 134 | dispatch_o_arr(i).dispatch_wr_en <= '0'; 135 | end if; 136 | end loop; 137 | end if; 138 | 139 | end process dispatch_fsm_state_process; 140 | 141 | dispatch_fsm_data_output_process: process(current_dispatch_state_s, dispatch_output_queue, dispatch_rd_valid_s_2, 142 | dispatch_data_s_2, dispatch_words_to_write) 143 | begin 144 | dispatch_rd_en_s <= '0'; 145 | dispatch_wr_en_s <= '0'; 146 | next_dispatch_output_queue <= dispatch_output_queue; 147 | next_dispatch_words_to_write <= dispatch_words_to_write; 148 | 149 | case current_dispatch_state_s is 150 | when DISPATCH_IDLE => 151 | next_dispatch_output_queue <= 0; 152 | next_dispatch_words_to_write <= 0; 153 | when DISPATCH_AWAIT_HEADER => 154 | dispatch_rd_en_s <= '1'; 155 | next_dispatch_words_to_write <= 0; 156 | when DISPATCH_READ_HEADER => 157 | dispatch_rd_en_s <= '1'; 158 | -- Write signal started one cycle before the header write to align 159 | -- when the data is available on the output queue 160 | dispatch_wr_en_s <= '1'; 161 | -- tsh_msg_type 162 | next_dispatch_output_queue <= to_integer(unsigned(dispatch_data_s_2(7 downto 0))); 163 | -- tsh_msg_len - Stored in network order 164 | next_dispatch_words_to_write <= to_integer(unsigned(dispatch_data_s_2(23 downto 16) & dispatch_data_s_2(31 downto 24))); 165 | when DISPATCH_WRITE_HEADER => 166 | -- Now that the header is available, it can be written-through to the 167 | -- output component 168 | dispatch_rd_en_s <= '1'; 169 | dispatch_wr_en_s <= '1'; 170 | next_dispatch_words_to_write <= dispatch_words_to_write - 1; 171 | when DISPATCH_WRITE_PACKET => 172 | dispatch_rd_en_s <= '1'; 173 | dispatch_wr_en_s <= dispatch_rd_valid_s_2; 174 | next_dispatch_words_to_write <= dispatch_words_to_write - 1; 175 | when DISPATCH_COMPLETE => 176 | next_dispatch_words_to_write <= 0; 177 | end case; 178 | 179 | end process dispatch_fsm_data_output_process; 180 | 181 | dispatch_fsm_state_select_process: process(current_dispatch_state_s, dispatch_rd_empty_s, dispatch_words_to_write, 182 | dispatch_rd_valid_s_1) 183 | begin 184 | 185 | -- Current state does not change by default 186 | next_dispatch_state_s <= current_dispatch_state_s; 187 | 188 | case current_dispatch_state_s is 189 | when DISPATCH_IDLE => 190 | if (dispatch_rd_empty_s = '0') then 191 | next_dispatch_state_s <= DISPATCH_AWAIT_HEADER; 192 | end if; 193 | when DISPATCH_AWAIT_HEADER => 194 | -- Wait for valid data to appear before continuing 195 | if (dispatch_rd_valid_s_1 = '1') then 196 | next_dispatch_state_s <= DISPATCH_READ_HEADER; 197 | end if; 198 | when DISPATCH_READ_HEADER => 199 | next_dispatch_state_s <= DISPATCH_WRITE_HEADER; 200 | when DISPATCH_WRITE_HEADER => 201 | next_dispatch_state_s <= DISPATCH_WRITE_PACKET; 202 | when DISPATCH_WRITE_PACKET => 203 | -- Its possible that a received packet straddles two USB packets 204 | -- Trust the count in the packet for how many words to transfer 205 | if (dispatch_words_to_write = 0) then 206 | next_dispatch_state_s <= DISPATCH_COMPLETE; 207 | end if; 208 | when DISPATCH_COMPLETE => 209 | next_dispatch_state_s <= DISPATCH_IDLE; 210 | end case; 211 | 212 | end process dispatch_fsm_state_select_process; 213 | 214 | end architecture RTL; 215 | -------------------------------------------------------------------------------- /src/design/tlp_streamer_top.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - Top Module 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | use work.tlp_streamer_records.all; 12 | 13 | entity tlp_streamer is 14 | port ( 15 | -- FT601 Pins 16 | ft601_clk_i : in std_logic; 17 | ft601_be_io : inout std_logic_vector(3 downto 0); 18 | ft601_data_io : inout std_logic_vector(31 downto 0); 19 | ft601_oe_n_o : out std_logic; 20 | ft601_rxf_n_i : in std_logic; 21 | ft601_rd_n_o : out std_logic; 22 | ft601_rst_n_o : out std_logic; 23 | ft601_txe_n_i : in std_logic; 24 | ft601_wr_n_o : out std_logic; 25 | ft601_siwu_n_o : out std_logic; 26 | -- PCIe Pins 27 | pcie_clk_p_i : in std_logic; 28 | pcie_clk_n_i : in std_logic; 29 | pcie_perst_n_i : in std_logic; 30 | pcie_wake_n_o : out std_logic; 31 | pcie_txp_o : out std_logic_vector(0 downto 0); 32 | pcie_txn_o : out std_logic_vector(0 downto 0); 33 | pcie_rxp_i : in std_logic_vector(0 downto 0); 34 | pcie_rxn_i : in std_logic_vector(0 downto 0); 35 | -- Others 36 | user_led_ld1 : out std_logic; 37 | user_led_ld2 : out std_logic; 38 | sys_clk : in std_logic); 39 | end entity tlp_streamer; 40 | 41 | architecture RTL of tlp_streamer is 42 | 43 | component tlp_streamer_reset is 44 | port( 45 | sys_clk_i : in std_logic; 46 | sys_reset_o : out std_logic); 47 | end component tlp_streamer_reset; 48 | 49 | component tlp_streamer_ft601 is 50 | port ( 51 | sys_clk_i : in std_logic; 52 | sys_reset_i : in std_logic; 53 | ft601_clk_i : in std_logic; 54 | ft601_be_io : inout std_logic_vector(3 downto 0); 55 | ft601_data_io : inout std_logic_vector(31 downto 0); 56 | ft601_oe_n_o : out std_logic; 57 | ft601_rxf_n_i : in std_logic; 58 | ft601_rd_n_o : out std_logic; 59 | ft601_rst_n_o : out std_logic; 60 | ft601_txe_n_i : in std_logic; 61 | ft601_wr_n_o : out std_logic; 62 | ft601_siwu_n_o : out std_logic; 63 | ft601_rx_fifo_rd_en_i : in std_logic; 64 | ft601_rx_fifo_rd_empty_o : out std_logic; 65 | ft601_rx_fifo_rd_valid_o : out std_logic; 66 | ft601_rx_fifo_rd_data_o : out std_logic_vector(35 downto 0); 67 | ft601_tx_fifo_wr_en_i : in std_logic; 68 | ft601_tx_fifo_wr_full_o : out std_logic; 69 | ft601_tx_fifo_wr_data_i : in std_logic_vector(35 downto 0)); 70 | end component tlp_streamer_ft601; 71 | 72 | component tlp_streamer_rx_dispatch is 73 | generic(NUM_OUTPUT_QUEUES : integer); 74 | port( 75 | sys_clk_i : in std_logic; 76 | sys_reset_i : in std_logic; 77 | -- Input FIFO to dispatch 78 | fifo_rd_en_o : out std_logic; 79 | fifo_rd_empty_i : in std_logic; 80 | fifo_rd_valid_i : in std_logic; 81 | fifo_rd_data_i : in std_logic_vector(35 downto 0); 82 | -- Output FIFOs to dispatch to 83 | dispatch_o_arr : out dispatch_producer_r_array(NUM_OUTPUT_QUEUES-1 downto 0); 84 | dispatch_i_arr : in dispatch_consumer_r_array(NUM_OUTPUT_QUEUES-1 downto 0)); 85 | end component tlp_streamer_rx_dispatch; 86 | 87 | component tlp_streamer_tx_arbiter is 88 | generic (NUM_INPUT_QUEUES : integer); 89 | port ( 90 | sys_clk_i : in std_logic; 91 | sys_reset_i : in std_logic; 92 | -- Input FIFOs to arbitrate 93 | arbiter_o_arr : out arbiter_producer_r_array(NUM_INPUT_QUEUES-1 downto 0); 94 | arbiter_i_arr : in arbiter_consumer_r_array(NUM_INPUT_QUEUES-1 downto 0); 95 | -- Output FIFO to feed 96 | arbiter_output_wr_en_o : out std_logic; 97 | arbiter_output_wr_full_i : in std_logic; 98 | arbiter_output_wr_data_o : out std_logic_vector(35 downto 0)); 99 | end component tlp_streamer_tx_arbiter; 100 | 101 | component tlp_streamer_loopback is 102 | port( 103 | sys_clk_i : in std_logic; 104 | sys_reset_i : in std_logic; 105 | -- Input from dispatch 106 | dispatch_i : in dispatch_producer_r; 107 | dispatch_o : out dispatch_consumer_r; 108 | -- Output to TX 109 | arbiter_i : in arbiter_producer_r; 110 | arbiter_o : out arbiter_consumer_r); 111 | end component tlp_streamer_loopback; 112 | 113 | component tlp_streamer_pcie is 114 | port( 115 | user_led_ld2 : out std_logic; 116 | sys_clk_i : in std_logic; 117 | sys_reset_i : in std_logic; 118 | pcie_clk_p_i : in std_logic; 119 | pcie_clk_n_i : in std_logic; 120 | pcie_perst_n_i : in std_logic; 121 | pcie_wake_n_o : out std_logic; 122 | pcie_txp_o : out std_logic_vector(0 downto 0); 123 | pcie_txn_o : out std_logic_vector(0 downto 0); 124 | pcie_rxp_i : in std_logic_vector(0 downto 0); 125 | pcie_rxn_i : in std_logic_vector(0 downto 0); 126 | pcie_usr_link_up_o : out std_logic; 127 | pcie_cfg_dispatch_i : in dispatch_producer_r; 128 | pcie_cfg_dispatch_o : out dispatch_consumer_r; 129 | pcie_cfg_arbiter_i : in arbiter_producer_r; 130 | pcie_cfg_arbiter_o : out arbiter_consumer_r; 131 | pcie_tlp_dispatch_i : in dispatch_producer_r; 132 | pcie_tlp_dispatch_o : out dispatch_consumer_r; 133 | pcie_tlp_arbiter_i : in arbiter_producer_r; 134 | pcie_tlp_arbiter_o : out arbiter_consumer_r); 135 | end component tlp_streamer_pcie; 136 | 137 | -- Signals for FT601 RX/TX 138 | signal ft601_rx_fifo_data_s, ft601_wr_data_s: std_logic_vector(35 downto 0); 139 | signal ft601_rx_fifo_rd_en_s, ft601_rx_fifo_rd_empty_s, ft601_rx_fifo_rd_valid_s: std_logic; 140 | signal ft601_tx_wr_en_s, ft601_wr_full_s : std_logic; 141 | 142 | -- Signals for system reset 143 | signal tlp_streamer_reset_s: std_logic; 144 | 145 | -- Signals for RX dispatch queues 146 | signal loopback_queue_out: dispatch_producer_r; 147 | signal loopback_queue_in: dispatch_consumer_r; 148 | signal pcie_cfg_rx_dispatch_out: dispatch_producer_r; 149 | signal pcie_cfg_rx_dispatch_in: dispatch_consumer_r; 150 | signal pcie_tlp_rx_dispatch_out: dispatch_producer_r; 151 | signal pcie_tlp_rx_dispatch_in: dispatch_consumer_r; 152 | 153 | -- Signals for TX arbitration 154 | signal loopback_tx_out: arbiter_producer_r; 155 | signal loopback_tx_in: arbiter_consumer_r; 156 | signal pcie_cfg_tx_arbiter_out: arbiter_producer_r; 157 | signal pcie_cfg_tx_arbiter_in: arbiter_consumer_r; 158 | signal pcie_tlp_tx_arbiter_out: arbiter_producer_r; 159 | signal pcie_tlp_tx_arbiter_in: arbiter_consumer_r; 160 | 161 | begin 162 | 163 | comp_tlp_streamer_reset: tlp_streamer_reset 164 | port map( 165 | sys_clk_i => sys_clk, 166 | sys_reset_o => tlp_streamer_reset_s); 167 | 168 | comp_tlp_streamer_ft601: tlp_streamer_ft601 169 | port map ( 170 | sys_clk_i => sys_clk, 171 | sys_reset_i => tlp_streamer_reset_s, 172 | ft601_clk_i => ft601_clk_i, 173 | ft601_be_io => ft601_be_io, 174 | ft601_data_io => ft601_data_io, 175 | ft601_oe_n_o => ft601_oe_n_o, 176 | ft601_rxf_n_i => ft601_rxf_n_i, 177 | ft601_rd_n_o => ft601_rd_n_o, 178 | ft601_rst_n_o => ft601_rst_n_o, 179 | ft601_txe_n_i => ft601_txe_n_i, 180 | ft601_wr_n_o => ft601_wr_n_o, 181 | ft601_siwu_n_o => ft601_siwu_n_o, 182 | ft601_rx_fifo_rd_en_i => ft601_rx_fifo_rd_en_s, 183 | ft601_rx_fifo_rd_empty_o => ft601_rx_fifo_rd_empty_s, 184 | ft601_rx_fifo_rd_valid_o => ft601_rx_fifo_rd_valid_s, 185 | ft601_rx_fifo_rd_data_o => ft601_rx_fifo_data_s, 186 | ft601_tx_fifo_wr_en_i => ft601_tx_wr_en_s, 187 | ft601_tx_fifo_wr_full_o => ft601_wr_full_s, 188 | ft601_tx_fifo_wr_data_i => ft601_wr_data_s); 189 | 190 | comp_tlp_streamer_pcie: tlp_streamer_pcie 191 | port map ( 192 | user_led_ld2 => user_led_ld2, 193 | sys_clk_i => sys_clk, 194 | sys_reset_i => tlp_streamer_reset_s, 195 | pcie_clk_p_i => pcie_clk_p_i, 196 | pcie_clk_n_i => pcie_clk_n_i, 197 | pcie_perst_n_i => pcie_perst_n_i, 198 | pcie_wake_n_o => pcie_wake_n_o, 199 | pcie_txp_o => pcie_txp_o, 200 | pcie_txn_o => pcie_txn_o, 201 | pcie_rxp_i => pcie_rxp_i, 202 | pcie_rxn_i => pcie_rxn_i, 203 | pcie_usr_link_up_o => open, 204 | -- Conguration management port 205 | pcie_cfg_dispatch_i => pcie_cfg_rx_dispatch_out, 206 | pcie_cfg_dispatch_o => pcie_cfg_rx_dispatch_in, 207 | pcie_cfg_arbiter_i => pcie_cfg_tx_arbiter_out, 208 | pcie_cfg_arbiter_o => pcie_cfg_tx_arbiter_in, 209 | -- TLP Packet handling 210 | pcie_tlp_dispatch_i => pcie_tlp_rx_dispatch_out, 211 | pcie_tlp_dispatch_o => pcie_tlp_rx_dispatch_in, 212 | pcie_tlp_arbiter_i => pcie_tlp_tx_arbiter_out, 213 | pcie_tlp_arbiter_o => pcie_tlp_tx_arbiter_in); 214 | 215 | comp_tlp_streamer_rx_dispatch: tlp_streamer_rx_dispatch 216 | generic map (NUM_OUTPUT_QUEUES => 3) 217 | port map( 218 | sys_clk_i => sys_clk, 219 | sys_reset_i => tlp_streamer_reset_s, 220 | -- Input FIFO to dispatch 221 | fifo_rd_en_o => ft601_rx_fifo_rd_en_s, 222 | fifo_rd_empty_i => ft601_rx_fifo_rd_empty_s, 223 | fifo_rd_valid_i => ft601_rx_fifo_rd_valid_s, 224 | fifo_rd_data_i => ft601_rx_fifo_data_s, 225 | -- Output Components 226 | -- These MUST correspond to tsh_msg_type_et. 227 | dispatch_o_arr(0) => loopback_queue_out, 228 | dispatch_o_arr(1) => pcie_cfg_rx_dispatch_out, 229 | dispatch_o_arr(2) => pcie_tlp_rx_dispatch_out, 230 | dispatch_i_arr(0) => loopback_queue_in, 231 | dispatch_i_arr(1) => pcie_cfg_rx_dispatch_in, 232 | dispatch_i_arr(2) => pcie_tlp_rx_dispatch_in); 233 | 234 | comp_tlp_streamer_tx_arbiter: tlp_streamer_tx_arbiter 235 | generic map (NUM_INPUT_QUEUES => 3) 236 | port map ( 237 | sys_clk_i => sys_clk, 238 | sys_reset_i => tlp_streamer_reset_s, 239 | -- Input FIFOs to arbitrate 240 | arbiter_o_arr(0) => loopback_tx_out, 241 | arbiter_o_arr(1) => pcie_cfg_tx_arbiter_out, 242 | arbiter_o_arr(2) => pcie_tlp_tx_arbiter_out, 243 | arbiter_i_arr(0) => loopback_tx_in, 244 | arbiter_i_arr(1) => pcie_cfg_tx_arbiter_in, 245 | arbiter_i_arr(2) => pcie_tlp_tx_arbiter_in, 246 | -- Output FIFO to feed 247 | arbiter_output_wr_en_o => ft601_tx_wr_en_s, 248 | arbiter_output_wr_full_i => ft601_wr_full_s, 249 | arbiter_output_wr_data_o => ft601_wr_data_s); 250 | 251 | comp_tlp_streamer_loopback: tlp_streamer_loopback 252 | port map( 253 | sys_clk_i => sys_clk, 254 | sys_reset_i => tlp_streamer_reset_s, 255 | -- Input from dispatch 256 | dispatch_i => loopback_queue_out, 257 | dispatch_o => loopback_queue_in, 258 | -- Output to TX 259 | arbiter_i => loopback_tx_out, 260 | arbiter_o => loopback_tx_in); 261 | 262 | user_led_ld1 <= tlp_streamer_reset_s; 263 | 264 | end architecture RTL; 265 | -------------------------------------------------------------------------------- /src/design/tlp_streamer_tx_arbiter.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - FPGA Packet TX Arbiter 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | use work.tlp_streamer_records.all; 12 | 13 | entity tlp_streamer_tx_arbiter is 14 | generic (NUM_INPUT_QUEUES : integer); 15 | port ( 16 | sys_clk_i : in std_logic; 17 | sys_reset_i : in std_logic; 18 | -- Input FIFOs to arbitrate 19 | arbiter_o_arr : out arbiter_producer_r_array(NUM_INPUT_QUEUES-1 downto 0); 20 | arbiter_i_arr : in arbiter_consumer_r_array(NUM_INPUT_QUEUES-1 downto 0); 21 | -- Output FIFO to feed 22 | arbiter_output_wr_en_o : out std_logic; 23 | arbiter_output_wr_full_i : in std_logic; 24 | arbiter_output_wr_data_o : out std_logic_vector(35 downto 0)); 25 | end entity tlp_streamer_tx_arbiter; 26 | 27 | architecture RTL of tlp_streamer_tx_arbiter is 28 | 29 | type arbiter_state is (ARBITER_IDLE, ARBITER_AWAIT_HEADER, ARBITER_READ_HEADER, 30 | ARBITER_WRITE_PACKET, ARBITER_COMPLETE_1, ARBITER_COMPLETE_2); 31 | 32 | signal current_arbiter_state_s, next_arbiter_state_s: arbiter_state; 33 | signal arbiter_words_to_write, next_arbiter_words_to_write: integer range 0 to 65535; 34 | signal arbiter_input_queue, next_arbiter_input_queue: integer range 0 to NUM_INPUT_QUEUES; 35 | 36 | signal arbiter_rd_en_s, arbiter_rd_valid_s_1, arbiter_rd_valid_s_2, arbiter_rd_empty_s, 37 | arbiter_wr_en_s : std_logic; 38 | signal arbiter_rd_data_s_1, arbiter_rd_data_s_2, arbiter_rd_data_s_3 : std_logic_vector(35 downto 0); 39 | 40 | begin 41 | 42 | arbiter_fsm_state_process: process(sys_clk_i, sys_reset_i, next_arbiter_state_s, 43 | arbiter_rd_en_s, arbiter_output_wr_full_i, 44 | arbiter_wr_en_s, arbiter_rd_data_s_1, 45 | arbiter_i_arr, arbiter_rd_data_s_2, 46 | arbiter_words_to_write, arbiter_rd_valid_s_1, 47 | arbiter_rd_valid_s_2, next_arbiter_input_queue) 48 | begin 49 | 50 | if (sys_reset_i = '1') then 51 | current_arbiter_state_s <= ARBITER_IDLE; 52 | arbiter_output_wr_en_o <= '0'; 53 | arbiter_rd_data_s_1 <= (others => '0'); 54 | arbiter_rd_data_s_2 <= (others => '0'); 55 | arbiter_rd_valid_s_1 <= '0'; 56 | arbiter_rd_valid_s_2 <= '0'; 57 | arbiter_rd_empty_s <= '1'; 58 | arbiter_input_queue <= NUM_INPUT_QUEUES; 59 | for i in 0 to NUM_INPUT_QUEUES-1 loop 60 | arbiter_o_arr(i).arbiter_rd_en <= '0'; 61 | arbiter_o_arr(i).arbiter_wr_full <= '0'; 62 | end loop; 63 | elsif (rising_edge(sys_clk_i)) then 64 | current_arbiter_state_s <= next_arbiter_state_s; 65 | 66 | for i in 0 to NUM_INPUT_QUEUES-1 loop 67 | if (i = next_arbiter_input_queue) then 68 | arbiter_rd_data_s_1 <= arbiter_i_arr(i).arbiter_rd_data; 69 | arbiter_rd_valid_s_1 <= arbiter_i_arr(i).arbiter_rd_valid; 70 | arbiter_rd_empty_s <= arbiter_i_arr(i).arbiter_rd_empty; 71 | arbiter_o_arr(i).arbiter_rd_en <= arbiter_rd_en_s; 72 | arbiter_o_arr(i).arbiter_wr_full <= arbiter_output_wr_full_i; 73 | -- There used to be an else statement here in order to set the 74 | -- signals for the unselected inputs to a known default but 75 | -- that seemed to optimize out some of the signals from the 76 | -- selected inputs. 77 | end if; 78 | end loop; 79 | 80 | arbiter_rd_data_s_2 <= arbiter_rd_data_s_1; 81 | arbiter_rd_valid_s_2 <= arbiter_rd_valid_s_1; 82 | 83 | arbiter_output_wr_data_o <= arbiter_rd_data_s_2; 84 | arbiter_rd_data_s_3 <= arbiter_rd_data_s_2; 85 | arbiter_output_wr_en_o <= arbiter_wr_en_s; 86 | 87 | arbiter_input_queue <= next_arbiter_input_queue; 88 | arbiter_words_to_write <= next_arbiter_words_to_write; 89 | end if; 90 | 91 | end process arbiter_fsm_state_process; 92 | 93 | arbiter_fsm_data_output_process: process(current_arbiter_state_s, arbiter_i_arr, arbiter_input_queue, 94 | arbiter_words_to_write, arbiter_rd_valid_s_2, arbiter_rd_data_s_3) 95 | begin 96 | 97 | arbiter_rd_en_s <= '0'; 98 | arbiter_wr_en_s <= '0'; 99 | next_arbiter_input_queue <= arbiter_input_queue; 100 | next_arbiter_words_to_write <= arbiter_words_to_write; 101 | 102 | case current_arbiter_state_s is 103 | when ARBITER_IDLE => 104 | for i in 0 to NUM_INPUT_QUEUES-1 loop 105 | if (arbiter_i_arr(i).arbiter_rd_empty = '0') then 106 | next_arbiter_input_queue <= i; 107 | end if; 108 | exit when arbiter_i_arr(i).arbiter_rd_empty = '0'; 109 | end loop; 110 | next_arbiter_words_to_write <= 0; 111 | when ARBITER_AWAIT_HEADER => 112 | arbiter_rd_en_s <= '1'; 113 | arbiter_wr_en_s <= arbiter_rd_valid_s_2; 114 | next_arbiter_words_to_write <= 0; 115 | when ARBITER_READ_HEADER => 116 | arbiter_rd_en_s <= '1'; 117 | arbiter_wr_en_s <= arbiter_rd_valid_s_2; 118 | next_arbiter_words_to_write <= to_integer(unsigned(arbiter_rd_data_s_3(23 downto 16) & arbiter_rd_data_s_3(31 downto 24))) - 1; 119 | when ARBITER_WRITE_PACKET => 120 | if (arbiter_words_to_write > 3) then 121 | arbiter_rd_en_s <= '1'; 122 | else 123 | arbiter_rd_en_s <= '0'; 124 | end if; 125 | arbiter_wr_en_s <= arbiter_rd_valid_s_2; 126 | next_arbiter_words_to_write <= arbiter_words_to_write - 1; 127 | when ARBITER_COMPLETE_1 => 128 | next_arbiter_words_to_write <= 0; 129 | when ARBITER_COMPLETE_2 => 130 | -- A second complete state is used to allow for the rd_en 131 | -- signal to be de-asserted for the selected input before 132 | -- resetting the input queue for the next TX packet 133 | next_arbiter_input_queue <= NUM_INPUT_QUEUES; 134 | next_arbiter_words_to_write <= 0; 135 | end case; 136 | 137 | end process arbiter_fsm_data_output_process; 138 | 139 | arbiter_fsm_state_select_process: process(current_arbiter_state_s, arbiter_i_arr, 140 | arbiter_words_to_write, arbiter_rd_valid_s_2, 141 | arbiter_input_queue) 142 | begin 143 | 144 | -- Current state does not change by default 145 | next_arbiter_state_s <= current_arbiter_state_s; 146 | 147 | case current_arbiter_state_s is 148 | when ARBITER_IDLE => 149 | -- Once an input queue is available and there is space in the output queue 150 | -- move to ARBITER_INPUT_SELECTED 151 | if (arbiter_input_queue < NUM_INPUT_QUEUES) then 152 | next_arbiter_state_s <= ARBITER_AWAIT_HEADER; 153 | end if; 154 | when ARBITER_AWAIT_HEADER => 155 | if (arbiter_rd_valid_s_2 = '1') then 156 | next_arbiter_state_s <= ARBITER_READ_HEADER; 157 | end if; 158 | when ARBITER_READ_HEADER => 159 | next_arbiter_state_s <= ARBITER_WRITE_PACKET; 160 | when ARBITER_WRITE_PACKET => 161 | if (arbiter_words_to_write = 0) then 162 | next_arbiter_state_s <= ARBITER_COMPLETE_1; 163 | end if; 164 | when ARBITER_COMPLETE_1 => 165 | next_arbiter_state_s <= ARBITER_COMPLETE_2; 166 | when ARBITER_COMPLETE_2 => 167 | next_arbiter_state_s <= ARBITER_IDLE; 168 | end case; 169 | 170 | end process arbiter_fsm_state_select_process; 171 | 172 | end architecture RTL; 173 | -------------------------------------------------------------------------------- /src/sim/tlp_streamer_usb_rx_sim.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- TLP Streamer - USB RX Simulation 3 | -- 4 | -- (c) MikeM64 - 2021 5 | -- 6 | 7 | library IEEE; 8 | use IEEE.std_logic_1164.all; 9 | use IEEE.numeric_std.all; 10 | 11 | entity tlp_usb_rx_sim is end tlp_usb_rx_sim; 12 | 13 | architecture test of tlp_usb_rx_sim is 14 | component tlp_streamer 15 | port( 16 | -- FT601 Pins 17 | ft601_clk_i : in std_logic; 18 | ft601_be_io : inout std_logic_vector(3 downto 0); 19 | ft601_data_io : inout std_logic_vector(31 downto 0); 20 | ft601_oe_n_o : out std_logic; 21 | ft601_rxf_n_i : in std_logic; 22 | ft601_rd_n_o : out std_logic; 23 | ft601_rst_n_o : out std_logic; 24 | ft601_txe_n_i : in std_logic; 25 | ft601_wr_n_o : out std_logic; 26 | ft601_siwu_n_o : out std_logic; 27 | -- PCIe Pins 28 | pcie_clk_p_i : in std_logic; 29 | pcie_clk_n_i : in std_logic; 30 | pcie_perst_n_i : in std_logic; 31 | pcie_wake_n_o : out std_logic; 32 | pcie_txp_o : out std_logic_vector(0 downto 0); 33 | pcie_txn_o : out std_logic_vector(0 downto 0); 34 | pcie_rxp_i : in std_logic_vector(0 downto 0); 35 | pcie_rxn_i : in std_logic_vector(0 downto 0); 36 | -- Others 37 | user_led_ld1 : out std_logic; 38 | user_led_ld2 : out std_logic; 39 | sys_clk : in std_logic); 40 | 41 | end component; 42 | 43 | signal test_ft601_clk: std_logic := '1'; 44 | signal test_sys_clk: std_logic := '1'; 45 | signal test_ft601_be: std_logic_vector(3 downto 0) := "0000"; 46 | signal test_ft601_data: std_logic_vector(31 downto 0) := "00000000000000000000000000000000"; 47 | 48 | signal test_ft601_bus_wr_s: std_logic := '1'; 49 | signal test_ft601_be_rd_i: std_logic_vector(3 downto 0); 50 | signal test_ft601_data_rd_i: std_logic_vector(31 downto 0); 51 | signal test_ft601_be_wr_o: std_logic_vector(3 downto 0); 52 | signal test_ft601_data_wr_o: std_logic_vector(31 downto 0); 53 | 54 | signal test_ft601_oe_n: std_logic := '1'; 55 | signal test_ft601_rxf_n: std_logic := '1'; 56 | signal test_ft601_rd_n: std_logic := '1'; 57 | signal test_ft601_rst_n: std_logic := '1'; 58 | signal test_ft601_txe_n: std_logic := '1'; 59 | signal test_ft601_wr_n: std_logic := '1'; 60 | signal test_ft601_siwu_n_o: std_logic := '0'; 61 | 62 | signal pcie_clk_p_i : std_logic := '0'; 63 | signal pcie_clk_n_i : std_logic := '0'; 64 | signal pcie_perst_n_i : std_logic := '0'; 65 | signal pcie_wake_n_o : std_logic := '0'; 66 | signal pcie_txp_o : std_logic_vector(0 downto 0) := "0"; 67 | signal pcie_txn_o : std_logic_vector(0 downto 0) := "0"; 68 | signal pcie_rxp_i : std_logic_vector(0 downto 0) := "0"; 69 | signal pcie_rxn_i : std_logic_vector(0 downto 0) := "0"; 70 | 71 | signal test_user_led_ld1: std_logic := '0'; 72 | signal test_user_led_ld2: std_logic := '0'; 73 | 74 | begin 75 | 76 | UUT: tlp_streamer 77 | port map( 78 | ft601_clk_i => test_ft601_clk, 79 | ft601_be_io => test_ft601_be, 80 | ft601_data_io => test_ft601_data, 81 | ft601_oe_n_o => test_ft601_oe_n, 82 | ft601_rxf_n_i => test_ft601_rxf_n, 83 | ft601_rd_n_o => test_ft601_rd_n, 84 | ft601_rst_n_o => test_ft601_rst_n, 85 | ft601_txe_n_i => test_ft601_txe_n, 86 | ft601_wr_n_o => test_ft601_wr_n, 87 | ft601_siwu_n_o => test_ft601_siwu_n_o, 88 | -- PCIe Pins 89 | pcie_clk_p_i => pcie_clk_p_i, 90 | pcie_clk_n_i => pcie_clk_n_i, 91 | pcie_perst_n_i => pcie_perst_n_i, 92 | pcie_wake_n_o => pcie_wake_n_o, 93 | pcie_txp_o => pcie_txp_o, 94 | pcie_txn_o => pcie_txn_o, 95 | pcie_rxp_i => pcie_rxp_i, 96 | pcie_rxn_i => pcie_rxn_i, 97 | 98 | user_led_ld1 => test_user_led_ld1, 99 | user_led_ld2 => test_user_led_ld2, 100 | sys_clk => test_sys_clk); 101 | 102 | test_ft601_clk <= not test_ft601_clk after 5ns; 103 | test_sys_clk <= not test_sys_clk after 5ns; 104 | 105 | bus_write: process(test_ft601_clk) begin 106 | 107 | if (test_ft601_clk'EVENT and test_ft601_clk = '1') then 108 | if (test_ft601_bus_wr_s = '1') then 109 | test_ft601_be <= test_ft601_be_wr_o; 110 | test_ft601_data <= test_ft601_data_wr_o; 111 | else 112 | test_ft601_be <= "ZZZZ"; 113 | test_ft601_data <= "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; 114 | end if; 115 | 116 | test_ft601_be_rd_i <= test_ft601_be; 117 | test_ft601_data_rd_i <= test_ft601_data; 118 | end if; 119 | 120 | end process bus_write; 121 | 122 | tb: process begin 123 | 124 | test_ft601_bus_wr_s <= '1'; 125 | test_ft601_be_wr_o <= "0000"; 126 | test_ft601_data_wr_o <= "00000000000000000000000000000000"; 127 | 128 | wait for 800ns; 129 | report "FPGA reset complete"; 130 | 131 | -- Refer to pg. 17 of the FT601 datasheet for the 132 | -- controller read timing diagram. This is what is 133 | -- being verified here. 134 | test_ft601_rxf_n <= '0'; 135 | 136 | wait for 30ns; 137 | test_ft601_be_wr_o <= "1111"; 138 | test_ft601_data_wr_o <= "00000000000001101111111100000000"; 139 | 140 | wait for 10ns; 141 | test_ft601_data_wr_o <= "00000000000000000000000000000000"; 142 | 143 | wait for 10ns; 144 | test_ft601_data_wr_o <= "01010101010101010101010101010101"; 145 | 146 | wait for 10ns; 147 | test_ft601_data_wr_o <= "10101010101010101010101010101010"; 148 | 149 | wait for 10ns; 150 | test_ft601_data_wr_o <= "10101010101010101010101010101010"; 151 | 152 | wait for 10ns; 153 | test_ft601_data_wr_o <= "10101010101010101010101010101010"; 154 | 155 | wait for 10ns; 156 | --assert test_ft601_oe_n = '0' report "The core has not asserted OE_N, 3 cycles after RXF_N" severity failure; 157 | test_ft601_be_wr_o <= "0000"; 158 | test_ft601_data_wr_o <= "00000000000000000000000000000000"; 159 | 160 | wait for 10ns; 161 | test_ft601_bus_wr_s <= '0'; 162 | test_ft601_rxf_n <= '1'; 163 | 164 | --assert test_ft601_rd_n = '0' report "The core has not asserted RD_N, 1 cycle after OE_N" severity failure; 165 | wait for 100ns; 166 | 167 | --assert test_ft601_oe_n = '1' report "The core has not de-asserted OE_N, 1 cycle after RXF_N" severity failure; 168 | --assert test_ft601_rd_n = '1' report "The core has not de-asserted RD_N, 1 cycle after RXF_N" severity failure; 169 | test_ft601_txe_n <= '0'; 170 | 171 | wait for 210ns; 172 | test_ft601_txe_n <= '1'; 173 | wait for 50ns; 174 | 175 | report "Simulation complete!"; 176 | 177 | end process tb; 178 | 179 | end architecture; -------------------------------------------------------------------------------- /src/sim/tlp_usb_rx_sim_behav.wcfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Test Signals 27 | label 28 | 29 | test_sys_clk 30 | test_sys_clk 31 | 32 | 33 | test_ft601_clk 34 | test_ft601_clk 35 | 36 | 37 | test_ft601_be[3:0] 38 | test_ft601_be[3:0] 39 | 40 | 41 | test_ft601_data[31:0] 42 | test_ft601_data[31:0] 43 | 44 | 45 | test_ft601_oe_n 46 | test_ft601_oe_n 47 | 48 | 49 | test_ft601_rd_n 50 | test_ft601_rd_n 51 | 52 | 53 | test_ft601_wr_n 54 | test_ft601_wr_n 55 | 56 | 57 | test_ft601_rxf_n 58 | test_ft601_rxf_n 59 | 60 | 61 | test_ft601_txe_n 62 | test_ft601_txe_n 63 | 64 | 65 | test_ft601_rst_n 66 | test_ft601_rst_n 67 | 68 | 69 | 70 | ft601_be_io[3:0] 71 | ft601_be_io[3:0] 72 | 73 | 74 | ft601_data_io[31:0] 75 | ft601_data_io[31:0] 76 | 77 | 78 | Bus FSM 79 | label 80 | 81 | 82 | 83 | label 84 | ft601_txe_n_i 85 | ft601_txe_n_i 86 | /tlp_usb_rx_sim/UUT/ft601_txe_n_ift601_txe_n_i 87 | 88 | 89 | ft601_wr_n_o 90 | ft601_wr_n_o 91 | 92 | 93 | ft601_rst_n_o 94 | ft601_rst_n_o 95 | 96 | 97 | RX FIFO 98 | label 99 | 100 | ft601_data_rd_i[31:0] 101 | ft601_data_rd_i[31:0] 102 | 103 | 104 | fifo_rx_wr_data_s[35:0] 105 | fifo_rx_wr_data_s[35:0] 106 | 107 | 108 | current_bus_state 109 | current_bus_state 110 | 111 | 112 | next_bus_state 113 | next_bus_state 114 | 115 | 116 | ft601_rx_fifo_rd_data_o[35:0] 117 | ft601_rx_fifo_rd_data_o[35:0] 118 | 119 | 120 | fifo_rx_wr_en_s 121 | fifo_rx_wr_en_s 122 | 123 | 124 | 125 | TX FIFO 126 | label 127 | 128 | fifo_tx_rd_data_s[35:0] 129 | fifo_tx_rd_data_s[35:0] 130 | 131 | 132 | fifo_tx_rd_en_s 133 | fifo_tx_rd_en_s 134 | 135 | 136 | fifo_tx_rd_empty_s 137 | fifo_tx_rd_empty_s 138 | 139 | 140 | fifo_tx_rd_valid_s 141 | fifo_tx_rd_valid_s 142 | 143 | 144 | wr_en 145 | wr_en 146 | 147 | 148 | full 149 | full 150 | 151 | 152 | empty 153 | empty 154 | 155 | 156 | ft601_tx_fifo_wr_full_o 157 | ft601_tx_fifo_wr_full_o 158 | 159 | 160 | ft601_tx_fifo_wr_data_i[35:0] 161 | ft601_tx_fifo_wr_data_i[35:0] 162 | 163 | 164 | ft601_tx_fifo_wr_en_i 165 | ft601_tx_fifo_wr_en_i 166 | 167 | 168 | 169 | RX Dispatch 170 | label 171 | 172 | 173 | fifo_rd_data_i[35:0] 174 | fifo_rd_data_i[35:0] 175 | 176 | 177 | fifo_rd_valid_i 178 | fifo_rd_valid_i 179 | 180 | 181 | fifo_rd_empty_i 182 | fifo_rd_empty_i 183 | 184 | 185 | fifo_rd_en_o 186 | fifo_rd_en_o 187 | 188 | 189 | current_dispatch_state_s 190 | current_dispatch_state_s 191 | 192 | 193 | next_dispatch_state_s 194 | next_dispatch_state_s 195 | 196 | 197 | dispatch_output_queue 198 | dispatch_output_queue 199 | 200 | 201 | dispatch_words_to_write 202 | dispatch_words_to_write 203 | 204 | 205 | next_dispatch_words_to_write 206 | next_dispatch_words_to_write 207 | 208 | 209 | dispatch_data_s_1[35:0] 210 | dispatch_data_s_1[35:0] 211 | 212 | 213 | dispatch_data_s_2[35:0] 214 | dispatch_data_s_2[35:0] 215 | 216 | 217 | dispatch_o_arr[1:0] 218 | dispatch_o_arr[1:0] 219 | 220 | 221 | [1] 222 | [1] 223 | 224 | 225 | [0] 226 | [0] 227 | 228 | 229 | 230 | 231 | dispatch_i_arr[1:0] 232 | dispatch_i_arr[1:0] 233 | 234 | 235 | 236 | TX Arbiter 237 | label 238 | 239 | 240 | current_arbiter_state_s 241 | current_arbiter_state_s 242 | 243 | 244 | next_arbiter_state_s 245 | next_arbiter_state_s 246 | 247 | 248 | arbiter_words_to_write 249 | arbiter_words_to_write 250 | 251 | 252 | next_arbiter_words_to_write 253 | next_arbiter_words_to_write 254 | 255 | 256 | arbiter_input_queue 257 | arbiter_input_queue 258 | 259 | 260 | next_arbiter_input_queue 261 | next_arbiter_input_queue 262 | 263 | 264 | arbiter_output_wr_full_i 265 | arbiter_output_wr_full_i 266 | 267 | 268 | arbiter_wr_en_s 269 | arbiter_wr_en_s 270 | 271 | 272 | arbiter_output_wr_en_o 273 | arbiter_output_wr_en_o 274 | 275 | 276 | arbiter_rd_en_s 277 | arbiter_rd_en_s 278 | 279 | 280 | arbiter_rd_valid_s_1 281 | arbiter_rd_valid_s_1 282 | 283 | 284 | arbiter_rd_valid_s_2 285 | arbiter_rd_valid_s_2 286 | 287 | 288 | arbiter_rd_data_s_1[35:0] 289 | arbiter_rd_data_s_1[35:0] 290 | 291 | 292 | arbiter_rd_data_s_2[35:0] 293 | arbiter_rd_data_s_2[35:0] 294 | 295 | 296 | arbiter_output_wr_data_o[35:0] 297 | arbiter_output_wr_data_o[35:0] 298 | 299 | 300 | arbiter_rd_data_s_3[35:0] 301 | arbiter_rd_data_s_3[35:0] 302 | 303 | 304 | arbiter_i_arr[1:0] 305 | arbiter_i_arr[1:0] 306 | 307 | 308 | [1] 309 | [1] 310 | 311 | 312 | 313 | [0] 314 | [0] 315 | 316 | 317 | 318 | 319 | arbiter_o_arr[1:0] 320 | arbiter_o_arr[1:0] 321 | 322 | 323 | [1] 324 | [1] 325 | 326 | 327 | 328 | [0] 329 | [0] 330 | 331 | 332 | 333 | 334 | 335 | Loopback 336 | label 337 | 338 | wr_en 339 | wr_en 340 | 341 | 342 | dispatch_i 343 | dispatch_i 344 | 345 | 346 | 347 | dispatch_o 348 | dispatch_o 349 | 350 | 351 | 352 | arbiter_i 353 | arbiter_i 354 | 355 | 356 | 357 | rd_en 358 | rd_en 359 | 360 | 361 | arbiter_o 362 | arbiter_o 363 | 364 | 365 | 366 | 367 | -------------------------------------------------------------------------------- /vivado_build.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # RUN FROM WITHIN "Vivado Tcl Shell" WITH COMMAND: 3 | # source vivado_build.tcl -notrace 4 | # 5 | reset_run synth_1 6 | puts "-------------------------------------------------------" 7 | puts " STARTING SYNTHESIS STEP. " 8 | puts "-------------------------------------------------------" 9 | launch_runs synth_1 10 | puts "-------------------------------------------------------" 11 | puts " WAITING FOR SYNTHESIS STEP TO FINISH ... " 12 | puts " THIS IS LIKELY TO TAKE A VERY LONG TIME. " 13 | puts "-------------------------------------------------------" 14 | wait_on_run synth_1 15 | puts "-------------------------------------------------------" 16 | puts " STARTING IMPLEMENTATION STEP. " 17 | puts "-------------------------------------------------------" 18 | launch_runs impl_1 -to_step write_bitstream 19 | puts "-------------------------------------------------------" 20 | puts " WAITING FOR IMPLEMENTATION STEP TO FINISH ... " 21 | puts " THIS IS LIKELY TO TAKE A VERY LONG TIME. " 22 | puts "-------------------------------------------------------" 23 | wait_on_run impl_1 24 | puts "-------------------------------------------------------" 25 | puts " BUILD HOPEFULLY COMPLETED. " 26 | puts "-------------------------------------------------------" 27 | quit 28 | -------------------------------------------------------------------------------- /vivado_generate_project.tcl: -------------------------------------------------------------------------------- 1 | #***************************************************************************************** 2 | # Vivado (TM) v2020.2 (64-bit) 3 | # 4 | # vivado_generate_project.tcl: Tcl script for re-creating project 'tlp-streamer' 5 | # 6 | # Generated by Vivado on Sun Jan 02 03:42:26 EST 2022 7 | # IP Build 3064653 on Wed Nov 18 14:17:31 MST 2020 8 | # 9 | # This file contains the Vivado Tcl commands for re-creating the project to the state* 10 | # when this script was generated. In order to re-create the project, please source this 11 | # file in the Vivado Tcl Shell. 12 | # 13 | # * Note that the runs in the created project will be configured the same way as the 14 | # original project, however they will not be launched automatically. To regenerate the 15 | # run results please launch the synthesis/implementation runs as needed. 16 | # 17 | #***************************************************************************************** 18 | # NOTE: In order to use this script for source control purposes, please make sure that the 19 | # following files are added to the source control system:- 20 | # 21 | # 1. This project restoration tcl script (vivado_generate_project.tcl) that was generated. 22 | # 23 | # 2. The following source(s) files that were local or imported into the original project. 24 | # (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) 25 | # 26 | # 27 | # 28 | # 3. The following remote source files that were added to the original project:- 29 | # 30 | # "./src/design/tlp_streamer_records.vhd" 31 | # "./src/design/tlp_streamer_top.vhd" 32 | # "./src/design/tlp_streamer_ft601.vhd" 33 | # "./src/design/tlp_streamer_pcie.vhd" 34 | # "./src/design/tlp_streamer_rx_dispatch.vhd" 35 | # "./src/design/tlp_streamer_loopback.vhd" 36 | # "./src/design/tlp_streamer_reset.vhd" 37 | # "./src/design/tlp_streamer_tx_arbiter.vhd" 38 | # "./src/design/tlp_streamer_pcie_tlp.vhd" 39 | # "./src/design/tlp_streamer_pcie_cfg.vhd" 40 | # "./ip/fifo_36_36_prim/fifo_36_36_prim.xci" 41 | # "./ip/fifo_32_32_bram/fifo_32_32_bram.xci" 42 | # "./ip/ila_0/ila_0.xci" 43 | # "./ip/fifo_pcie_tlp_r32_w64_4096_bram/fifo_pcie_tlp_r32_w64_4096_bram.xci" 44 | # "./ip/pcie_tlp_ila/pcie_tlp_ila.xci" 45 | # "./ip/fifo_pcie_tlp_r64_w32_4096_bram/fifo_pcie_tlp_r64_w32_4096_bram.xci" 46 | # "./ip/pcie_7x_0/pcie_7x_0.xci" 47 | # "./src/constrs/screamer_m2.xdc" 48 | # "./src/sim/tlp_streamer_usb_rx_sim.vhd" 49 | # "./src/sim/tlp_usb_rx_sim_behav.wcfg" 50 | # 51 | #***************************************************************************************** 52 | 53 | # Check file required for this script exists 54 | proc checkRequiredFiles { origin_dir} { 55 | set status true 56 | set files [list \ 57 | "./src/design/tlp_streamer_records.vhd" \ 58 | "./src/design/tlp_streamer_top.vhd" \ 59 | "./src/design/tlp_streamer_ft601.vhd" \ 60 | "./src/design/tlp_streamer_pcie.vhd" \ 61 | "./src/design/tlp_streamer_rx_dispatch.vhd" \ 62 | "./src/design/tlp_streamer_loopback.vhd" \ 63 | "./src/design/tlp_streamer_reset.vhd" \ 64 | "./src/design/tlp_streamer_tx_arbiter.vhd" \ 65 | "./src/design/tlp_streamer_pcie_tlp.vhd" \ 66 | "./src/design/tlp_streamer_pcie_cfg.vhd" \ 67 | "./ip/fifo_36_36_prim/fifo_36_36_prim.xci" \ 68 | "./ip/fifo_32_32_bram/fifo_32_32_bram.xci" \ 69 | "./ip/ila_0/ila_0.xci" \ 70 | "./ip/fifo_pcie_tlp_r32_w64_4096_bram/fifo_pcie_tlp_r32_w64_4096_bram.xci" \ 71 | "./ip/pcie_tlp_ila/pcie_tlp_ila.xci" \ 72 | "./ip/fifo_pcie_tlp_r64_w32_4096_bram/fifo_pcie_tlp_r64_w32_4096_bram.xci" \ 73 | "./ip/pcie_7x_0/pcie_7x_0.xci" \ 74 | "./src/constrs/screamer_m2.xdc" \ 75 | "./src/sim/tlp_streamer_usb_rx_sim.vhd" \ 76 | "./src/sim/tlp_usb_rx_sim_behav.wcfg" \ 77 | ] 78 | foreach ifile $files { 79 | if { ![file isfile $ifile] } { 80 | puts " Could not find remote file $ifile " 81 | set status false 82 | } 83 | } 84 | 85 | return $status 86 | } 87 | # Set the reference directory for source file relative paths (by default the value is script directory path) 88 | set origin_dir "." 89 | 90 | # Use origin directory path location variable, if specified in the tcl shell 91 | if { [info exists ::origin_dir_loc] } { 92 | set origin_dir $::origin_dir_loc 93 | } 94 | 95 | # Set the project name 96 | set _xil_proj_name_ "tlp-streamer" 97 | 98 | # Use project name variable, if specified in the tcl shell 99 | if { [info exists ::user_project_name] } { 100 | set _xil_proj_name_ $::user_project_name 101 | } 102 | 103 | variable script_file 104 | set script_file "vivado_generate_project.tcl" 105 | 106 | # Help information for this script 107 | proc print_help {} { 108 | variable script_file 109 | puts "\nDescription:" 110 | puts "Recreate a Vivado project from this script. The created project will be" 111 | puts "functionally equivalent to the original project for which this script was" 112 | puts "generated. The script contains commands for creating a project, filesets," 113 | puts "runs, adding/importing sources and setting properties on various objects.\n" 114 | puts "Syntax:" 115 | puts "$script_file" 116 | puts "$script_file -tclargs \[--origin_dir \]" 117 | puts "$script_file -tclargs \[--project_name \]" 118 | puts "$script_file -tclargs \[--help\]\n" 119 | puts "Usage:" 120 | puts "Name Description" 121 | puts "-------------------------------------------------------------------------" 122 | puts "\[--origin_dir \] Determine source file paths wrt this path. Default" 123 | puts " origin_dir path value is \".\", otherwise, the value" 124 | puts " that was set with the \"-paths_relative_to\" switch" 125 | puts " when this script was generated.\n" 126 | puts "\[--project_name \] Create project with the specified name. Default" 127 | puts " name is the name of the project from where this" 128 | puts " script was generated.\n" 129 | puts "\[--help\] Print help information for this script" 130 | puts "-------------------------------------------------------------------------\n" 131 | exit 0 132 | } 133 | 134 | if { $::argc > 0 } { 135 | for {set i 0} {$i < $::argc} {incr i} { 136 | set option [string trim [lindex $::argv $i]] 137 | switch -regexp -- $option { 138 | "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } 139 | "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } 140 | "--help" { print_help } 141 | default { 142 | if { [regexp {^-} $option] } { 143 | puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" 144 | return 1 145 | } 146 | } 147 | } 148 | } 149 | } 150 | 151 | # Set the directory path for the original project from where this script was exported 152 | set orig_proj_dir "[file normalize "$origin_dir/tlp-streamer"]" 153 | 154 | # Check for paths and files needed for project creation 155 | set validate_required 0 156 | if { $validate_required } { 157 | if { [checkRequiredFiles $origin_dir] } { 158 | puts "Tcl file $script_file is valid. All files required for project creation is accesable. " 159 | } else { 160 | puts "Tcl file $script_file is not valid. Not all files required for project creation is accesable. " 161 | return 162 | } 163 | } 164 | 165 | # Create project 166 | create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7a35tcsg325-2 167 | 168 | # Set the directory path for the new project 169 | set proj_dir [get_property directory [current_project]] 170 | 171 | # Set project properties 172 | set obj [current_project] 173 | set_property -name "default_lib" -value "xil_defaultlib" -objects $obj 174 | set_property -name "enable_vhdl_2008" -value "1" -objects $obj 175 | set_property -name "ip_cache_permissions" -value "read write" -objects $obj 176 | set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj 177 | set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj 178 | set_property -name "part" -value "xc7a35tcsg325-2" -objects $obj 179 | set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj 180 | set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj 181 | set_property -name "simulator_language" -value "Mixed" -objects $obj 182 | set_property -name "source_mgmt_mode" -value "DisplayOnly" -objects $obj 183 | set_property -name "target_language" -value "VHDL" -objects $obj 184 | set_property -name "webtalk.activehdl_export_sim" -value "97" -objects $obj 185 | set_property -name "webtalk.ies_export_sim" -value "97" -objects $obj 186 | set_property -name "webtalk.modelsim_export_sim" -value "97" -objects $obj 187 | set_property -name "webtalk.questa_export_sim" -value "97" -objects $obj 188 | set_property -name "webtalk.riviera_export_sim" -value "97" -objects $obj 189 | set_property -name "webtalk.vcs_export_sim" -value "97" -objects $obj 190 | set_property -name "webtalk.xcelium_export_sim" -value "4" -objects $obj 191 | set_property -name "webtalk.xsim_export_sim" -value "97" -objects $obj 192 | set_property -name "webtalk.xsim_launch_sim" -value "507" -objects $obj 193 | set_property -name "xpm_libraries" -value "XPM_CDC XPM_MEMORY" -objects $obj 194 | 195 | # Create 'sources_1' fileset (if not found) 196 | if {[string equal [get_filesets -quiet sources_1] ""]} { 197 | create_fileset -srcset sources_1 198 | } 199 | 200 | # Set 'sources_1' fileset object 201 | set obj [get_filesets sources_1] 202 | set files [list \ 203 | [file normalize "${origin_dir}/src/design/tlp_streamer_records.vhd"] \ 204 | [file normalize "${origin_dir}/src/design/tlp_streamer_top.vhd"] \ 205 | [file normalize "${origin_dir}/src/design/tlp_streamer_ft601.vhd"] \ 206 | [file normalize "${origin_dir}/src/design/tlp_streamer_pcie.vhd"] \ 207 | [file normalize "${origin_dir}/src/design/tlp_streamer_rx_dispatch.vhd"] \ 208 | [file normalize "${origin_dir}/src/design/tlp_streamer_loopback.vhd"] \ 209 | [file normalize "${origin_dir}/src/design/tlp_streamer_reset.vhd"] \ 210 | [file normalize "${origin_dir}/src/design/tlp_streamer_tx_arbiter.vhd"] \ 211 | [file normalize "${origin_dir}/src/design/tlp_streamer_pcie_tlp.vhd"] \ 212 | [file normalize "${origin_dir}/src/design/tlp_streamer_pcie_cfg.vhd"] \ 213 | [file normalize "${origin_dir}/ip/fifo_36_36_prim/fifo_36_36_prim.xci"] \ 214 | [file normalize "${origin_dir}/ip/fifo_32_32_bram/fifo_32_32_bram.xci"] \ 215 | [file normalize "${origin_dir}/ip/ila_0/ila_0.xci"] \ 216 | [file normalize "${origin_dir}/ip/fifo_pcie_tlp_r32_w64_4096_bram/fifo_pcie_tlp_r32_w64_4096_bram.xci"] \ 217 | [file normalize "${origin_dir}/ip/pcie_tlp_ila/pcie_tlp_ila.xci"] \ 218 | [file normalize "${origin_dir}/ip/fifo_pcie_tlp_r64_w32_4096_bram/fifo_pcie_tlp_r64_w32_4096_bram.xci"] \ 219 | ] 220 | add_files -norecurse -fileset $obj $files 221 | 222 | # Set 'sources_1' fileset file properties for remote files 223 | set file "$origin_dir/src/design/tlp_streamer_records.vhd" 224 | set file [file normalize $file] 225 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 226 | set_property -name "file_type" -value "VHDL" -objects $file_obj 227 | 228 | set file "$origin_dir/src/design/tlp_streamer_top.vhd" 229 | set file [file normalize $file] 230 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 231 | set_property -name "file_type" -value "VHDL" -objects $file_obj 232 | 233 | set file "$origin_dir/src/design/tlp_streamer_ft601.vhd" 234 | set file [file normalize $file] 235 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 236 | set_property -name "file_type" -value "VHDL" -objects $file_obj 237 | 238 | set file "$origin_dir/src/design/tlp_streamer_pcie.vhd" 239 | set file [file normalize $file] 240 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 241 | set_property -name "file_type" -value "VHDL" -objects $file_obj 242 | 243 | set file "$origin_dir/src/design/tlp_streamer_rx_dispatch.vhd" 244 | set file [file normalize $file] 245 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 246 | set_property -name "file_type" -value "VHDL" -objects $file_obj 247 | 248 | set file "$origin_dir/src/design/tlp_streamer_loopback.vhd" 249 | set file [file normalize $file] 250 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 251 | set_property -name "file_type" -value "VHDL" -objects $file_obj 252 | 253 | set file "$origin_dir/src/design/tlp_streamer_reset.vhd" 254 | set file [file normalize $file] 255 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 256 | set_property -name "file_type" -value "VHDL" -objects $file_obj 257 | 258 | set file "$origin_dir/src/design/tlp_streamer_tx_arbiter.vhd" 259 | set file [file normalize $file] 260 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 261 | set_property -name "file_type" -value "VHDL" -objects $file_obj 262 | 263 | set file "$origin_dir/src/design/tlp_streamer_pcie_tlp.vhd" 264 | set file [file normalize $file] 265 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 266 | set_property -name "file_type" -value "VHDL" -objects $file_obj 267 | 268 | set file "$origin_dir/src/design/tlp_streamer_pcie_cfg.vhd" 269 | set file [file normalize $file] 270 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 271 | set_property -name "file_type" -value "VHDL" -objects $file_obj 272 | 273 | set file "$origin_dir/ip/fifo_36_36_prim/fifo_36_36_prim.xci" 274 | set file [file normalize $file] 275 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 276 | set_property -name "generate_files_for_reference" -value "0" -objects $file_obj 277 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 278 | if { ![get_property "is_locked" $file_obj] } { 279 | set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj 280 | } 281 | 282 | set file "$origin_dir/ip/fifo_32_32_bram/fifo_32_32_bram.xci" 283 | set file [file normalize $file] 284 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 285 | set_property -name "generate_files_for_reference" -value "0" -objects $file_obj 286 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 287 | if { ![get_property "is_locked" $file_obj] } { 288 | set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj 289 | } 290 | 291 | set file "$origin_dir/ip/ila_0/ila_0.xci" 292 | set file [file normalize $file] 293 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 294 | set_property -name "generate_files_for_reference" -value "0" -objects $file_obj 295 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 296 | if { ![get_property "is_locked" $file_obj] } { 297 | set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj 298 | } 299 | 300 | set file "$origin_dir/ip/fifo_pcie_tlp_r32_w64_4096_bram/fifo_pcie_tlp_r32_w64_4096_bram.xci" 301 | set file [file normalize $file] 302 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 303 | set_property -name "generate_files_for_reference" -value "0" -objects $file_obj 304 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 305 | if { ![get_property "is_locked" $file_obj] } { 306 | set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj 307 | } 308 | 309 | set file "$origin_dir/ip/pcie_tlp_ila/pcie_tlp_ila.xci" 310 | set file [file normalize $file] 311 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 312 | set_property -name "generate_files_for_reference" -value "0" -objects $file_obj 313 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 314 | if { ![get_property "is_locked" $file_obj] } { 315 | set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj 316 | } 317 | 318 | set file "$origin_dir/ip/fifo_pcie_tlp_r64_w32_4096_bram/fifo_pcie_tlp_r64_w32_4096_bram.xci" 319 | set file [file normalize $file] 320 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 321 | set_property -name "generate_files_for_reference" -value "0" -objects $file_obj 322 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 323 | if { ![get_property "is_locked" $file_obj] } { 324 | set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj 325 | } 326 | 327 | 328 | # Set 'sources_1' fileset file properties for local files 329 | # None 330 | 331 | # Set 'sources_1' fileset properties 332 | set obj [get_filesets sources_1] 333 | set_property -name "top" -value "tlp_streamer" -objects $obj 334 | set_property -name "top_auto_set" -value "0" -objects $obj 335 | 336 | # Set 'sources_1' fileset object 337 | set obj [get_filesets sources_1] 338 | set files [list \ 339 | [file normalize "${origin_dir}/ip/pcie_7x_0/pcie_7x_0.xci"] \ 340 | ] 341 | add_files -norecurse -fileset $obj $files 342 | 343 | # Set 'sources_1' fileset file properties for remote files 344 | set file "$origin_dir/ip/pcie_7x_0/pcie_7x_0.xci" 345 | set file [file normalize $file] 346 | set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] 347 | set_property -name "generate_files_for_reference" -value "0" -objects $file_obj 348 | set_property -name "registered_with_manager" -value "1" -objects $file_obj 349 | if { ![get_property "is_locked" $file_obj] } { 350 | set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj 351 | } 352 | 353 | 354 | # Set 'sources_1' fileset file properties for local files 355 | # None 356 | 357 | # Create 'constrs_1' fileset (if not found) 358 | if {[string equal [get_filesets -quiet constrs_1] ""]} { 359 | create_fileset -constrset constrs_1 360 | } 361 | 362 | # Set 'constrs_1' fileset object 363 | set obj [get_filesets constrs_1] 364 | 365 | # Add/Import constrs file and set constrs file properties 366 | set file "[file normalize "$origin_dir/src/constrs/screamer_m2.xdc"]" 367 | set file_added [add_files -norecurse -fileset $obj [list $file]] 368 | set file "$origin_dir/src/constrs/screamer_m2.xdc" 369 | set file [file normalize $file] 370 | set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]] 371 | set_property -name "file_type" -value "XDC" -objects $file_obj 372 | 373 | # Set 'constrs_1' fileset properties 374 | set obj [get_filesets constrs_1] 375 | set_property -name "target_constrs_file" -value "[file normalize "$origin_dir/src/constrs/screamer_m2.xdc"]" -objects $obj 376 | set_property -name "target_part" -value "xc7a35tcsg325-2" -objects $obj 377 | set_property -name "target_ucf" -value "[file normalize "$origin_dir/src/constrs/screamer_m2.xdc"]" -objects $obj 378 | 379 | # Create 'sim_1' fileset (if not found) 380 | if {[string equal [get_filesets -quiet sim_1] ""]} { 381 | create_fileset -simset sim_1 382 | } 383 | 384 | # Set 'sim_1' fileset object 385 | set obj [get_filesets sim_1] 386 | set files [list \ 387 | [file normalize "${origin_dir}/src/sim/tlp_streamer_usb_rx_sim.vhd"] \ 388 | [file normalize "${origin_dir}/src/sim/tlp_usb_rx_sim_behav.wcfg"] \ 389 | ] 390 | add_files -norecurse -fileset $obj $files 391 | 392 | # Set 'sim_1' fileset file properties for remote files 393 | set file "$origin_dir/src/sim/tlp_streamer_usb_rx_sim.vhd" 394 | set file [file normalize $file] 395 | set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]] 396 | set_property -name "file_type" -value "VHDL" -objects $file_obj 397 | 398 | 399 | # Set 'sim_1' fileset file properties for local files 400 | # None 401 | 402 | # Set 'sim_1' fileset properties 403 | set obj [get_filesets sim_1] 404 | set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj 405 | set_property -name "top" -value "tlp_usb_rx_sim" -objects $obj 406 | set_property -name "top_auto_set" -value "0" -objects $obj 407 | set_property -name "top_lib" -value "xil_defaultlib" -objects $obj 408 | set_property -name "xsim.simulate.log_all_signals" -value "1" -objects $obj 409 | set_property -name "xsim.simulate.runtime" -value "1500" -objects $obj 410 | 411 | # Set 'utils_1' fileset object 412 | set obj [get_filesets utils_1] 413 | # Empty (no sources present) 414 | 415 | # Set 'utils_1' fileset properties 416 | set obj [get_filesets utils_1] 417 | 418 | # Create 'synth_1' run (if not found) 419 | if {[string equal [get_runs -quiet synth_1] ""]} { 420 | create_run -name synth_1 -part xc7a35tcsg325-2 -flow {Vivado Synthesis 2020} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 421 | } else { 422 | set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] 423 | set_property flow "Vivado Synthesis 2020" [get_runs synth_1] 424 | } 425 | set obj [get_runs synth_1] 426 | set_property set_report_strategy_name 1 $obj 427 | set_property report_strategy {Vivado Synthesis Default Reports} $obj 428 | set_property set_report_strategy_name 0 $obj 429 | # Create 'synth_1_synth_report_utilization_0' report (if not found) 430 | if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { 431 | create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 432 | } 433 | set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] 434 | if { $obj != "" } { 435 | 436 | } 437 | set obj [get_runs synth_1] 438 | set_property -name "needs_refresh" -value "1" -objects $obj 439 | set_property -name "part" -value "xc7a35tcsg325-2" -objects $obj 440 | set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj 441 | set_property -name "steps.synth_design.args.fsm_extraction" -value "one_hot" -objects $obj 442 | set_property -name "steps.synth_design.args.keep_equivalent_registers" -value "1" -objects $obj 443 | 444 | # set the current synth run 445 | current_run -synthesis [get_runs synth_1] 446 | 447 | # Create 'impl_1' run (if not found) 448 | if {[string equal [get_runs -quiet impl_1] ""]} { 449 | create_run -name impl_1 -part xc7a35tcsg325-2 -flow {Vivado Implementation 2020} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 450 | } else { 451 | set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] 452 | set_property flow "Vivado Implementation 2020" [get_runs impl_1] 453 | } 454 | set obj [get_runs impl_1] 455 | set_property set_report_strategy_name 1 $obj 456 | set_property report_strategy {Vivado Implementation Default Reports} $obj 457 | set_property set_report_strategy_name 0 $obj 458 | # Create 'impl_1_init_report_timing_summary_0' report (if not found) 459 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { 460 | create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 461 | } 462 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] 463 | if { $obj != "" } { 464 | set_property -name "is_enabled" -value "0" -objects $obj 465 | set_property -name "options.max_paths" -value "10" -objects $obj 466 | 467 | } 468 | # Create 'impl_1_opt_report_drc_0' report (if not found) 469 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { 470 | create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 471 | } 472 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] 473 | if { $obj != "" } { 474 | 475 | } 476 | # Create 'impl_1_opt_report_timing_summary_0' report (if not found) 477 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { 478 | create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 479 | } 480 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] 481 | if { $obj != "" } { 482 | set_property -name "is_enabled" -value "0" -objects $obj 483 | set_property -name "options.max_paths" -value "10" -objects $obj 484 | 485 | } 486 | # Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) 487 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { 488 | create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 489 | } 490 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] 491 | if { $obj != "" } { 492 | set_property -name "is_enabled" -value "0" -objects $obj 493 | set_property -name "options.max_paths" -value "10" -objects $obj 494 | 495 | } 496 | # Create 'impl_1_place_report_io_0' report (if not found) 497 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { 498 | create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 499 | } 500 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] 501 | if { $obj != "" } { 502 | 503 | } 504 | # Create 'impl_1_place_report_utilization_0' report (if not found) 505 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { 506 | create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 507 | } 508 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] 509 | if { $obj != "" } { 510 | 511 | } 512 | # Create 'impl_1_place_report_control_sets_0' report (if not found) 513 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { 514 | create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 515 | } 516 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] 517 | if { $obj != "" } { 518 | set_property -name "options.verbose" -value "1" -objects $obj 519 | 520 | } 521 | # Create 'impl_1_place_report_incremental_reuse_0' report (if not found) 522 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { 523 | create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 524 | } 525 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] 526 | if { $obj != "" } { 527 | set_property -name "is_enabled" -value "0" -objects $obj 528 | 529 | } 530 | # Create 'impl_1_place_report_incremental_reuse_1' report (if not found) 531 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { 532 | create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 533 | } 534 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] 535 | if { $obj != "" } { 536 | set_property -name "is_enabled" -value "0" -objects $obj 537 | 538 | } 539 | # Create 'impl_1_place_report_timing_summary_0' report (if not found) 540 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { 541 | create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 542 | } 543 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] 544 | if { $obj != "" } { 545 | set_property -name "is_enabled" -value "0" -objects $obj 546 | set_property -name "options.max_paths" -value "10" -objects $obj 547 | 548 | } 549 | # Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) 550 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { 551 | create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 552 | } 553 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] 554 | if { $obj != "" } { 555 | set_property -name "is_enabled" -value "0" -objects $obj 556 | set_property -name "options.max_paths" -value "10" -objects $obj 557 | 558 | } 559 | # Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) 560 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { 561 | create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 562 | } 563 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] 564 | if { $obj != "" } { 565 | set_property -name "is_enabled" -value "0" -objects $obj 566 | set_property -name "options.max_paths" -value "10" -objects $obj 567 | 568 | } 569 | # Create 'impl_1_route_report_drc_0' report (if not found) 570 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { 571 | create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 572 | } 573 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] 574 | if { $obj != "" } { 575 | 576 | } 577 | # Create 'impl_1_route_report_methodology_0' report (if not found) 578 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { 579 | create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 580 | } 581 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] 582 | if { $obj != "" } { 583 | 584 | } 585 | # Create 'impl_1_route_report_power_0' report (if not found) 586 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { 587 | create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 588 | } 589 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] 590 | if { $obj != "" } { 591 | 592 | } 593 | # Create 'impl_1_route_report_route_status_0' report (if not found) 594 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { 595 | create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 596 | } 597 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] 598 | if { $obj != "" } { 599 | 600 | } 601 | # Create 'impl_1_route_report_timing_summary_0' report (if not found) 602 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { 603 | create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 604 | } 605 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] 606 | if { $obj != "" } { 607 | set_property -name "options.max_paths" -value "10" -objects $obj 608 | 609 | } 610 | # Create 'impl_1_route_report_incremental_reuse_0' report (if not found) 611 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { 612 | create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 613 | } 614 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] 615 | if { $obj != "" } { 616 | 617 | } 618 | # Create 'impl_1_route_report_clock_utilization_0' report (if not found) 619 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { 620 | create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 621 | } 622 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] 623 | if { $obj != "" } { 624 | 625 | } 626 | # Create 'impl_1_route_report_bus_skew_0' report (if not found) 627 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { 628 | create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 629 | } 630 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] 631 | if { $obj != "" } { 632 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 633 | 634 | } 635 | # Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) 636 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { 637 | create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 638 | } 639 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] 640 | if { $obj != "" } { 641 | set_property -name "options.max_paths" -value "10" -objects $obj 642 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 643 | 644 | } 645 | # Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) 646 | if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { 647 | create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 648 | } 649 | set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] 650 | if { $obj != "" } { 651 | set_property -name "options.warn_on_violation" -value "1" -objects $obj 652 | 653 | } 654 | set obj [get_runs impl_1] 655 | set_property -name "needs_refresh" -value "1" -objects $obj 656 | set_property -name "part" -value "xc7a35tcsg325-2" -objects $obj 657 | set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj 658 | set_property -name "steps.place_design.args.directive" -value "ExtraTimingOpt" -objects $obj 659 | set_property -name "steps.write_bitstream.args.bin_file" -value "1" -objects $obj 660 | set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj 661 | set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj 662 | 663 | # set the current impl run 664 | current_run -implementation [get_runs impl_1] 665 | 666 | puts "INFO: Project created:${_xil_proj_name_}" 667 | # Create 'drc_1' gadget (if not found) 668 | if {[string equal [get_dashboard_gadgets [ list "drc_1" ] ] ""]} { 669 | create_dashboard_gadget -name {drc_1} -type drc 670 | } 671 | set obj [get_dashboard_gadgets [ list "drc_1" ] ] 672 | set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj 673 | 674 | # Create 'methodology_1' gadget (if not found) 675 | if {[string equal [get_dashboard_gadgets [ list "methodology_1" ] ] ""]} { 676 | create_dashboard_gadget -name {methodology_1} -type methodology 677 | } 678 | set obj [get_dashboard_gadgets [ list "methodology_1" ] ] 679 | set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj 680 | 681 | # Create 'power_1' gadget (if not found) 682 | if {[string equal [get_dashboard_gadgets [ list "power_1" ] ] ""]} { 683 | create_dashboard_gadget -name {power_1} -type power 684 | } 685 | set obj [get_dashboard_gadgets [ list "power_1" ] ] 686 | set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj 687 | 688 | # Create 'timing_1' gadget (if not found) 689 | if {[string equal [get_dashboard_gadgets [ list "timing_1" ] ] ""]} { 690 | create_dashboard_gadget -name {timing_1} -type timing 691 | } 692 | set obj [get_dashboard_gadgets [ list "timing_1" ] ] 693 | set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj 694 | 695 | # Create 'utilization_1' gadget (if not found) 696 | if {[string equal [get_dashboard_gadgets [ list "utilization_1" ] ] ""]} { 697 | create_dashboard_gadget -name {utilization_1} -type utilization 698 | } 699 | set obj [get_dashboard_gadgets [ list "utilization_1" ] ] 700 | set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj 701 | set_property -name "run.step" -value "synth_design" -objects $obj 702 | set_property -name "run.type" -value "synthesis" -objects $obj 703 | 704 | # Create 'utilization_2' gadget (if not found) 705 | if {[string equal [get_dashboard_gadgets [ list "utilization_2" ] ] ""]} { 706 | create_dashboard_gadget -name {utilization_2} -type utilization 707 | } 708 | set obj [get_dashboard_gadgets [ list "utilization_2" ] ] 709 | set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj 710 | 711 | move_dashboard_gadget -name {utilization_1} -row 0 -col 0 712 | move_dashboard_gadget -name {power_1} -row 1 -col 0 713 | move_dashboard_gadget -name {drc_1} -row 2 -col 0 714 | move_dashboard_gadget -name {timing_1} -row 0 -col 1 715 | move_dashboard_gadget -name {utilization_2} -row 1 -col 1 716 | move_dashboard_gadget -name {methodology_1} -row 2 -col 1 717 | --------------------------------------------------------------------------------