[prim_pad_wrapper] Update pad wrapper

This updates the pad wrapper to better reflect the ASIC pad we are going
to use. Specifically, the following changes are made:

- an input buffer enable signal is added
- a variant parameter is added which allows us to differentiate between
different pad implementations for the same technology node
- a warl_o signal is added. this signal is constant and defines which
attributes are supported by a specific pad wrapper configuration.
- the WarlOnly parameter is added for use together with warl_o
- additional pad attributes such as schmitt trigger enable and slew rate
are added
- the pull-up/pull-down attributes are re-encoded such that no invalid
configuration can be set where both pull-up and pull-down are activated

Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv b/hw/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv
index ecf3354..962d3b5 100644
--- a/hw/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv
+++ b/hw/ip/prim_generic/rtl/prim_generic_pad_wrapper.sv
@@ -8,46 +8,87 @@
 `include "prim_assert.sv"
 
 module prim_generic_pad_wrapper #(
-  parameter int unsigned AttrDw = 6
+  parameter int Variant  =  0, // currently ignored
+  parameter int AttrDw   = 10,
+  parameter bit WarlOnly =  0  // If set to 1, no pad is instantiated and only warl_o is driven
 ) (
   inout wire         inout_io, // bidirectional pad
   output logic       in_o,     // input data
+  input              ie_i,     // input enable
   input              out_i,    // output data
   input              oe_i,     // output enable
-  // additional attributes {drive strength, keeper, pull-up, pull-down, open-drain, invert}
-  input [AttrDw-1:0] attr_i
+  // additional attributes
+  input        [AttrDw-1:0] attr_i,
+  output logic [AttrDw-1:0] warl_o
 );
 
-  // get pad attributes
-  logic kp, pu, pd, od, inv;
-  typedef enum logic {STRONG_DRIVE = 1'b0, WEAK_DRIVE = 1'b1} drv_e;
-  drv_e drv;
-  assign {drv, kp, pu, pd, od, inv} = attr_i[5:0];
+  // Supported attributes:
+  // [x] Bit   0: input/output inversion,
+  // [x] Bit   1: Virtual open drain enable.
+  // [x] Bit   2: Pull enable.
+  // [x] Bit   3: Pull select (0: pull down, 1: pull up).
+  // [x] Bit   4: Keeper enable.
+  // [ ] Bit   5: Schmitt trigger enable.
+  // [ ] Bit   6: Slew rate (0: slow, 1: fast).
+  // [x] Bit 7/8: Drive strength (00: weakest, 11: strongest).
+  // [ ] Bit   9: Reserved.
+  assign warl_o = AttrDw'(10'h19F);
 
-  // input inversion
-  assign in_o     = inv ^ inout_io;
+  if (WarlOnly) begin : gen_warl
+    assign inout_io = 1'bz;
+    assign in_o     = 1'b0;
 
-  // virtual open drain emulation
-  logic oe, out;
-  assign out      = out_i ^ inv;
-  assign oe       = oe_i & ((od & ~out) | ~od);
+    logic [AttrDw-1:0] unused_attr;
+    logic  unused_ie, unused_oe, unused_out, unused_inout;
+    assign unused_ie   = ie_i;
+    assign unused_oe   = oe_i;
+    assign unused_out  = out_i;
+    assign unused_attr = attr_i;
+    assign unused_inout = inout_io;
+  end else begin : gen_pad
+    // get pad attributes
+    logic unused_sm, kp, unused_sr, ps, pe, od, inv;
+    typedef enum logic [1:0] {DRIVE_00  = 2'b00,
+                              DRIVE_01  = 2'b01,
+                              DRIVE_10  = 2'b10,
+                              DRIVE_11  = 2'b11} drv_e;
+    drv_e drv;
+    assign {drv, unused_sr, unused_sm, kp, ps, pe, od, inv} = attr_i[8:0];
 
-// driving strength attributes are not supported by verilator
+    if (AttrDw > 9) begin : gen_unused_attr
+      logic [AttrDw-9-1:0] unused_attr;
+      assign unused_attr = attr_i[AttrDw-1:9];
+    end
+
+    // input inversion
+    logic in;
+    assign in     = inv ^ inout_io;
+
+    // virtual open drain emulation
+    logic oe, out;
+    assign out      = out_i ^ inv;
+    assign oe       = oe_i & ((od & ~out) | ~od);
+
+  // driving strength attributes are not supported by verilator
 `ifdef VERILATOR
-  assign inout_io = (oe) ? out : 1'bz;
+    assign inout_io = (oe)   ? out : 1'bz;
+    // received data driver
+    assign in_o     = (ie_i) ? in  : 1'bz;
 `else
-  // different driver types
-  assign (strong0, strong1) inout_io = (oe && drv == STRONG_DRIVE) ? out : 1'bz;
-  assign (pull0, pull1)     inout_io = (oe && drv == WEAK_DRIVE)   ? out : 1'bz;
-  // pullup / pulldown termination
-  // default to high-Z in case both PU and PD are asserted (safety mechanism).
-  assign (highz0, weak1)    inout_io = pu & ~pd;
-  assign (weak0, highz1)    inout_io = pu | ~pd;
-  // fake trireg emulation
-  assign (weak0, weak1)     inout_io = (kp) ? inout_io : 1'bz;
+    // different driver types
+    assign (strong0, strong1) inout_io = (oe && drv != DRIVE_00) ? out : 1'bz;
+    assign (pull0, pull1)     inout_io = (oe && drv == DRIVE_00) ? out : 1'bz;
+    // pullup / pulldown termination
+    assign (highz0, weak1)    inout_io = pe & ps;  // enabled and select = 1
+    assign (weak0, highz1)    inout_io = pe & ~ps; // enabled and select = 0
+    // fake trireg emulation
+    assign (weak0, weak1)     inout_io = (kp) ? inout_io : 1'bz;
+    // received data driver
+    assign in_o     = (ie_i) ? in  : 1'bz;
 `endif
+  end
 
   // assertions
-  `ASSERT_INIT(AttrDwCheck_A, AttrDw >= 7)
+  `ASSERT_INIT(AttrDwCheck_A, AttrDw >= 9)
 
 endmodule : prim_generic_pad_wrapper
diff --git a/hw/ip/prim_xilinx/rtl/prim_xilinx_pad_wrapper.sv b/hw/ip/prim_xilinx/rtl/prim_xilinx_pad_wrapper.sv
index 57e9bb4..f9649dd 100644
--- a/hw/ip/prim_xilinx/rtl/prim_xilinx_pad_wrapper.sv
+++ b/hw/ip/prim_xilinx/rtl/prim_xilinx_pad_wrapper.sv
@@ -7,37 +7,72 @@
 
 
 module prim_xilinx_pad_wrapper #(
-  parameter int unsigned AttrDw = 2
+  parameter int Variant  =  0, // currently ignored
+  parameter int AttrDw   = 10,
+  parameter bit WarlOnly =  0  // If set to 1, no pad is instantiated and only warl_o is driven
 ) (
   inout wire         inout_io, // bidirectional pad
   output logic       in_o,     // input data
+  input              ie_i,     // input enable
   input              out_i,    // output data
   input              oe_i,     // output enable
   // additional attributes
-  input [AttrDw-1:0] attr_i
+  input        [AttrDw-1:0] attr_i,
+  output logic [AttrDw-1:0] warl_o
 );
 
-  // get pad attributes
-  logic od, inv;
-  assign {od, inv} = attr_i[1:0];
+  // Supported attributes:
+  // [x] Bit   0: input/output inversion,
+  // [x] Bit   1: Virtual open drain enable.
+  // [ ] Bit   2: Pull enable.
+  // [ ] Bit   3: Pull select (0: pull down, 1: pull up).
+  // [ ] Bit   4: Keeper enable.
+  // [ ] Bit   5: Schmitt trigger enable.
+  // [ ] Bit   6: Slew rate (0: slow, 1: fast).
+  // [ ] Bit 7/8: Drive strength (00: weakest, 11: strongest).
+  // [ ] Bit   9: Reserved.
+  assign warl_o = AttrDw'(2'h3);
 
-  // input inversion
-  logic in;
-  assign in_o     = inv ^ in;
+  if (WarlOnly) begin : gen_warl
+    assign inout_io = 1'bz;
+    assign in_o     = 1'b0;
 
-  // virtual open drain emulation
-  logic oe_n, out;
-  assign out      = out_i ^ inv;
-  // oe_n = 0: enable driver
-  // oe_n = 1: disable driver
-  assign oe_n     = ~oe_i | (out & od);
+    logic [AttrDw-1:0] unused_attr;
+    logic  unused_ie, unused_oe, unused_out, unused_inout;
+    assign unused_ie   = ie_i;
+    assign unused_oe   = oe_i;
+    assign unused_out  = out_i;
+    assign unused_attr = attr_i;
+    assign unused_inout = inout_io;
+  end else begin : gen_pad
 
-  // driver
-  IOBUF i_iobuf (
-    .T(oe_n),
-    .I(out),
-    .O(in),
-    .IO(inout_io)
-  );
+    // get pad attributes
+    logic od, inv;
+    assign {od, inv} = attr_i[1:0];
+
+    if (AttrDw > 9) begin : gen_unused_attr
+      logic [AttrDw-9-1:0] unused_attr;
+      assign unused_attr = attr_i[AttrDw-1:9];
+    end
+
+    // input inversion and buffer
+    logic in;
+    assign in_o     = (ie_i) ? inv ^ in : 1'bz;
+
+    // virtual open drain emulation
+    logic oe_n, out;
+    assign out      = out_i ^ inv;
+    // oe_n = 0: enable driver
+    // oe_n = 1: disable driver
+    assign oe_n     = ~oe_i | (out & od);
+
+    // driver
+    IOBUF i_iobuf (
+      .T  ( oe_n     ),
+      .I  ( out      ),
+      .O  ( in       ),
+      .IO ( inout_io )
+    );
+  end
 
 endmodule : prim_xilinx_pad_wrapper