///////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
////////////////////////////////////////////////////////////////

import SiliconNetTypes::*;
import NetworkTypes::IP4Address;

module SiliconNet
#(
    ////////// Connector
    // Interface parameter
    parameter DATA_WIDTH                        = SN_DATA_WIDTH,
    parameter UID_WIDTH                         = SN_UID_WIDTH,
    parameter LENGTH_WIDTH                      = SN_LENGTH_WIDTH,
    parameter FLAG_WIDTH                        = SN_FLAG_WIDTH,
    parameter SEQNUM_WIDTH                      = SN_SEQNUM_WIDTH,
    parameter TYPE_WIDTH                        = SN_TYPE_WIDTH,
    parameter PARAM_WIDTH                       = SN_PARAM_WIDTH,
    parameter NUM_PORTS                         = SN_NUM_PORTS,
    parameter MAX_MSG_LENGTH                    = SN_MAX_MSG_LENGTH,
    // ForwardingTable related
    parameter NUM_TABLES                        = 2,
    parameter NUM_KEYS_HIGH                     = 16,
    parameter NUM_KEYS_LOW                      = 64,
    parameter WIDTH_HIGH                        = $bits(IP4Address),
    parameter WIDTH_LOW                         = SN_DEVID_WIDTH,
    // ForwardingTable config parameters
    parameter CTL_REG_WRITE_KEY_ADDR            = SN_CTL_REG_WRITE_KEY_ADDR,
    parameter CTL_REG_WRITE_MSK_ADDR            = SN_CTL_REG_WRITE_MSK_ADDR,
    parameter CTL_REG_READ_KEY_ADDR             = SN_CTL_REG_READ_KEY_ADDR,
    parameter CTL_REG_READ_MSK_ADDR             = SN_CTL_REG_READ_MSK_ADDR,
    parameter CTL_REG_READ_EP_ADDR              = SN_CTL_REG_READ_EP_ADDR,
    parameter CTL_REG_ADDR                      = SN_CTL_REG_ADDR,
    // Connector counter
    parameter CTL_REG_COUNTER_VALUE_ADDR        = SN_CTL_REG_COUNTER_VALUE_ADDR,

    ////////// SiliconSwitch
    // Core parameter
    parameter NUM_VCS                           = SN_NUM_VCS,
    parameter PHIT_WIDTH                        = SN_PHIT_WIDTH,
    parameter FLIT_WIDTH                        = SN_FLIT_WIDTH,
    // Per-Input Port Parameters
    parameter NUM_FLITS                         = SN_NUM_FLITS,
    parameter FLITS_PER_MESSAGE                 = SN_FLITS_PER_MESSAGE,
    // Per-Output Downstream Parameters
    parameter MAX_FLITS_PER_PORT_DOWNSTREAM     = SN_FLITS_PER_PORT_DOWNSTREAM,
    parameter MAX_CREDIT_WIDTH                  = SN_MAX_CREDIT_WIDTH,
    // Optimization
    parameter DISABLE_UTURN                     = SN_DISABLE_UTURN,
    parameter USE_LUTRAM                        = SN_USE_LUTRAM
)
(
    input                                 clk,
    input                                 rst,

    // Stack/App side
    input                                 sa_clk                    [NUM_PORTS-1:0],
    input                                 sa_rst                    [NUM_PORTS-1:0],

    // Stack/App Side - (RX: SiliconNet -> Stack/App)
    output reg [DATA_WIDTH-1:0]           sa_data_out               [NUM_PORTS-1:0],
    output reg                            sa_valid_out              [NUM_PORTS-1:0],
    output reg                            sa_first_out              [NUM_PORTS-1:0],
    output reg                            sa_last_out               [NUM_PORTS-1:0],
    input                                 sa_ready_in               [NUM_PORTS-1:0],

    // Stack/App Side - (TX: Stack/App -> SiliconNet)
    input      [DATA_WIDTH-1:0]           sa_data_in                [NUM_PORTS-1:0],
    input                                 sa_valid_in               [NUM_PORTS-1:0],
    input                                 sa_first_in               [NUM_PORTS-1:0],
    input                                 sa_last_in                [NUM_PORTS-1:0],
    output reg                            sa_ready_out              [NUM_PORTS-1:0],

    // ForwardingTable in Connector Configuration
    input                                 ctl_read_in,
    input                                 ctl_write_in,
    input      [15:0]                     ctl_addr_in,
    input      [63:0]                     ctl_wrdata_in,
    output reg [63:0]                     ctl_rddata_out,
    output reg                            ctl_rdvalid_out
);

    // Address high field configure
    reg                                   high_cfg_in               [NUM_PORTS-1:0];
    reg     [$clog2(NUM_KEYS_HIGH):0]     high_cfg_index_in         [NUM_PORTS-1:0];
    reg                                   high_cfg_valid_in         [NUM_PORTS-1:0];
    reg     [WIDTH_HIGH-1:0]              high_cfg_key_in           [NUM_PORTS-1:0];
    reg     [WIDTH_HIGH-1:0]              high_cfg_msk_in           [NUM_PORTS-1:0];
    reg     [$clog2(NUM_PORTS)-1:0]       high_cfg_endpoint_in      [NUM_PORTS-1:0];
    //
    reg                                   high_cfg_read_in          [NUM_PORTS-1:0];
    wire                                  high_cfg_read_valid_out   [NUM_PORTS-1:0];
    wire                                  high_cfg_valid_out        [NUM_PORTS-1:0];
    wire    [WIDTH_HIGH-1:0]              high_cfg_key_out          [NUM_PORTS-1:0];
    wire    [WIDTH_HIGH-1:0]              high_cfg_msk_out          [NUM_PORTS-1:0];
    wire    [$clog2(NUM_PORTS)-1:0]       high_cfg_endpoint_out     [NUM_PORTS-1:0];

    // Address low field onfigure
    reg                                   low_cfg_in                [NUM_PORTS-1:0];
    reg     [$clog2(NUM_KEYS_LOW):0]      low_cfg_index_in          [NUM_PORTS-1:0];
    reg                                   low_cfg_valid_in          [NUM_PORTS-1:0];
    reg     [WIDTH_LOW-1:0]               low_cfg_key_in            [NUM_PORTS-1:0];
    reg     [WIDTH_LOW-1:0]               low_cfg_msk_in            [NUM_PORTS-1:0];
    reg     [$clog2(NUM_PORTS)-1:0]       low_cfg_endpoint_in       [NUM_PORTS-1:0];
    //
    reg                                   low_cfg_read_in           [NUM_PORTS-1:0];
    wire                                  low_cfg_read_valid_out    [NUM_PORTS-1:0];
    wire                                  low_cfg_valid_out         [NUM_PORTS-1:0];
    wire    [WIDTH_LOW-1:0]               low_cfg_key_out           [NUM_PORTS-1:0];
    wire    [WIDTH_LOW-1:0]               low_cfg_msk_out           [NUM_PORTS-1:0];
    wire    [$clog2(NUM_PORTS)-1:0]       low_cfg_endpoint_out      [NUM_PORTS-1:0];

    // counter related
    reg                                   counter_read_in           [NUM_PORTS-1:0];
    reg     [2:0]                         counter_index_in          [NUM_PORTS-1:0];
    wire                                  counter_value_valid_out   [NUM_PORTS-1:0];
    wire    [63:0]                        counter_value_out         [NUM_PORTS-1:0];

    // Input ports
    SwitchInterface                      rtr_input_ifc    [NUM_PORTS-1:0];
    logic [NUM_PORTS-1:0]                rtr_input_valid;

    // Input-side Credits
    SwitchCredit                         rtr_credit_out   [NUM_PORTS-1:0];
    logic                                rtr_credack_in   [NUM_PORTS-1:0];

    // Output port
    logic                                rtr_output_rst   [NUM_PORTS-1:0];
    SwitchInterface                      rtr_output_ifc   [NUM_PORTS-1:0];
    logic [NUM_PORTS-1:0]                rtr_output_valid;
    logic                                rtr_output_stall [NUM_PORTS-1:0];

    // Credit returns
    SwitchCredit                         rtr_credit_in    [NUM_PORTS-1:0];
    logic                                rtr_credack_out  [NUM_PORTS-1:0];

    // ShimInterface
    SwitchInterface                      usr_in_ifc       [NUM_PORTS-1:0];
    logic [NUM_PORTS-1:0]                usr_in_wren;
    logic [NUM_PORTS-1:0]                usr_out_full     [NUM_PORTS-1:0];//20180308

    SwitchInterface                      usr_out_ifc      [NUM_PORTS-1:0];
    logic [NUM_PORTS-1:0]                usr_out_wren;
    logic [NUM_PORTS-1:0]                usr_in_full;

    // debug only
    SiliconNetHead                       dbg_head_send    [NUM_PORTS-1:0];
    SiliconData256                       dbg_data_send    [NUM_PORTS-1:0];
    SiliconNetHead                       dbg_head_receive [NUM_PORTS-1:0];
    SiliconData256                       dbg_data_receive [NUM_PORTS-1:0];

    genvar i;

    ////////////////////////////////////////////////////////////////////////
    //SiliconSwitch/////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    SiliconSwitch
    #(
        .NUM_VCS                        (NUM_VCS),
        .PHIT_WIDTH                     (PHIT_WIDTH),
        .FLIT_WIDTH                     (FLIT_WIDTH),
        .NUM_PORTS                      (NUM_PORTS),

        .NUM_FLITS                      (NUM_FLITS),
        .FLITS_PER_MESSAGE              (FLITS_PER_MESSAGE),

        .MAX_FLITS_PER_PORT_DOWNSTREAM  (MAX_FLITS_PER_PORT_DOWNSTREAM),
        .MAX_CREDIT_WIDTH               (MAX_CREDIT_WIDTH),

        .DISABLE_UTURN                  (DISABLE_UTURN),
        .USE_LUTRAM                     (USE_LUTRAM)
    )
    SiliconSwitch
    (
        .clk                            (clk),
        .rst                            (rst),

        .input_ifc_in                   (rtr_input_ifc),
        .input_valid_in                 (rtr_input_valid),
        .credit_out                     (rtr_credit_out),
        .credack_in                     (rtr_credack_in),

        .output_ifc_out                 (rtr_output_ifc),
        .output_valid_out               (rtr_output_valid),
        .output_stall_in                (rtr_output_stall),
        .credit_in                      (rtr_credit_in),
        .credack_out                    (rtr_credack_out)
    );

    ////////////////////////////////////////////////////////////////////////
    //ShimInterface/////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    generate
        for(i=0; i < NUM_PORTS; i=i+1) begin : gen_ShimInterface
            ShimInterface
            #(
                .FLIT_WIDTH                     (FLIT_WIDTH),
                .PHIT_WIDTH                     (PHIT_WIDTH),
                .NUM_VCS                        (NUM_VCS),
                .NUM_PORTS                      (NUM_PORTS),
                .MAX_CREDIT_WIDTH               (MAX_CREDIT_WIDTH),
                .DISABLE_FULL_PIPE              (0)
            )
            ShimInterface
            (
                .clk                            (clk),
                .rst                            (rst),

                .usr_ifc_in                     (usr_in_ifc[i]),
                .usr_wren_in                    (usr_in_wren[i]),
                .usr_full_out                   (usr_out_full[i]),

                .usr_ifc_out                    (usr_out_ifc[i]),
                .usr_wren_out                   (usr_out_wren[i]),
                .usr_full_in                    (usr_in_full[i]),

                .rtr_ifc_out                    (rtr_input_ifc[i]),
                .rtr_valid_out                  (rtr_input_valid[i]),
                .rtr_credit_in                  (rtr_credit_out[i]),
                .rtr_credack_out                (rtr_credack_in[i]),

                .rtr_ifc_in                     (rtr_output_ifc[i]),
                .rtr_valid_in                   (rtr_output_valid[i]),
                .rtr_output_stall_out           (rtr_output_stall[i]),
                .rtr_credit_out                 (rtr_credit_in[i]),
                .rtr_credack_in                 (rtr_credack_out[i])
            );
        end
    endgenerate

    ////////////////////////////////////////////////////////////////////////
    //Connector/////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    generate
        for(i=0; i < NUM_PORTS; i=i+1) begin : gen_Connector
            Connector
            #(
                .DATA_WIDTH                      (DATA_WIDTH),
                .UID_WIDTH                       (UID_WIDTH),
                .LENGTH_WIDTH                    (LENGTH_WIDTH),
                .FLAG_WIDTH                      (FLAG_WIDTH),
                .SEQNUM_WIDTH                    (SEQNUM_WIDTH),
                .TYPE_WIDTH                      (TYPE_WIDTH),
                .PARAM_WIDTH                     (PARAM_WIDTH),
                .NUM_PORTS                       (NUM_PORTS),
                .MAX_MSG_LENGTH                  (MAX_MSG_LENGTH),
                .THIS_ID_PORT                    (i),
                .THIS_ID_VC                      (1),

                .NUM_TABLES                      (NUM_TABLES),
                .NUM_KEYS_HIGH                   (NUM_KEYS_HIGH),
                .NUM_KEYS_LOW                    (NUM_KEYS_LOW),
                .WIDTH_HIGH                      (WIDTH_HIGH),
                .WIDTH_LOW                       (WIDTH_LOW)
            )
            Connector
            (
                .clk                             (clk),
                .rst                             (rst),

                // Stack/App side
                .sa_clk                          (sa_clk[i]),
                .sa_rst                          (sa_rst[i]),

                // Full Switch Side - (RX: ShimInterface -> Connector)
                .fs_ifc_in                       (usr_out_ifc[i]),
                .fs_wren_in                      (usr_out_wren[i]),
                .fs_full_out                     (usr_in_full[i]),

                // Full Switch Side - (TX: Connctor -> ShimInterface)
                .fs_ifc_out                      (usr_in_ifc[i]),
                .fs_wren_out                     (usr_in_wren[i]),
                .fs_full_in                      (usr_out_full[i]),

                // Stack/App Side - (RX: Connector -> Stack/App)
                .sa_data_out                     (sa_data_out[i]),
                .sa_valid_out                    (sa_valid_out[i]),
                .sa_first_out                    (sa_first_out[i]),
                .sa_last_out                     (sa_last_out[i]),
                .sa_ready_in                     (sa_ready_in[i]),

                // Stack/App Side - (TX: Stack/App -> Connector)
                .sa_data_in                      (sa_data_in[i]),
                .sa_valid_in                     (sa_valid_in[i]),
                .sa_first_in                     (sa_first_in[i]),
                .sa_last_in                      (sa_last_in[i]),
                .sa_ready_out                    (sa_ready_out[i]),

                // Configure to FPGA CA

                // Address high field configure
                .high_cfg_in                     (high_cfg_in[i]),
                .high_cfg_index_in               (high_cfg_index_in[i]),
                .high_cfg_valid_in               (high_cfg_valid_in[i]),
                .high_cfg_key_in                 (high_cfg_key_in[i]),
                .high_cfg_msk_in                 (high_cfg_msk_in[i]),
                .high_cfg_endpoint_in            (high_cfg_endpoint_in[i]),
                //
                .high_cfg_read_in                (high_cfg_read_in[i]),
                .high_cfg_read_valid_out         (high_cfg_read_valid_out[i]),
                .high_cfg_valid_out              (high_cfg_valid_out[i]),
                .high_cfg_key_out                (high_cfg_key_out[i]),
                .high_cfg_msk_out                (high_cfg_msk_out[i]),
                .high_cfg_endpoint_out           (high_cfg_endpoint_out[i]),

                // Address low field onfigure
                .low_cfg_in                      (low_cfg_in[i]),
                .low_cfg_index_in                (low_cfg_index_in[i]),
                .low_cfg_valid_in                (low_cfg_valid_in[i]),
                .low_cfg_key_in                  (low_cfg_key_in[i]),
                .low_cfg_msk_in                  (low_cfg_msk_in[i]),
                .low_cfg_endpoint_in             (low_cfg_endpoint_in[i]),
                //
                .low_cfg_read_in                 (low_cfg_read_in[i]),
                .low_cfg_read_valid_out          (low_cfg_read_valid_out[i]),
                .low_cfg_valid_out               (low_cfg_valid_out[i]),
                .low_cfg_key_out                 (low_cfg_key_out[i]),
                .low_cfg_msk_out                 (low_cfg_msk_out[i]),
                .low_cfg_endpoint_out            (low_cfg_endpoint_out[i]),

                .counter_read_in                 (counter_read_in[i]),
                .counter_index_in                (counter_index_in[i]),
                .counter_value_valid_out         (counter_value_valid_out[i]),
                .counter_value_out               (counter_value_out[i])
            );
        end
    endgenerate

    ////////////////////////////////////////////////////////////////////////
    //Controller////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////
    SiliconNetController
    #(

        .NUM_PORTS                         (NUM_PORTS),

        .NUM_TABLES                        (NUM_TABLES),
        .NUM_KEYS_HIGH                     (NUM_KEYS_HIGH),
        .NUM_KEYS_LOW                      (NUM_KEYS_LOW),
        .WIDTH_HIGH                        (WIDTH_HIGH),
        .WIDTH_LOW                         (WIDTH_LOW),

        .CTL_REG_WRITE_KEY_ADDR            (CTL_REG_WRITE_KEY_ADDR),
        .CTL_REG_WRITE_MSK_ADDR            (CTL_REG_WRITE_MSK_ADDR),
        .CTL_REG_READ_KEY_ADDR             (CTL_REG_READ_KEY_ADDR),
        .CTL_REG_READ_MSK_ADDR             (CTL_REG_READ_MSK_ADDR),
        .CTL_REG_ADDR                      (CTL_REG_ADDR),

        .CTL_REG_COUNTER_VALUE_ADDR        (CTL_REG_COUNTER_VALUE_ADDR)
    )
    SiliconNetController
    (
        .clk                         (clk),
        .rst                         (rst),

        .ctl_read_in                 (ctl_read_in),
        .ctl_write_in                (ctl_write_in),
        .ctl_addr_in                 (ctl_addr_in),
        .ctl_wrdata_in               (ctl_wrdata_in),
        .ctl_rddata_out              (ctl_rddata_out),
        .ctl_rdvalid_out             (ctl_rdvalid_out),

        .high_cfg_out                (high_cfg_in),
        .high_cfg_index_out          (high_cfg_index_in),
        .high_cfg_valid_out          (high_cfg_valid_in),
        .high_cfg_key_out            (high_cfg_key_in),
        .high_cfg_msk_out            (high_cfg_msk_in),
        .high_cfg_endpoint_out       (high_cfg_endpoint_in),

        .high_cfg_read_out           (high_cfg_read_in),

        .high_cfg_valid_in           (high_cfg_valid_out),
        .high_cfg_key_in             (high_cfg_key_out),
        .high_cfg_msk_in             (high_cfg_msk_out),
        .high_cfg_endpoint_in        (high_cfg_endpoint_out),

        .low_cfg_out                 (low_cfg_in),
        .low_cfg_index_out           (low_cfg_index_in),
        .low_cfg_valid_out           (low_cfg_valid_in),
        .low_cfg_key_out             (low_cfg_key_in),
        .low_cfg_msk_out             (low_cfg_msk_in),
        .low_cfg_endpoint_out        (low_cfg_endpoint_in),

        .low_cfg_read_out            (low_cfg_read_in),
        .low_cfg_read_valid_in       (low_cfg_read_valid_out),
        .low_cfg_valid_in            (low_cfg_valid_out),
        .low_cfg_key_in              (low_cfg_key_out),
        .low_cfg_msk_in              (low_cfg_msk_out),
        .low_cfg_endpoint_in         (low_cfg_endpoint_out),

        .counter_read_out            (counter_read_in),
        .counter_index_out           (counter_index_in),
        .counter_value_valid_in      (counter_value_valid_out),
        .counter_value_in            (counter_value_out)
    );

    // debug only
    genvar gen_i;
    // check send msg header
    generate
        for (gen_i = 0; gen_i < NUM_PORTS; gen_i++) begin : gen_dbg_head_send
            assign dbg_head_send[gen_i] = sa_first_in[gen_i] ? sa_data_in[gen_i] : {$bits(SiliconNetHead){1'bx}};
        end
    endgenerate
    // check send msg data
    generate
        for (gen_i = 0; gen_i < NUM_PORTS; gen_i++) begin : gen_dbg_data_send
            assign dbg_data_send[gen_i] = sa_valid_in[gen_i] ? (sa_first_in[gen_i] ? {{($bits(sa_data_in[gen_i])-1){1'bz}},1'b0} : sa_data_in[gen_i]) : {($bits(sa_data_in[gen_i])){1'bx}};
        end
    endgenerate

    // check received msg header
    generate
        for (gen_i = 0; gen_i < NUM_PORTS; gen_i++) begin : gen_dbg_head_receive
            assign dbg_head_receive[gen_i] = sa_first_out[gen_i] ? sa_data_out[gen_i] : {$bits(SiliconNetHead){1'bx}};
        end
    endgenerate
    // check received msg data
    generate
        for (gen_i = 0; gen_i < NUM_PORTS; gen_i++) begin : gen_dbg_data_receive
            assign dbg_data_receive[gen_i] = sa_valid_out[gen_i] ? (sa_first_out[gen_i] ? {{($bits(sa_data_out[gen_i])-1){1'bz}},1'b0} : sa_data_out[gen_i]) : {($bits(sa_data_out[gen_i])){1'bx}};
        end
    endgenerate

endmodule

.high_cfg_read_valid_in      (high_cfg_read_valid_out),


`include "transaction.sv"
`include "ChainParentClass.sv"
`include "ChainClasses.sv"

module top;

  ChainOne addChain;
  ChainTwo subChain;
  ChainThree mulChain;
  ChainFour divChain;

  // Simple method to define how to build chain. It is implemented in top module
  // for simplicity. It can be done in a wrapper class.
  function void build_chain ();
    addChain = new();
    subChain = new();
    mulChain = new();
    divChain = new();
    addChain.SetNextChainObject(subChain);
    subChain.SetNextChainObject(mulChain);
    mulChain.SetNextChainObject(divChain);
    //Div Chain Object will be the final one
    divChain.is_last_chain_part();
  endfunction

  initial begin
    transaction tr = new();
    int Result;
    build_chain();

      tr.randomize();

      //Feed the transaction to the first chain part
      Result = addChain.process(tr);

      $display("op:%p\t a1=%0d a2=%0d \t\t\t Result=%0d",tr.op_e,tr.a1,tr.a2,Result);
    end
  end
endmodule


// Copyright (c) 2023 - 2024 Meinhard Kissich
// -----------------------------------------------------------------------------
// File  :  fsoc_sim.sv
// Usage :  Simulation wrapper for the fsoc SoC.
// -----------------------------------------------------------------------------

`default_nettype none

module fsoc_sim #(
  parameter MEMFILE   = "",
  parameter MEMSIZE   = 8192,
  parameter CHUNKSIZE = 1,
  parameter RFTYPE    = "BRAM",
  parameter CONF      = "MIN",
  parameter MTVAL     = 'h0,
  parameter BOOTADR   = 'h1000
) (
  input  logic clk_i,
  input  logic rst_in,
  output logic q
);

localparam MEMDLY1  = 0;
localparam GPOCNT   = 3;

logic [4095:0] firmware_file;
initial
  if ($value$plusargs("firmware=%s", firmware_file)) begin
	  $display("Loading RAM from %0s", firmware_file);
	  $readmemh(firmware_file, i_fsoc.i_mem.mem_r);
  end

logic [GPOCNT-1:0] gpo;

assign q = gpo[0];

// gpo is used by embench to determine timing
logic [1023:0]      embench_file;
logic [GPOCNT-1:0]  gpo_r = '0;

real    start_time;
real    release_time;
integer f = 0;

initial begin
  $timeformat(-6, 0, "", 1);

  /* verilator lint_off WIDTH */
  if ($value$plusargs("embench=%s", embench_file)) begin
    $display("Writing embench_file timing to %0s", embench_file);
    f = $fopen(embench_file, "w");
  end
  /* verilator lint_on WIDTH */
end

logic rst_r = 'b0;
always @(posedge clk_i) begin
  rst_r <= rst_in;
  if (~rst_r & rst_in) begin
    release_time = $realtime;
  end
end

always @(posedge clk_i) begin
  gpo_r <= gpo;
  if ((~gpo_r[0] & gpo[0]) & (f != 0)) begin
    start_time = $realtime - release_time;
    $display("Test started");
  end else if((gpo_r[0] & ~gpo[0]) & (f != 0)) begin
    $fwrite(f, "Bench time: %t\n", $realtime-start_time);
    $display("Test complete, waiting for validation");
  end

  if ((gpo[2] | gpo[1]) & (f != 0)) begin
    if (gpo[2]) begin
      $fwrite(f, "FAILED @ %t\n", $realtime-start_time);
      $display("FAILED");
      $finish;
    end else begin
      $fwrite(f, "SUCCESS @ %t\n", $realtime-start_time);
      $display("SUCCESS");
      $finish;
    end
  end
end

fsoc #(
  .CHUNKSIZE  ( CHUNKSIZE ),
  .CONF       ( CONF      ),
  .RFTYPE     ( RFTYPE    ),
  .MTVAL      ( MTVAL     ),
  .BOOTADR    ( BOOTADR   ),
  .MEMFILE    ( MEMFILE   ),
  .MEMSIZE    ( MEMSIZE   ),
  .MEMDLY1    ( MEMDLY1   ),
  .GPOCNT     ( GPOCNT    )
) i_fsoc (
  .clk_i      ( clk_i   ),
  .rst_in     ( rst_in  ),
  //.tirq_i     ( 1'b0    ),
  //.trap_o     ( ),
  .gpi_i      ( 1'b0    ),
  .gpo_o      ( gpo     )
);

logic [63:0] mcycle_r;

// --- Cylce counter ---
always @(posedge clk_i) begin
  if (~rst_in) begin
    mcycle_r = 'b0;
  end else begin
    mcycle_r = mcycle_r + 'b1;
  end
end

// --- Instr to ASCII ---
/* verilator lint_off WIDTHEXPAND */
logic [128:0] dbg_ascii_instr;

//                         30    25    20    15    10     5     0
//                          |     |     |     |     |     |     |
`define INSTR_LUI     (32'b??_?????_?????_?????_?????_???01_10111)
`define INSTR_AUIPC   (32'b??_?????_?????_?????_?????_???00_10111)
`define INSTR_JAL     (32'b??_?????_?????_?????_?????_???11_01111)
`define INSTR_JALR    (32'b??_?????_?????_?????_000??_???11_00111)
`define INSTR_BEQ     (32'b??_?????_?????_?????_000??_???11_00011)
`define INSTR_BNE     (32'b??_?????_?????_?????_001??_???11_00011)
`define INSTR_BLT     (32'b??_?????_?????_?????_100??_???11_00011)
`define INSTR_BGE     (32'b??_?????_?????_?????_101??_???11_00011)
`define INSTR_BLTU    (32'b??_?????_?????_?????_110??_???11_00011)
`define INSTR_BGEU    (32'b??_?????_?????_?????_111??_???11_00011)
`define INSTR_LB      (32'b??_?????_?????_?????_000??_???00_00011)
`define INSTR_LH      (32'b??_?????_?????_?????_001??_???00_00011)
`define INSTR_LW      (32'b??_?????_?????_?????_010??_???00_00011)
`define INSTR_LBU     (32'b??_?????_?????_?????_100??_???00_00011)
`define INSTR_LHU     (32'b??_?????_?????_?????_101??_???00_00011)
`define INSTR_SB      (32'b??_?????_?????_?????_000??_???01_00011)
`define INSTR_SH      (32'b??_?????_?????_?????_001??_???01_00011)
`define INSTR_SW      (32'b??_?????_?????_?????_010??_???01_00011)
`define INSTR_ADDI    (32'b??_?????_?????_?????_000??_???00_10011)
`define INSTR_SLTI    (32'b??_?????_?????_?????_010??_???00_10011)
`define INSTR_SLTIU   (32'b??_?????_?????_?????_011??_???00_10011)
`define INSTR_XORI    (32'b??_?????_?????_?????_100??_???00_10011)
`define INSTR_ORI     (32'b??_?????_?????_?????_110??_???00_10011)
`define INSTR_ANDI    (32'b??_?????_?????_?????_111??_???00_10011)
`define INSTR_SLLI    (32'b00_00000_?????_?????_001??_???00_10011)
`define INSTR_SRLI    (32'b00_00000_?????_?????_101??_???00_10011)
`define INSTR_SRAI    (32'b01_00000_?????_?????_101??_???00_10011)
`define INSTR_ADD     (32'b00_00000_?????_?????_000??_???01_10011)
`define INSTR_SUB     (32'b01_00000_?????_?????_000??_???01_10011)
`define INSTR_SLL     (32'b00_00000_?????_?????_001??_???01_10011)
`define INSTR_SLT     (32'b00_00000_?????_?????_010??_???01_10011)
`define INSTR_SLTU    (32'b00_00000_?????_?????_011??_???01_10011)
`define INSTR_XOR     (32'b00_00000_?????_?????_100??_???01_10011)
`define INSTR_SRL     (32'b00_00000_?????_?????_101??_???01_10011)
`define INSTR_SRA     (32'b01_00000_?????_?????_101??_???01_10011)
`define INSTR_OR      (32'b00_00000_?????_?????_110??_???01_10011)
`define INSTR_AND     (32'b00_00000_?????_?????_111??_???01_10011)
`define INSTR_ECALL   (32'b??_0????_????0_?????_000??_???11_10011)
`define INSTR_EBREAK  (32'b??_0????_????1_?????_000??_???11_10011)
`define INSTR_CSRRW   (32'b??_?????_?????_?????_001??_???11_10011)
`define INSTR_CSRRS   (32'b??_?????_?????_?????_010??_???11_10011)
`define INSTR_CSRRC   (32'b??_?????_?????_?????_011??_???11_10011)
`define INSTR_CSRRWI  (32'b??_?????_?????_?????_101??_???11_10011)
`define INSTR_CSRRSI  (32'b??_?????_?????_?????_110??_???11_10011)
`define INSTR_CSRRCI  (32'b??_?????_?????_?????_111??_???11_10011)
`define INSTR_MRET    (32'b??_1????_?????_?????_000??_???11_10011)

always_comb begin
  casez(i_fsoc.i_fazyrv_core.wb_imem_dat_i)
    `INSTR_LUI:     dbg_ascii_instr = "lui";
    `INSTR_AUIPC:   dbg_ascii_instr = "auipc";
    `INSTR_JAL:     dbg_ascii_instr = "jal";
    `INSTR_JALR:    dbg_ascii_instr = "jalr";
    `INSTR_BEQ:     dbg_ascii_instr = "beq";
    `INSTR_BNE:     dbg_ascii_instr = "bne";
    `INSTR_BLT:     dbg_ascii_instr = "blt";

    `INSTR_BLTU:    dbg_ascii_instr = "bltu";
    `INSTR_BGEU:    dbg_ascii_instr = "bgeu";
    `INSTR_LB:      dbg_ascii_instr = "lb";
    `INSTR_LH:      dbg_ascii_instr = "lh";
    `INSTR_LW:      dbg_ascii_instr = "lw";
    `INSTR_LBU:     dbg_ascii_instr = "lbu";
    `INSTR_LHU:     dbg_ascii_instr = "lhu";
    `INSTR_SB:      dbg_ascii_instr = "sb";
    `INSTR_SH:      dbg_ascii_instr = "sh";
    `INSTR_SW:      dbg_ascii_instr = "sw";
    `INSTR_ADDI:    dbg_ascii_instr = "addi";
    `INSTR_SLTI:    dbg_ascii_instr = "slti";
    `INSTR_SLTIU:   dbg_ascii_instr = "sltiu";
    `INSTR_XORI:    dbg_ascii_instr = "xori";
    `INSTR_ORI:     dbg_ascii_instr = "ori";
    `INSTR_ANDI:    dbg_ascii_instr = "andi";
    `INSTR_SLLI:    dbg_ascii_instr = "slli";
    `INSTR_SRLI:    dbg_ascii_instr = "srli";
    `INSTR_SRAI:    dbg_ascii_instr = "srai";
    `INSTR_ADD:     dbg_ascii_instr = "add";
    `INSTR_SUB:     dbg_ascii_instr = "sub";
    `INSTR_SLL:     dbg_ascii_instr = "sll";
    `INSTR_SLT:     dbg_ascii_instr = "slt";
    `INSTR_SLTU:    dbg_ascii_instr = "sltu";
    `INSTR_XOR:     dbg_ascii_instr = "xor";
    `INSTR_SRL:     dbg_ascii_instr = "srl";
    `INSTR_SRA:     dbg_ascii_instr = "sra";
    `INSTR_OR:      dbg_ascii_instr = "or";
    `INSTR_AND:     dbg_ascii_instr = "and";
    `INSTR_CSRRW:   dbg_ascii_instr = "csrrw";
    `INSTR_CSRRS:   dbg_ascii_instr = "csrrs";
    `INSTR_CSRRC:   dbg_ascii_instr = "csrrc";
    `INSTR_CSRRW:   dbg_ascii_instr = "csrrw";
    `INSTR_CSRRS:   dbg_ascii_instr = "csrrs";
    `INSTR_CSRRC:   dbg_ascii_instr = "csrrc";
    `INSTR_CSRRWI:  dbg_ascii_instr = "csrrwi";
    `INSTR_CSRRSI:  dbg_ascii_instr = "csrrsi";
    `INSTR_CSRRCI:  dbg_ascii_instr = "csrrci";
    `INSTR_ECALL:   dbg_ascii_instr = "ecall";
    `INSTR_EBREAK:  dbg_ascii_instr = "ebreak";
    `INSTR_MRET:    dbg_ascii_instr = "mret";
    default:        dbg_ascii_instr = "illegal";
  endcase
end
/* verilator lint_on WIDTHEXPAND */

logic [1023:0] timing_file;
integer f_timing = 0;
logic q_r;

initial begin
  if ($value$plusargs("timing=%s", timing_file)) begin
    f_timing = $fopen(timing_file, "w");
  end
end

always_ff @(posedge clk_i) begin
  q_r <= q;
end

(* keep *) logic dly_stb;
always_ff @(posedge clk_i) begin
  dly_stb <= i_fsoc.i_fazyrv_core.wb_imem_stb_o;
end

(* keep *) logic fwrite_stb;

generate
if (MEMDLY1 == 1) begin
  assign fwrite_stb = dly_stb;
end else begin
  assign fwrite_stb = i_fsoc.i_fazyrv_core.wb_imem_stb_o & i_fsoc.i_fazyrv_core.wb_imem_ack_i;
end

endgenerate

always @(posedge clk_i) begin
  if ((f_timing != 0) && (q | q_r)) begin
    if (fwrite_stb) begin
      $fwrite(f_timing, "## %-s %d\n", dbg_ascii_instr, mcycle_r);
    end
  end

  if (q_r & ~q) begin
    $fclose(f_timing);
    f_timing = 0;
  end
end

endmodule

    `INSTR_BGE:     dbg_ascii_instr = "bge";
    `INSTR_BLTU:    dbg_ascii_instr = "bltu";
    `INSTR_BGEU:    dbg_ascii_instr = "bgeu";
    `INSTR_BEQ:     dbg_ascii_instr = "beq";


////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017, Matt Dew @ Dew Technologies, LLC
//
// This program is free software (logic verification): you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public License (LGPL)
// as published by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
// for more details.
//
// License:	LGPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/lgpl.html
//
//
// Author's intent:  If you use this AXI verification code and find or fix bugs
//                   or make improvements, then share those fixes or improvements.
//                   If you use this in a bigger project, I don't care about,
//                   or want, any changes or code outside this block.
//                   Example: If you use this in an SoC simulation/testbench
//                            I don't want, or care about, your SoC or other blocks.
//                            I just care about the enhancements to these AXI files.
//                   That's why I have choosen the LGPL instead of the GPL.
////////////////////////////////////////////////////////////////////////////////
/*! \class axi_sequential_reads_test
 * \brief Sequential AXI reads. No pipelining.
 *
 * Backdoor write memory, then Send ReadAddress, wait for ReadData and verify.
 * Then repeat.
 */
class axi_sequential_reads_test extends axi_base_test;

  `uvm_component_utils(axi_sequential_reads_test)

  axi_agent_config  driver_agent_config;
  axi_agent_config  responder_agent_config;

    super.new(name, parent);
  endfunction : new

  function void build_phase(uvm_phase phase);

    axi_seq::type_id::set_type_override(axi_sequential_reads_seq::get_type(), 1);

    driver_agent_config = axi_agent_config::type_id::create("driver_agent_config", this);

    assert(driver_agent_config.randomize() with {
                                                 //bready_toggle_pattern == 32'hFFFF_FFFF;
                                                // rready_toggle_pattern == 32'hFFFF_FFFF;

                                                 // these don't matter for sequential since
                                                 // they wont be back to back
                                                 min_clks_between_ar_transfers == 0;
                                                 max_clks_between_ar_transfers == 3;
                                                 min_clks_between_aw_transfers == 0;
                                                 max_clks_between_aw_transfers == 3;
                                                 min_clks_between_w_transfers  == 0;
                                                 max_clks_between_w_transfers  == 3;
                                              });

    driver_agent_config.m_active            = UVM_ACTIVE;
    driver_agent_config.drv_type            = e_DRIVER;

    //  Put the agent_config handle into config_db
    uvm_config_db #(axi_agent_config)::set(null, "*", "m_axidriver_agent.m_config", driver_agent_config);

    responder_agent_config = axi_agent_config::type_id::create("responder_agent_config", this);

  assert(responder_agent_config.randomize() with {
                                                 // awready_toggle_pattern == 32'hFFFF_FFFF;
                                                 //  wready_toggle_pattern == 32'h111_1111;
                                                 // arready_toggle_pattern == 32'hFFFF_FFFF;

                                                  min_clks_between_r_transfers == 0;
                                                  max_clks_between_r_transfers == 3;
                                                  min_clks_between_b_transfers == 0;
                                                  max_clks_between_b_transfers == 3;

                                                  });

  responder_agent_config.m_active            = UVM_ACTIVE;
  responder_agent_config.drv_type            = e_RESPONDER;
  responder_agent_config.axi_incompatible_wvalid_toggling_mode=0;

  //responder_agent_config.rvalid              = new[1];
  //responder_agent_config.rvalid[0]           = 1'b1;

  //  Put the agent_config handle into config_db
    uvm_config_db #(axi_agent_config)::set(null, "*", "m_axiresponder_agent.m_config", responder_agent_config);

    super.build_phase(phase);

  endfunction : build_phase

  task run_phase(uvm_phase phase);

    //bit valid[];

    phase.raise_objection(this);

    fork
       m_resp_seq.start(m_env.m_responder_seqr);
    join_none

    m_seq.start(m_env.m_driver_seqr);

     phase.drop_objection(this);
  endtask : run_phase

endclass : axi_sequential_reads_test

function new (string name="axi_sequential_reads_test", uvm_component parent=null);


module key_input
(
    input clk,
    input clk_ce,
    input reset,
    input [8:0] keys_active,
    input [23:0] bus_address_in,
    output logic [7:0] bus_data_out,
    output logic [8:0] key_irqs
);

wire [7:0] reg_keys = reset ? 8'hFF: ~keys_active[7:0];

reg [8:0] key_latches;
always @ (posedge clk)
begin
    if(clk_ce)

    end
end

always_comb
begin
    bus_data_out = 0;
    if(bus_address_in == 24'h2052)
        bus_data_out = reg_keys;
end

endmodule

    begin
        for(int i = 0; i < 9; ++i)
        begin
            key_irqs[i]    <= 0;
            key_latches[i] <= keys_active[i];


//
// UART transmitter
//
// reviewed 2024-06-25
//
`timescale 1ns / 1ps
//
`default_nettype none
// `define DBG
// `define INFO

module uarttx #(
    parameter int unsigned ClockFrequencyHz = 66_000_000,
    parameter int unsigned BaudRate = 9600
) (
    input wire rst_n,
    input wire clk,

    input wire [7:0] data,
    // data to send

    input wire go,
    // enable to start transmission
    // disable after 'busy' has gone low to acknowledge that data has been sent
    //   then enable to start sending new data

    output logic tx,
    // UART tx wire

    output logic busy
    // enabled while sending
    //  after sending, 'busy' is set to low and needs to be acknowledged by setting 'go' low
    //   before transmitting new 'data' by enabling 'go'
);

  localparam int unsigned BIT_TIME = ClockFrequencyHz / BaudRate;

  typedef enum {
    Idle,
    StartBit,
    DataBits,
    StopBit,
    WaitForGoLow
  } state_e;

  state_e state;

  logic [2:0] bit_count;  // 3 bits to fit number 7

  logic [(BIT_TIME == 1 ? 1 : $clog2(BIT_TIME))-1:0] bit_time_counter;

  always_comb begin
    unique case (state)

      Idle: begin
        if (go) begin
          // start sending start bit in this cycle
          tx   = 0;
          busy = 1;
        end else begin
          tx   = 1;
          busy = 0;
        end

        // this also flukes:
        // tx   = go ? 0 : 1;
        // busy = go ? 1 : 0;

      end

      StartBit: begin
        tx   = 0;
        busy = 1;
      end

      DataBits: begin
        tx   = data[bit_count];
        busy = 1;
      end

      StopBit: begin
        tx   = 1;
        busy = 1;
      end

      WaitForGoLow: begin
        tx   = 1;
        busy = 0;
      end

      default: begin
        // note: not necessary but otherwise Gowin EDA 1.9.10.03 Educational
        //       infers latches for 'busy' and 'tx'
        tx   = 1;
        busy = 0;
      end

    endcase
  end

  always_ff @(posedge clk) begin
    if (!rst_n) begin
      state <= Idle;
    end else begin
      unique case (state)

        Idle: begin
          if (go) begin
            // start bit starts sending during this cycle
            if (BIT_TIME == 1) begin
              // special case: full start bit was sent during
              // this cycle. jump to send data bits
              bit_time_counter <= BIT_TIME - 1;
              bit_count <= 0;
              state <= DataBits;
            end else begin
              bit_time_counter <= BIT_TIME - 2;
              // note: -1 because first cycle in the start bit
              //       is sent during this cycle and another -1
              //       because of the comparison when non-blocking
              //       assignments
              state <= StartBit;
            end
          end
        end

        StartBit: begin
          bit_time_counter <= bit_time_counter - 1'b1;
          if (bit_time_counter == 0) begin
            bit_time_counter <= BIT_TIME - 1;
            bit_count <= 0;

            bit_time_counter <= BIT_TIME - 1;
            bit_count <= bit_count + 1'b1;
            if (bit_count == 8 - 1) begin
              state <= StopBit;
            end
          end
        end

        StopBit: begin
          bit_time_counter <= bit_time_counter - 1'b1;
          if (bit_time_counter == 0) begin
            state <= WaitForGoLow;
          end
        end

        WaitForGoLow: begin
          // wait for acknowledge that 'data' has been sent
          if (!go) begin
            state <= Idle;
          end
        end

        default: ;  // note: not necessary

      endcase
    end
  end

endmodule

`undef DBG
`undef INFO
`default_nettype wire

            state <= DataBits;
          end
        end


// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 28/09/2018
// Description: Mock replacement for UART in testbench (not synthesiesable!)

module mock_uart  #(
  parameter int  UART_IDX = 0
 )(
    input  logic          clk_i,
    input  logic          rst_ni,
    input  logic          penable_i,
    input  logic          pwrite_i,
    input  logic [31:0]   paddr_i,
    input  logic          psel_i,
    input  logic [31:0]   pwdata_i,
    output logic [31:0]   prdata_o,
    output logic          pready_o,
    output logic          pslverr_o
);
    localparam RBR = 0;
    localparam THR = 0;
    localparam IER = 1;
    localparam IIR = 2;
    localparam FCR = 2;
    localparam LCR = 3;
    localparam MCR = 4;
    localparam LSR = 5;
    localparam MSR = 6;
    localparam SCR = 7;
    localparam DLL = 0;
    localparam DLM = 1;

    localparam THRE = 5; // transmit holding register empty
    localparam TEMT = 6; // transmit holding register empty

    byte lcr = 0;
    byte dlm = 0;
    byte dll = 0;
    byte mcr = 0;
    byte lsr = 0;
    byte ier = 0;
    byte msr = 0;
    byte scr = 0;
    logic fifo_enabled = 1'b0;

    integer charnum = 0;
    logic [256*8-1:0] stringa = '0;

    assign pready_o = 1'b1;
    assign pslverr_o = 1'b0;

    function void uart_tx(byte ch);
        if(ch==8'h0A) begin
          $display("[TB UART %2d] %s", UART_IDX, stringa);
          charnum = 0;
          stringa = '0;
        end else begin
          stringa[(255-charnum)*8 +: 8] = ch;
          charnum = charnum + 1;
        end
    endfunction : uart_tx

    always_ff @(posedge clk_i or negedge rst_ni) begin
        if (rst_ni) begin
            if (psel_i & penable_i & pwrite_i) begin
                case ((paddr_i >> 'h2) & 'h7)
                    THR: begin
                        if (lcr & 'h80) dll <= byte'(pwdata_i[7:0]);
                        else begin
                           uart_tx(byte'(pwdata_i[7:0]));
                        end
                    end
                    IER: begin
                        if (lcr & 'h80) dlm <= byte'(pwdata_i[7:0]);
                        else ier <= byte'(pwdata_i[7:0] & 'hF);
                    end
                    FCR: begin
                        if (pwdata_i[0]) fifo_enabled <= 1'b1;
                        else fifo_enabled <= 1'b0;
                    end

            end
        end
    end

    always_comb begin
        prdata_o = '0;
        if (psel_i & penable_i & ~pwrite_i) begin
            case ((paddr_i >> 'h2) & 'h7)
                THR: begin
                    if (lcr & 'h80) prdata_o = {24'b0, dll};
                end
                IER: begin
                    if (lcr & 'h80) prdata_o = {24'b0, dlm};
                    else prdata_o = {24'b0, ier};
                end
                IIR: begin
                    if (fifo_enabled) prdata_o = {24'b0, 8'hc0};
                    else prdata_o = {24'b0, 8'b0};
                end
                LCR: prdata_o = {24'b0, lcr};
                MCR: prdata_o = {24'b0, mcr};
                LSR: prdata_o = {24'b0, (lsr | (1 << THRE) | (1 << TEMT))};
                MSR: prdata_o = {24'b0, msr};
                SCR: prdata_o = {24'b0, scr};
                default:;
            endcase
        end
    end
endmodule

                    LCR: lcr <= byte'(pwdata_i[7:0]);
                    MCR: mcr <= byte'(pwdata_i[7:0] & 'h1F);
                    LSR: lsr <= byte'(pwdata_i[7:0]);
                    MSR: msr <= byte'(pwdata_i[7:0]);


/******************************************************************************
 * (C) Copyright 2015 AMIQ Consulting
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * MODULE:       svaunit_sequence_test.svh
 * PROJECT:      svaunit
 * Description:  svaunit test class which starts a sequence
 *******************************************************************************/

`ifndef SVAUNIT_SEQUENCE_TEST_SVH
`define SVAUNIT_SEQUENCE_TEST_SVH

/* SVAUnit test class which starts a sequence
 * SEQ_TYPE : sequence type used to check a scenario
 */

   `uvm_component_param_utils(svaunit_sequence_test#(SEQ_TYPE))

   // Sequence which contains the SVA scenario
   SEQ_TYPE seq;

   /* Constructor for svaunit_sequence_test
    * @param name   : instance name for svaunit_sequence_test object
    * @param parent : hierarchical parent for svaunit_sequence_test
    */
   function new(string name="svaunit_sequence_test", uvm_component parent);
      super.new(name, parent);
   endfunction

   // Will set the name of the current test
   virtual function void set_name_for_test();
      update_test_name(seq.get_test_name());
   endfunction

   /* Form the test topology as a tree
    * @param a_level : the level where the test is created
    * @return a string representing the tree
    */
   virtual function string form_tree(int a_level);
      string extra = "";

      for(int level_idx = 0; level_idx < a_level; level_idx++) begin
         extra = {"\t", extra};
      end

      return $sformatf("%s%s", extra, seq.form_tree(a_level));
   endfunction

   // Task used to start testing - a sequence will be started here
   virtual task test();
      if(!seq.randomize()) begin
         `uvm_error("SVAUNIT_SEQUENCE_TEST_RANDOMIZE_ERR",
            $sformatf("The sequence for %s could not be randomize", get_test_name()))
      end
      seq.start(sequencer);
   endtask
endclass

`endif

class svaunit_sequence_test#(type SEQ_TYPE=svaunit_base_sequence) extends svaunit_test;


// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// This file is auto-generated.

`ifndef PRIM_DEFAULT_IMPL
  `define PRIM_DEFAULT_IMPL prim_pkg::ImplGeneric
`endif

// This is to prevent AscentLint warnings in the generated
// abstract prim wrapper. These warnings occur due to the .*
// use. TODO: we may want to move these inline waivers
// into a separate, generated waiver file for consistency.
//ri lint_check_off OUTPUT_NOT_DRIVEN INPUT_NOT_READ
module prim_pad_wrapper
import prim_pad_wrapper_pkg::*;
#(

  // These parameters are ignored in this model.
  parameter pad_type_e PadType = BidirStd,
  parameter scan_role_e ScanRole = NoScan

) (
  // This is only used for scanmode (not used in generic models)
  input              clk_scan_i,
  input              scanmode_i,
  // Power sequencing signals (not used in generic models)
  input pad_pok_t    pok_i,
  // Main Pad signals

if (Impl == prim_pkg::ImplXilinx) begin : gen_xilinx
    prim_xilinx_pad_wrapper #(
      .PadType(PadType),
      .ScanRole(ScanRole)
    ) u_impl_xilinx (
      .*
    );
end else begin : gen_generic
    prim_generic_pad_wrapper #(
      .PadType(PadType),
      .ScanRole(ScanRole)
    ) u_impl_generic (
      .*
    );
end

endmodule
//ri lint_check_on OUTPUT_NOT_DRIVEN INPUT_NOT_READ

  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


// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// AES core implementation

`include "prim_assert.sv"

module aes_core
  import aes_pkg::*;
  import aes_reg_pkg::*;
#(
  parameter bit          AES192Enable         = 1,
  parameter bit          Masking              = 0,
  parameter sbox_impl_e  SBoxImpl             = SBoxImplLut,
  parameter int unsigned SecStartTriggerDelay = 0,
  parameter bit          SecAllowForcingMasks = 0,

  localparam int         NumShares            = Masking ? 2 : 1, // derived parameter

  parameter logic [WidthPRDClearing-1:0] SeedClearing = DefaultSeedClearing,
  parameter logic  [WidthPRDMasking-1:0] SeedMasking  = DefaultSeedMasking
) (
  input  logic                        clk_i,
  input  logic                        rst_ni,

  // Entropy request interfaces for clearing and masking PRNGs
  output logic                        entropy_clearing_req_o,
  input  logic                        entropy_clearing_ack_i,
  input  logic [WidthPRDClearing-1:0] entropy_clearing_i,
  output logic                        entropy_masking_req_o,
  input  logic                        entropy_masking_ack_i,
  input  logic  [WidthPRDMasking-1:0] entropy_masking_i,

  // Alerts
  output logic                        ctrl_err_update_o,
  output logic                        ctrl_err_storage_o,

  // Bus Interface
  input  aes_reg2hw_t                 reg2hw,
  output aes_hw2reg_t                 hw2reg
);

  // Signals
  logic                        ctrl_re;
  logic                        ctrl_qe;
  logic                        ctrl_we;
  aes_op_e                     aes_op_q;
  aes_mode_e                   mode;
  aes_mode_e                   aes_mode_q;
  ciph_op_e                    cipher_op;
  key_len_e                    key_len;
  key_len_e                    key_len_q;
  logic                        manual_operation_q;
  logic                        force_zero_masks_q;
  ctrl_reg_t                   ctrl_d, ctrl_q;

  logic        [3:0][3:0][7:0] state_in;
  si_sel_e                     state_in_sel;
  logic        [3:0][3:0][7:0] add_state_in;
  add_si_sel_e                 add_state_in_sel;

  logic        [3:0][3:0][7:0] state_mask;
  logic        [3:0][3:0][7:0] state_init [NumShares];
  logic        [3:0][3:0][7:0] state_done [NumShares];
  logic        [3:0][3:0][7:0] state_out;

  logic            [7:0][31:0] key_init [2];
  logic            [7:0]       key_init_qe [2];
  logic            [7:0][31:0] key_init_d [2];
  logic            [7:0][31:0] key_init_q [2];
  logic            [7:0][31:0] key_init_cipher [NumShares];
  logic            [7:0]       key_init_we [2];
  key_init_sel_e               key_init_sel;

  logic            [3:0][31:0] iv;
  logic            [3:0]       iv_qe;
  logic            [7:0][15:0] iv_d;
  logic            [7:0][15:0] iv_q;
  logic            [7:0]       iv_we;
  iv_sel_e                     iv_sel;

  logic            [7:0][15:0] ctr;
  logic            [7:0]       ctr_we;
  logic                        ctr_incr;
  logic                        ctr_ready;

  logic            [3:0][31:0] data_in_prev_d;
  logic            [3:0][31:0] data_in_prev_q;
  logic                        data_in_prev_we;
  dip_sel_e                    data_in_prev_sel;

  logic            [3:0][31:0] data_in;
  logic            [3:0]       data_in_qe;
  logic                        data_in_we;

  logic        [3:0][3:0][7:0] add_state_out;
  add_so_sel_e                 add_state_out_sel;

  logic            [3:0][31:0] data_out_d;
  logic            [3:0][31:0] data_out_q;
  logic                        data_out_we;
  logic                  [3:0] data_out_re;

  logic                        cipher_in_valid;
  logic                        cipher_in_ready;
  logic                        cipher_out_valid;
  logic                        cipher_out_ready;
  logic                        cipher_crypt;
  logic                        cipher_crypt_busy;
  logic                        cipher_dec_key_gen;
  logic                        cipher_dec_key_gen_busy;
  logic                        cipher_key_clear;
  logic                        cipher_key_clear_busy;
  logic                        cipher_data_out_clear;
  logic                        cipher_data_out_clear_busy;

  // Pseudo-random data for clearing purposes
  logic [WidthPRDClearing-1:0] prd_clearing;
  logic                        prd_clearing_upd_req;
  logic                        prd_clearing_upd_ack;
  logic                        prd_clearing_rsd_req;
  logic                        prd_clearing_rsd_ack;
  logic                [127:0] prd_clearing_128;
  logic                [255:0] prd_clearing_256;

  // Unused signals
  logic            [3:0][31:0] unused_data_out_q;
  logic                        unused_force_zero_masks;

  // The clearing PRNG provides pseudo-random data for register clearing purposes.
  aes_prng_clearing #(
    .Width       ( WidthPRDClearing ),
    .DefaultSeed ( SeedClearing     )
  ) u_aes_prng_clearing (
    .clk_i         ( clk_i                  ),
    .rst_ni        ( rst_ni                 ),

    .data_req_i    ( prd_clearing_upd_req   ),
    .data_ack_o    ( prd_clearing_upd_ack   ),
    .data_o        ( prd_clearing           ),
    .reseed_req_i  ( prd_clearing_rsd_req   ),
    .reseed_ack_o  ( prd_clearing_rsd_ack   ),

    .entropy_req_o ( entropy_clearing_req_o ),
    .entropy_ack_i ( entropy_clearing_ack_i ),
    .entropy_i     ( entropy_clearing_i     )
  );

  // Generate clearing signals of appropriate widths.
  localparam int unsigned NumChunks = 128/WidthPRDClearing;
  for (genvar c = 0; c < NumChunks; c++) begin : gen_prd_clearing
    assign prd_clearing_128[c * WidthPRDClearing       +: WidthPRDClearing] = prd_clearing;
    assign prd_clearing_256[c * WidthPRDClearing       +: WidthPRDClearing] = prd_clearing;
    assign prd_clearing_256[c * WidthPRDClearing + 128 +: WidthPRDClearing] = prd_clearing;
  end

  ////////////
  // Inputs //
  ////////////

  always_comb begin : key_init_get
    for (int i=0; i<8; i++) begin
      key_init[0][i]    = reg2hw.key_share0[i].q;
      key_init_qe[0][i] = reg2hw.key_share0[i].qe;
      key_init[1][i]    = reg2hw.key_share1[i].q;
      key_init_qe[1][i] = reg2hw.key_share1[i].qe;
    end
  end

  always_comb begin : iv_get
    for (int i=0; i<4; i++) begin
      iv[i]    = reg2hw.iv[i].q;
      iv_qe[i] = reg2hw.iv[i].qe;
    end
  end

  always_comb begin : data_in_get
    for (int i=0; i<4; i++) begin
      data_in[i]    = reg2hw.data_in[i].q;
      data_in_qe[i] = reg2hw.data_in[i].qe;
    end
  end

  always_comb begin : data_out_get
    for (int i=0; i<4; i++) begin
      // data_out is actually hwo, but we need hrw for hwre
      unused_data_out_q[i] = reg2hw.data_out[i].q;
      data_out_re[i]       = reg2hw.data_out[i].re;
    end
  end

  //////////////////////
  // Key, IV and Data //
  //////////////////////

  // Initial Key registers
  always_comb begin : key_init_mux

      for (int i=0; i<8; i++) begin
        if (key_init_we[s][i]) begin
          key_init_q[s][i] <= key_init_d[s][i];
        end
      end
    end
  end

  // IV registers
  always_comb begin : iv_mux
    unique case (iv_sel)
      IV_INPUT:        iv_d = iv;
      IV_DATA_OUT:     iv_d = data_out_d;
      IV_DATA_OUT_RAW: iv_d = aes_transpose(state_out);
      IV_DATA_IN_PREV: iv_d = data_in_prev_q;
      IV_CTR:          iv_d = ctr;
      IV_CLEAR:        iv_d = prd_clearing_128;
      default:         iv_d = prd_clearing_128;
    endcase
  end

  always_ff @(posedge clk_i) begin : iv_reg
    for (int i=0; i<8; i++) begin
      if (iv_we[i]) begin
        iv_q[i] <= iv_d[i];
      end
    end
  end

  // Previous input data register
  always_comb begin : data_in_prev_mux
    unique case (data_in_prev_sel)
      DIP_DATA_IN: data_in_prev_d = data_in;
      DIP_CLEAR:   data_in_prev_d = prd_clearing_128;
      default:     data_in_prev_d = prd_clearing_128;
    endcase
  end

  always_ff @(posedge clk_i) begin : data_in_prev_reg
    if (data_in_prev_we) begin
      data_in_prev_q <= data_in_prev_d;
    end
  end

  /////////////
  // Counter //
  /////////////

  aes_ctr u_aes_ctr (
    .clk_i    ( clk_i     ),
    .rst_ni   ( rst_ni    ),

    .incr_i   ( ctr_incr  ),
    .ready_o  ( ctr_ready ),

    .ctr_i    ( iv_q      ),
    .ctr_o    ( ctr       ),
    .ctr_we_o ( ctr_we    )
  );

  /////////////////
  // Cipher Core //
  /////////////////

  // Cipher core operation
  assign cipher_op = (aes_mode_q == AES_ECB && aes_op_q == AES_ENC) ? CIPH_FWD :
                     (aes_mode_q == AES_ECB && aes_op_q == AES_DEC) ? CIPH_INV :
                     (aes_mode_q == AES_CBC && aes_op_q == AES_ENC) ? CIPH_FWD :
                     (aes_mode_q == AES_CBC && aes_op_q == AES_DEC) ? CIPH_INV :
                     (aes_mode_q == AES_CFB)                        ? CIPH_FWD :
                     (aes_mode_q == AES_OFB)                        ? CIPH_FWD :
                     (aes_mode_q == AES_CTR)                        ? CIPH_FWD : CIPH_FWD;

  // Convert input data/IV to state format (every word corresponds to one state column).
  // Mux for state input
  always_comb begin : state_in_mux
    unique case (state_in_sel)
      SI_ZERO: state_in = '0;
      SI_DATA: state_in = aes_transpose(data_in);
      default: state_in = '0;
    endcase
  end

  // Mux for addition to state input
  always_comb begin : add_state_in_mux
    unique case (add_state_in_sel)
      ADD_SI_ZERO: add_state_in = '0;
      ADD_SI_IV:   add_state_in = aes_transpose(iv_q);
      default:     add_state_in = '0;
    endcase
  end

  if (!Masking) begin : gen_state_init_unmasked
    assign state_init[0] = state_in ^ add_state_in;

    logic [3:0][3:0][7:0] unused_state_mask;
    assign unused_state_mask = state_mask;

  end else begin : gen_state_init_masked
    assign state_init[0] = (state_in ^ add_state_in) ^ state_mask; // Masked data share
    assign state_init[1] = state_mask;                             // Mask share
  end

  if (!Masking) begin : gen_key_init_unmasked
    // Combine the two key shares for the unmasked cipher core. This causes SCA leakage of the key
    // and thus should be avoided.
    assign key_init_cipher[0] = key_init_q[0] ^ key_init_q[1];

  end else begin : gen_key_init_masked
    // Forward the masked key share and the mask share to the masked cipher core.
    assign key_init_cipher    = key_init_q;
  end

  // Cipher core
  aes_cipher_core #(
    .AES192Enable         ( AES192Enable         ),
    .Masking              ( Masking              ),
    .SBoxImpl             ( SBoxImpl             ),
    .SecAllowForcingMasks ( SecAllowForcingMasks ),
    .SeedMasking          ( SeedMasking          )
  ) u_aes_cipher_core (
    .clk_i              ( clk_i                      ),
    .rst_ni             ( rst_ni                     ),

    .in_valid_i         ( cipher_in_valid            ),
    .in_ready_o         ( cipher_in_ready            ),

    .out_valid_o        ( cipher_out_valid           ),
    .out_ready_i        ( cipher_out_ready           ),

    .cfg_valid_i        ( ~ctrl_err_storage_o        ),
    .op_i               ( cipher_op                  ),
    .key_len_i          ( key_len_q                  ),
    .crypt_i            ( cipher_crypt               ),
    .crypt_o            ( cipher_crypt_busy          ),
    .dec_key_gen_i      ( cipher_dec_key_gen         ),
    .dec_key_gen_o      ( cipher_dec_key_gen_busy    ),
    .key_clear_i        ( cipher_key_clear           ),
    .key_clear_o        ( cipher_key_clear_busy      ),
    .data_out_clear_i   ( cipher_data_out_clear      ),
    .data_out_clear_o   ( cipher_data_out_clear_busy ),

    .prd_clearing_i     ( prd_clearing               ),

    .force_zero_masks_i ( force_zero_masks_q         ),
    .data_in_mask_o     ( state_mask                 ),
    .entropy_req_o      ( entropy_masking_req_o      ),
    .entropy_ack_i      ( entropy_masking_ack_i      ),
    .entropy_i          ( entropy_masking_i          ),

    .state_init_i       ( state_init                 ),
    .key_init_i         ( key_init_cipher            ),
    .state_o            ( state_done                 )
  );

  if (!Masking) begin : gen_state_out_unmasked
    assign state_out = state_done[0];
  end else begin : gen_state_out_masked
    // Unmask the cipher core output. This causes SCA leakage and should thus be avoided. This will
    // be reworked in the future when masking the counter and feedback path through the IV regs.
    assign state_out = state_done[0] ^ state_done[1];
  end

  // Mux for addition to state output
  always_comb begin : add_state_out_mux
    unique case (add_state_out_sel)
      ADD_SO_ZERO: add_state_out = '0;
      ADD_SO_IV:   add_state_out = aes_transpose(iv_q);
      ADD_SO_DIP:  add_state_out = aes_transpose(data_in_prev_q);
      default:     add_state_out = '0;
    endcase
  end

  // Convert output state to output data format (every column corresponds to one output word).
  assign data_out_d = aes_transpose(state_out ^ add_state_out);

  //////////////////////
  // Control Register //
  //////////////////////

  // Get and resolve values from register interface.
  assign ctrl_d.operation = aes_op_e'(reg2hw.ctrl_shadowed.operation.q);

  assign mode = aes_mode_e'(reg2hw.ctrl_shadowed.mode.q);
  always_comb begin : mode_get
    unique case (mode)
      AES_ECB: ctrl_d.mode = AES_ECB;
      AES_CBC: ctrl_d.mode = AES_CBC;
      AES_CFB: ctrl_d.mode = AES_CFB;
      AES_OFB: ctrl_d.mode = AES_OFB;
      AES_CTR: ctrl_d.mode = AES_CTR;
      default: ctrl_d.mode = AES_NONE; // unsupported values are mapped to AES_NONE
    endcase
  end

  assign key_len = key_len_e'(reg2hw.ctrl_shadowed.key_len.q);
  always_comb begin : key_len_get
    unique case (key_len)
      AES_128: ctrl_d.key_len = AES_128;
      AES_256: ctrl_d.key_len = AES_256;
      AES_192: ctrl_d.key_len = AES192Enable ? AES_192 : AES_256;
      default: ctrl_d.key_len = AES_256; // unsupported values are mapped to AES_256
    endcase
  end

  assign ctrl_d.manual_operation = reg2hw.ctrl_shadowed.manual_operation.q;

  // SecAllowForcingMasks forbids forcing the masks. Forcing the masks to zero is only
  // useful for SCA.
  assign ctrl_d.force_zero_masks = SecAllowForcingMasks ?
      reg2hw.ctrl_shadowed.force_zero_masks.q : 1'b0;
  assign unused_force_zero_masks = SecAllowForcingMasks ?
      1'b0 : reg2hw.ctrl_shadowed.force_zero_masks.q;

  // Get and forward write enable. Writes are only allowed if the module is idle.
  assign ctrl_re = reg2hw.ctrl_shadowed.operation.re & reg2hw.ctrl_shadowed.mode.re &
      reg2hw.ctrl_shadowed.key_len.re & reg2hw.ctrl_shadowed.manual_operation.re &
      reg2hw.ctrl_shadowed.force_zero_masks.re;
  assign ctrl_qe = reg2hw.ctrl_shadowed.operation.qe & reg2hw.ctrl_shadowed.mode.qe &
      reg2hw.ctrl_shadowed.key_len.qe & reg2hw.ctrl_shadowed.manual_operation.qe &
      reg2hw.ctrl_shadowed.force_zero_masks.qe;

  // Shadowed register primitve
  prim_subreg_shadow #(
    .DW       ( $bits(ctrl_reg_t) ),
    .SWACCESS ( "WO"              ),
    .RESVAL   ( CTRL_RESET        )
  ) u_ctrl_reg_shadowed (
    .clk_i       ( clk_i              ),
    .rst_ni      ( rst_ni             ),
    .re          ( ctrl_re            ),
    .we          ( ctrl_we            ),
    .wd          ( ctrl_d             ),
    .de          ( 1'b0               ),
    .d           ( '0                 ),
    .qe          (                    ),
    .q           ( ctrl_q             ),
    .qs          (                    ),
    .err_update  ( ctrl_err_update_o  ),
    .err_storage ( ctrl_err_storage_o )
  );

  // Make sure the storage error is observable via status register.
  assign hw2reg.status.ctrl_err_storage.d  = ctrl_err_storage_o;
  assign hw2reg.status.ctrl_err_storage.de = ctrl_err_storage_o;

  // Get shorter references.
  assign aes_op_q           = ctrl_q.operation;
  assign aes_mode_q         = ctrl_q.mode;
  assign key_len_q          = ctrl_q.key_len;
  assign manual_operation_q = ctrl_q.manual_operation;
  assign force_zero_masks_q = ctrl_q.force_zero_masks;

  // Unused alert signals
  logic unused_alert_signals;
  assign unused_alert_signals = ^reg2hw.alert_test;

  /////////////
  // Control //
  /////////////

  // Control
  aes_control #(
    .SecStartTriggerDelay ( SecStartTriggerDelay )
  ) u_aes_control (
    .clk_i                   ( clk_i                            ),
    .rst_ni                  ( rst_ni                           ),

    .ctrl_qe_i               ( ctrl_qe                          ),
    .ctrl_we_o               ( ctrl_we                          ),
    .ctrl_err_storage_i      ( ctrl_err_storage_o               ),
    .op_i                    ( aes_op_q                         ),
    .mode_i                  ( aes_mode_q                       ),
    .cipher_op_i             ( cipher_op                        ),
    .manual_operation_i      ( manual_operation_q               ),
    .start_i                 ( reg2hw.trigger.start.q           ),
    .key_clear_i             ( reg2hw.trigger.key_clear.q       ),
    .iv_clear_i              ( reg2hw.trigger.iv_clear.q        ),
    .data_in_clear_i         ( reg2hw.trigger.data_in_clear.q   ),
    .data_out_clear_i        ( reg2hw.trigger.data_out_clear.q  ),
    .prng_reseed_i           ( reg2hw.trigger.prng_reseed.q     ),

    .key_init_qe_i           ( key_init_qe                      ),
    .iv_qe_i                 ( iv_qe                            ),
    .data_in_qe_i            ( data_in_qe                       ),
    .data_out_re_i           ( data_out_re                      ),
    .data_in_we_o            ( data_in_we                       ),
    .data_out_we_o           ( data_out_we                      ),

    .data_in_prev_sel_o      ( data_in_prev_sel                 ),
    .data_in_prev_we_o       ( data_in_prev_we                  ),

    .state_in_sel_o          ( state_in_sel                     ),
    .add_state_in_sel_o      ( add_state_in_sel                 ),
    .add_state_out_sel_o     ( add_state_out_sel                ),

    .ctr_incr_o              ( ctr_incr                         ),
    .ctr_ready_i             ( ctr_ready                        ),
    .ctr_we_i                ( ctr_we                           ),

    .cipher_in_valid_o       ( cipher_in_valid                  ),
    .cipher_in_ready_i       ( cipher_in_ready                  ),
    .cipher_out_valid_i      ( cipher_out_valid                 ),
    .cipher_out_ready_o      ( cipher_out_ready                 ),
    .cipher_crypt_o          ( cipher_crypt                     ),
    .cipher_crypt_i          ( cipher_crypt_busy                ),
    .cipher_dec_key_gen_o    ( cipher_dec_key_gen               ),
    .cipher_dec_key_gen_i    ( cipher_dec_key_gen_busy          ),
    .cipher_key_clear_o      ( cipher_key_clear                 ),
    .cipher_key_clear_i      ( cipher_key_clear_busy            ),
    .cipher_data_out_clear_o ( cipher_data_out_clear            ),
    .cipher_data_out_clear_i ( cipher_data_out_clear_busy       ),

    .key_init_sel_o          ( key_init_sel                     ),
    .key_init_we_o           ( key_init_we                      ),
    .iv_sel_o                ( iv_sel                           ),
    .iv_we_o                 ( iv_we                            ),

    .prng_data_req_o         ( prd_clearing_upd_req             ),
    .prng_data_ack_i         ( prd_clearing_upd_ack             ),
    .prng_reseed_req_o       ( prd_clearing_rsd_req             ),
    .prng_reseed_ack_i       ( prd_clearing_rsd_ack             ),

    .start_o                 ( hw2reg.trigger.start.d           ),
    .start_we_o              ( hw2reg.trigger.start.de          ),
    .key_clear_o             ( hw2reg.trigger.key_clear.d       ),
    .key_clear_we_o          ( hw2reg.trigger.key_clear.de      ),
    .iv_clear_o              ( hw2reg.trigger.iv_clear.d        ),
    .iv_clear_we_o           ( hw2reg.trigger.iv_clear.de       ),
    .data_in_clear_o         ( hw2reg.trigger.data_in_clear.d   ),
    .data_in_clear_we_o      ( hw2reg.trigger.data_in_clear.de  ),
    .data_out_clear_o        ( hw2reg.trigger.data_out_clear.d  ),
    .data_out_clear_we_o     ( hw2reg.trigger.data_out_clear.de ),
    .prng_reseed_o           ( hw2reg.trigger.prng_reseed.d     ),
    .prng_reseed_we_o        ( hw2reg.trigger.prng_reseed.de    ),

    .output_valid_o          ( hw2reg.status.output_valid.d     ),
    .output_valid_we_o       ( hw2reg.status.output_valid.de    ),
    .input_ready_o           ( hw2reg.status.input_ready.d      ),
    .input_ready_we_o        ( hw2reg.status.input_ready.de     ),
    .idle_o                  ( hw2reg.status.idle.d             ),
    .idle_we_o               ( hw2reg.status.idle.de            ),
    .stall_o                 ( hw2reg.status.stall.d            ),
    .stall_we_o              ( hw2reg.status.stall.de           )
  );

  // Input data register clear
  always_comb begin : data_in_reg_clear
    for (int i=0; i<4; i++) begin
      hw2reg.data_in[i].d  = '0;
      hw2reg.data_in[i].de = data_in_we;
    end
  end

  /////////////
  // Outputs //
  /////////////

  always_ff @(posedge clk_i) begin : data_out_reg
    if (data_out_we) begin
      data_out_q <= data_out_d;
    end
  end

  always_comb begin : key_reg_put
    for (int i=0; i<8; i++) begin
      hw2reg.key_share0[i].d = key_init_q[0][i];
      hw2reg.key_share1[i].d = key_init_q[1][i];
    end
  end

  always_comb begin : iv_reg_put
    for (int i=0; i<4; i++) begin
      hw2reg.iv[i].d  = {iv_q[2*i+1], iv_q[2*i]};
    end
  end

  always_comb begin : data_out_put
    for (int i=0; i<4; i++) begin
      hw2reg.data_out[i].d = data_out_q[i];
    end
  end

  assign hw2reg.ctrl_shadowed.mode.d    = {aes_mode_q};
  assign hw2reg.ctrl_shadowed.key_len.d = {key_len_q};

  // These fields are actually hro. But software must be able observe the current value (rw).
  assign hw2reg.ctrl_shadowed.operation.d        = {aes_op_q};
  assign hw2reg.ctrl_shadowed.manual_operation.d = manual_operation_q;
  assign hw2reg.ctrl_shadowed.force_zero_masks.d = force_zero_masks_q;

  ////////////////
  // Assertions //
  ////////////////

  // Selectors must be known/valid
  `ASSERT_KNOWN(AesKeyInitSelKnown, key_init_sel)
  `ASSERT(AesIvSelValid, iv_sel inside {
      IV_INPUT,
      IV_DATA_OUT,
      IV_DATA_OUT_RAW,
      IV_DATA_IN_PREV,
      IV_CTR,
      IV_CLEAR
      })
  `ASSERT_KNOWN(AesDataInPrevSelKnown, data_in_prev_sel)
  `ASSERT(AesModeValid, !ctrl_err_storage_o |-> aes_mode_q inside {
      AES_ECB,
      AES_CBC,
      AES_CFB,
      AES_OFB,
      AES_CTR,
      AES_NONE
      })
  `ASSERT_KNOWN(AesOpKnown, aes_op_q)
  `ASSERT_KNOWN(AesStateInSelKnown, state_in_sel)
  `ASSERT_KNOWN(AesAddStateInSelKnown, add_state_in_sel)
  `ASSERT(AesAddStateOutSelValid, add_state_out_sel inside {
      ADD_SO_ZERO,
      ADD_SO_IV,
      ADD_SO_DIP
      })

endmodule

    unique case (key_init_sel)
      KEY_INIT_INPUT: key_init_d = key_init;
      KEY_INIT_CLEAR: key_init_d = '{default: prd_clearing_256};
      default:        key_init_d = '{default: prd_clearing_256};
    endcase


module mycpu_top (
    input wire aclk,
    input wire aresetn,

    input [5:0] ext_int,            //interrupt

    output wire[3:0] arid,
    output wire[31:0] araddr,
    output wire[7:0] arlen,
    output wire[2:0] arsize,
    output wire[1:0] arburst,
    output wire[1:0] arlock,
    output wire[3:0] arcache,
    output wire[2:0] arprot,
    output wire arvalid,
    input wire arready,

    input wire[3:0] rid,
    input wire[31:0] rdata,
    input wire[1:0] rresp,
    input wire rlast,
    input wire rvalid,
    output wire rready,

    output wire[3:0] awid,
    output wire[31:0] awaddr,
    output wire[7:0] awlen,
    output wire[2:0] awsize,
    output wire[1:0] awburst,
    output wire[1:0] awlock,
    output wire[3:0] awcache,
    output wire[2:0] awprot,
    output wire awvalid,
    input wire awready,

    output wire[3:0] wid,
    output wire[31:0] wdata,
    output wire[3:0] wstrb,
    output wire wlast,
    output wire wvalid,
    input wire wready,

    input wire[3:0] bid,
    input wire[1:0] bresp,
    input bvalid,
    output bready,

    //debug interface
    output wire[31:0] debug_wb_pc,
    output wire[3:0] debug_wb_rf_wen,
    output wire[4:0] debug_wb_rf_wnum,
    output wire[31:0] debug_wb_rf_wdata,
    // soc-simulator + cemu debug interface
    output wire [31:0] debug_cp0_count,
    output wire [31:0] debug_cp0_random,
    output wire [31:0] debug_cp0_cause,
    output wire debug_int,
    output wire debug_commit
);
    wire clk, rst;
    assign clk = aclk; // assign clk = aclk;
    assign rst = ~aresetn;

    //d_tlb - d_cache
    wire no_cache_d         ;   //数据
    wire no_cache_i         ;   //指令

    //datapath - cache
    wire inst_en            ;
    wire [31:0] pcF         ;
    wire [31:0] pcF_dp     ;
    wire [31:0] pc_next     ;
    wire [31:0] pc_next_dp ;
    wire i_cache_stall      ;
    wire stallF             ;
    wire stallM             ;
    wire inst_data_ok1      ;
    wire inst_data_ok2      ;
    wire inst_tlb_refill    ;
    wire inst_tlb_invalid   ;
    wire [31:0] inst_rdata1 ;
    wire [31:0] inst_rdata2 ;
    wire        fence_iE;
    wire [31:0] fence_addrE;
    wire        fence_dM;
    wire [31:0] fence_addrM;
    wire        fence_tlbE;
    wire [31:13]itlb_vpn2;
    wire        itlb_found;
    tlb_entry   itlb_entry;

    wire data_en            ;
    wire [31:0] data_addr   ;
    wire [31:0] data_addr_dp;
    wire [31:0] data_rdata  ;
    wire [ 1:0] data_rlen   ;
    wire [3:0] data_wen     ;
    wire [31:0] data_wdata  ;
    wire d_cache_stall      ;
    wire [31:0] mem_addrE   ;
    wire [31:0] mem_addrE_dp;
    wire mem_read_enE       ;
    wire mem_write_enE      ;

    //i_cache - arbitrater
    wire [31:0] i_araddr    ;
    wire [7:0] i_arlen      ;
    wire [2:0] i_arsize     ;
    wire i_arvalid          ;
    wire i_arready          ;

    wire [31:0] i_rdata     ;
    wire i_rlast            ;
    wire i_rvalid           ;
    wire i_rready           ;

    //d_cache - arbitrater
    wire [31:0] d_araddr    ;
    wire [7:0] d_arlen      ;
    wire [2:0] d_arsize     ;
    wire d_arvalid          ;
    wire d_arready          ;

    wire[31:0] d_rdata      ;
    wire d_rlast            ;
    wire d_rvalid           ;
    wire d_rready           ;

    wire [31:0] d_awaddr    ;
    wire [7:0] d_awlen      ;
    wire [2:0] d_awsize     ;
    wire d_awvalid          ;
    wire d_awready          ;

    wire [31:0] d_wdata     ;
    wire [3:0] d_wstrb      ;
    wire d_wlast            ;
    wire d_wvalid           ;
    wire d_wready           ;

    wire d_bvalid           ;
    wire d_bready           ;

    wire [31:13]    dtlb_vpn2;
    wire            dtlb_found;
    tlb_entry       dtlb_entry;
    wire            fence_tlbM;

    wire            data_tlb_refill;
    wire            data_tlb_invalid;
    wire            data_tlb_mod;

    wire no_cache_E         ;
    datapath u_datapath(
        //ports
        .clk               		( clk               		),
        .rst               		( rst               		),
        .ext_int           		( ext_int           		),
        // inst
        .i_stall           		( i_cache_stall        		),
        .stallF            		( stallF            		),
        .inst_sram_en      		( inst_en            		),
        .F_pc              		( pcF_dp              		),
        .F_pc_next         		( pc_next_dp         		),
        .inst_data_ok1     		( inst_data_ok1     		),
        .inst_data_ok2     		( inst_data_ok2     		),
        .inst_tlb_refill        ( inst_tlb_refill           ),
        .inst_tlb_invalid       ( inst_tlb_invalid          ),
        .inst_rdata1       		( inst_rdata1       		),
        .inst_rdata2       		( inst_rdata2       		),
        .fence_iE               ( fence_iE                  ),
        .fence_addrE            ( fence_addrE               ),
        .fence_dM               ( fence_dM                  ),
        .fence_addrM            ( fence_addrM               ),
        .fence_tlbE             ( fence_tlbE                ),
        .itlb_vpn2              ( itlb_vpn2                 ),
        .itlb_found             ( itlb_found                ),
        .itlb_entry             ( itlb_entry                ),
        // data
        .d_stall           		( d_cache_stall           	),
        .stallM            		( stallM            		),
        .mem_read_enE      		( mem_read_enE      		),
        .mem_write_enE     		( mem_write_enE     		),
        .E_mem_va               ( mem_addrE                 ),
        .mem_addrE         		( mem_addrE_dp      		), // TODO: delete
        .data_sram_enM     		( data_en           		),
        .data_sram_rdataM  		( data_rdata          		),
        .data_sram_rlenM   		( data_rlen           		),
        .data_sram_wenM    		( data_wen             		),
        .M_mem_va               ( data_addr                 ),
        .data_sram_addrM   		( data_addr_dp         		), // TODO: delete
        .data_sram_wdataM  		( data_wdata          		),
        .dtlb_vpn2              ( dtlb_vpn2                 ),
        .dtlb_found             ( dtlb_found                ),
        .dtlb_entry             ( dtlb_entry                ),
        .fence_tlbM             ( fence_tlbM                ),
        .data_tlb_refill        ( data_tlb_refill           ),
        .data_tlb_invalid       ( data_tlb_invalid          ),
        .data_tlb_mod           ( data_tlb_mod              ),
        // debug
        .debug_wb_pc       		( debug_wb_pc       		),
        .debug_wb_rf_wen   		( debug_wb_rf_wen   		),
        .debug_wb_rf_wnum  		( debug_wb_rf_wnum  		),
        .debug_wb_rf_wdata 		( debug_wb_rf_wdata 		),
        .debug_cp0_count        ( debug_cp0_count           ),
        .debug_cp0_random       ( debug_cp0_random          ),
        .debug_cp0_cause        ( debug_cp0_cause           ),
        .debug_int              ( debug_int                 ),
        .debug_commit           ( debug_commit              )
    );

    i_cache i_cache_inst (
        .clk                ( clk           ),
        .rst                ( rst           ),
        .inst_en            ( inst_en       ),
        .inst_va            ( pcF_dp        ),
        .inst_va_next       ( pc_next_dp    ),
        .inst_rdata0        ( inst_rdata1   ),
        .inst_rdata1        ( inst_rdata2   ),
        .inst_ok0           ( inst_data_ok1 ),
        .inst_ok1           ( inst_data_ok2 ),
        .inst_tlb_refill    (inst_tlb_refill  ),
        .inst_tlb_invalid   (inst_tlb_invalid ),
        .stallF             ( stallF        ),
        .istall             ( i_cache_stall ),
        .fence_i            ( fence_iE      ),
        .fence_addr         ( fence_addrE   ),
        .fence_tlb          ( fence_tlbE    ),
        .itlb_vpn2          ( itlb_vpn2     ),
        .itlb_found         ( itlb_found    ),
        .itlb_entry         ( itlb_entry    ),
        .araddr             ( i_araddr      ),
        .arlen              ( i_arlen       ),
        .arsize             ( i_arsize      ),
        .arvalid            ( i_arvalid     ),
        .arready            ( i_arready     ),
        .rdata              ( i_rdata       ),
        .rlast              ( i_rlast       ),
        .rvalid             ( i_rvalid      ),
        .rready             ( i_rready      )
    );

    d_cache d_cache_inst (
        .clk                ( clk           ),
        .rst                ( rst           ),
        .stallM             ( stallM        ),
        .dstall             ( d_cache_stall ),
        .E_mem_va           ( mem_addrE     ), // only used for match bram
        .M_mem_va           ( data_addr     ),
        .M_fence_addr       ( fence_addrM   ), // used for fence
        .M_fence_d          ( fence_dM      ), // fence address reuse the M_memva. Note: we shouldn't raise M_fence_en with M_mem_en.
        .M_mem_en           ( data_en       ),
        .M_mem_write        ( |data_wen     ),
        .M_wmask            ( data_wen      ),
        .M_mem_size         ( data_rlen     ),
        .M_wdata            ( data_wdata    ),
        .M_rdata            ( data_rdata    ),
        .dtlb_vpn2          ( dtlb_vpn2     ),
        .dtlb_found         ( dtlb_found    ),
        .dtlb_entry         ( dtlb_entry    ),
        .fence_tlb          ( fence_tlbM    ),
        .data_tlb_refill    ( data_tlb_refill),
        .data_tlb_invalid   ( data_tlb_invalid),
        .data_tlb_mod       ( data_tlb_mod  ),
        .araddr             ( d_araddr      ),
        .arlen              ( d_arlen       ),
        .arsize             ( d_arsize      ),
        .arvalid            ( d_arvalid     ),
        .arready            ( d_arready     ),
        .rdata              ( d_rdata       ),
        .rlast              ( d_rlast       ),
        .rvalid             ( d_rvalid      ),
        .rready             ( d_rready      ),
        .awaddr             ( d_awaddr      ),
        .awlen              ( d_awlen       ),
        .awsize             ( d_awsize      ),
        .awvalid            ( d_awvalid     ),
        .awready            ( d_awready     ),
        .wdata              ( d_wdata       ),
        .wstrb              ( d_wstrb       ),
        .wlast              ( d_wlast       ),
        .wvalid             ( d_wvalid      ),
        .wready             ( d_wready      ),
        .bvalid             ( d_bvalid      ),
        .bready             ( d_bready      )
    );

    arbitrater u_arbitrater(
        .clk(clk),
        .rst(rst),
    //I CACHE
        .i_araddr          (i_araddr ),
        .i_arlen           (i_arlen  ),
        .i_arsize          (i_arsize ),
        .i_arvalid         (i_arvalid),
        .i_arready         (i_arready),

        .i_rdata           (i_rdata ),
        .i_rlast           (i_rlast ),
        .i_rvalid          (i_rvalid),
        .i_rready          (i_rready),

    //D CACHE
        .d_araddr          (d_araddr ),
        .d_arlen           (d_arlen  ),
        .d_arsize          (d_arsize ),
        .d_arvalid         (d_arvalid),
        .d_arready         (d_arready),

        .d_rlast           (d_rlast ),
        .d_rvalid          (d_rvalid),
        .d_rready          (d_rready),

        .d_awaddr          (d_awaddr ),
        .d_awlen           (d_awlen  ),
        .d_awsize          (d_awsize ),
        .d_awvalid         (d_awvalid),
        .d_awready         (d_awready),

        .d_wdata           (d_wdata ),
        .d_wstrb           (d_wstrb ),
        .d_wlast           (d_wlast ),
        .d_wvalid          (d_wvalid),
        .d_wready          (d_wready),

        .d_bvalid          (d_bvalid),
        .d_bready          (d_bready),
    //Outer
        .arid            (arid   ),
        .araddr          (araddr ),
        .arlen           (arlen  ),
        .arsize          (arsize ),
        .arburst         (arburst),
        .arlock          (arlock ),
        .arcache         (arcache),
        .arprot          (arprot ),
        .arvalid         (arvalid),
        .arready         (arready),

        .rid             (rid   ),
        .rdata           (rdata ),
        .rresp           (rresp ),
        .rlast           (rlast ),
        .rvalid          (rvalid),
        .rready          (rready),

        .awid            (awid   ),
        .awaddr          (awaddr ),
        .awlen           (awlen  ),
        .awsize          (awsize ),
        .awburst         (awburst),
        .awlock          (awlock ),
        .awcache         (awcache),
        .awprot          (awprot ),
        .awvalid         (awvalid),
        .awready         (awready),

        .wid             (wid   ),
        .wdata           (wdata ),
        .wstrb           (wstrb ),
        .wlast           (wlast ),
        .wvalid          (wvalid),
        .wready          (wready),
        .bid             (bid   ),
        .bresp           (bresp ),
        .bvalid          (bvalid),
        .bready          (bready)
    );
endmodule


    parameter INNER_DIMENSION = 50,
    parameter RIGHT_MATRIX_COL = 50,


// Copyright 2017 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// Company:        IIS @ ETHZ - Federal Institute of Technology               //
//                                                                            //
// Engineers:      Lei Li  lile@iis.ee.ethz.ch                                //
//		                                                              //
// Additional contributions by:                                               //
//                                                                            //
//                                                                            //
//                                                                            //
// Create Date:    01/12/2016                                                 //
// Design Name:    fmac                                                       //
// Module Name:    booth_selector.sv                                          //
// Project Name:   Private FPU                                                //
// Language:       SystemVerilog                                              //
//                                                                            //
// Description:    Booth Seletor                                              //
//                                                                            //
//                                                                            //
//                                                                            //
// Revision:        20/06/2017                                                //
////////////////////////////////////////////////////////////////////////////////

import fpu_defs_fmac::*;

module booth_selector
  (//Inputs
   input logic [1:0]               Booth_a_DI,

   input  logic                    Sel_1x_SI,
   input logic                     Sel_2x_SI,
   input logic                     Sel_sign_SI,
   //Outputs
   output logic                    Booth_pp_DO