| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // Bidirectional IO buffer for Xilinx FPGAs. Implements inversion and |
| // virtual open drain feature. |
| |
| `include "prim_assert.sv" |
| |
| module prim_xilinx_pad_wrapper |
| import prim_pad_wrapper_pkg::*; |
| #( |
| // These parameters are ignored in this Xilinx variant. |
| parameter pad_type_e PadType = BidirStd, |
| parameter scan_role_e ScanRole = NoScan |
| ) ( |
| // This is only used for scanmode (not used in this Xilinx variant) |
| input clk_scan_i, |
| input scanmode_i, |
| // Power sequencing signals (not used in this Xilinx variant) |
| input pad_pok_t pok_i, |
| // Main Pad signals |
| inout wire inout_io, // bidirectional pad |
| output logic in_o, // input data |
| output logic in_raw_o, // uninverted output data |
| input ie_i, // input enable |
| input out_i, // output data |
| input oe_i, // output enable |
| input pad_attr_t attr_i // additional pad attributes |
| ); |
| |
| // analog pads cannot have a scan role. |
| `ASSERT_INIT(AnalogNoScan_A, PadType != AnalogIn0 || ScanRole == NoScan) |
| |
| // not all signals are used here. |
| logic unused_sigs; |
| assign unused_sigs = ^{attr_i.slew_rate, |
| attr_i.drive_strength, |
| attr_i.od_en, |
| attr_i.schmitt_en, |
| attr_i.keep_en, |
| attr_i.pull_en, |
| attr_i.pull_select, |
| scanmode_i, |
| pok_i}; |
| |
| |
| if (PadType == InputStd) begin : gen_input_only |
| logic unused_sigs; |
| assign unused_sigs = ^{out_i, |
| oe_i, |
| attr_i.virt_od_en}; |
| |
| // input inversion |
| logic in; |
| assign in_raw_o = (ie_i) ? in : 1'bz; |
| assign in_o = attr_i.invert ^ in_raw_o; |
| |
| IBUF u_ibuf ( |
| .I ( inout_io ), |
| .O ( in ) |
| ); |
| end else if (PadType == BidirTol || |
| PadType == DualBidirTol || |
| PadType == BidirOd || |
| PadType == BidirStd) begin : gen_bidir |
| |
| // input inversion |
| logic in; |
| assign in_raw_o = (ie_i) ? in : 1'bz; |
| assign in_o = attr_i.invert ^ in_raw_o; |
| |
| // virtual open drain emulation |
| logic oe_n, out; |
| assign out = out_i ^ attr_i.invert; |
| // oe_n = 0: enable driver |
| // oe_n = 1: disable driver |
| assign oe_n = ~oe_i | (out & attr_i.virt_od_en); |
| |
| IOBUF u_iobuf ( |
| .T ( oe_n ), |
| .I ( out ), |
| .O ( in ), |
| .IO ( inout_io ) |
| ); |
| end else if (PadType == AnalogIn0 || PadType == AnalogIn1) begin : gen_analog |
| |
| logic unused_sigs; |
| assign unused_sigs = ^{out_i, |
| oe_i, |
| attr_i.invert, |
| attr_i.virt_od_en}; |
| // this is currently modeled as a logic feed through. |
| IBUF u_ibuf ( |
| .I ( inout_io ), |
| .O ( in_raw_o ) |
| ); |
| |
| assign in_raw_o = inout_io; |
| |
| end else begin : gen_invalid_config |
| // this should throw link warnings in elaboration |
| assert_static_in_generate_config_not_available |
| assert_static_in_generate_config_not_available(); |
| end |
| |
| endmodule : prim_xilinx_pad_wrapper |