// Copyright (C) 2020-2021  The SymbiFlow Authors.
//
// Use of this source code is governed by a ISC-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/ISC
//
// SPDX-License-Identifier:ISC

module inv (
    output Q,
    input  A
);
  assign Q = A ? 0 : 1;
endmodule

module buff (
    output Q,
    input  A
);
  assign Q = A;
endmodule

module logic_0 (
    output a
);
  assign a = 0;
endmodule

module logic_1 (
    output a
);
  assign a = 1;
endmodule

module gclkbuff (
    input  A,
    output Z
);
  specify
    (A => Z) = 0;
  endspecify

  assign Z = A;
endmodule

module inpad (
    output Q,
    (* iopad_external_pin *)
    input  P
);
  specify
    (P => Q) = 0;
  endspecify
  assign Q = P;
endmodule

module outpad (
    (* iopad_external_pin *)
    output P,
    input  A
);
  specify
    (A => P) = 0;
  endspecify
  assign P = A;
endmodule

module ckpad (
    output Q,
    (* iopad_external_pin *)
    input  P
);
  specify
    (P => Q) = 0;
  endspecify
  assign Q = P;
endmodule

module bipad (
    input  A,
    input  EN,
    output Q,
    (* iopad_external_pin *)
    inout  P
);
  assign Q = P;
  assign P = EN ? A : 1'bz;
endmodule

module dff (
    output reg Q,
    input D,
    (* clkbuf_sink *)
    input CLK
);
  parameter [0:0] INIT = 1'b0;
  initial Q = INIT;
  always @(posedge CLK) Q <= D;
endmodule

module dffc (
    output reg Q,
    input D,
    (* clkbuf_sink *)
    input CLK,
    (* clkbuf_sink *)
    input CLR
);
  parameter [0:0] INIT = 1'b0;
  initial Q = INIT;

  always @(posedge CLK or posedge CLR)
    if (CLR) Q <= 1'b0;
    else Q <= D;
endmodule

module dffp (
    output reg Q,
    input D,
    (* clkbuf_sink *)
    input CLK,
    (* clkbuf_sink *)
    input PRE
);
  parameter [0:0] INIT = 1'b0;
  initial Q = INIT;

  always @(posedge CLK or posedge PRE)
    if (PRE) Q <= 1'b1;
    else Q <= D;
endmodule

module dffpc (
    output reg Q,
    input D,
    (* clkbuf_sink *)
    input CLK,
    (* clkbuf_sink *)
    input CLR,
    (* clkbuf_sink *)
    input PRE
);
  parameter [0:0] INIT = 1'b0;
  initial Q = INIT;

  always @(posedge CLK or posedge CLR or posedge PRE)
    if (CLR) Q <= 1'b0;
    else if (PRE) Q <= 1'b1;
    else Q <= D;
endmodule

module dffe (
    output reg Q,
    input D,
    (* clkbuf_sink *)
    input CLK,
    input EN
);
  parameter [0:0] INIT = 1'b0;
  initial Q = INIT;
  always @(posedge CLK) if (EN) Q <= D;
endmodule

module dffec (
    output reg Q,
    input D,
    (* clkbuf_sink *)
    input CLK,
    input EN,
    (* clkbuf_sink *)
    input CLR
);
  parameter [0:0] INIT = 1'b0;
  initial Q = INIT;

  always @(posedge CLK or posedge CLR)
    if (CLR) Q <= 1'b0;
    else if (EN) Q <= D;
endmodule

(* lib_whitebox *)
module dffepc (
    output reg Q,
    input D,
    (* clkbuf_sink *)
    input CLK,
    input EN,
    (* clkbuf_sink *)
    input CLR,
    (* clkbuf_sink *)
    input PRE
);
  parameter [0:0] INIT = 1'b0;

  specify
    if (EN) (posedge CLK => (Q : D)) = 1701;  // QCK -> QZ
    if (CLR) (CLR => Q) = 967;  // QRT -> QZ
    if (PRE) (PRE => Q) = 1252;  // QST -> QZ
    $setup(D, posedge CLK, 216);  // QCK -> QDS
    $setup(EN, posedge CLK, 590);  // QCK -> QEN
  endspecify

  initial Q = INIT;
  always @(posedge CLK or posedge CLR or posedge PRE)
    if (CLR) Q <= 1'b0;
    else if (PRE) Q <= 1'b1;
    else if (EN) Q <= D;
endmodule

//                  FZ       FS F2 (F1 TO 0)
(* abc9_box, lib_whitebox *)
module AND2I0 (
    output Q,
    input  A,
    B
);
  specify
    (A => Q) = 698;  // FS -> FZ
    (B => Q) = 639;  // F2 -> FZ
  endspecify

  assign Q = A ? B : 0;
endmodule

(* abc9_box, lib_whitebox *)
module mux2x0 (
    output Q,
    input  S,
    A,
    B
);
  specify
    (S => Q) = 698;  // FS -> FZ
    (A => Q) = 639;  // F1 -> FZ
    (B => Q) = 639;  // F2 -> FZ
  endspecify

  assign Q = S ? B : A;
endmodule

(* abc9_box, lib_whitebox *)
module mux2x1 (
    output Q,
    input  S,
    A,
    B
);
  specify
    (S => Q) = 698;  // FS -> FZ
    (A => Q) = 639;  // F1 -> FZ
    (B => Q) = 639;  // F2 -> FZ
  endspecify

  assign Q = S ? B : A;
endmodule

(* abc9_box, lib_whitebox *)
module mux4x0 (
    output Q,
    input  S0,
    S1,
    A,
    B,
    C,
    D
);
  specify
    (S0 => Q) = 1251;  // TAB -> TZ
    (S1 => Q) = 1406;  // TSL -> TZ
    (A => Q) = 1699;  // TA1 -> TZ
    (B => Q) = 1687;  // TA2 -> TZ
    (C => Q) = 1669;  // TB1 -> TZ
    (D => Q) = 1679;  // TB2 -> TZ
  endspecify

  assign Q = S1 ? (S0 ? D : C) : (S0 ? B : A);
endmodule

// S0 BSL TSL
// S1 BAB TAB
// S2 TBS
// A TA1
// B TA2
// C TB1
// D TB2
// E BA1
// F BA2
// G BB1
// H BB2
// Q CZ
(* abc9_box, lib_whitebox *)
module mux8x0 (
    output Q,
    input  S0,
    S1,
    S2,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H
);
  specify
    (S0 => Q) = 1593;  // ('TSL', 'BSL') -> CZ
    (S1 => Q) = 1437;  // ('TAB', 'BAB') -> CZ
    (S2 => Q) = 995;  // TBS -> CZ
    (A => Q) = 1887;  // TA1 -> CZ
    (B => Q) = 1873;  // TA2 -> CZ
    (C => Q) = 1856;  // TB1 -> CZ
    (D => Q) = 1860;  // TB2 -> CZ
    (E => Q) = 1714;  // BA1 -> CZ
    (F => Q) = 1773;  // BA2 -> CZ
    (G => Q) = 1749;  // BB1 -> CZ
    (H => Q) = 1723;  // BB2 -> CZ
  endspecify

  assign Q = S2 ? (S1 ? (S0 ? H : G) : (S0 ? F : E)) : (S1 ? (S0 ? D : C) : (S0 ? B : A));
endmodule

(* abc9_lut=1, lib_whitebox *)
module LUT1 (
    output O,
    input  I0
);
  parameter [1:0] INIT = 0;
  parameter EQN = "(I0)";

  // These timings are for PolarPro 3E; other families will need updating.
  specify
    (I0 => O) = 698;  // FS -> FZ
  endspecify

  assign O = I0 ? INIT[1] : INIT[0];
endmodule

//               TZ        TSL TAB
(* abc9_lut=2, lib_whitebox *)
module LUT2 (
    output O,
    input  I0,
    I1
);
  parameter [3:0] INIT = 4'h0;
  parameter EQN = "(I0)";

  // These timings are for PolarPro 3E; other families will need updating.
  specify
    (I0 => O) = 1251;  // TAB -> TZ
    (I1 => O) = 1406;  // TSL -> TZ
  endspecify

  wire [1:0] s1 = I1 ? INIT[3:2] : INIT[1:0];
  assign O = I0 ? s1[1] : s1[0];
endmodule

(* abc9_lut=2, lib_whitebox *)
module LUT3 (
    output O,
    input  I0,
    I1,
    I2
);
  parameter [7:0] INIT = 8'h0;
  parameter EQN = "(I0)";

  // These timings are for PolarPro 3E; other families will need updating.
  specify
    (I0 => O) = 1251;  // TAB -> TZ
    (I1 => O) = 1406;  // TSL -> TZ
    (I2 => O) = 1699;  // ('TA1', 'TA2', 'TB1', 'TB2') -> TZ
  endspecify

  wire [3:0] s2 = I2 ? INIT[7:4] : INIT[3:0];
  wire [1:0] s1 = I1 ? s2[3:2] : s2[1:0];
  assign O = I0 ? s1[1] : s1[0];
endmodule

(* abc9_lut=4, lib_whitebox *)
module LUT4 (
    output O,
    input  I0,
    I1,
    I2,
    I3
);
  parameter [15:0] INIT = 16'h0;
  parameter EQN = "(I0)";

  // These timings are for PolarPro 3E; other families will need updating.
  specify
    (I0 => O) = 995;  // TBS -> CZ
    (I1 => O) = 1437;  // ('TAB', 'BAB') -> CZ
    (I2 => O) = 1593;  // ('TSL', 'BSL') -> CZ
    (I3 => O) = 1887;  // ('TA1', 'TA2', 'TB1', 'TB2', 'BA1', 'BA2', 'BB1', 'BB2') -> CZ
  endspecify

  wire [7:0] s3 = I3 ? INIT[15:8] : INIT[7:0];
  wire [3:0] s2 = I2 ? s3[7:4] : s3[3:0];
  wire [1:0] s1 = I1 ? s2[3:2] : s2[1:0];
  assign O = I0 ? s1[1] : s1[0];
endmodule

module logic_cell_macro (
    input  BA1,
    input  BA2,
    input  BAB,
    input  BAS1,
    input  BAS2,
    input  BB1,
    input  BB2,
    input  BBS1,
    input  BBS2,
    input  BSL,
    input  F1,
    input  F2,
    input  FS,
    input  QCK,
    input  QCKS,
    input  QDI,
    input  QDS,
    input  QEN,
    input  QRT,
    input  QST,
    input  TA1,
    input  TA2,
    input  TAB,
    input  TAS1,
    input  TAS2,
    input  TB1,
    input  TB2,
    input  TBS,
    input  TBS1,
    input  TBS2,
    input  TSL,
    output CZ,
    output FZ,
    output QZ,
    output TZ
);

  wire TAP1, TAP2, TBP1, TBP2, BAP1, BAP2, BBP1, BBP2, QCKP, TAI, TBI, BAI, BBI, TZI, BZI, CZI, QZI;
  reg QZ_r;

  initial begin
    QZ_r = 1'b0;
  end
  assign QZ   = QZ_r;
  assign TAP1 = TAS1 ? ~TA1 : TA1;
  assign TAP2 = TAS2 ? ~TA2 : TA2;
  assign TBP1 = TBS1 ? ~TB1 : TB1;
  assign TBP2 = TBS2 ? ~TB2 : TB2;
  assign BAP1 = BAS1 ? ~BA1 : BA1;
  assign BAP2 = BAS2 ? ~BA2 : BA2;
  assign BBP1 = BBS1 ? ~BB1 : BB1;
  assign BBP2 = BBS2 ? ~BB2 : BB2;

  assign TAI  = TSL ? TAP2 : TAP1;
  assign TBI  = TSL ? TBP2 : TBP1;
  assign BAI  = BSL ? BAP2 : BAP1;
  assign BBI  = BSL ? BBP2 : BBP1;
  assign TZI  = TAB ? TBI : TAI;
  assign BZI  = BAB ? BBI : BAI;
  assign CZI  = TBS ? BZI : TZI;
  assign QZI  = QDS ? QDI : CZI;
  assign FZ   = FS ? F2 : F1;
  assign TZ   = TZI;
  assign CZ   = CZI;
  assign QCKP = QCKS ? QCK : ~QCK;


  always @(posedge QCKP) if (~QRT && ~QST) if (QEN) QZ_r = QZI;
  always @(QRT or QST)
    if (QRT) QZ_r = 1'b0;
    else if (QST) QZ_r = 1'b1;

endmodule

// Include simulation models of QLAL4S3B eFPGA interface
`include "qlal4s3b_sim.v"
// Include simulation models for QLAL3 hard blocks
`include "qlal3_sim.v"
// Include BRAM and FIFO simulation models
`include "brams_sim.v"
// Include MULT simulation models
`include "mult_sim.v"

