[prim_clock_mux2] Adds a clock mux2 and updates the clk inv primitive

The clock inverter primitive now has a parameter to optionally disable
the scanmode bypass feature. The scanmode bypass is now realized with a
technology dependent clock mux primitive.

Note: this commit also updates the portlist of the clock inverter
instance in spi device.
diff --git a/hw/ip/prim/abstract/prim_clock_mux2.sv b/hw/ip/prim/abstract/prim_clock_mux2.sv
new file mode 100644
index 0000000..6f266b6
--- /dev/null
+++ b/hw/ip/prim/abstract/prim_clock_mux2.sv
@@ -0,0 +1,41 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// TODO: This module is a hard-coded stopgap to select an implementation of an
+// "abstract module". This module is to be replaced by generated code.
+
+`ifndef PRIM_DEFAULT_IMPL
+  `define PRIM_DEFAULT_IMPL prim_pkg::ImplGeneric
+`endif
+
+module prim_clock_mux2 #(
+  parameter prim_pkg::impl_e Impl = `PRIM_DEFAULT_IMPL
+) (
+  input        clk0_i,
+  input        clk1_i,
+  input        sel_i,
+  output logic clk_o
+);
+
+  import prim_pkg::*;
+
+  if (Impl == ImplGeneric) begin : gen_generic
+    prim_generic_clock_mux2 u_impl_generic (
+      .clk0_i,
+      .clk1_i,
+      .sel_i,
+      .clk_o
+    );
+  end else if (Impl == ImplXilinx) begin : gen_xilinx
+    prim_xilinx_clock_mux2 u_impl_xilinx (
+      .clk0_i,
+      .clk1_i,
+      .sel_i,
+      .clk_o
+    );
+  end else begin : gen_failure
+    // TODO: Find code that works across tools and causes a compile failure
+  end
+
+endmodule : prim_clock_mux2
diff --git a/hw/ip/prim/prim.core b/hw/ip/prim/prim.core
index 47831bc..d4b5b59 100644
--- a/hw/ip/prim/prim.core
+++ b/hw/ip/prim/prim.core
@@ -14,6 +14,7 @@
       - lowrisc:prim:diff_decode # for prim_alert_sender/receiver
       - lowrisc:prim:pad_wrapper
       - lowrisc:prim:prim_pkg
+      - lowrisc:prim:clock_mux2
     files:
       - rtl/prim_clock_inverter.sv
       - rtl/prim_alert_receiver.sv
diff --git a/hw/ip/prim/prim_clock_mux2.core b/hw/ip/prim/prim_clock_mux2.core
new file mode 100644
index 0000000..c681b2b
--- /dev/null
+++ b/hw/ip/prim/prim_clock_mux2.core
@@ -0,0 +1,21 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+name: "lowrisc:prim:clock_mux2"
+description: "two-input clock multiplexer primitive"
+filesets:
+  files_rtl:
+    depend:
+      - lowrisc:prim_generic:clock_mux2
+      - lowrisc:prim_xilinx:clock_mux2
+      - lowrisc:prim:prim_pkg
+    files:
+      - abstract/prim_clock_mux2.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_rtl
diff --git a/hw/ip/prim/rtl/prim_clock_inverter.sv b/hw/ip/prim/rtl/prim_clock_inverter.sv
index e24febb..3113c55 100644
--- a/hw/ip/prim/rtl/prim_clock_inverter.sv
+++ b/hw/ip/prim/rtl/prim_clock_inverter.sv
@@ -5,17 +5,25 @@
 // Clock inverter
 //   Varies on the process
 
-module prim_clock_inverter (
-  input clk_i,
-  output logic clk_n_o,   // Inverted
-
-  input scanmode_i
+module prim_clock_inverter #(
+  parameter bit HasScanMode = 1'b1
+) (
+  input        clk_i,
+  input        scanmode_i,
+  output logic clk_no      // Inverted
 );
 
-  // Model
-  assign clk_n_o = (scanmode_i) ? clk_i : ~clk_i;
-
-  // make sure scanmode_i is never X (including during reset)
-  `ASSERT_KNOWN(scanmodeKnown, scanmode_i, clk_i, 0)
+  if (HasScanMode) begin : gen_scan
+    prim_clock_mux2 i_dft_tck_mux (
+     .clk0_i ( ~clk_i     ),
+     .clk1_i ( clk_i      ), // bypass the inverted clock for testing
+     .sel_i  ( scanmode_i ),
+     .clk_o  ( clk_no     )
+    );
+  end else begin : gen_noscan
+    logic unused_scanmode;
+    assign unused_scanmode = scanmode_i;
+    assign clk_no = ~clk_i;
+  end
 
 endmodule
diff --git a/hw/ip/prim_generic/prim_generic_clock_mux2.core b/hw/ip/prim_generic/prim_generic_clock_mux2.core
new file mode 100644
index 0000000..39cbcde
--- /dev/null
+++ b/hw/ip/prim_generic/prim_generic_clock_mux2.core
@@ -0,0 +1,17 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+name: "lowrisc:prim_generic:clock_mux2"
+description: "two-input clock multiplexer primitive"
+filesets:
+  files_rtl:
+    files:
+      - rtl/prim_generic_clock_mux2.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_rtl
diff --git a/hw/ip/prim_generic/rtl/prim_generic_clock_mux2.sv b/hw/ip/prim_generic/rtl/prim_generic_clock_mux2.sv
new file mode 100644
index 0000000..a0a9128
--- /dev/null
+++ b/hw/ip/prim_generic/rtl/prim_generic_clock_mux2.sv
@@ -0,0 +1,20 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+module prim_generic_clock_mux2 (
+  input        clk0_i,
+  input        clk1_i,
+  input        sel_i,
+  output logic clk_o
+);
+
+  assign clk_o = (sel_i) ? clk1_i : clk0_i;
+
+  // make sure sel is never X (including during reset)
+  // need to use ##1 as this could break with inverted clocks that
+  // start with a rising edge at the beginning of the simulation.
+  `ASSERT(selKnown0, ##1 !$isunknown(sel_i), clk0_i, 0)
+  `ASSERT(selKnown1, ##1 !$isunknown(sel_i), clk1_i, 0)
+
+endmodule : prim_generic_clock_mux2
diff --git a/hw/ip/prim_xilinx/prim_xilinx_clock_mux2.core b/hw/ip/prim_xilinx/prim_xilinx_clock_mux2.core
new file mode 100644
index 0000000..3001e70
--- /dev/null
+++ b/hw/ip/prim_xilinx/prim_xilinx_clock_mux2.core
@@ -0,0 +1,17 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+name: "lowrisc:prim_xilinx:clock_mux2"
+description: "two-input clock multiplexer primitive"
+filesets:
+  files_rtl:
+    files:
+      - rtl/prim_xilinx_clock_mux2.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_rtl
diff --git a/hw/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv b/hw/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv
new file mode 100644
index 0000000..b567b07
--- /dev/null
+++ b/hw/ip/prim_xilinx/rtl/prim_xilinx_clock_mux2.sv
@@ -0,0 +1,28 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+module prim_xilinx_clock_mux2 (
+  input        clk0_i,
+  input        clk1_i,
+  input        sel_i,
+  output logic clk_o
+);
+
+  // for more info, refer to the Xilinx technology primitives userguide, e.g.:
+  // ug953-vivado-7series-libraries.pdf
+  // ug974-vivado-ultrascale-libraries.pdf
+  BUFGMUX bufgmux_i (
+    .S  ( sel_i  ),
+    .I0 ( clk0_i ),
+    .I1 ( clk1_i ),
+    .O  ( clk_o  )
+  );
+
+  // make sure sel is never X (including during reset)
+  // need to use ##1 as this could break with inverted clocks that
+  // start with a rising edge at the beginning of the simulation.
+  `ASSERT(selKnown0, ##1 !$isunknown(sel_i), clk0_i, 0)
+  `ASSERT(selKnown1, ##1 !$isunknown(sel_i), clk1_i, 0)
+
+endmodule : prim_xilinx_clock_mux2
diff --git a/hw/ip/spi_device/rtl/spi_device.sv b/hw/ip/spi_device/rtl/spi_device.sv
index 8b7a64e..4fb24c9 100644
--- a/hw/ip/spi_device/rtl/spi_device.sv
+++ b/hw/ip/spi_device/rtl/spi_device.sv
@@ -303,7 +303,7 @@
   logic sck_n;
   logic rst_spi_n;
 
-  prim_clock_inverter u_clk_spi (.clk_i(cio_sck_i), .clk_n_o(sck_n), .scanmode_i);
+  prim_clock_inverter u_clk_spi (.clk_i(cio_sck_i), .clk_no(sck_n), .scanmode_i);
   assign clk_spi_in  = (cpha ^ cpol) ? sck_n    : cio_sck_i   ;
   assign clk_spi_out = (cpha ^ cpol) ? cio_sck_i    : sck_n   ;