1// 2// Copyright 2016-2017 Ettus Research LLC 3// Copyright 2017 Ettus Research, a National Instruments Company 4// 5// SPDX-License-Identifier: LGPL-3.0-or-later 6// 7// sfpp_io_core 8// - mdio_master 9// - One Gige phy + MAC 10// - Ten Gige phy + MAC 11// - Aurora phy + MAC 12// 13////////////////////////////////////////////////////////////////////// 14 15module x300_sfpp_io_core #( 16 parameter PROTOCOL = "10GbE", // Must be {10GbE, 1GbE, Aurora} 17 parameter PORTNUM = 8'd0 18)( 19 input areset, 20 input bus_rst, 21 input bus_rst_div2, 22 23 input gt_refclk, 24 input gb_refclk, 25 input misc_clk, 26 input bus_clk, 27 input bus_clk_div2, 28 29 output txp, 30 output txn, 31 input rxp, 32 input rxn, 33 34 input sfpp_rxlos, 35 input sfpp_tx_fault, 36 output sfpp_tx_disable, 37 38 input [63:0] s_axis_tdata, 39 input [3:0] s_axis_tuser, 40 input s_axis_tlast, 41 input s_axis_tvalid, 42 output s_axis_tready, 43 44 output [63:0] m_axis_tdata, 45 output [3:0] m_axis_tuser, 46 output m_axis_tlast, 47 output m_axis_tvalid, 48 input m_axis_tready, 49 50 input [7:0] wb_adr_i, 51 input wb_cyc_i, 52 input [31:0] wb_dat_i, 53 input wb_stb_i, 54 input wb_we_i, 55 output wb_ack_o, 56 output [31:0] wb_dat_o, 57 output wb_int_o, 58 59 output [15:0] phy_status, 60 output link_up, 61 output activity 62); 63 64 wire mdc, mdio_in, mdio_out; 65 66 // Flush logic: If the link is not up, we will flush all packets coming from 67 // the device. This avoids the MAC backpressuring when the PHY is down. 68 // The device will always send discovery packets to the transports during 69 // initialization, and they have no way of knowing if it's safe to travel 70 // down this route. c2mac == "CHDR to MAC" 71 wire [63:0] c2mac_tdata; 72 wire [3:0] c2mac_tuser; 73 wire c2mac_tlast; 74 wire c2mac_tvalid; 75 wire c2mac_tready; 76 77 axis_packet_flush #( 78 .WIDTH(64+3), // tdata + tuser 79 .TIMEOUT_W(1), // Not using timeout 80 .FLUSH_PARTIAL_PKTS(0), 81 .PIPELINE("NONE") 82 ) linkup_flush ( 83 .clk(bus_clk), 84 .reset(bus_rst), 85 .enable(~link_up), // enable flushing when link down 86 .timeout(1'b0), 87 .flushing(/* not required */), 88 .done(/* not required */), 89 // Input from device/crossbar 90 .s_axis_tdata ({s_axis_tuser, s_axis_tdata}), 91 .s_axis_tlast (s_axis_tlast), 92 .s_axis_tvalid (s_axis_tvalid), 93 .s_axis_tready (s_axis_tready), 94 // Output to MAC 95 .m_axis_tdata ({c2mac_tuser, c2mac_tdata}), 96 .m_axis_tlast (c2mac_tlast), 97 .m_axis_tvalid (c2mac_tvalid), 98 .m_axis_tready (c2mac_tready) 99 ); 100 101 102generate 103 if (PROTOCOL == "10GbE") begin 104 //----------------------------------------------------------------- 105 // 10 Gigabit Ethernet 106 //----------------------------------------------------------------- 107 wire [63:0] xgmii_txd; 108 wire [7:0] xgmii_txc; 109 wire [63:0] xgmii_rxd; 110 wire [7:0] xgmii_rxc; 111 wire [7:0] xgmii_status; 112 wire xge_phy_resetdone; 113 114 ten_gige_phy ten_gige_phy_i 115 ( 116 // Clocks and Reset 117 .areset(areset), // Asynchronous reset for entire core. 118 .refclk(gt_refclk), // Transciever reference clock: 156.25MHz 119 .clk156(gb_refclk), // Globally buffered core clock: 156.25MHz 120 .dclk(misc_clk), // Management/DRP clock: 78.125MHz 121 .sim_speedup_control(1'b0), 122 // GMII Interface (client MAC <=> PCS) 123 .xgmii_txd(xgmii_txd), // Transmit data from client MAC. 124 .xgmii_txc(xgmii_txc), // Transmit control signal from client MAC. 125 .xgmii_rxd(xgmii_rxd), // Received Data to client MAC. 126 .xgmii_rxc(xgmii_rxc), // Received control signal to client MAC. 127 // Tranceiver Interface 128 .txp(txp), // Differential +ve of serial transmission from PMA to PMD. 129 .txn(txn), // Differential -ve of serial transmission from PMA to PMD. 130 .rxp(rxp), // Differential +ve for serial reception from PMD to PMA. 131 .rxn(rxn), // Differential -ve for serial reception from PMD to PMA. 132 // Management: MDIO Interface 133 .mdc(mdc), // Management Data Clock 134 .mdio_in(mdio_in), // Management Data In 135 .mdio_out(mdio_out), // Management Data Out 136 .mdio_tri(), // Management Data Tristate 137 .prtad(5'd4), // MDIO address is 4 138 // General IO's 139 .core_status(xgmii_status), // Core status 140 .resetdone(xge_phy_resetdone), 141 .signal_detect(~sfpp_rxlos), // Input from PMD to indicate presence of optical input. (Undocumented, but it seems Xilinx expect this to be inverted.) 142 .tx_fault(sfpp_tx_fault), 143 .tx_disable(sfpp_tx_disable) 144 ); 145 146 xge_mac_wrapper #( 147 .PORTNUM(PORTNUM), 148 .WISHBONE(1) 149 ) xge_mac_wrapper_i ( 150 // XGMII 151 .xgmii_clk(gb_refclk), 152 .xgmii_txd(xgmii_txd), 153 .xgmii_txc(xgmii_txc), 154 .xgmii_rxd(xgmii_rxd), 155 .xgmii_rxc(xgmii_rxc), 156 // MDIO 157 .mdc(mdc), 158 .mdio_in(mdio_in), 159 .mdio_out(mdio_out), 160 // Wishbone I/F 161 .wb_clk_i(bus_clk_div2), 162 .wb_rst_i(bus_rst_div2), 163 .wb_adr_i(wb_adr_i), 164 .wb_cyc_i(wb_cyc_i), 165 .wb_dat_i(wb_dat_i), 166 .wb_stb_i(wb_stb_i), 167 .wb_we_i(wb_we_i), 168 .wb_ack_o(wb_ack_o), 169 .wb_dat_o(wb_dat_o), 170 .wb_int_o(wb_int_o), 171 // Client FIFO Interfaces 172 .sys_clk(bus_clk), 173 .sys_rst(bus_rst), 174 .rx_tdata(m_axis_tdata), 175 .rx_tuser(m_axis_tuser), 176 .rx_tlast(m_axis_tlast), 177 .rx_tvalid(m_axis_tvalid), 178 .rx_tready(m_axis_tready), 179 .tx_tdata(c2mac_tdata), 180 .tx_tuser(c2mac_tuser), // Bit[3] (error) is ignored for now. 181 .tx_tlast(c2mac_tlast), 182 .tx_tvalid(c2mac_tvalid), 183 .tx_tready(c2mac_tready), 184 // Other 185 .phy_ready(xge_phy_resetdone) 186 ); 187 188 assign phy_status = {8'h00, xgmii_status}; 189 190 // Use the PCS Block Lock signal to drive the link_up LED on the FP. 191 // For further details, see Xilinx' PG068, Table 2-11 (core_status[0] signal). 192 synchronizer #(.INITIAL_VAL(1'b0)) link_up_sync ( 193 .clk(bus_clk), .rst(1'b0 /* no reset */), .in(xgmii_status[0]), .out(link_up)); 194 195 196 end else if (PROTOCOL == "1GbE") begin 197 198 //----------------------------------------------------------------- 199 // 1 Gigabit Ethernet 200 //----------------------------------------------------------------- 201 wire [7:0] gmii_txd, gmii_rxd; 202 wire gmii_tx_en, gmii_tx_er, gmii_rx_dv, gmii_rx_er; 203 wire gmii_clk; 204 205 assign sfpp_tx_disable = 1'b0; // Always on. 206 207 one_gige_phy one_gige_phy_i 208 ( 209 .reset(areset), // Asynchronous reset for entire core. 210 .independent_clock(bus_clk), 211 // Tranceiver Interface 212 .gtrefclk(gt_refclk), // Reference clock for MGT: 125MHz, very high quality. 213 .gtrefclk_bufg(gb_refclk), // Reference clock routed through a BUFG 214 .txp(txp), // Differential +ve of serial transmission from PMA to PMD. 215 .txn(txn), // Differential -ve of serial transmission from PMA to PMD. 216 .rxp(rxp), // Differential +ve for serial reception from PMD to PMA. 217 .rxn(rxn), // Differential -ve for serial reception from PMD to PMA. 218 // GMII Interface (client MAC <=> PCS) 219 .gmii_clk(gmii_clk), // Clock to client MAC. 220 .gmii_txd(gmii_txd), // Transmit data from client MAC. 221 .gmii_tx_en(gmii_tx_en), // Transmit control signal from client MAC. 222 .gmii_tx_er(gmii_tx_er), // Transmit control signal from client MAC. 223 .gmii_rxd(gmii_rxd), // Received Data to client MAC. 224 .gmii_rx_dv(gmii_rx_dv), // Received control signal to client MAC. 225 .gmii_rx_er(gmii_rx_er), // Received control signal to client MAC. 226 // Management: MDIO Interface 227 .mdc(mdc), // Management Data Clock 228 .mdio_i(mdio_in), // Management Data In 229 .mdio_o(mdio_out), // Management Data Out 230 .mdio_t(), // Management Data Tristate 231 .configuration_vector(5'd0), // Alternative to MDIO interface. 232 .configuration_valid(1'b1), // Validation signal for Config vector (MUST be 1 for proper functionality...undocumented) 233 // General IO's 234 .status_vector(phy_status), // Core status. 235 .signal_detect(1'b1 /*Optical module not supported*/) // Input from PMD to indicate presence of optical input. 236 ); 237 238 simple_gemac_wrapper #(.RX_FLOW_CTRL(0), .PORTNUM(PORTNUM)) simple_gemac_wrapper_i 239 ( 240 .clk125(gmii_clk), 241 .reset(areset), 242 243 .GMII_GTX_CLK(), 244 .GMII_TX_EN(gmii_tx_en), 245 .GMII_TX_ER(gmii_tx_er), 246 .GMII_TXD(gmii_txd), 247 .GMII_RX_CLK(gmii_clk), 248 .GMII_RX_DV(gmii_rx_dv), 249 .GMII_RX_ER(gmii_rx_er), 250 .GMII_RXD(gmii_rxd), 251 252 .sys_clk(bus_clk), 253 .rx_tdata(m_axis_tdata), 254 .rx_tuser(m_axis_tuser), 255 .rx_tlast(m_axis_tlast), 256 .rx_tvalid(m_axis_tvalid), 257 .rx_tready(m_axis_tready), 258 .tx_tdata(c2mac_tdata), 259 .tx_tuser(c2mac_tuser), 260 .tx_tlast(c2mac_tlast), 261 .tx_tvalid(c2mac_tvalid), 262 .tx_tready(c2mac_tready), 263 // MDIO 264 .mdc(mdc), 265 .mdio_in(mdio_in), 266 .mdio_out(mdio_out), 267 .mdio_tri(), 268 // Wishbone I/F 269 .wb_clk_i(bus_clk_div2), 270 .wb_rst_i(bus_rst_div2), 271 .wb_adr_i(wb_adr_i), 272 .wb_cyc_i(wb_cyc_i), 273 .wb_dat_i(wb_dat_o), 274 .wb_stb_i(wb_stb_i), 275 .wb_we_i(wb_we_i), 276 .wb_ack_o(wb_ack_o), 277 .wb_dat_o(wb_dat_i), 278 .wb_int_o(wb_int_o), 279 // Debug 280 .debug_tx(), .debug_rx() 281 ); 282 283 // Use the Link Status signal to drive the link_up LED on the FP. 284 // For further details, see Xilinx' PG047, Table 2-76 (status_vector[0]). 285 synchronizer #(.INITIAL_VAL(1'b0)) link_up_sync ( 286 .clk(bus_clk), .rst(1'b0 /* no reset */), .in(phy_status[0]), .out(link_up)); 287 288 289 end else if (PROTOCOL == "Aurora") begin 290 291 //----------------------------------------------------------------- 292 // Aurora 293 //----------------------------------------------------------------- 294 wire au_user_clk, au_user_rst, phy_areset; 295 wire [63:0] i_tdata, o_tdata; 296 wire i_tvalid, i_tready, o_tvalid; 297 wire channel_up, hard_err, soft_err; 298 wire mac_clear; 299 300 assign sfpp_tx_disable = 1'b0; // Always on. 301 302 aurora_phy_x1 aurora_phy_i ( 303 // Resets 304 .areset(areset | phy_areset), 305 // Clocks 306 .refclk(gt_refclk), 307 .init_clk(misc_clk), 308 .user_clk(au_user_clk), 309 .user_rst(au_user_rst), 310 // GTX Serial I/O 311 .tx_p(txp), 312 .tx_n(txn), 313 .rx_p(rxp), 314 .rx_n(rxn), 315 // AXI4-Stream TX Interface 316 .s_axis_tdata(i_tdata), 317 .s_axis_tvalid(i_tvalid), 318 .s_axis_tready(i_tready), 319 // AXI4-Stream RX Interface 320 .m_axis_tdata(o_tdata), 321 .m_axis_tvalid(o_tvalid), 322 // AXI4-Lite Config Interface: TODO: Hook up to WB->AXI4Lite converter 323 .s_axi_awaddr(32'h0), 324 .s_axi_araddr(32'h0), 325 .s_axi_awvalid(1'b0), 326 .s_axi_awready(), 327 .s_axi_wdata(32'h0), 328 .s_axi_wvalid(1'b0), 329 .s_axi_wstrb(1'b0), 330 .s_axi_wready(), 331 .s_axi_bvalid(), 332 .s_axi_bresp(), 333 .s_axi_bready(1'b1), 334 .s_axi_arready(), 335 .s_axi_arvalid(1'b0), 336 .s_axi_rdata(), 337 .s_axi_rvalid(), 338 .s_axi_rresp(), 339 .s_axi_rready(1'b1), 340 // Status and Error Reporting Interface 341 .channel_up(channel_up), 342 .hard_err(hard_err), 343 .soft_err(soft_err) 344 ); 345 346 assign phy_status = {14'd0, hard_err, channel_up}; 347 348 wire bist_gen_en, bist_checker_en, bist_loopback_en; 349 wire bist_checker_locked; 350 wire [5:0] bist_gen_rate; 351 wire [47:0] bist_checker_samps, bist_checker_errors; 352 wire [31:0] overruns, checksum_errors; 353 354 aurora_axis_mac #( 355 .PHY_ENDIANNESS ("LITTLE"), 356 .PACKET_MODE (1), 357 .MAX_PACKET_SIZE(1024), 358 .BIST_ENABLED (1) 359 ) aurora_mac_i ( 360 // Clocks and resets 361 .phy_clk(au_user_clk), .phy_rst(au_user_rst), 362 .sys_clk(bus_clk), .sys_rst(bus_rst), 363 .clear(mac_clear), 364 // PHY Interface (Synchronous to phy_clk) 365 .phy_s_axis_tdata(o_tdata), 366 .phy_s_axis_tvalid(o_tvalid), 367 .phy_m_axis_tdata(i_tdata), 368 .phy_m_axis_tvalid(i_tvalid), 369 .phy_m_axis_tready(i_tready), 370 // User Interface (Synchronous to sys_clk) 371 .s_axis_tdata(c2mac_tdata), 372 .s_axis_tlast(c2mac_tlast), 373 .s_axis_tvalid(c2mac_tvalid), 374 .s_axis_tready(c2mac_tready), 375 .m_axis_tdata(m_axis_tdata), 376 .m_axis_tlast(m_axis_tlast), 377 .m_axis_tvalid(m_axis_tvalid), 378 .m_axis_tready(m_axis_tready), 379 // PHY Status Inputs (Synchronous to phy_clk) 380 .channel_up(channel_up), 381 .hard_err(hard_err), 382 .soft_err(soft_err), 383 // Status and Error Outputs (Synchronous to sys_clk) 384 .overruns(overruns), 385 .soft_errors(), 386 .checksum_errors(checksum_errors), 387 .critical_err(mac_crit_err), 388 // BIST Interface (Synchronous to sys_clk) 389 .bist_gen_en(bist_gen_en), 390 .bist_gen_rate(bist_gen_rate), 391 .bist_checker_en(bist_checker_en), 392 .bist_loopback_en(bist_loopback_en), 393 .bist_checker_locked(bist_checker_locked), 394 .bist_checker_samps(bist_checker_samps), 395 .bist_checker_errors(bist_checker_errors) 396 ); 397 398 reg mac_crit_err_latch; 399 always @(posedge bus_clk) begin 400 if (bus_rst | mac_clear) begin 401 mac_crit_err_latch <= 1'b0; 402 end else begin 403 if (mac_crit_err_bclk) 404 mac_crit_err_latch <= 1'b1; 405 end 406 end 407 408 assign m_axis_tuser = 4'd0; 409 410 wire set_stb; 411 wire [3:0] set_addr, rb_addr; 412 wire [31:0] set_data; 413 reg [31:0] rb_data; 414 415 settings_bus #(.AWIDTH(8), .DWIDTH(32), .SWIDTH(4)) settings_bus_i ( 416 .wb_clk(bus_clk), .wb_rst(bus_rst), 417 .wb_adr_i(wb_adr_i), .wb_dat_i(wb_dat_i), 418 .wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_ack_o(wb_ack_o), 419 .strobe(set_stb), .addr(set_addr), .data(set_data) 420 ); 421 422 settings_readback #(.AWIDTH(8),.DWIDTH(32), .RB_ADDRW(4)) settings_readback_i ( 423 .wb_clk(bus_clk), .wb_rst(bus_rst), 424 .wb_adr_i(wb_adr_i), .wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_dat_o(wb_dat_o), 425 .rb_data(rb_data), .rb_addr(rb_addr), .rb_rd_stb() 426 ); 427 428 setting_reg #(.my_addr(4'd0), .awidth(4), .width(11), .at_reset(11'h000)) set_core_control_i ( 429 .clk(bus_clk), .rst(bus_rst), 430 .strobe(set_stb), .addr(set_addr), .in(set_data), 431 .out({mac_clear, phy_areset, bist_gen_rate, bist_loopback_en, bist_gen_en, bist_checker_en}), .changed() 432 ); 433 434 wire channel_up_bclk, hard_err_bclk, soft_err_bclk, mac_crit_err_bclk; 435 synchronizer #(.INITIAL_VAL(1'b0)) channel_up_sync ( 436 .clk(bus_clk), .rst(1'b0 /* no reset */), .in(channel_up), .out(channel_up_bclk)); 437 synchronizer #(.INITIAL_VAL(1'b0)) hard_err_sync ( 438 .clk(bus_clk), .rst(1'b0 /* no reset */), .in(hard_err), .out(hard_err_bclk)); 439 synchronizer #(.INITIAL_VAL(1'b0)) soft_err_sync ( 440 .clk(bus_clk), .rst(1'b0 /* no reset */), .in(soft_err), .out(soft_err_bclk)); 441 synchronizer #(.INITIAL_VAL(1'b0)) mac_crit_err_sync ( 442 .clk(bus_clk), .rst(1'b0 /* no reset */), .in(mac_crit_err), .out(mac_crit_err_bclk)); 443 444 reg [19:0] bist_lock_latency; 445 always @(posedge bus_clk) begin 446 if (!bist_checker_en && !bist_checker_locked) 447 bist_lock_latency <= 20'd0; 448 else if (bist_checker_en && !bist_checker_locked) 449 bist_lock_latency <= bist_lock_latency + 20'd1; 450 end 451 452 reg mac_crit_err_latch; 453 always @(posedge bus_clk) begin 454 if (bus_rst | mac_clear) begin 455 mac_crit_err_latch <= 1'b0; 456 end else begin 457 if (mac_crit_err_bclk) 458 mac_crit_err_latch <= 1'b1; 459 end 460 end 461 462 wire [31:0] core_status = { 463 6'h0, //[31:26] 464 mac_crit_err_latch, //[25] 465 1, //[24] mmcm_locked_bclk 466 1, //[23] gt_pll_locked_bclk 467 0, //[22] qpll_refclklost_bclk 468 1, //[21] qpll_lock_bclk 469 0, //[20] qpll_reset_bclk 470 bist_lock_latency[19:4], //[19:4] 471 bist_checker_locked, //[3] 472 soft_err_bclk, //[2] 473 hard_err_bclk, //[1] 474 channel_up_bclk //[0] 475 }; 476 477 assign link_up = channel_up_bclk; 478 479 always @(*) 480 case (rb_addr) 481 4'd0: rb_data = core_status; 482 4'd1: rb_data = overruns; 483 4'd2: rb_data = checksum_errors; 484 4'd3: rb_data = bist_checker_samps[47:16]; //Scale num sample by 2^16 485 4'd4: rb_data = bist_checker_errors[31:0]; //Dont scale errors 486 default: rb_data = 32'h0; 487 endcase // case (rb_addr) 488 489 end else begin 490 491 //Invalid protocol 492 493 end 494endgenerate 495 496 //----------------------------------------------------------------- 497 // Activity detector 498 //----------------------------------------------------------------- 499 500 pulse_stretch act_pulse_str_i ( 501 .clk(bus_clk), 502 .rst(bus_rst | ~link_up), 503 .pulse((s_axis_tvalid & s_axis_tready) | (m_axis_tvalid & m_axis_tready)), 504 .pulse_stretched(activity) 505 ); 506 507endmodule 508 509