├── README.md └── pcileech_pcie_cfg_a7.sv /README.md: -------------------------------------------------------------------------------- 1 | ## WARNING 2 | Lately, someone's been pretending to be me on Telegram, claiming to sell "aceking firmware." Just to clear things up: **I only use Discord for contact,Stay safe and don't get scammed!** 3 | 4 | 5 | I have released a new project, EmuScan, for detecting emulated firmware and have answered some frequently asked questions. 6 | 7 | [emuscan](https://github.com/Manut0/emuscan) 8 | 9 | Thanks to my friend kilmu1337。I will show you how to make your firmware "active" 10 | 11 | # What is an active device? 12 | An "active device" is actually a misnomer used by firmware developers. Instead of saying a device is "active," it's more accurate to say that the device frequently initiates DMA (Direct Memory Access) transfers. After a DMA transfer is completed, an interrupt is used to notify the CPU that the data has been successfully transferred. This mechanism is often referred to as the "doorbell" mechanism, which is a very apt analogy—just like a delivery person ringing the doorbell to notify you that your package has arrived, the device "rings the doorbell" to inform the CPU that the data is ready. 13 | 14 | In a normal operation, if a device initiates a DMA transfer, there will be an interrupt to notify the CPU. In PCIe (Peripheral Component Interconnect Express), interrupts are typically implemented in three ways: **Legacy Interrupt**, **MSI (Message Signaled Interrupt)**, and **MSI-X (Message Signaled Interrupt Extended)**. 15 | 16 | - **Legacy Interrupt** is the traditional method used by PCI devices to send interrupts. 17 | - **MSI** and **MSI-X** are more commonly used in PCIe devices. 18 | 19 | Once MSI or MSI-X is enabled in the PCIe device's configuration space (CFG space), the device will use MSI or MSI-X to send interrupts to the CPU. 20 | # How to make your firmware "active" 21 | The way to make your firmware "active" is by using the cfg interrupt interface provided in the Xilinx PCIe IP core to send interrupts to the Root Complex (RC). 22 | The code example is as follows: 23 | ```verilog 24 | assign ctx.cfg_interrupt_di = cfg_int_di; 25 | assign ctx.cfg_pciecap_interrupt_msgnum = cfg_msg_num; 26 | assign ctx.cfg_interrupt_assert = cfg_int_assert; 27 | assign ctx.cfg_interrupt = cfg_int_valid; 28 | assign ctx.cfg_interrupt_stat = cfg_int_stat; 29 | always @ ( posedge clk_pcie ) begin 30 | if ( rst ) begin 31 | cfg_int_valid <= 1'b0; 32 | cfg_msg_num <= 5'b0; 33 | cfg_int_assert <= 1'b0; 34 | cfg_int_di <= 8'b0; 35 | cfg_int_stat <= 1'b0; 36 | end else if (cfg_int_ready && cfg_int_valid) begin 37 | cfg_int_valid <= 1'b0; 38 | end else if (o_int) begin 39 | cfg_int_valid <= 1'b0; 40 | end 41 | end 42 | time int_cnt = 0; 43 | always @ ( posedge clk_pcie ) begin 44 | if (rst) begin 45 | int_cnt <= 0; 46 | end else if (int_cnt == 32'd100000) begin 47 | int_cnt <= 0; 48 | end else if (int_enable) begin 49 | int_cnt <= int_cnt + 1; 50 | end 51 | end 52 | 53 | assign o_int = (int_cnt == 32'd100000); 54 | ``` 55 | This method is widely used, but it has a critical drawback: when the emulated device has an MSI-X capability (MSI-X CAP), this method cannot transmit interrupts. The reason is that the interrupt interface in the Xilinx IP core does not support sending MSI-X type interrupts. Therefore, when the emulated device has an MSI-X CAP, you need to manually construct a TLP (Transaction Layer Packet) to send an interrupt signal to the Root Complex (RC). 56 | According to PCIe documentation, an interrupt is essentially a `MEMWR64` type TLP packet sent to the RC. 57 | The code for manually constructing and sending this packet is as follows: 58 | ```verilog 59 | bit msix_valid; 60 | bit msix_has_data; 61 | bit[127:0] msix_tlp; 62 | assign tlps_static.tdata[127:0] = msix_tlp; 63 | assign tlps_static.tkeepdw = 4'hf; 64 | assign tlps_static.tlast = 1'b1; 65 | assign tlps_static.tuser[0] = 1'b1; 66 | assign tlps_static.tvalid = msix_valid; 67 | assign tlps_static.has_data = msix_has_data; 68 | wire [31:0] HDR_MEMWR64 = 32'b01000000_00000000_00000000_00000001; 69 | wire [31:0] MWR64_DW2 = {`_bs16(pcie_id), 8'b00000000, 8'b00001111}; 70 | wire [31:0] MWR64_DW3 = {i_addr[31:2], 2'b0}; 71 | wire [31:0] MWR64_DW4 = {i_data}; 72 | 73 | always @ ( posedge clk_pcie ) begin 74 | if ( rst ) begin 75 | msix_valid <= 1'b0; 76 | msix_has_data <= 1'b0; 77 | msix_tlp <= 127'b0; 78 | end else if (msix_valid) begin 79 | msix_valid <= 1'b0; 80 | end else if (msix_has_data && tlps_static.tready) begin 81 | msix_valid <= 1'b1; 82 | msix_has_data <= 1'b0; 83 | end else if (o_int) begin 84 | // msix_valid <= 1'b1; 85 | msix_has_data <= 1'b1; 86 | msix_tlp <= {MWR64_DW4, MWR64_DW3, MWR64_DW2,HDR_MEMWR64}; 87 | end 88 | end 89 | time int_cnt = 0; 90 | always @ ( posedge clk_pcie ) begin 91 | if (rst) begin 92 | int_cnt <= 0; 93 | end else if (int_cnt == 32'd100000) begin 94 | int_cnt <= 0; 95 | end else if (int_enable) begin 96 | int_cnt <= int_cnt + 1; 97 | end 98 | end 99 | assign o_int = (int_cnt == 32'd100000); 100 | ``` 101 | 102 | The complete code will be released on pcileech_pcie_cfg_a7.sv. 103 | 104 | 105 | # What is "FULL EMU"? 106 | Many firmwares are incorrectly labeled as "FULL EMU" firmware. In reality, most authors are just using BARs (Base Address Registers) obtained by dumping the device after an Arbor scan. Such firmwares are not truly "FULL EMU" firmwares. In the future, I will release an update with a detection method specifically targeting the most widely used Realtek firmware. This method will help distinguish between genuine "FULL EMU" firmware and "DUMP EMU" firmware. 107 | 108 | # Credit 109 | @AceKingSuited (Discord id ace_king_suited/Channel Link: https://discord.gg/AaRx5CSRru) 110 | @kilmu1337 (Discord id kilmu1337/Channel Link: https://discord.gg/sXeTPJfpaN) 111 | # Sponsor 112 | https://scarlet.technology/ 113 | -------------------------------------------------------------------------------- /pcileech_pcie_cfg_a7.sv: -------------------------------------------------------------------------------- 1 | // 2 | // PCILeech FPGA. 3 | // 4 | // PCIe configuration module - CFG handling for Artix-7. 5 | // 6 | // (c) Ulf Frisk, 2018-2024 7 | // Author: Ulf Frisk, pcileech@frizk.net 8 | // MSIX TLP Author: AceKingSuited ( https://discord.gg/E32e7Yca ) 9 | // Kilmu1337 ( https://discord.gg/sXeTPJfpaN ) 10 | `timescale 1ns / 1ps 11 | `include "pcileech_header.svh" 12 | 13 | module pcileech_pcie_cfg_a7( 14 | input rst, 15 | input clk_sys, 16 | input clk_pcie, 17 | IfPCIeFifoCfg.mp_pcie dfifo, 18 | IfPCIeSignals.mpm ctx, 19 | IfAXIS128.source tlps_static, 20 | input i_valid, 21 | input [31:0] i_addr, 22 | input [31:0] i_data, 23 | // output wire o_int, 24 | input int_enable, 25 | output [15:0] pcie_id, 26 | output wire [31:0] base_address_register 27 | ); 28 | 29 | // ---------------------------------------------------- 30 | // TickCount64 31 | // ---------------------------------------------------- 32 | 33 | time tickcount64 = 0; 34 | always @ ( posedge clk_pcie ) 35 | tickcount64 <= tickcount64 + 1; 36 | 37 | // ---------------------------------------------------------------------------- 38 | // Convert received CFG data from FT601 to PCIe clock domain 39 | // FIFO depth: 512 / 64-bits 40 | // ---------------------------------------------------------------------------- 41 | reg in_rden; 42 | wire [63:0] in_dout; 43 | wire in_empty; 44 | wire in_valid; 45 | 46 | reg [63:0] in_data64; 47 | wire [31:0] in_data32 = in_data64[63:32]; 48 | wire [15:0] in_data16 = in_data64[31:16]; 49 | wire [3:0] in_type = in_data64[15:12]; 50 | 51 | fifo_64_64 i_fifo_pcie_cfg_tx( 52 | .rst ( rst ), 53 | .wr_clk ( clk_sys ), 54 | .rd_clk ( clk_pcie ), 55 | .din ( dfifo.tx_data ), 56 | .wr_en ( dfifo.tx_valid ), 57 | .rd_en ( in_rden ), 58 | .dout ( in_dout ), 59 | .full ( ), 60 | .empty ( in_empty ), 61 | .valid ( in_valid ) 62 | ); 63 | 64 | // ------------------------------------------------------------------------ 65 | // Convert received CFG from PCIe core and transmit onwards to FT601 66 | // FIFO depth: 512 / 64-bits. 67 | // ------------------------------------------------------------------------ 68 | reg out_wren; 69 | reg [31:0] out_data; 70 | wire pcie_cfg_rx_almost_full; 71 | 72 | fifo_32_32_clk2 i_fifo_pcie_cfg_rx( 73 | .rst ( rst ), 74 | .wr_clk ( clk_pcie ), 75 | .rd_clk ( clk_sys ), 76 | .din ( out_data ), 77 | .wr_en ( out_wren ), 78 | .rd_en ( dfifo.rx_rd_en ), 79 | .dout ( dfifo.rx_data ), 80 | .full ( ), 81 | .almost_full ( pcie_cfg_rx_almost_full ), 82 | .empty ( ), 83 | .valid ( dfifo.rx_valid ) 84 | ); 85 | 86 | // ------------------------------------------------------------------------ 87 | // REGISTER FILE: COMMON 88 | // ------------------------------------------------------------------------ 89 | 90 | wire [383:0] ro; 91 | reg [703:0] rw; 92 | 93 | // special non-user accessible registers 94 | reg rwi_cfg_mgmt_rd_en; 95 | reg rwi_cfg_mgmt_wr_en; 96 | reg rwi_cfgrd_valid; 97 | reg [9:0] rwi_cfgrd_addr; 98 | reg [3:0] rwi_cfgrd_byte_en; 99 | reg [31:0] rwi_cfgrd_data; 100 | reg rwi_tlp_static_valid; 101 | reg rwi_tlp_static_2nd; 102 | reg rwi_tlp_static_has_data; 103 | reg [31:0] rwi_count_cfgspace_status_cl; 104 | bit [31:0] base_address_register_reg; 105 | 106 | // ------------------------------------------------------------------------ 107 | // REGISTER FILE: READ-ONLY LAYOUT/SPECIFICATION 108 | // ------------------------------------------------------------------------ 109 | 110 | // MAGIC 111 | assign base_address_register = base_address_register_reg; 112 | assign ro[15:0] = 16'h2301; // +000: MAGIC 113 | // SPECIAL 114 | assign ro[16] = ctx.cfg_mgmt_rd_en; // +002: SPECIAL 115 | assign ro[17] = ctx.cfg_mgmt_wr_en; // 116 | assign ro[31:18] = 0; // 117 | // SIZEOF / BYTECOUNT [little-endian] 118 | assign ro[63:32] = $bits(ro) >> 3; // +004: BYTECOUNT 119 | // PCIe CFG STATUS 120 | assign ro[71:64] = ctx.cfg_bus_number; // +008: 121 | assign ro[76:72] = ctx.cfg_device_number; // 122 | assign ro[79:77] = ctx.cfg_function_number; // 123 | // PCIe PL PHY 124 | assign ro[85:80] = ctx.pl_ltssm_state; // +00A 125 | assign ro[87:86] = ctx.pl_rx_pm_state; // 126 | assign ro[90:88] = ctx.pl_tx_pm_state; // +00B 127 | assign ro[93:91] = ctx.pl_initial_link_width; // 128 | assign ro[95:94] = ctx.pl_lane_reversal_mode; // 129 | assign ro[97:96] = ctx.pl_sel_lnk_width; // +00C 130 | assign ro[98] = ctx.pl_phy_lnk_up; // 131 | assign ro[99] = ctx.pl_link_gen2_cap; // 132 | assign ro[100] = ctx.pl_link_partner_gen2_supported; // 133 | assign ro[101] = ctx.pl_link_upcfg_cap; // 134 | assign ro[102] = ctx.pl_sel_lnk_rate; // 135 | assign ro[103] = ctx.pl_directed_change_done; // +00D: 136 | assign ro[104] = ctx.pl_received_hot_rst; // 137 | assign ro[126:105] = 0; // SLACK 138 | assign ro[127] = ctx.cfg_mgmt_rd_wr_done; // 139 | // PCIe CFG MGMT 140 | assign ro[159:128] = ctx.cfg_mgmt_do; // +010: 141 | // PCIe CFG STATUS 142 | assign ro[175:160] = ctx.cfg_command; // +014: 143 | assign ro[176] = ctx.cfg_aer_rooterr_corr_err_received; // +016: 144 | assign ro[177] = ctx.cfg_aer_rooterr_corr_err_reporting_en; // 145 | assign ro[178] = ctx.cfg_aer_rooterr_fatal_err_received; // 146 | assign ro[179] = ctx.cfg_aer_rooterr_fatal_err_reporting_en; // 147 | assign ro[180] = ctx.cfg_aer_rooterr_non_fatal_err_received; // 148 | assign ro[181] = ctx.cfg_aer_rooterr_non_fatal_err_reporting_en; // 149 | assign ro[182] = ctx.cfg_bridge_serr_en; // 150 | assign ro[183] = ctx.cfg_received_func_lvl_rst; // 151 | assign ro[186:184] = ctx.cfg_pcie_link_state; // +017: 152 | assign ro[187] = ctx.cfg_pmcsr_pme_en; // 153 | assign ro[189:188] = ctx.cfg_pmcsr_powerstate; // 154 | assign ro[190] = ctx.cfg_pmcsr_pme_status; // 155 | assign ro[191] = 0; // SLACK 156 | assign ro[207:192] = ctx.cfg_dcommand; // +018: 157 | assign ro[223:208] = ctx.cfg_dcommand2; // +01A: 158 | assign ro[239:224] = ctx.cfg_dstatus; // +01C: 159 | assign ro[255:240] = ctx.cfg_lcommand; // +01E: 160 | assign ro[271:256] = ctx.cfg_lstatus; // +020: 161 | assign ro[287:272] = ctx.cfg_status; // +022: 162 | assign ro[293:288] = ctx.tx_buf_av; // +024: 163 | assign ro[294] = ctx.tx_cfg_req; // 164 | assign ro[295] = ctx.tx_err_drop; // 165 | assign ro[302:296] = ctx.cfg_vc_tcvc_map; // +025: 166 | assign ro[303] = 0; // SLACK 167 | assign ro[304] = ctx.cfg_root_control_pme_int_en; // +026: 168 | assign ro[305] = ctx.cfg_root_control_syserr_corr_err_en; // 169 | assign ro[306] = ctx.cfg_root_control_syserr_fatal_err_en; // 170 | assign ro[307] = ctx.cfg_root_control_syserr_non_fatal_err_en; // 171 | assign ro[308] = ctx.cfg_slot_control_electromech_il_ctl_pulse;// 172 | assign ro[309] = ctx.cfg_to_turnoff; // 173 | assign ro[319:310] = 0; // SLACK 174 | // PCIe INTERRUPT 175 | assign ro[327:320] = ctx.cfg_interrupt_do; // +028: 176 | assign ro[330:328] = ctx.cfg_interrupt_mmenable; // +029: 177 | assign ro[331] = ctx.cfg_interrupt_msienable; // 178 | assign ro[332] = ctx.cfg_interrupt_msixenable; // 179 | assign ro[333] = ctx.cfg_interrupt_msixfm; // 180 | assign ro[334] = ctx.cfg_interrupt_rdy; // 181 | assign ro[335] = 0; // SLACK 182 | // CFG SPACE READ RESULT 183 | assign ro[345:336] = rwi_cfgrd_addr; // +02A: 184 | assign ro[346] = 0; // SLACK 185 | assign ro[347] = rwi_cfgrd_valid; // 186 | assign ro[351:348] = rwi_cfgrd_byte_en; // 187 | assign ro[383:352] = rwi_cfgrd_data; // +02C: 188 | // 0030 - 189 | 190 | 191 | // ------------------------------------------------------------------------ 192 | // INITIALIZATION/RESET BLOCK _AND_ 193 | // REGISTER FILE: READ-WRITE LAYOUT/SPECIFICATION 194 | // ------------------------------------------------------------------------ 195 | 196 | localparam integer RWPOS_CFG_RD_EN = 16; 197 | localparam integer RWPOS_CFG_WR_EN = 17; 198 | localparam integer RWPOS_CFG_WAIT_COMPLETE = 18; 199 | localparam integer RWPOS_CFG_STATIC_TLP_TX_EN = 19; 200 | localparam integer RWPOS_CFG_CFGSPACE_STATUS_CL_EN = 20; 201 | localparam integer RWPOS_CFG_CFGSPACE_COMMAND_EN = 21; 202 | 203 | task pcileech_pcie_cfg_a7_initialvalues; // task is non automatic 204 | begin 205 | out_wren <= 1'b0; 206 | 207 | rwi_cfg_mgmt_rd_en <= 1'b0; 208 | rwi_cfg_mgmt_wr_en <= 1'b0; 209 | base_address_register_reg <= 32'h00000000; 210 | 211 | // MAGIC 212 | rw[15:0] <= 16'h6745; // +000: 213 | // SPECIAL START TASK BLOCK (write 1 to start action) 214 | rw[16] <= 0; // +002: CFG RD EN 215 | rw[17] <= 0; // CFG WR EN 216 | rw[18] <= 0; // WAIT FOR PCIe CFG SPACE RD/WR COMPLETION BEFORE ACCEPT NEW FIFO READ/WRITES 217 | rw[19] <= 0; // TLP_STATIC TX ENABLE 218 | rw[20] <= 1; // CFGSPACE_STATUS_REGISTER_AUTO_CLEAR [master abort flag] 219 | rw[21] <= 0; // CFGSPACE_COMMAND_REGISTER_AUTO_SET [bus master and other flags (set in rw[143:128] <= 16'h....;)] 220 | rw[31:22] <= 0; // RESERVED FUTURE 221 | // SIZEOF / BYTECOUNT [little-endian] 222 | rw[63:32] <= $bits(rw) >> 3; // +004: bytecount [little endian] 223 | // DSN 224 | rw[127:64] <= 64'h001000203EF540; // +008: cfg_dsn 225 | // PCIe CFG MGMT 226 | rw[159:128] <= 0; // +010: cfg_mgmt_di 227 | rw[169:160] <= 0; // +014: cfg_mgmt_dwaddr 228 | rw[170] <= 0; // cfg_mgmt_wr_readonly 229 | rw[171] <= 0; // cfg_mgmt_wr_rw1c_as_rw 230 | rw[175:172] <= 4'hf; // cfg_mgmt_byte_en 231 | // PCIe PL PHY 232 | rw[176] <= 0; // +016: pl_directed_link_auton 233 | rw[178:177] <= 0; // pl_directed_link_change 234 | rw[179] <= 1; // pl_directed_link_speed 235 | rw[181:180] <= 0; // pl_directed_link_width 236 | rw[182] <= 1; // pl_upstream_prefer_deemph 237 | rw[183] <= 0; // pl_transmit_hot_rst 238 | rw[184] <= 0; // +017: pl_downstream_deemph_source 239 | rw[191:185] <= 0; // SLACK 240 | // PCIe INTERRUPT 241 | rw[199:192] <= 0; // +018: cfg_interrupt_di 242 | rw[204:200] <= 0; // +019: cfg_pciecap_interrupt_msgnum 243 | rw[205] <= 0; // cfg_interrupt_assert 244 | rw[206] <= 0; // cfg_interrupt 245 | rw[207] <= 0; // cfg_interrupt_stat 246 | // PCIe CTRL 247 | rw[209:208] <= 0; // +01A: cfg_pm_force_state 248 | rw[210] <= 0; // cfg_pm_force_state_en 249 | rw[211] <= 0; // cfg_pm_halt_aspm_l0s 250 | rw[212] <= 0; // cfg_pm_halt_aspm_l1 251 | rw[213] <= 0; // cfg_pm_send_pme_to 252 | rw[214] <= 0; // cfg_pm_wake 253 | rw[215] <= 0; // cfg_trn_pending 254 | rw[216] <= 0; // +01B: cfg_turnoff_ok 255 | rw[217] <= 1; // rx_np_ok 256 | rw[218] <= 1; // rx_np_req 257 | rw[219] <= 1; // tx_cfg_gnt 258 | rw[223:220] <= 0; // SLACK 259 | // PCIe STATIC TLP TRANSMIT 260 | rw[224+:8] <= 0; // +01C: TLP_STATIC TLP DWORD VALID [each-2bit: [0] = last, [1] = valid] [TLP DWORD 0-3] 261 | rw[232+:8] <= 0; // +01D: TLP_STATIC TLP DWORD VALID [each-2bit: [0] = last, [1] = valid] [TLP DWORD 4-7] 262 | rw[240+:16] <= 0; // +01E: TLP_STATIC TLP TX SLEEP (ticks) [little-endian] 263 | rw[256+:384] <= 0; // +020: TLP_STATIC TLP [8*32-bit hdr+data] 264 | rw[640+:32] <= 0; // +050: TLP_STATIC TLP RETRANSMIT COUNT 265 | // PCIe STATUS register clear timer 266 | rw[672+:32] <= 62500; // +054: CFGSPACE_STATUS_CLEAR TIMER (ticks) [little-endian] [default = 1ms - 62.5k @ 62.5MHz] 267 | 268 | end 269 | endtask 270 | reg[7:0] cfg_int_di; 271 | reg[4:0] cfg_msg_num; 272 | reg cfg_int_assert; 273 | reg cfg_int_valid; 274 | wire cfg_int_ready = ctx.cfg_interrupt_rdy; 275 | reg cfg_int_stat; 276 | 277 | assign ctx.cfg_mgmt_rd_en = rwi_cfg_mgmt_rd_en & ~ctx.cfg_mgmt_rd_wr_done; 278 | assign ctx.cfg_mgmt_wr_en = rwi_cfg_mgmt_wr_en & ~ctx.cfg_mgmt_rd_wr_done; 279 | 280 | assign ctx.cfg_dsn = rw[127:64]; 281 | assign ctx.cfg_mgmt_di = rw[159:128]; 282 | assign ctx.cfg_mgmt_dwaddr = rw[169:160]; 283 | assign ctx.cfg_mgmt_wr_readonly = rw[170]; 284 | assign ctx.cfg_mgmt_wr_rw1c_as_rw = rw[171]; 285 | assign ctx.cfg_mgmt_byte_en = rw[175:172]; 286 | 287 | assign ctx.pl_directed_link_auton = rw[176]; 288 | assign ctx.pl_directed_link_change = rw[178:177]; 289 | assign ctx.pl_directed_link_speed = rw[179]; 290 | assign ctx.pl_directed_link_width = rw[181:180]; 291 | assign ctx.pl_upstream_prefer_deemph = rw[182]; 292 | assign ctx.pl_transmit_hot_rst = rw[183]; 293 | assign ctx.pl_downstream_deemph_source = rw[184]; 294 | 295 | // assign ctx.cfg_interrupt_di = rw[199:192]; 296 | // assign ctx.cfg_pciecap_interrupt_msgnum = rw[204:200]; 297 | // assign ctx.cfg_interrupt_assert = rw[205]; 298 | // assign ctx.cfg_interrupt = rw[206]; 299 | // assign ctx.cfg_interrupt_stat = rw[207]; 300 | 301 | assign ctx.cfg_interrupt_di = cfg_int_di; 302 | assign ctx.cfg_pciecap_interrupt_msgnum = cfg_msg_num; 303 | assign ctx.cfg_interrupt_assert = cfg_int_assert; 304 | assign ctx.cfg_interrupt = cfg_int_valid; 305 | assign ctx.cfg_interrupt_stat = cfg_int_stat; 306 | 307 | assign ctx.cfg_pm_force_state = rw[209:208]; 308 | assign ctx.cfg_pm_force_state_en = rw[210]; 309 | assign ctx.cfg_pm_halt_aspm_l0s = rw[211]; 310 | assign ctx.cfg_pm_halt_aspm_l1 = rw[212]; 311 | assign ctx.cfg_pm_send_pme_to = rw[213]; 312 | assign ctx.cfg_pm_wake = rw[214]; 313 | assign ctx.cfg_trn_pending = rw[215]; 314 | assign ctx.cfg_turnoff_ok = rw[216]; 315 | assign ctx.rx_np_ok = rw[217]; 316 | assign ctx.rx_np_req = rw[218]; 317 | assign ctx.tx_cfg_gnt = rw[219]; 318 | 319 | // assign tlps_static.tdata[127:0] = rwi_tlp_static_2nd ? { 320 | // rw[(256+32*7+00)+:8], rw[(256+32*7+08)+:8], rw[(256+32*7+16)+:8], rw[(256+32*7+24)+:8], // STATIC TLP DWORD7 321 | // rw[(256+32*6+00)+:8], rw[(256+32*6+08)+:8], rw[(256+32*6+16)+:8], rw[(256+32*6+24)+:8], // STATIC TLP DWORD6 322 | // rw[(256+32*5+00)+:8], rw[(256+32*5+08)+:8], rw[(256+32*5+16)+:8], rw[(256+32*5+24)+:8], // STATIC TLP DWORD5 323 | // rw[(256+32*4+00)+:8], rw[(256+32*4+08)+:8], rw[(256+32*4+16)+:8], rw[(256+32*4+24)+:8] // STATIC TLP DWORD4 324 | // } : { 325 | // rw[(256+32*3+00)+:8], rw[(256+32*3+08)+:8], rw[(256+32*3+16)+:8], rw[(256+32*3+24)+:8], // STATIC TLP DWORD3 326 | // rw[(256+32*2+00)+:8], rw[(256+32*2+08)+:8], rw[(256+32*2+16)+:8], rw[(256+32*2+24)+:8], // STATIC TLP DWORD2 327 | // rw[(256+32*1+00)+:8], rw[(256+32*1+08)+:8], rw[(256+32*1+16)+:8], rw[(256+32*1+24)+:8], // STATIC TLP DWORD1 328 | // rw[(256+32*0+00)+:8], rw[(256+32*0+08)+:8], rw[(256+32*0+16)+:8], rw[(256+32*0+24)+:8] // STATIC TLP DWORD0 329 | // }; 330 | // assign tlps_static.tkeepdw = rwi_tlp_static_2nd ? { rw[224+2*7], rw[224+2*6], rw[224+2*5], rw[224+2*4] } : { rw[224+2*3], rw[224+2*2], rw[224+2*1], rw[224+2*0] }; 331 | // assign tlps_static.tlast = rwi_tlp_static_2nd || rw[224+2*3+1] || rw[224+2*2+1] || rw[224+2*1+1] || rw[224+2*0+1]; 332 | // assign tlps_static.tuser[0] = !rwi_tlp_static_2nd; 333 | // assign tlps_static.tvalid = rwi_tlp_static_valid && tlps_static.tkeepdw[0]; 334 | // assign tlps_static.has_data = rwi_tlp_static_has_data; 335 | bit msix_valid; 336 | bit msix_has_data; 337 | bit[127:0] msix_tlp; 338 | assign tlps_static.tdata[127:0] = msix_tlp; 339 | assign tlps_static.tkeepdw = 4'hf; 340 | assign tlps_static.tlast = 1'b1; 341 | assign tlps_static.tuser[0] = 1'b1; 342 | assign tlps_static.tvalid = msix_valid; 343 | assign tlps_static.has_data = msix_has_data; 344 | 345 | assign pcie_id = ro[79:64]; 346 | 347 | // ------------------------------------------------------------------------ 348 | // STATE MACHINE / LOGIC FOR READ/WRITE AND OTHER HOUSEKEEPING TASKS 349 | // ------------------------------------------------------------------------ 350 | 351 | integer i_write, i_tlpstatic; 352 | wire [15:0] in_cmd_address_byte = in_dout[31:16]; 353 | wire [17:0] in_cmd_address_bit = {in_cmd_address_byte[14:0], 3'b000}; 354 | wire [15:0] in_cmd_value = {in_dout[48+:8], in_dout[56+:8]}; 355 | wire [15:0] in_cmd_mask = {in_dout[32+:8], in_dout[40+:8]}; 356 | wire f_rw = in_cmd_address_byte[15]; 357 | wire [15:0] in_cmd_data_in = (in_cmd_address_bit < (f_rw ? $bits(rw) : $bits(ro))) ? (f_rw ? rw[in_cmd_address_bit+:16] : ro[in_cmd_address_bit+:16]) : 16'h0000; 358 | wire in_cmd_read = in_dout[12] & in_valid; 359 | wire in_cmd_write = in_dout[13] & in_cmd_address_byte[15] & in_valid; 360 | wire pcie_cfg_rw_en = rwi_cfg_mgmt_rd_en | rwi_cfg_mgmt_wr_en | rw[RWPOS_CFG_RD_EN] | rw[RWPOS_CFG_WR_EN]; 361 | // in_rden = request data from incoming fifo. Only do this if there is space 362 | // in the output fifo and every 2nd clock cycle (in case a resulting write 363 | // starts an action that will last longer than a single clock there must be 364 | // time to react and stop reading incoming read/writes until processed). 365 | assign in_rden = tickcount64[1] & ~pcie_cfg_rx_almost_full & ( ~rw[RWPOS_CFG_WAIT_COMPLETE] | ~pcie_cfg_rw_en); 366 | wire [31:0] HDR_MEMWR64 = 32'b01000000_00000000_00000000_00000001; 367 | // localparam [31:0] MWR64_DW2 = {, 8'b00000000, 8'b00001111}; 368 | wire [31:0] MWR64_DW2 = {`_bs16(pcie_id), 8'b00000000, 8'b00001111}; 369 | wire [31:0] MWR64_DW3 = {i_addr[31:2], 2'b0}; 370 | wire [31:0] MWR64_DW4 = {i_data}; 371 | wire o_int; 372 | initial pcileech_pcie_cfg_a7_initialvalues(); 373 | 374 | always @ ( posedge clk_pcie ) 375 | if ( rst ) 376 | pcileech_pcie_cfg_a7_initialvalues(); 377 | else 378 | begin 379 | // READ config 380 | out_wren <= in_cmd_read; 381 | if ( in_cmd_read ) 382 | begin 383 | out_data[31:16] <= in_cmd_address_byte; 384 | out_data[15:0] <= {in_cmd_data_in[7:0], in_cmd_data_in[15:8]}; 385 | end 386 | 387 | // WRITE config 388 | if ( in_cmd_write ) 389 | for ( i_write = 0; i_write < 16; i_write = i_write + 1 ) 390 | begin 391 | if ( in_cmd_mask[i_write] ) 392 | rw[in_cmd_address_bit+i_write] <= in_cmd_value[i_write]; 393 | end 394 | 395 | // STATUS REGISTER CLEAR 396 | if ( (rw[RWPOS_CFG_CFGSPACE_STATUS_CL_EN] | rw[RWPOS_CFG_CFGSPACE_COMMAND_EN]) & ~in_cmd_read & ~in_cmd_write & ~rw[RWPOS_CFG_RD_EN] & ~rw[RWPOS_CFG_WR_EN] & ~rwi_cfg_mgmt_rd_en & ~rwi_cfg_mgmt_wr_en ) 397 | if ( rwi_count_cfgspace_status_cl < rw[672+:32] ) 398 | rwi_count_cfgspace_status_cl <= rwi_count_cfgspace_status_cl + 1; 399 | else begin 400 | rwi_count_cfgspace_status_cl <= 0; 401 | rw[RWPOS_CFG_WR_EN] <= 1'b1; 402 | rw[143:128] <= 16'h0007; // cfg_mgmt_di: command register [update to set individual command register bits] 403 | rw[159:144] <= 16'hff00; // cfg_mgmt_di: status register [do not update] 404 | rw[169:160] <= 1; // cfg_mgmt_dwaddr 405 | rw[170] <= 0; // cfg_mgmt_wr_readonly 406 | rw[171] <= 0; // cfg_mgmt_wr_rw1c_as_rw 407 | rw[172] <= rw[RWPOS_CFG_CFGSPACE_COMMAND_EN]; // cfg_mgmt_byte_en: command register 408 | rw[173] <= rw[RWPOS_CFG_CFGSPACE_COMMAND_EN]; // cfg_mgmt_byte_en: command register 409 | rw[174] <= 0; // cfg_mgmt_byte_en: status register 410 | rw[175] <= rw[RWPOS_CFG_CFGSPACE_STATUS_CL_EN]; // cfg_mgmt_byte_en: status register 411 | end 412 | 413 | if ((base_address_register_reg == 32'h00000000) | (base_address_register_reg == 32'hFFFFC004) |(base_address_register_reg == 32'h00000004) ) 414 | if ( ~in_cmd_read & ~in_cmd_write & ~rw[RWPOS_CFG_RD_EN] & ~rw[RWPOS_CFG_WR_EN] & ~rwi_cfg_mgmt_rd_en & ~rwi_cfg_mgmt_wr_en ) 415 | begin 416 | rw[RWPOS_CFG_RD_EN] <= 1'b1; 417 | rw[169:160] <= 6; // cfg_mgmt_dwaddr 418 | rw[172] <= 0; // cfg_mgmt_byte_en 419 | rw[173] <= 0; // cfg_mgmt_byte_en 420 | rw[174] <= 0; // cfg_mgmt_byte_en 421 | rw[175] <= 0; // cfg_mgmt_byte_en 422 | end 423 | 424 | // CONFIG SPACE READ/WRITE 425 | if ( ctx.cfg_mgmt_rd_wr_done ) 426 | begin 427 | // 428 | // if BAR0 was requested, lets save it. 429 | // 430 | if ((base_address_register_reg == 32'h00000000) | (base_address_register_reg == 32'hFFFFC004) |(base_address_register_reg == 32'h00000004)) 431 | if ((ctx.cfg_mgmt_dwaddr == 8'h06) & rwi_cfg_mgmt_rd_en) 432 | base_address_register_reg <= ctx.cfg_mgmt_do; 433 | 434 | 435 | rwi_cfg_mgmt_rd_en <= 1'b0; 436 | rwi_cfg_mgmt_wr_en <= 1'b0; 437 | rwi_cfgrd_valid <= 1'b1; 438 | rwi_cfgrd_addr <= ctx.cfg_mgmt_dwaddr; 439 | rwi_cfgrd_data <= ctx.cfg_mgmt_do; 440 | rwi_cfgrd_byte_en <= ctx.cfg_mgmt_byte_en; 441 | end 442 | else if ( rw[RWPOS_CFG_RD_EN] ) 443 | begin 444 | rw[RWPOS_CFG_RD_EN] <= 1'b0; 445 | rwi_cfg_mgmt_rd_en <= 1'b1; 446 | rwi_cfgrd_valid <= 1'b0; 447 | end 448 | else if ( rw[RWPOS_CFG_WR_EN] ) 449 | begin 450 | rw[RWPOS_CFG_WR_EN] <= 1'b0; 451 | rwi_cfg_mgmt_wr_en <= 1'b1; 452 | rwi_cfgrd_valid <= 1'b0; 453 | end 454 | 455 | // STATIC_TLP TRANSMIT 456 | // if ( (rwi_tlp_static_valid && rwi_tlp_static_2nd) || ~rw[RWPOS_CFG_STATIC_TLP_TX_EN] ) begin // STATE (3) 457 | // rwi_tlp_static_valid <= 1'b0; 458 | // rwi_tlp_static_has_data <= 1'b0; 459 | // end 460 | // else if ( rwi_tlp_static_has_data && tlps_static.tready && rwi_tlp_static_2nd ) begin // STATE (1) 461 | // rwi_tlp_static_valid <= 1'b1; 462 | // rwi_tlp_static_2nd <= 1'b0; 463 | // end 464 | // else if ( rwi_tlp_static_has_data && tlps_static.tready && !rwi_tlp_static_2nd ) begin // STATE (2) 465 | // rwi_tlp_static_valid <= 1'b1; 466 | // rwi_tlp_static_2nd <= 1'b1; 467 | // end 468 | // else if ( ((tickcount64[0+:16] & rw[240+:16]) == rw[240+:16]) & (rw[640+:32] > 0) & rw[224+2*0] ) begin // IDLE STATE (0) 469 | // rwi_tlp_static_has_data <= 1'b1; 470 | // rwi_tlp_static_2nd <= 1'b1; 471 | // rw[640+:32] <= rw[640+:32] - 1; // count - 1 472 | // if ( rw[640+:32] == 32'h00000001 ) 473 | // rw[RWPOS_CFG_STATIC_TLP_TX_EN] <= 1'b0; 474 | // end 475 | 476 | end 477 | //reg o_int_reg = 1'b0; 478 | 479 | always @ ( posedge clk_pcie ) begin 480 | if ( rst ) begin 481 | cfg_int_valid <= 1'b0; 482 | cfg_msg_num <= 5'b0; 483 | cfg_int_assert <= 1'b0; 484 | cfg_int_di <= 8'b0; 485 | cfg_int_stat <= 1'b0; 486 | end else if (cfg_int_ready && cfg_int_valid) begin 487 | cfg_int_valid <= 1'b0; 488 | end else if (o_int) begin 489 | cfg_int_valid <= 1'b0; 490 | end 491 | end 492 | always @ ( posedge clk_pcie ) begin 493 | if ( rst ) begin 494 | msix_valid <= 1'b0; 495 | msix_has_data <= 1'b0; 496 | msix_tlp <= 127'b0; 497 | end else if (msix_valid) begin 498 | msix_valid <= 1'b0; 499 | end else if (msix_has_data && tlps_static.tready) begin 500 | msix_valid <= 1'b1; 501 | msix_has_data <= 1'b0; 502 | end else if (o_int && i_valid) begin 503 | // msix_valid <= 1'b1; 504 | msix_has_data <= 1'b1; 505 | msix_tlp <= {MWR64_DW4, MWR64_DW3, MWR64_DW2,HDR_MEMWR64}; 506 | end 507 | end 508 | time int_cnt = 0; 509 | always @ ( posedge clk_pcie ) begin 510 | if (rst) begin 511 | int_cnt <= 0; 512 | end else if (int_cnt == 32'd100000) begin 513 | int_cnt <= 0; 514 | end else if (int_enable) begin 515 | int_cnt <= int_cnt + 1; 516 | end 517 | end 518 | 519 | assign o_int = (int_cnt == 32'd100000); 520 | endmodule 521 | --------------------------------------------------------------------------------