// Copyright 2018-2020 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.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// Florian Zaruba <zarubaf@iis.ee.ethz.ch>

/// A protocol converter from AXI4-Lite to a register interface.
module axi_lite_to_reg #(
  /// The width of the address.
  parameter int ADDR_WIDTH = -1,
  /// The width of the data.
  parameter int DATA_WIDTH = -1,
  /// Buffer depth (how many outstanding transactions do we allow)
  parameter int BUFFER_DEPTH = 2,
  /// Whether the AXI-Lite W channel should be decoupled with a register. This
  /// can help break long paths at the expense of registers.
  parameter bit DECOUPLE_W = 1,
  /// AXI-Lite request struct type.
  parameter type axi_lite_req_t = logic,
  /// AXI-Lite response struct type.
  parameter type axi_lite_rsp_t = logic,
  /// Regbus request struct type.
  parameter type reg_req_t = logic,
  /// Regbus response struct type.
  parameter type reg_rsp_t = logic
) (
  input  logic           clk_i         ,
  input  logic           rst_ni        ,
  input  axi_lite_req_t  axi_lite_req_i,
  output axi_lite_rsp_t  axi_lite_rsp_o,
  output reg_req_t       reg_req_o     ,
  input  reg_rsp_t       reg_rsp_i
);

  `ifndef SYNTHESIS
  initial begin
    assert(BUFFER_DEPTH > 0);
    assert(ADDR_WIDTH > 0);
    assert(DATA_WIDTH > 0);
  end
  `endif

  typedef struct packed {
    logic [ADDR_WIDTH-1:0]   addr;
    logic [DATA_WIDTH-1:0]   data;
    logic [DATA_WIDTH/8-1:0] strb; // byte-wise strobe
  } write_t;

  typedef struct packed {
    logic [ADDR_WIDTH-1:0] addr;
    logic write;
  } req_t;

  typedef struct packed {
    logic [DATA_WIDTH-1:0] data;
    logic error;
  } resp_t;

  logic   write_fifo_full, write_fifo_empty;
  write_t write_fifo_in,   write_fifo_out;
  logic   write_fifo_push, write_fifo_pop;

  logic   write_resp_fifo_full, write_resp_fifo_empty;
  logic   write_resp_fifo_in,   write_resp_fifo_out;
  logic   write_resp_fifo_push, write_resp_fifo_pop;

  logic   read_fifo_full, read_fifo_empty;
  logic [ADDR_WIDTH-1:0]  read_fifo_in,   read_fifo_out;
  logic   read_fifo_push, read_fifo_pop;

  logic   read_resp_fifo_full, read_resp_fifo_empty;
  resp_t  read_resp_fifo_in,   read_resp_fifo_out;
  logic   read_resp_fifo_push, read_resp_fifo_pop;

  req_t read_req, write_req, arb_req;
  logic read_valid, write_valid;
  logic read_ready, write_ready;

  // Combine AW/W Channel
  fifo_v3 #(
    .FALL_THROUGH ( !DECOUPLE_W  ),
    .DEPTH        ( BUFFER_DEPTH ),
    .dtype        ( write_t      )
  ) i_fifo_write_req (
    .clk_i,
    .rst_ni,
    .flush_i    ( 1'b0             ),
    .testmode_i ( 1'b0             ),
    .full_o     ( write_fifo_full  ),
    .empty_o    ( write_fifo_empty ),
    .usage_o    ( /* open */       ),
    .data_i     ( write_fifo_in    ),
    .push_i     ( write_fifo_push  ),
    .data_o     ( write_fifo_out   ),
    .pop_i      ( write_fifo_pop   )
  );

  assign axi_lite_rsp_o.aw_ready = write_fifo_push;
  assign axi_lite_rsp_o.w_ready = write_fifo_push;
  assign write_fifo_push = axi_lite_req_i.aw_valid & axi_lite_req_i.w_valid & ~write_fifo_full;
  assign write_fifo_in.addr = axi_lite_req_i.aw.addr;
  assign write_fifo_in.data = axi_lite_req_i.w.data;
  assign write_fifo_in.strb = axi_lite_req_i.w.strb;
  assign write_fifo_pop = write_valid & write_ready;

  //  B Channel
  fifo_v3 #(
    .DEPTH        ( BUFFER_DEPTH ),
    .dtype        ( logic        )
  ) i_fifo_write_resp (
    .clk_i,
    .rst_ni,
    .flush_i    ( 1'b0                  ),
    .testmode_i ( 1'b0                  ),
    .full_o     ( write_resp_fifo_full  ),
    .empty_o    ( write_resp_fifo_empty ),
    .usage_o    ( /* open */            ),
    .data_i     ( write_resp_fifo_in    ),
    .push_i     ( write_resp_fifo_push  ),
    .data_o     ( write_resp_fifo_out   ),
    .pop_i      ( write_resp_fifo_pop   )
  );

  assign axi_lite_rsp_o.b_valid = ~write_resp_fifo_empty;
  assign axi_lite_rsp_o.b.resp = write_resp_fifo_out ? axi_pkg::RESP_SLVERR : axi_pkg::RESP_OKAY;
  assign write_resp_fifo_in = reg_rsp_i.error;
  assign write_resp_fifo_push = reg_req_o.valid & reg_rsp_i.ready & reg_req_o.write;
  assign write_resp_fifo_pop = axi_lite_rsp_o.b_valid & axi_lite_req_i.b_ready;

  // AR Channel
  fifo_v3 #(
    .DEPTH        ( BUFFER_DEPTH ),
    .DATA_WIDTH   ( ADDR_WIDTH   )
  ) i_fifo_read (
    .clk_i,
    .rst_ni,
    .flush_i    ( 1'b0            ),
    .testmode_i ( 1'b0            ),
    .full_o     ( read_fifo_full  ),
    .empty_o    ( read_fifo_empty ),
    .usage_o    ( /* open */      ),
    .data_i     ( read_fifo_in    ),
    .push_i     ( read_fifo_push  ),
    .data_o     ( read_fifo_out   ),
    .pop_i      ( read_fifo_pop   )
  );

  assign read_fifo_pop = read_valid && read_ready;
  assign axi_lite_rsp_o.ar_ready = ~read_fifo_full;
  assign read_fifo_push = axi_lite_rsp_o.ar_ready & axi_lite_req_i.ar_valid;
  assign read_fifo_in = axi_lite_req_i.ar.addr;

  // R Channel
  fifo_v3 #(
    .DEPTH        ( BUFFER_DEPTH ),
    .dtype        ( resp_t       )
  ) i_fifo_read_resp (
    .clk_i,
    .rst_ni,
    .flush_i    ( 1'b0                 ),
    .testmode_i ( 1'b0                 ),
    .full_o     ( read_resp_fifo_full  ),
    .empty_o    ( read_resp_fifo_empty ),
    .usage_o    ( /* open */           ),
    .data_i     ( read_resp_fifo_in    ),
    .push_i     ( read_resp_fifo_push  ),
    .data_o     ( read_resp_fifo_out   ),
    .pop_i      ( read_resp_fifo_pop   )
  );

  assign axi_lite_rsp_o.r.data = read_resp_fifo_out.data;
  assign axi_lite_rsp_o.r.resp =
    read_resp_fifo_out.error ? axi_pkg::RESP_SLVERR : axi_pkg::RESP_OKAY;
  assign axi_lite_rsp_o.r_valid = ~read_resp_fifo_empty;
  assign read_resp_fifo_pop = axi_lite_rsp_o.r_valid & axi_lite_req_i.r_ready;
  assign read_resp_fifo_push = reg_req_o.valid & reg_rsp_i.ready & ~reg_req_o.write;
  assign read_resp_fifo_in.data = reg_rsp_i.rdata;
  assign read_resp_fifo_in.error = reg_rsp_i.error;

  // Make sure we can capture the responses (e.g. have enough fifo space)
  assign read_valid = ~read_fifo_empty & ~read_resp_fifo_full;
  assign write_valid = ~write_fifo_empty & ~write_resp_fifo_full;

  // Arbitrate between read/write
  assign read_req.addr = read_fifo_out;
  assign read_req.write = 1'b0;
  assign write_req.addr = write_fifo_out.addr;
  assign write_req.write = 1'b1;

  stream_arbiter #(
    .DATA_T  ( req_t ),
    .N_INP   ( 2     ),
    .ARBITER ( "rr"  )
  ) i_stream_arbiter (
    .clk_i,
    .rst_ni,
    .inp_data_i  ( {read_req,   write_req}   ),
    .inp_valid_i ( {read_valid, write_valid} ),
    .inp_ready_o ( {read_ready, write_ready} ),
    .oup_data_o  ( arb_req     ),
    .oup_valid_o ( reg_req_o.valid ),
    .oup_ready_i ( reg_rsp_i.ready )
  );

  assign reg_req_o.addr = arb_req.addr;
  assign reg_req_o.write = arb_req.write;
  assign reg_req_o.wdata = write_fifo_out.data;
  assign reg_req_o.wstrb = write_fifo_out.strb;

endmodule

`include "register_interface/typedef.svh"
`include "register_interface/assign.svh"
`include "axi/typedef.svh"
`include "axi/assign.svh"

/// Interface wrapper.
module axi_lite_to_reg_intf #(
  /// The width of the address.
  parameter int ADDR_WIDTH = -1,
  /// The width of the data.
  parameter int DATA_WIDTH = -1,
  /// Buffer depth (how many outstanding transactions do we allow)
  parameter int BUFFER_DEPTH = 2,
  /// Whether the AXI-Lite W channel should be decoupled with a register. This
  /// can help break long paths at the expense of registers.

  typedef logic [ADDR_WIDTH-1:0] addr_t;
  typedef logic [DATA_WIDTH-1:0] data_t;
  typedef logic [DATA_WIDTH/8-1:0] strb_t;

  `REG_BUS_TYPEDEF_REQ(reg_req_t, addr_t, data_t, strb_t)
  `REG_BUS_TYPEDEF_RSP(reg_rsp_t, data_t)

  `AXI_LITE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t)
  `AXI_LITE_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t)
  `AXI_LITE_TYPEDEF_B_CHAN_T(b_chan_t)
  `AXI_LITE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t)
  `AXI_LITE_TYPEDEF_R_CHAN_T(r_chan_t, data_t)
  `AXI_LITE_TYPEDEF_REQ_T(axi_req_t, aw_chan_t, w_chan_t, ar_chan_t)
  `AXI_LITE_TYPEDEF_RESP_T(axi_resp_t, b_chan_t, r_chan_t)

  axi_req_t  axi_req;
  axi_resp_t axi_resp;
  reg_req_t reg_req;
  reg_rsp_t reg_rsp;

  `AXI_LITE_ASSIGN_TO_REQ(axi_req, axi_i)
  `AXI_LITE_ASSIGN_FROM_RESP(axi_i, axi_resp)

  `REG_BUS_ASSIGN_FROM_REQ(reg_o, reg_req)
  `REG_BUS_ASSIGN_TO_RSP(reg_rsp, reg_o)

  axi_lite_to_reg #(
    .ADDR_WIDTH (ADDR_WIDTH),
    .DATA_WIDTH (DATA_WIDTH),
    .BUFFER_DEPTH (BUFFER_DEPTH),
    .DECOUPLE_W (DECOUPLE_W),
    .axi_lite_req_t (axi_req_t),
    .axi_lite_rsp_t (axi_resp_t),
    .reg_req_t (reg_req_t),
    .reg_rsp_t (reg_rsp_t)
  ) i_axi_lite_to_reg (
    .clk_i (clk_i),
    .rst_ni (rst_ni),
    .axi_lite_req_i (axi_req),
    .axi_lite_rsp_o (axi_resp),
    .reg_req_o (reg_req),
    .reg_rsp_i (reg_rsp)
  );

endmodule

  parameter bit DECOUPLE_W = 1
) (
  input  logic   clk_i  ,
  input  logic   rst_ni ,


`default_nettype none
`timescale 1ns/1ps
/***********************************************************************************************************************
*                                                                                *
* STARSHIPRAIDER v0.1                                                                                *
*                                                                                *
* Copyright (c) 2012-2020 Andrew D. Zonenberg                                                                          *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                *
*                                                                                *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                *
*                                                                                *
***********************************************************************************************************************/

/**
	@file
	@author Andrew D. Zonenberg
	@brief Clock generation for MAXWELL
 */
module ClockSynthesis(

	//156.25 MHz LVDS clock from LMK04806
	input wire		k7_clk_p,
	input wire		k7_clk_n,

	//50 MHz RMII reference clock
	output wire		clk_50mhz,

	//125 MHz clock for RGMII
	output wire		clk_125mhz,

	//156.25 MHz system clock
	output wire		clk_156mhz,

	//200 MHz clock for IDELAYCTRL
	output wire		clk_200mhz,

	//250 MHz clock for RGMII
	output wire		clk_250mhz,

	//312.5 MHz system clock
	output wire		clk_312mhz,

	//400 MHz clock for IDELAYCTRL
	output wire		clk_400mhz,

	//625 MHz clock for LVDS probe inputs
	output wire		clk_625mhz,

	output wire		locked
);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Input clock buffer

	wire	k7_clk;

	DifferentialInputBuffer #(
		.WIDTH(1),
		.IOSTANDARD("LVDS_25"),
		.ODT(1),
		.OPTIMIZE("SPEED")
	) ibuf_clk (
		.pad_in_p(k7_clk_p),
		.pad_in_n(k7_clk_n),
		.fabric_out(k7_clk)
	);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Primary clock PLL used for all system clocks

	wire	main_locked;

	ReconfigurablePLL #(
		.OUTPUT_GATE(6'b111111),
		.OUTPUT_BUF_GLOBAL(6'b111111),
		.IN0_PERIOD(6.4),
		.IN1_PERIOD(6.4),
		.OUT0_MIN_PERIOD(20),	//clk_50mhz
		.OUT1_MIN_PERIOD(8),	//clk_125mhz,
		.OUT2_MIN_PERIOD(6.4),	//clk_156mhz,
		.OUT3_MIN_PERIOD(4),	//clk_250mhz,
		.OUT4_MIN_PERIOD(3.2),	//clk_312mhz
		.OUT5_MIN_PERIOD(1.6),	//clk_625mhz
		.ACTIVE_ON_START(1)		//start PLL automatically out of reset
	) main_pll (
		.clkin({k7_clk, k7_clk}),
		.clksel(1'b0),

		.clkout({clk_625mhz, clk_312mhz, clk_250mhz, clk_156mhz, clk_125mhz, clk_50mhz}),
		.reset(1'b0),
		.locked(main_locked),

		.busy(),
		.reconfig_clk(k7_clk),
		.reconfig_start(1'b0),
		.reconfig_finish(1'b0),
		.reconfig_cmd_done(),
		.reconfig_vco_en(1'b0),
		.reconfig_vco_mult(7'b0),
		.reconfig_vco_indiv(7'b0),
		.reconfig_vco_bandwidth(1'b0),
		.reconfig_output_en(1'b0),
		.reconfig_output_idx(3'b0),
		.reconfig_output_div(8'b0),
		.reconfig_output_phase(9'b0)
	);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Cascaded PLL used to produce the 400 MHz IDELAYCTRL clock and other even frequencies

	wire[3:0] unused;

	wire	even_locked;

	ReconfigurablePLL #(
		.OUTPUT_GATE(6'b000011),
		.OUTPUT_BUF_GLOBAL(6'b000011),
		.IN0_PERIOD(20),
		.IN1_PERIOD(20),
		.OUT0_MIN_PERIOD(2.5),	//clk_400mhz
		.OUT1_MIN_PERIOD(5),	//clk_200mhz
		.OUT2_MIN_PERIOD(2.5),	//unused
		.OUT3_MIN_PERIOD(2.5),	//unused
		.OUT4_MIN_PERIOD(2.5),	//unused
		.OUT5_MIN_PERIOD(2.5),	//unused
		.ACTIVE_ON_START(1)		//start PLL automatically out of reset

		.clkin({clk_50mhz, clk_50mhz}),
		.clksel(1'b0),

		.clkout({unused, clk_200mhz, clk_400mhz}),
		.reset(1'b0),
		.locked(even_locked),

		.busy(),
		.reconfig_clk(k7_clk),
		.reconfig_start(1'b0),
		.reconfig_finish(1'b0),
		.reconfig_cmd_done(),
		.reconfig_vco_en(1'b0),
		.reconfig_vco_mult(7'b0),
		.reconfig_vco_indiv(7'b0),
		.reconfig_vco_bandwidth(1'b0),
		.reconfig_output_en(1'b0),
		.reconfig_output_idx(3'b0),
		.reconfig_output_div(8'b0),
		.reconfig_output_phase(9'b0)
	);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Status output

	assign locked = main_locked && even_locked;

endmodule


`ifndef ASYNCF_DOWN_TRANSACTION__SV
`define ASYNCF_DOWN_TRANSACTION__SV

class asyncf_down_transaction extends uvm_sequence_item;

   rand bit rinc;

   `uvm_object_utils_begin(asyncf_down_transaction)
      `uvm_field_int(rinc, UVM_ALL_ON)
   `uvm_object_utils_end

      super.new();
   endfunction

endclass
`endif

function new(string name = "asyncf_down_transaction");


            mask <= '0;
        end else if (srst) begin
            mask <= '0;
        end else begin
            if (en && |grant) begin
                if      (grant[0]) mask <= 8'b11111110;
                else if (grant[1]) mask <= 8'b11111100;
                else if (grant[2]) mask <= 8'b11111000;
                else if (grant[3]) mask <= 8'b11110000;
                else if (grant[4]) mask <= 8'b11100000;
                else if (grant[5]) mask <= 8'b11000000;
                else if (grant[6]) mask <= 8'b10000000;
                else               mask <= 8'b11111111;

            end
        end
    end

    end
    endgenerate

endmodule

`resetall

    end

    end else if (REQ_NB==8) begin : REQ_8


//-----------------------------------------------------------------------------
// Project       : fpga-hash-table
//-----------------------------------------------------------------------------
// Author        : Ivan Shevchuk (github/johan92)
//-----------------------------------------------------------------------------

package hash_table;

  parameter KEY_WIDTH        = 32;
  parameter VALUE_WIDTH      = 16;
  parameter BUCKET_WIDTH     = 8;
  parameter HASH_TYPE        = "dummy";
  parameter TABLE_ADDR_WIDTH = 10;
  parameter HEAD_PTR_WIDTH   = TABLE_ADDR_WIDTH;

  typedef enum logic [1:0] {
    OP_SEARCH,
    OP_INSERT,
    OP_DELETE
  } ht_opcode_t;

  typedef enum int unsigned {
    SEARCH_FOUND,
    SEARCH_NOT_SUCCESS_NO_ENTRY,

    INSERT_SUCCESS,
    INSERT_SUCCESS_SAME_KEY,
    INSERT_NOT_SUCCESS_TABLE_IS_FULL,

    DELETE_SUCCESS,
    DELETE_NOT_SUCCESS_NO_ENTRY
  } ht_rescode_t;

  typedef enum int unsigned {
    READ_NO_HEAD,
    KEY_MATCH,
    KEY_NO_MATCH_HAVE_NEXT_PTR,
    GOT_TAIL
  } ht_data_table_state_t;

  typedef enum int unsigned {
    NO_CHAIN,

    IN_HEAD,
    IN_MIDDLE,
    IN_TAIL,

    IN_TAIL_NO_MATCH
  } ht_chain_state_t;

  typedef struct packed {
    logic [HEAD_PTR_WIDTH-1:0] ptr;
    logic                      ptr_val;
  } head_ram_data_t;

  typedef struct packed {
    logic [KEY_WIDTH-1:0]      key;
    logic [VALUE_WIDTH-1:0]    value;
    logic [HEAD_PTR_WIDTH-1:0] next_ptr;
    logic                      next_ptr_val;
  } ram_data_t;

  typedef struct packed {
    logic        [KEY_WIDTH-1:0]    key;
    logic        [VALUE_WIDTH-1:0]  value;
    ht_opcode_t                     opcode;
  } ht_command_t;

  // pdata - data to pipeline/proccessing
  typedef struct packed {
    ht_command_t                cmd;

    logic  [BUCKET_WIDTH-1:0]   bucket;

    logic  [HEAD_PTR_WIDTH-1:0] head_ptr;
    logic                       head_ptr_val;
  } ht_pdata_t;

  typedef struct packed {
    ht_command_t                cmd;
    ht_rescode_t                rescode;

    logic  [BUCKET_WIDTH-1:0]   bucket;

    // valid only for opcode = OP_SEARCH
    logic [VALUE_WIDTH-1:0]     found_value;

    // only for verification
    ht_chain_state_t            chain_state;
  } ht_result_t;

  function string pdata2str( input ht_pdata_t pdata );
    string s;

    $sformat( s, "opcode = %s key = 0x%x value = 0x%x head_ptr = 0x%x head_ptr_val = 0x%x",
                  pdata.cmd.opcode, pdata.cmd.key, pdata.cmd.value, pdata.head_ptr, pdata.head_ptr_val );

    return s;
  endfunction

  function string ram_data2str( input ram_data_t data );
    string s;

    $sformat( s, "key = 0x%x value = 0x%x next_ptr = 0x%x next_ptr_val = 0x%x",
                    data.key, data.value, data.next_ptr, data.next_ptr_val );

    return s;
  endfunction

  function string result2str( input ht_result_t result );
    string s;
    case( result.cmd.opcode )
      OP_SEARCH:
        $sformat( s, "key = 0x%x value = 0x%x rescode = %s chain_state = %s",

      OP_INSERT, OP_DELETE:
        $sformat( s, "key = 0x%x value = 0x%x rescode = %s chain_state = %s",
                      result.cmd.key, result.cmd.value, result.rescode, result.chain_state );
    endcase

    return s;
  endfunction

endpackage

result.cmd.key, result.found_value, result.rescode, result.chain_state );


// Copyright 2021 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51

// Florian Zaruba <zarubaf@iis.ee.ethz.ch>

/// A set of testbench utilities for the DMI interfaces.
package dmi_test;

  import dm::*;

  class req_t #(
    parameter int AW = 7
  );
    rand logic [AW-1:0] addr;
    rand dtm_op_e       op;
    rand logic [31:0]   data;

    /// Compare objects of same type.
    function do_compare(req_t rhs);
      return addr == rhs.addr &
             op == rhs.op &
             data == rhs.data;
    endfunction

  endclass

  class rsp_t;
    rand logic [31:0]   data;
    rand logic [1:0]    resp;

    /// Compare objects of same type.
    function do_compare(rsp_t rhs);
      return data == rhs.data &
             resp == rhs.resp;
    endfunction

  endclass

  /// A driver for the DMI interface.
  class dmi_driver #(
    parameter int  AW = -1,
    parameter time TA = 0 , // stimuli application time
    parameter time TT = 0   // stimuli test time
  );
    virtual DMI_BUS_DV #(
      .ADDR_WIDTH(AW)
    ) bus;

    function new(
      virtual DMI_BUS_DV #(
        .ADDR_WIDTH(AW)
      ) bus
    );
      this.bus = bus;
    endfunction

    task reset_master;
      bus.q_addr  <= '0;
      bus.q_op    <= DTM_NOP;
      bus.q_data  <= '0;
      bus.q_valid <= '0;
      bus.p_ready <= '0;
    endtask

    task reset_slave;
      bus.q_ready <= '0;
      bus.p_data  <= '0;
      bus.p_resp  <= '0;
      bus.p_valid <= '0;
    endtask

    task cycle_start;
      #TT;
    endtask

    task cycle_end;
      @(posedge bus.clk_i);
    endtask

    /// Send a request.
    task send_req (input req_t req);
      bus.q_addr  <= #TA req.addr;
      bus.q_op    <= #TA req.op;
      bus.q_data  <= #TA req.data;
      bus.q_valid <= #TA 1;
      cycle_start();

      cycle_end();
      bus.q_addr  <= #TA '0;
      bus.q_op    <= #TA DTM_NOP;
      bus.q_data  <= #TA '0;
      bus.q_valid <= #TA 0;
    endtask

    /// Send a response.
    task send_rsp (input rsp_t rsp);
      bus.p_data  <= #TA rsp.data;
      bus.p_resp   <= #TA rsp.resp;
      bus.p_valid <= #TA 1;
      cycle_start();
      while (bus.p_ready != 1) begin cycle_end(); cycle_start(); end
      cycle_end();
      bus.p_data  <= #TA '0;
      bus.p_resp  <= #TA '0;
      bus.p_valid <= #TA 0;
    endtask

    /// Receive a request.
    task recv_req (output req_t req);
      bus.q_ready <= #TA 1;
      cycle_start();
      while (bus.q_valid != 1) begin cycle_end(); cycle_start(); end
      req = new;
      req.addr  = bus.q_addr;
      req.op    = bus.q_op;
      req.data  = bus.q_data;
      cycle_end();
      bus.q_ready <= #TA 0;
    endtask

    /// Receive a response.
    task recv_rsp (output rsp_t rsp);
      bus.p_ready <= #TA 1;
      cycle_start();
      while (bus.p_valid != 1) begin cycle_end(); cycle_start(); end
      rsp = new;
      rsp.data  = bus.p_data;
      rsp.resp = bus.p_resp;
      cycle_end();
      bus.p_ready <= #TA 0;
    endtask

    /// Monitor request.
    task mon_req (output req_t req);
      cycle_start();
      while (!(bus.q_valid && bus.q_ready)) begin cycle_end(); cycle_start(); end
      req = new;
      req.addr  = bus.q_addr;
      req.op    = bus.q_op;
      req.data  = bus.q_data;
      cycle_end();
    endtask

    /// Monitor response.
    task mon_rsp (output rsp_t rsp);
      cycle_start();
      while (!(bus.p_valid && bus.p_ready)) begin cycle_end(); cycle_start(); end
      rsp = new;
      rsp.data  = bus.p_data;
      rsp.resp = bus.p_resp;
      cycle_end();
    endtask

  endclass

  // Super class for random dmi drivers.
  virtual class rand_dmi #(
    // dmi interface parameters
    parameter int   AW = 32,
    // Stimuli application and test time
    parameter time  TA = 0ps,
    parameter time  TT = 0ps
  );

    typedef dmi_test::dmi_driver #(
      // dmi bus interface parameters;
      .AW ( AW ),
      // Stimuli application and test time
      .TA ( TA ),
      .TT ( TT )
    ) dmi_driver_t;

    dmi_driver_t drv;

    function new(virtual DMI_BUS_DV #( .ADDR_WIDTH (AW)) bus);
      this.drv = new (bus);
    endfunction

    task automatic rand_wait(input int unsigned min, input int unsigned max);
      int unsigned rand_success, cycles;
      rand_success = std::randomize(cycles) with {
        cycles >= min;
        cycles <= max;
        // Weigh the distribution so that the minimum cycle time is the common
        // case.
        cycles dist {min := 10, [min+1:max] := 1};
      };
      assert (rand_success) else $error("Failed to randomize wait cycles!");
      repeat (cycles) @(posedge this.drv.bus.clk_i);
    endtask

  endclass

  /// Generate random requests as a master device.
  class rand_dmi_master #(
    // dmi interface parameters
    parameter int   AW = 32,
    // Stimuli application and test time
    parameter time  TA = 0ps,
    parameter time  TT = 0ps,
    parameter int unsigned REQ_MIN_WAIT_CYCLES = 1,
    parameter int unsigned REQ_MAX_WAIT_CYCLES = 20,
    parameter int unsigned RSP_MIN_WAIT_CYCLES = 1,
    parameter int unsigned RSP_MAX_WAIT_CYCLES = 20
  ) extends rand_dmi #(.AW(AW), .TA(TA), .TT(TT));

    int unsigned cnt = 0;
    bit req_done = 0;

    /// Reset the driver.
    task reset();
      drv.reset_master();
    endtask

    /// Constructor.
    function new(virtual DMI_BUS_DV #( .ADDR_WIDTH (AW)) bus);
      super.new(bus);
    endfunction

    task run(input int n);
      fork
        send_requests(n);
        recv_response();
      join
    endtask

    /// Send random requests.
    task send_requests (input int n);
      automatic req_t r = new;

      repeat (n) begin
        this.cnt++;
        assert(r.randomize());
        rand_wait(REQ_MIN_WAIT_CYCLES, REQ_MAX_WAIT_CYCLES);
        this.drv.send_req(r);
      end
      this.req_done = 1;
    endtask

    /// Receive random responses.
    task recv_response;
      while (!this.req_done || this.cnt > 0) begin
        automatic rsp_t rsp;
        this.cnt--;
        rand_wait(RSP_MIN_WAIT_CYCLES, RSP_MAX_WAIT_CYCLES);
        this.drv.recv_rsp(rsp);
      end
    endtask
  endclass

  class rand_dmi_slave #(
    // dmi interface parameters
    parameter int   AW = 32,
    // Stimuli application and test time
    parameter time  TA = 0ps,
    parameter time  TT = 0ps,
    parameter int unsigned REQ_MIN_WAIT_CYCLES = 0,
    parameter int unsigned REQ_MAX_WAIT_CYCLES = 10,
    parameter int unsigned RSP_MIN_WAIT_CYCLES = 0,
    parameter int unsigned RSP_MAX_WAIT_CYCLES = 10
  ) extends rand_dmi #(.AW(AW), .TA(TA), .TT(TT));

    mailbox req_mbx = new();

    /// Reset the driver.
    task reset();
      drv.reset_slave();
    endtask

    task run();
      fork
        recv_requests();
        send_responses();
      join
    endtask

    /// Constructor.
    function new(virtual DMI_BUS_DV #( .ADDR_WIDTH (AW)) bus);
      super.new(bus);
    endfunction

    task recv_requests();
      forever begin
        automatic req_t req;
        rand_wait(REQ_MIN_WAIT_CYCLES, REQ_MAX_WAIT_CYCLES);
        this.drv.recv_req(req);
        req_mbx.put(req);
      end
    endtask

    task send_responses();
      automatic rsp_t rsp = new;
      automatic req_t req;
      forever begin
        req_mbx.get(req);
        assert(rsp.randomize());
        @(posedge this.drv.bus.clk_i);
        rand_wait(RSP_MIN_WAIT_CYCLES, RSP_MAX_WAIT_CYCLES);
        this.drv.send_rsp(rsp);
      end
    endtask
  endclass

  class dmi_monitor #(
    // dmi interface parameters
    parameter int   AW = 32,
    // Stimuli application and test time
    parameter time  TA = 0ps,
    parameter time  TT = 0ps
  ) extends rand_dmi #(.AW(AW), .TA(TA), .TT(TT));

    mailbox req_mbx = new, rsp_mbx = new;

    /// Constructor.
    function new(virtual DMI_BUS_DV #( .ADDR_WIDTH (AW)) bus);
      super.new(bus);
    endfunction

    // dmi Monitor.
    task monitor;
      fork
        forever begin
          automatic dmi_test::req_t req;
          this.drv.mon_req(req);
          req_mbx.put(req);
        end
        forever begin
          automatic dmi_test::rsp_t rsp;
          this.drv.mon_rsp(rsp);
          rsp_mbx.put(rsp);
        end
      join
    endtask
  endclass

endpackage

while (bus.q_ready != 1) begin cycle_end(); cycle_start(); end


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// File Name: apb_reg_por_read_test.sv
// Author: Farshad
// Email: farshad112@gmail.com
// Revision: 0.1
// Description: power on reset test. Read the default value of the RAM after power on reset.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class apb_reg_por_read_test extends apb_base_test;
    `uvm_component_utils(apb_reg_por_read_test)

    // constructor function
    function new(string name="apb_reg_por_read_test", uvm_component parent=null);
        super.new(name, parent);
    endfunction: new

    // build_phase
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
    endfunction: build_phase

    // connect_phase
    virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
    endfunction: connect_phase

    // run_phase
    virtual task run_phase(uvm_phase phase);

        phase.raise_objection(this);
            // read all memories after reset
            for(int i=0; i< `APB_SRAM_SIZE; i++) begin
                rd_nd_compare_mem(i, 0);
            end
        phase.drop_objection(this);
    endtask: run_phase

endclass: apb_reg_por_read_test


/*****************************************************************************
** Company: Si-Vision & FOE ASU
** Author: AHMED MOSTAFA KAMAL , ADHAM HAZEM ALGENDI AND AHMED MOHAMED AMIN
**
** Create Date:     24/3/2022
** Edited on  :     21/4/2022
** Module Name: asu_ddr5_write_fsm
** Description: this file contains the FSM RTL, the design implementation
** is based on IEEE standard (Std 802.15.4-2011)
**
**
*****************************************************************************/

`timescale 1ns / 1ps

// Defining the module external interface (NAME ,input ports and output ports).
module ddr5_phy_write_fsm
          # (parameter pDRAM_SIZE = 4 ) //DRAM size
(
                   //////input signals ////////////

            input	wire 				clk_i    ,              // system  phy clock

  			input  	wire 				rst_i    ,              // system reset

  			input  	wire 				enable_i ,              // system  block enable

  			input  	wire     			wr_en_i  ,              // write enable signal from freq ratio block

			input  	wire                preamble_valid_i   ,    // valid signal that indcates correct  preamble pattern is sent on dqs signal

			input  	wire				preamble_done_i    ,    // signal that  indicates  that whole preamble pattern is sent

			input  	wire				postamble_done_i   ,    // signal that  indicates  that whole postamble pattern is sent on dqs bus

			input  	wire				interamble_done_i  ,    // signal that  indicates  that whole interamble pattern is sent ondqs bus

			input  	wire				wrdata_crc_done_i  ,    // signal that  indicates  that whole data is sent on DQ bus  (MC crc support)

			input  	wire                wrdata_done_i      ,    // signal that  indicates  that whole data is sent on DQ bus  (phy crc support)

			input  	wire                data_burst_done_i  ,    // signal that indicates data  is sent on DQ bus (burst length = 8)

			input  	wire                wrmask_done_i      ,    // signal that indicates  whole data is sent on DQ bus (data mask)

			input  	wire                crc_generate_i     ,    // indicates that phy will generate crc or not

			input  	wire                interamble_i       ,    // indicates that if there is interamble exist

			input  	wire	[1: 0]		preamble_bits_i    ,    // preamble bits result from shifting preamble pattern

			input  	wire    [1:0]       interamble_bits_i  ,    // interamble bits result from shifting interamble pattern

			input  	wire    [3:0]       gap_i          ,        // signal detect number of cycles at which  write enable is low

			input  	wire    [2*pDRAM_SIZE  -1: 0]	wr_data_i      ,        // input wrdata from freq ratio block

			input  	wire    [(pDRAM_SIZE /4-1):0]	wr_datamask_i  ,        // input data mask  from freq ratio block

			input 	wire    [2*pDRAM_SIZE -1: 0]	crc_code_i     ,        // input crc data from crc block

			input 	wire    [1:0]       burstlength_i  ,        // input burstlength from command block

			  /////////output signals ////////////////

			output  reg                 data_state_o     ,      // output signal indicates  to  write data states

			output  reg 				preamble_state_o ,      // output signal indicates to preamble , postamble ,interamble states

			output  reg  [2*pDRAM_SIZE  -1: 0]	crc_data_o       ,      // output data to crc block

  			output  reg  				crc_enable_o     ,      // output enable to crc block

			output  reg   [1:0]		    dqs_o            ,      // output data strobe to DRAM

  			output  reg   [2*pDRAM_SIZE  -1: 0]   dq_o             ,      // output data to DRAM

			output  reg     			dqs_valid_o      ,      //  output signal indicates that data strobe is sent or not

			output  reg 				dq_valid_o       ,      //  output signal indicates that data  is sent or not

			output  reg   [(pDRAM_SIZE /4-1):0]  	dm_o             ,      // output data mask to DRAM

			output  reg                 interamble_valid_o      // output signal indicates that interamble bits is sent ondqs bus

);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// internal signals and registers

 //state defintions
 typedef enum reg [2:0] {  idle , preamble , wr_data_crc ,  wr_data , data_burst8 ,crc , postamble ,  interamble  }  state_t ;
 state_t current_state , next_state ;

reg [1:0]			dqs  ;
reg [2*pDRAM_SIZE -1 : 0] 	dq ;
reg   				dqs_valid ;
reg  				dq_valid ;
reg [(pDRAM_SIZE /4-1):0]   	dm  ;

// state transition
always_ff @(posedge clk_i or negedge rst_i)
 begin
	if(!rst_i)              // Asynchronous active low reset
	  begin
		current_state <= idle ;
	  end

	else if (enable_i)       // enable fsm
	  begin
	  current_state <= next_state ;
	  end

 end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// next_state and output logic
always_comb
 begin
  case(current_state)
  idle : 		begin
                    dq  = {(2*pDRAM_SIZE){1'b0}} ;
		            dq_valid = 1'b0 ;
			        dm = {(pDRAM_SIZE /4){1'b0}} ;
					dqs = 2'b00 ;
					interamble_valid_o= 1'b0 ;
					dqs_valid = 1'b0 ;
					data_state_o  = 1'b0 ;
					preamble_state_o = 1'b0 ;
			        crc_data_o = {(2*pDRAM_SIZE){1'b0}} ;
                    crc_enable_o = 1'b0 ;

					if(wr_en_i)
					  next_state = preamble;
					else
					  next_state = idle ;
				end

					// no operation in this state, when wr_en is high move to preamble state

  preamble :	begin
                     // preamble pattern is sent ondqs bus ,anddqs valid will be high when the correct pattern is sent
                    dq  = {(2*pDRAM_SIZE){1'b0}};
		            dq_valid = 1'b0 ;
			        dm = {(pDRAM_SIZE /4){1'b0}} ;
             	    dqs = preamble_bits_i ;
				    interamble_valid_o= 1'b0 ;
			        dqs_valid = preamble_valid_i ;
				    data_state_o  = 1'b0 ;
				    preamble_state_o = 1'b1 ;
			     	crc_data_o = {(2*pDRAM_SIZE){1'b0}} ;
                    crc_enable_o = 1'b0 ;

					 // when preamble is sent ondqs bus and check crc_generate_i if low then move to wr_data_crc or if crc_generate_i is high then move to wr_data

                    if (  preamble_done_i && !crc_generate_i )
					  next_state = wr_data_crc ;
					else if (   preamble_done_i && crc_generate_i  )
					  next_state = wr_data ;
					else
					  next_state = preamble ;
				end

  wr_data_crc  : begin                                       // (MC crc support or data mask)
                       // wr_data from MC will be sent on dq bus with dq_valid ,dqS will be phy _clock,wrdata mask is sent on dm bus
                    dq  = wr_data_i ;
		            dq_valid = 1'b1 ;
			        dm = wr_datamask_i  ;
					dqs = 2'b10 ;
				    interamble_valid_o= 1'b0 ;
			        dqs_valid = 1'b1 ;
					data_state_o  = 1'b1 ;
					preamble_state_o = 1'b0 ;
			        crc_data_o = {(2*pDRAM_SIZE){1'b0}} ;
                    crc_enable_o = 1'b0 ;

				     // when data is sent on  dq bus and check i_interamble if high move to interamble state ,if low move to postamble
					if( !interamble_i && (wrdata_crc_done_i|| wrmask_done_i)  )
					  next_state = postamble ;
					else if (  interamble_i &&(wrdata_crc_done_i|| wrmask_done_i)  )
					  next_state = interamble ;
					else
					  next_state = wr_data_crc;
				 end

					// when data is sent on  dq bus and check interamble_i if high move to interamble state ,if low move to postamble

	wr_data  :	begin                     // (phy crc support)
	                  // data will be sent on dq bus and to crc block to generate crc anddqs will be phy _clock
	                dq  = wr_data_i ;
		            dq_valid = 1'b1 ;
			        dm = {(pDRAM_SIZE /4){1'b0}}  ;
			        dqs = 2'b10 ;
				    interamble_valid_o= 1'b0 ;
			        dqs_valid = 1'b1 ;
                    crc_data_o = wr_data_i ;
                    crc_enable_o = 1'b1 ;
				    data_state_o  = 1'b1 ;
				    preamble_state_o = 1'b0 ;

                    // when data is sent on dq bus and checkburstlength_i if burstlength_i = 8 ,move to data_burst8 state
					if(burstlength_i == 2'b01 && data_burst_done_i  )
					  next_state = data_burst8 ;
					else if (wrdata_done_i)
					  next_state = crc ;
					else
					 next_state = wr_data;
				end

	data_burst8  : begin           	// (i_burstlength = 8)

	             // rest of wr_data will be completed with ones and sent it on dq bus and crc block
		            dq_valid = 1'b1 ;                 //(burstlength =8)
				    dq  = {(2*pDRAM_SIZE){1'b1}} ;              // rest of wr_data will be completed with ones and sent it on dq bus and crc block
			        dm = {(pDRAM_SIZE /4){1'b0}}  ;
					dqs = 2'b10 ;
					interamble_valid_o= 1'b0 ;
					dqs_valid = 1'b1 ;
				    crc_data_o = {(2*pDRAM_SIZE){1'b1}} ;
                    crc_enable_o = 1'b1 ;
					data_state_o  = 1'b1 ;
					preamble_state_o= 1'b0 ;

					// when rest of  wr_data is sent on dq bus move to crc state
					if(wrdata_done_i  )
					  next_state = crc ;
					else
					  next_state = data_burst8;
				  end

	crc      :   begin            	// (phy crc support)
	                // crc code is taken from crc block and sent it after data on dq bus
                    // sends interamble_valid to shift register to shift interamble pattern
	                dq  = crc_code_i ;
		            dq_valid = 1'b1 ;
			        dm = {(pDRAM_SIZE /4){1'b0}} ;
			        dqs = 2'b10 ;
				    interamble_valid_o = 1'b1 ;
			        dqs_valid = 1'b1 ;
				    crc_data_o = {(2*pDRAM_SIZE){1'b0}} ;
				    crc_enable_o = 1'b1 ;
				    data_state_o  = 1'b0 ;
			    	preamble_state_o = 1'b0 ;

                   // check interamble_i if high move to interamble state ,if not move to postamble state
					if (gap_i ==3'b001 )

				end

  postamble     : begin
                         // postaamble pattern is sent ondqs bus
                    dq  = {(2*pDRAM_SIZE){1'b0}} ;
		            dq_valid = 1'b0 ;
			        dm = {(pDRAM_SIZE /4){1'b0}}  ;
			        dqs = 2'b00 ;
				    interamble_valid_o= 1'b1 ;
			        dqs_valid = 1'b1 ;
				    crc_data_o = {(2*pDRAM_SIZE){1'b0}} ;
                    crc_enable_o = 1'b0 ;
				    data_state_o  = 1'b0 ;
				    preamble_state_o = 1'b0 ;

					  // when postamble pattern is sent ondqs bus , check wr_en_i if high move to preamble state ,if low move to idle
					if (postamble_done_i && !wr_en_i)
					  next_state =idle ;
					else if (  postamble_done_i && wr_en_i  )
					  next_state = preamble ;
					else
					  next_state = postamble;
				end

   interamble   :begin
                          // interamble pattern is sent ondqs bus
                    dq  = {(2*pDRAM_SIZE){1'b0}} ;
		            dq_valid = 1'b0 ;
			        dm = {(pDRAM_SIZE /4){1'b0}}  ;
			        dqs =  interamble_bits_i ;
				    interamble_valid_o= 1'b1 ;
			        dqs_valid = 1'b1 ;
					crc_data_o = {(2*pDRAM_SIZE){1'b0}} ;
					data_state_o  = 1'b0 ;
					preamble_state_o = 1'b0 ;
					crc_enable_o = 1'b0 ;
					   // when interamble pattern is ent ondqs ,check crc_generate_i if low then move to wr_data_crc , if crc_generate_i is high then move to wr_data

					if (interamble_done_i&&crc_generate_i)
					  next_state = wr_data ;
					else if (interamble_done_i&&!crc_generate_i)
					  next_state = wr_data_crc ;
					else
					  next_state = interamble;

				end

   default : begin
					dq_valid = 1'b0 ;
					dm = {(pDRAM_SIZE /4){1'b0}}  ;
					dqs = 2'b00;
					interamble_valid_o= 1'b0 ;
					dqs_valid = 1'b0 ;
					crc_enable_o = 1'b0 ;
					next_state = idle ;
             end
    endcase

 end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// registered output
always_ff @(posedge clk_i or negedge rst_i)
  begin
	if(!rst_i)              // Asynchronous active low reset
	  begin
		dq_o <= {(2*pDRAM_SIZE){1'b0}} ;
		dqs_o <= 2'b00 ;
		dq_valid_o <= 1'b0;
        dqs_valid_o <=1'b0  ;
       	dm_o <= 	{(pDRAM_SIZE /4){1'b0}}  ;
	  end

	else if (enable_i)       // enable fsm
	  begin
	    dq_o <= dq ;
		dqs_o <=dqs ;
		dq_valid_o  <= dq_valid ;
        dqs_valid_o <=dqs_valid  ;
       	dm_o <= dm;
	  end
 end

endmodule

					  next_state = wr_data ;
					else if (interamble_i)
					  next_state = interamble ;


//  ###########################################################################
//
//  Licensed to the Apache Software Foundation (ASF) under one
//  or more contributor license agreements.  See the NOTICE file
//  distributed with this work for additional information
//  regarding copyright ownership.  The ASF licenses this file
//  to you 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.
//
//  ###########################################################################

class axi_virtual_seqr extends uvm_sequencer #(axi_seq_item);

	axi_master_sequencer mstr_vseqr_h;
	axi_slave_sequencer slv_vseqr_h;

//Fatory Registration
	`uvm_component_utils(axi_virtual_seqr)

//Constructor

    	super.new(name, parent);
	endfunction

	function void build_phase (uvm_phase phase);
		super.build_phase(phase);
	endfunction

endclass

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


/*******************************************************************************
** ? Copyright 2010 - 2011 Xilinx, Inc. All rights reserved.
** This file contains confidential and proprietary information of Xilinx, Inc. and
** is protected under U.S. and international copyright and other intellectual property laww
w
s.
*******************************************************************************
**   ____  ____
**  /   /\/   /
** /___/  \  /   Vendor: Xilinx
** \   \   \/
**  \   \
**  /   /
** /___/   /\
** \   \  /  \   Virtex-7 XT Connectivity Domain Targeted Reference Design
**  \___\/\___\
**
**  Device: xc7k325t-ffg900-2
**  Version: 1.0
**
*******************************************************************************
**
*******************************************************************************/

/******************************************************************************
The module performs address filtering on the receive. The receive logic FSM detects
a good frame and makes it available to the packet FIFO interface. Two state machines
are implemented: one FSM covers the write data from XGEMAC interface and another FSM controls
the read logic to packet FIFO
*******************************************************************************/

`timescale 1ps / 1ps

module rx_interface #(
    parameter      FIFO_CNT_WIDTH = 11
)
(
    input [63:0]   axi_str_tdata_from_xgmac,
    input [7:0]    axi_str_tkeep_from_xgmac,
    input          axi_str_tvalid_from_xgmac,
    input          axi_str_tlast_from_xgmac,
    input          axi_str_tuser_from_xgmac,

    input          axi_str_tready_from_fifo,

    output [63:0]  axi_str_tdata_to_fifo,
    output [7:0]   axi_str_tkeep_to_fifo,
    output         axi_str_tvalid_to_fifo,
    output         axi_str_tlast_to_fifo,
    output [15:0]  rd_pkt_len,
    output reg     rx_fifo_overflow = 1'b0,

    input  [13:0]  rx_statistics_vector,
    input          rx_statistics_valid,

    output [FIFO_CNT_WIDTH-1:0]  rd_data_count ,

    input          user_clk,
    input          reset

);

  //Wire declaration
  //wire                       broadcast_detect;
  //wire [47:0]                rx_mac_id_i;
  wire                       axis_rd_tlast;
  wire                       axis_rd_tvalid;
  wire [63:0]                axis_rd_tdata;
  wire [7:0]                 axis_rd_tkeep;
  wire                       axis_wr_tlast;
  wire                       axis_wr_tvalid;
  wire [63:0]                axis_wr_tdata;
  wire [7:0]                 axis_wr_tkeep;
  //wire                       da_match ;
  wire                       full;
  wire                       empty;
  wire                       valid_cmd;
  wire                       crc_pass;
  wire [15:0]                cmd_out;
  wire                       axis_wr_tready;
  wire [FIFO_CNT_WIDTH-1:0]  wr_data_count ;
  wire [FIFO_CNT_WIDTH-1:0]  left_over_space_in_fifo;
  wire                       wr_reached_threshold;
  wire                       wr_reached_threshold_extend;
  //wire [47:0]                mac_id_sync;
  //wire                       mac_id_valid_sync;
  //wire                       promiscuous_mode_en_sync;
  wire                       frame_len_ctr_valid;

  //Reg declaration
  reg  [63:0]  axi_str_tdata_from_xgmac_r ;
  reg  [7:0]   axi_str_tkeep_from_xgmac_r ;
  reg          axi_str_tvalid_from_xgmac_r;
  reg          axi_str_tlast_from_xgmac_r ;
  reg          axi_str_tuser_from_xgmac_r ;
  reg          force_tlast_to_fifo='d0 ;
  reg          address_chk_en = 'd0;
  reg          assert_rd='d0;
  reg  [15:0]  cmd_in = 'd0;
  reg          wr_en=1'b0;
  reg          rd_en=1'b0;
  reg          axis_rd_tready='d0 ;
  reg          axis_rd_tvalid_from_fsm=1'b0;
  reg  [3:0]   tkeep_decoded_value;
//  reg          axi_str_tvalid_from_fsm=1'b0;
  reg  [12:0]  rd_pkt_len_count='d0;
  reg  [13:0]  rx_stats_vec_reg='d0;

  reg  [3:0]   frame_len_ctr;

localparam
   //states for Write FSM
   IDLE_WR       = 4'b0001,
   DA_DECODE     = 4'b0010,
   BEGIN_WRITE   = 4'b0100,
   DROP_FRAME    = 4'b1000,

   //states for Read FSM
   IDLE_RD         = 4'b0001,
   PREP_READ_1     = 4'b0010,
   PREP_READ_2     = 4'b0100,
   BEGIN_READ      = 4'b1000;

localparam   THRESHOLD           = 200;
localparam   THRESHOLD_EXT       = 400;

  reg  [3:0]   state_wr = IDLE_WR;
  reg  [3:0]   state_rd = IDLE_RD;

  //Synchronize mac_id, promiscuous_mode_en and mac_id_valid with the destination clock
  /*synchronizer_simple #(.DATA_WIDTH (1)) sync_to_mac_clk_0
  (
   .data_in          (promiscuous_mode_en),
   .new_clk          (user_clk),
   .data_out         (promiscuous_mode_en_sync)
  );

  synchronizer_simple #(.DATA_WIDTH (1)) sync_to_mac_clk_1
  (
   .data_in          (mac_id_valid),
   .new_clk          (user_clk),
   .data_out         (mac_id_valid_sync)
  );

  synchronizer_simple #(.DATA_WIDTH (48)) sync_to_mac_clk_2
  (
   .data_in          (mac_id),
   .new_clk          (user_clk),
   .data_out         (mac_id_sync)
  );*/

  //assign broadcast_detect = ((axi_str_tdata_from_xgmac_r[47:0]== {48{1'b1}}) &&  (address_chk_en == 1'b1))?1'b1:1'b0;

  //assign rx_mac_id_i = (address_chk_en == 1'b1)?axi_str_tdata_from_xgmac_r[47:0]:48'b0;

  //assign da_match = ((rx_mac_id_i == mac_id_sync) & mac_id_valid_sync)?1'b1:1'b0;

  //Add a pipelining stage for received data from xgemac interface.
  //This is necessary for FSM control logic
  always @(posedge user_clk)
  begin
         axi_str_tdata_from_xgmac_r   <= axi_str_tdata_from_xgmac;
         axi_str_tkeep_from_xgmac_r   <= axi_str_tkeep_from_xgmac;
         axi_str_tvalid_from_xgmac_r  <= axi_str_tvalid_from_xgmac;
         axi_str_tlast_from_xgmac_r   <= axi_str_tlast_from_xgmac;
         axi_str_tuser_from_xgmac_r   <= axi_str_tuser_from_xgmac;
  end

  begin
    assign axis_wr_tvalid = (state_wr==DROP_FRAME) ? 1'b0 :
   (axi_str_tvalid_from_xgmac_r | (force_tlast_to_fifo & (state_wr == BEGIN_WRITE)));
  end

  assign axis_wr_tlast  = (axi_str_tlast_from_xgmac_r | force_tlast_to_fifo);
  assign axis_wr_tkeep  = axi_str_tkeep_from_xgmac_r;
  assign axis_wr_tdata  = axi_str_tdata_from_xgmac_r;

  //Register Rx statistics vector to be used in the read FSM later
  //Rx statistics is valid only if rx_statistics_valid is asserted
  //from XGEMAC
  //- bits 18:5 in stats vector provide frame length including FCS, hence
  //subtract 4 bytes to get the frame length only.
  always @(posedge user_clk)
  begin
       if(rx_statistics_valid)
             rx_stats_vec_reg <= rx_statistics_vector[13:0] - 14'd4;
  end

  assign left_over_space_in_fifo = {1'b1,{(FIFO_CNT_WIDTH-1){1'b0}}} - wr_data_count[FIFO_CNT_WIDTH-1:0];

  assign wr_reached_threshold        = (left_over_space_in_fifo < THRESHOLD)?1'b1:1'b0;
  assign wr_reached_threshold_extend = (left_over_space_in_fifo < THRESHOLD_EXT)?1'b1:1'b0;

  always @(posedge user_clk)
  begin
        if(force_tlast_to_fifo)
             force_tlast_to_fifo <= 1'b0;
        else if(wr_reached_threshold & !(axi_str_tlast_from_xgmac & axi_str_tvalid_from_xgmac))
             force_tlast_to_fifo <= 1'b1;
  end

  // Counter to count frame length when length is less than 64B
  // For frame length less than 64B, XGEMAC core reports length including the
  // padded characters. To overcome this situation, a separate counter is implemented
  always @(posedge user_clk)
  begin
        if (reset)
            frame_len_ctr <= 'd0;
        else if (axi_str_tlast_from_xgmac & axi_str_tvalid_from_xgmac)
            frame_len_ctr <= 'd0;
        else if (frame_len_ctr > 4'h8)
            frame_len_ctr <= frame_len_ctr;
        else if(axi_str_tvalid_from_xgmac)
            frame_len_ctr <= frame_len_ctr+1;
  end

  assign frame_len_ctr_valid = (frame_len_ctr != 0) & (frame_len_ctr < 8) & axi_str_tvalid_from_xgmac & axi_str_tlast_from_xgmac;

  // Decoder for TKEEP signal
  always @(axi_str_tkeep_from_xgmac)
   case(axi_str_tkeep_from_xgmac)
      'h00 : tkeep_decoded_value <= 'd0;
      'h01 : tkeep_decoded_value <= 'd1;
      'h03 : tkeep_decoded_value <= 'd2;
      'h07 : tkeep_decoded_value <= 'd3;
      'h0F : tkeep_decoded_value <= 'd4;
      'h1F : tkeep_decoded_value <= 'd5;
      'h3F : tkeep_decoded_value <= 'd6;
      'h7F : tkeep_decoded_value <= 'd7;
      'hFF : tkeep_decoded_value <= 'd8;
      default : tkeep_decoded_value <= 'h00;
   endcase

  //Two FIFOs are implemented: one for XGEMAC data(data FIFO) and the other for controlling
  //read side command(command FIFO).
  //Write FSM: 6 states control the entire write operation
  //cmd_in is an input to the command FIFO and controls the read side command
  //Ethernet packet frame size is available from Rx statistics vector and is
  //made available to the read side through command FIFO
  //FSM states:
  //IDLE_WR  : Wait in this state until valid is received from XGEMAC. If the
  //           data FIFO is full or tready is de-asserted from FIFO interface
  //           it drops the current frame from XGEMAC
  //DA_DECODE: Destination Address from XGEMAC is decoded in this state. If destination
  //           address matches with MAC address or promiscuous mode is enabled
  //           or broadcast is detected, next state is BEGIN_WRITE. Else the FSM transitions
  //           to IDLE_WR state
  //BEGIN_WRITE: The FSM continues to write data into data FIFO until tlast from XGEMAC is hit.
  //             FSM transitions to CHECK_ERROR state if tlast has arrived
  //DROP_FRAME: The FSM enters into this state if the data FIFO is full or tready from data FIFO is de-asserted
  //            In this state, tvalid to FIFO is de-asserted
always @(posedge user_clk)
  begin
         if(reset)
                 state_wr  <= IDLE_WR;
         else
         begin
             case(state_wr)
                  IDLE_WR : begin
                             cmd_in           <= 'b0;
                             wr_en            <= 1'b0;

                             if(axi_str_tvalid_from_xgmac & (full | wr_reached_threshold))
                             begin
                                  state_wr                <=  DROP_FRAME;
                             end
                             else if(axi_str_tvalid_from_xgmac)
                             begin
                                  state_wr       <=  DA_DECODE;
                             end
                             else
                             begin
                                  state_wr       <=  IDLE_WR;
                             end
                             end
                  DA_DECODE : begin

          ((frame_len_ctr << 3) + tkeep_decoded_value) : rx_stats_vec_reg;
                             if(force_tlast_to_fifo)
                             begin
                                    wr_en     <= 1'b1;
                                    cmd_in[0] <= 1'b0;
                                    state_wr  <= DROP_FRAME;
                             end
                             else if(axi_str_tlast_from_xgmac & axi_str_tvalid_from_xgmac)
                             begin
                                    wr_en            <= 1'b1;
                                    cmd_in[0] <= axi_str_tuser_from_xgmac;
                                    state_wr <= IDLE_WR;
                             end
                             else
                             begin
                                    wr_en            <= 1'b0;
                                    cmd_in[0] <= 1'b0;
                                    state_wr <= BEGIN_WRITE;
                             end
                             end
                  DROP_FRAME : begin
                             wr_en            <= 1'b0;
                               if(axi_str_tlast_from_xgmac_r & axi_str_tvalid_from_xgmac_r & !wr_reached_threshold_extend)

                               begin
                                  //- signals a back 2 back packet
                                 if(axi_str_tvalid_from_xgmac)
                                 begin
                                      state_wr       <=  DA_DECODE;
                                 end
                                 else
                                    state_wr    <= IDLE_WR;
                               end
                               else
                                    state_wr    <= DROP_FRAME;
                               end
                   default :   state_wr    <= IDLE_WR;
             endcase
          end
  end

  assign  valid_cmd  = cmd_out[1];
  assign  crc_pass   = ~cmd_out[0];
  assign  rd_pkt_len = {2'b0,cmd_out[15:2]};

  //Read FSM reads out the data from data FIFO and present it to the packet FIFO interface
  //The read FSM starts reading data from the data FIFO as soon as it decodes a valid command
  //from the command FIFO. Various state transitions are basically controlled by the command FIFO
  //empty flag and tready assertion from packet FIFO interface
  //FSM states
  //IDLE_RD: The FSM stays in this state until command FIFO empty is de-asserted and tready from packet
  //         FIFO interface is active low.
  //PREP_READ_1: This is an idle cycle, used basically to de-assert rd_en so that command FIFO is read only
  //             once
  //PREP_READ_2: If the decoded command from command FIFO is valid and CRC detects no error for the frame
  //             the FSM transitions to BEGIN_READ state. tready to FIFO is controlled by tready
  //             from the packet FIFO interface. If CRC fails for a frame, the entire frame is dropped
  //             by de-asserting tvalid to packet FIFO interface
  //BEGIN_READ: In this state, the FSM reads data until tlast from XGEMAC is encountered
  always @(posedge user_clk)
  begin
         if(reset)
         begin
                 state_rd  <= IDLE_RD;
         end
         else
         begin
             case(state_rd)
                  IDLE_RD : begin
                             if(axi_str_tready_from_fifo & !empty)
                             begin
                                  state_rd <=  PREP_READ_1;
                                  rd_en    <=  1'b1;
                             end
                             else
                             begin
                                  state_rd <=  IDLE_RD;
                             end
                             end
                  PREP_READ_1 : begin
                             rd_en    <= 1'b0;
                             state_rd <= PREP_READ_2;
                             end
                  PREP_READ_2 : begin
                             //Continue reading data if CRC passes for a forthcoming frame
                             //CRC check is passed through command FIFO from write side logic
                             if(valid_cmd & crc_pass)
                             begin
                                  state_rd                <= BEGIN_READ;
                             end
                             else
                             begin
                                  state_rd                <= BEGIN_READ;
                             end
                             end
                  BEGIN_READ : begin
                             //Continue reading data until tlast from XGEMAC is received
                             if(axis_rd_tlast & axis_rd_tvalid & axis_rd_tready)
                             begin
                                  state_rd                <= IDLE_RD;
                             end
                             else
                             begin
                                  state_rd                <= BEGIN_READ;
                             end
                             end
                  default    :   state_rd                <= IDLE_RD;
             endcase
         end
  end

  always @(state_rd, valid_cmd, crc_pass,axis_rd_tlast,axis_rd_tvalid,axi_str_tready_from_fifo)
  begin
       if(state_rd==PREP_READ_2)
       begin
               if(valid_cmd & crc_pass)
               begin
                    axis_rd_tready          <= axi_str_tready_from_fifo;
                    axis_rd_tvalid_from_fsm <= axis_rd_tvalid;
                   // rd_pkt_len_count <= rd_pkt_len;
               end
               else
               begin
                    axis_rd_tready          <= 1'b1;
                    axis_rd_tvalid_from_fsm <= 1'b0;
               end
       end
       else if(state_rd==BEGIN_READ)
       begin
        if (valid_cmd & crc_pass)
        begin
               //if (rd_pkt_len_count >
               axis_rd_tready          <= axi_str_tready_from_fifo;
               axis_rd_tvalid_from_fsm <= axis_rd_tvalid;
               //rd_pkt_len_count <= rd_pkt_len_count -= 8;
        end
        else
        begin
               axis_rd_tready          <= 1'b1;
               axis_rd_tvalid_from_fsm <= 1'b0;
        end
       end
       else
       begin
              axis_rd_tready          <= 1'b0;
              axis_rd_tvalid_from_fsm <= 1'b0;
       end
  end

  //-Data FIFO instance: AXI Stream Asynchronous FIFO
  //XGEMAC interface outputs an entire frame in a single shot
  //TREADY signal from slave interface of FIFO is left unconnected
  axis_sync_fifo axis_fifo_inst1 (
    .m_axis_tready        (axis_rd_tready           ),
    .s_aresetn            (~reset                   ),
    .s_axis_tready        (axis_wr_tready           ),
    //.s_aclk               (user_clk                 ),
    .s_axis_tvalid        (axis_wr_tvalid           ),
    .m_axis_tvalid        (axis_rd_tvalid           ),
    .s_aclk               (user_clk                 ),
    .m_axis_tlast         (axis_rd_tlast            ),
    .s_axis_tlast         (axis_wr_tlast            ),
    .s_axis_tdata         (axis_wr_tdata            ),
    .m_axis_tdata         (axis_rd_tdata            ),
    .s_axis_tkeep         (axis_wr_tkeep            ),
    .m_axis_tkeep         (axis_rd_tkeep            ),
    //.axis_rd_data_count   (rd_data_count            ),
    //.axis_wr_data_count   (wr_data_count            )
    .axis_data_count   (wr_data_count            ) //1024 items = [10:0]
  );

  //command FIFO interface for controlling the read side interface
  cmd_fifo_xgemac_rxif cmd_fifo_inst (
        .clk         (user_clk   ),
        .rst         (reset      ),
        .din         (cmd_in     ), // Bus [15 : 0]
        .wr_en       (wr_en      ),
        .rd_en       (rd_en      ),
        .dout        (cmd_out    ), // Bus [15 : 0]
        .full        (full       ),
        .empty       (empty      )
  );

  assign  axi_str_tdata_to_fifo  = axis_rd_tdata;
  assign  axi_str_tkeep_to_fifo  = axis_rd_tkeep;
  assign  axi_str_tlast_to_fifo  = axis_rd_tlast;
  assign  axi_str_tvalid_to_fifo = axis_rd_tvalid_from_fsm;

 always @(posedge user_clk)
    if (reset)
      rx_fifo_overflow  <= 1'b0;
    else if (state_wr==DROP_FRAME)
      rx_fifo_overflow  <= 1'b1;

/*wire [35:0] control0;
wire [35:0] control1;
wire [63:0] vio_signals;
wire [127:0] debug_signal;

icon icon_isnt
(
  .CONTROL0 (control0),
  .CONTROL1 (control1)
);

ila ila_inst
(
    .CLK (user_clk),
    .CONTROL (control0),
    .TRIG0 (debug_signal)
);

vio vio_inst
(
    .CLK (user_clk),
    .CONTROL (control1),
    .SYNC_OUT (vio_signals)
);

reg[2:0] pkg_count;

always @(posedge user_clk)
begin
    if (reset == 1) begin
        pkg_count <= 3'b000;
    end
    else begin
        if ((axi_str_tvalid_from_xgmac == 1'b1) && (axi_str_tlast_from_xgmac == 1'b1)) begin
            pkg_count <= pkg_count + 1;
        end
    end
end

assign debug_signal[3:0] =  frame_len_ctr;
assign debug_signal[4] = frame_len_ctr_valid;
assign debug_signal[8:5] = state_wr;
assign debug_signal[12:9] = state_rd;
assign debug_signal[28:13] = cmd_in;
assign debug_signal[31:29] = cmd_out[3:0];
assign debug_signal[63:32] = axi_str_tdata_from_xgmac[31:0];
assign debug_signal[71:64] = axi_str_tkeep_from_xgmac;
assign debug_signal[72] = axi_str_tvalid_from_xgmac;
assign debug_signal[73] = rx_statistics_valid;
assign debug_signal[87:74] = rx_stats_vec_reg;
assign debug_signal[105:90] = axi_str_tdata_to_fifo[15:0];
assign debug_signal[113:106] = axi_str_tkeep_to_fifo;
assign debug_signal[114] = axi_str_tvalid_to_fifo;
assign debug_signal[115] = axi_str_tready_from_fifo;
//assign debug_signal[118:116] = rx_stats_vec_reg[2:0];
//assign debug_signal[116] = ap_ready;
//assign debug_signal[117] = ap_done;
//assign debug_signal[118] = ap_idle;
assign debug_signal[119] = axi_str_tlast_from_xgmac;
assign debug_signal[120] = axi_str_tlast_to_fifo;
assign debug_signal[123:121] = pkg_count;
assign debug_signal[124] = force_tlast_to_fifo;

assign debug_signal[125] = axis_rd_tvalid;
assign debug_signal[126] = axis_rd_tready;
assign debug_signal[127] = axis_rd_tlast;*/

endmodule

                             wr_en            <= 1'b0;
                             cmd_in[1]      <= 1'b1;

                                    state_wr <= BEGIN_WRITE;


/*
    Karlsen Fast Ladder low-pass filter.

    Pipelined version that only requires 1 18x18 multiplier block.

    Inspired by:
    https://www.musicdsp.org/en/latest/Filters/240-karlsen-fast-ladder.html

    Translated to Verilog by Seb (me@sebholzapfel.com)

    Note on parameters and fixed point scaling:
    - g = cutoff = tan(pi * cutoff_freq / fs) => (0 is 0, 1 is about 0.2fs)
       -> Fixed point we expect g is in [0, 32768], where 32678 represents 1 (0.2fs)
    - resonance scales from 0 to 4 (where 4 is far in self-oscillation)
       -> Fixed point we expect resonance in [0, 32768] wher 32768 scales to 2.
*/

`default_nettype none

// Helper module to perform one `a + (b - a) * scale` operation. The
// ladder filter does this operation 5 times in a row so this is shared.
module smul_shift_18x18 (
    input signed [17:0] a,
    input signed [17:0] b,

    input rst,
    input clk,
    input strobe,
    // See header comment for what these parameters mean.
    input signed [W-1:0] g,
    input signed [W-1:0] resonance,
    input signed [W-1:0] sample_in,
    output logic signed [W-1:0] sample_out
);

`define CLAMP(x) ((x>MAX)?MAX:((x<MIN)?MIN:x))
`define CLAMP_POSITIVE(x) ((x<0)?0:WMULT'(x))

localparam WMULT = 18; // Width of multiplier input
localparam signed [WMULT-1:0] MAX = (2**(W-1))-1;
localparam signed [WMULT-1:0] MIN = -(2**(W-1));

logic [3:0] state;

logic signed [WMULT-1:0] in_ex;
logic signed [WMULT-1:0] g_ex;
logic signed [WMULT-1:0] resonance_ex;

logic signed [WMULT-1:0] clip;
logic signed [WMULT-1:0] a1;
logic signed [WMULT-1:0] a2;
logic signed [WMULT-1:0] a3;
logic signed [WMULT-1:0] a4;

logic signed [WMULT-1:0] smul_a, smul_b, smul_scale;
logic signed [35:0] smul_out;

assign in_ex = WMULT'(sample_in);
assign g_ex = `CLAMP_POSITIVE(g);
assign resonance_ex = `CLAMP_POSITIVE(resonance) <<< 2;

smul_shift_18x18 multiplier(.a(smul_a), .b(smul_b), .scale(smul_scale), .o(smul_out));

always_ff @(posedge clk) begin
    if (rst) begin
        state <= 0;
        a1 <= 0;
        a2 <= 0;
        a3 <= 0;
        a4 <= 0;
        sample_out <= 0;
    end else begin
        if (strobe) begin
            state <= 0;
        end else begin
            if (state < 8)
                state <= state + 1;
            case (state)
                0: begin
                    // Resonance
                    // rezz <= (in_ex - (((W2'(sample_out) - in_ex) * resonance_ex) >>> W));
                    smul_a <= WMULT'(in_ex);
                    smul_b <= a4;
                    smul_scale <= resonance_ex;
                end
                1: begin
                    // Fix sign of smul_shift operation
                    clip <= (in_ex<<<1) - WMULT'(smul_out);
                end
                2: begin
                    // Saturation (simplified)
                    clip <= `CLAMP(clip);
                end
                3: begin
                    // a1 <= a1 + (((-a1 + sat) * g_ex) >>> W);
                    smul_a <= a1;
                    smul_b <= clip;
                    smul_scale <= g_ex;
                end
                4: begin
                    // a2 <= a2 + (((-a2 + a1) * g_ex) >>> W);
                    a1 <= WMULT'(smul_out);
                    smul_a <= a2;
                    smul_b <= WMULT'(smul_out);
                end
                5: begin
                    // a3 <= a3 + (((-a3 + a2) * g_ex) >>> W);
                    a2 <= WMULT'(smul_out);
                    smul_a <= a3;
                    smul_b <= WMULT'(smul_out);
                end
                6: begin
                    // a4 <= a4 + (((-a4 + a3) * g_ex) >>> W);
                    a3 <= WMULT'(smul_out);
                    smul_a <= a4;
                    smul_b <= WMULT'(smul_out);
                end
                7: begin
                    a4 <= WMULT'(smul_out);
                    sample_out <= smul_out[W-1:0];
                end
                default: begin
                    // Sit here until next sample.
                end
            endcase
        end
    end
end

`ifdef COCOTB_SIM
initial begin
  $dumpfile ("karlsen_lpf_pipelined.vcd");
  $dumpvars;
  #1;
end
`endif

endmodule

    input signed [17:0] scale,
    output signed [35:0] o
);
assign o = 36'(a) + (36'(18'(-a + b) * 18'(scale)) >>> 16);
endmodule


    input logic arst_n
);

    // Instruction memory signals
    logic        instr_rvalid;
    logic [31:0] instr_rdata;
    logic        instr_req;
    logic [31:0] instr_addr;

    // Data memory signals
    logic        data_rvalid;
    logic [31:0] data_rdata;
    logic        data_req;
    logic [31:0] data_wdata;
    logic [31:0] data_addr;
    logic        data_we;
    logic [ 3:0] data_be;

    function void get_bus_status (
        miriscv_test_pkg::miriscv_mem_item t
    );
        t.instr_rvalid = instr_rvalid;
        t.instr_rdata  = instr_rdata;
        t.instr_req    = instr_req;
        t.instr_addr   = instr_addr;
        t.data_rvalid  = data_rvalid;
        t.data_rdata   = data_rdata;
        t.data_req     = data_req;
        t.data_wdata   = data_wdata;
        t.data_addr    = data_addr;
        t.data_we      = data_we;
        t.data_be      = data_be;
    endfunction

    task wait_clks(input int num);
      repeat (num) @(posedge clk);
    endtask

    task wait_neg_clks(input int num);
      repeat (num) @(negedge clk);
    endtask

endinterface


`timescale 1ns/1ps
`default_nettype none

module gradient_descent (
    input logic clk,
    input logic rst,

    // learning rate
    input logic [15:0] lr_in,

    // old weight
    input logic [15:0] value_old_in,

    // gradient
    input logic [15:0] grad_in,

    // start signal
    input logic grad_descent_valid_in,

    // bias or weight
    input logic grad_bias_or_weight,

    // updated weight and done signal
    output logic [15:0] value_updated_out,
    output logic grad_descent_done_out
);

    logic [15:0] sub_value_out;
    logic grad_descent_in_reg;
    logic [15:0] sub_in_a;
    logic [15:0] mul_out;

    fxp_mul mul_inst (
        .ina(grad_in),
        .inb(lr_in),
        .out(mul_out),
        .overflow()
    );

    fxp_addsub sub_inst (
        .ina(sub_in_a),
        .inb(mul_out),
        .sub(1'b1),
        .out(sub_value_out),
        .overflow()
    );

    always_comb begin
        case(grad_bias_or_weight)
            1'b0: begin
                if(grad_descent_done_out) begin
                    sub_in_a = value_updated_out;
                end else begin
                    sub_in_a = value_old_in;
                end
            end

                sub_in_a = value_old_in;
            end
        endcase
    end

    always_ff @(posedge clk or posedge rst) begin
        if(rst) begin
            sub_in_a <= '0;
            value_updated_out <= '0;
            grad_descent_done_out <= '0;
        end else begin
            grad_descent_done_out <= grad_descent_valid_in;
            if(grad_descent_valid_in) begin
                value_updated_out <= sub_value_out;
            end else begin
                value_updated_out <= '0;
            end
        end
    end

endmodule


//////////////////////////////////////////////////////////////////////////////////
// Engineer: 		Travis
//
// Create Date: 	12/17/2020 Thu 10:30
// Filename: 		ahb2apb_scb.svh
// class Name: 		ahb2apb_scb
// Project Name: 	ahb2apb_bridge
// Revision 0.01 - File Created
// Additional Comments:
// -------------------------------------------------------------------------------
// 	-> Compare AHBL pkt with apb pkt
//////////////////////////////////////////////////////////////////////////////////

class ahb2apb_scb extends uvm_scoreboard;

	//------------------------------------------
	// Data, Interface, port  Members
	//------------------------------------------
	uvm_blocking_get_port #(apb_trans) 	apb_port;
	uvm_blocking_get_port #(ahbl_trans)	ahbl_port;

	func_cov	fcov;

	//Factory Registration
	//
	`uvm_component_utils(ahb2apb_scb)

	//----------------------------------------------
	// Methods
	// ---------------------------------------------
	// Standard UVM Methods:
	extern function new(string name = "ahb2apb_scb", uvm_component parent);
	extern virtual function void build_phase(uvm_phase phase);
	extern virtual task main_phase(uvm_phase phase);
	// User Defined Methods:
	extern virtual task check_pkt();
endclass

//Constructor
function ahb2apb_scb::new(string name = "ahb2apb_scb", uvm_component parent);
	super.new(name, parent);
endfunction

//Build_Phase
function void ahb2apb_scb::build_phase(uvm_phase phase);
	super.build_phase(phase);
	apb_port = new("apb_port", this);
	ahbl_port = new("ahbl_port", this);
	fcov = new("fcov");
endfunction

//Main_Phase
task ahb2apb_scb::main_phase(uvm_phase phase);
	check_pkt();
endtask

task ahb2apb_scb::check_pkt();
	apb_trans	apb_pkt;
	ahbl_trans	ahbl_pkt;
	bit 		err_flag;

	while(1) begin
		err_flag = 0;
		ahbl_port.get(ahbl_pkt);
		apb_port.get(apb_pkt);

		fcov.cg.sample(ahbl_pkt, apb_pkt);
		//------------------------------------------
		//Check address:
		//------------------------------------------

		if(ahbl_pkt.haddr[15:2] != apb_pkt.paddr[15:2])  begin
			`uvm_error(get_type_name(), $sformatf("address mismatch! ahb-addr[15:2][%0h], apb-addr[15:2][%0h]",ahbl_pkt.haddr[15:2], apb_pkt.paddr[15:2]))
			err_flag = 1;
		end
		//------------------------------------------
		//Check data:
		//------------------------------------------
		if(ahbl_pkt.hwrite)
			if(ahbl_pkt.hrwdata != apb_pkt.data) begin
				`uvm_error(get_type_name(), $sformatf("write data mismatch! ahb-data = %0h, apb-data = %0h",ahbl_pkt.hrwdata, apb_pkt.data))
				err_flag = 1;
			end
		else if(!ahbl_pkt.hwrite)
			if(ahbl_pkt.hrwdata != apb_pkt.prdata) begin
				`uvm_error(get_type_name(), $sformatf("read data mismatch! ahb-data = %0h, apb-prdata = %0h",ahbl_pkt.hrwdata, apb_pkt.prdata))
				err_flag = 1;
			end
		//------------------------------------------
		//Check read of write:
		//------------------------------------------
		if(ahbl_pkt.hwrite == (apb_pkt.kind == apb_slv_pkg::READ)) begin
			`uvm_error(get_type_name(), "AHB-packet and APB-packet read/write mismatch! ahb-write, apb-read")
			err_flag = 1;
		end

		//------------------------------------------
		if(!ahbl_pkt.hwrite == (apb_pkt.kind == apb_slv_pkg::WRITE)) begin

			err_flag = 1;
		end

		//------------------------------------------
		//Check hprot and pprot signal:
		//------------------------------------------
		/*
			HPROT[3]:Modifiable
			HPROT[2]:Bufferable
			HPROT[1]:Privileged
			HPROT[0]:Data/Opcode */

		//user or priviledged
		if(ahbl_pkt.hprot[1] != apb_pkt.pprot[0]) begin
			`uvm_error(get_type_name(), $sformatf("hprot/pprot mismatch ahbl[1] =%0h ,apb[0] = %0h ", ahbl_pkt.hprot[1], apb_pkt.pprot[0] ))
			err_flag = 1;
		end

		//secure or non-secure
		if(ahbl_pkt.hprot[0] == apb_pkt.pprot[2]) begin
			`uvm_error(get_type_name(), $sformatf("hprot/pprot mismatch ahbl[0] = %0h , apb[2] = %0h ",  ahbl_pkt.hprot[0], apb_pkt.pprot[2]))
			err_flag = 1;
		end

		//------------------------------------------
		//check hsize and pstrb when it is a write access
		//------------------------------------------
		if((ahbl_pkt.hsize == WORD) & (apb_pkt.pstrb != 4'b1111))begin
			`uvm_error(get_type_name(), $sformatf("hsize/haddr/pstrb mismatch! ahbl-size:WORD, apb-pstrb:%4b", apb_pkt.pstrb))
			err_flag = 1;
		end

		if(	((ahbl_pkt.hsize == HWORD) & !ahbl_pkt.haddr[1] & (apb_pkt.pstrb != 4'b0011))
			| ((ahbl_pkt.hsize == HWORD) & ahbl_pkt.haddr[1] & (apb_pkt.pstrb != 4'b1100)))begin
			`uvm_error(get_type_name(), $sformatf("hsize/haddr/pstrb mismatch! ahbl-size:HWORD, ahbl-addr[1]:%d, apb-pstrb:%4b", ahbl_pkt.haddr[1], apb_pkt.pstrb))
			err_flag = 1;
		end

		if(	  ((ahbl_pkt.hsize == BYTE) & (ahbl_pkt.haddr[1:0] == 2'b00) & (apb_pkt.pstrb != 4'b0001))
			| ((ahbl_pkt.hsize == BYTE) & (ahbl_pkt.haddr[1:0] == 2'b01) & (apb_pkt.pstrb != 4'b0010))
			| ((ahbl_pkt.hsize == BYTE) & (ahbl_pkt.haddr[1:0] == 2'b10) & (apb_pkt.pstrb != 4'b0100))
			| ((ahbl_pkt.hsize == BYTE) & (ahbl_pkt.haddr[1:0] == 2'b11) & (apb_pkt.pstrb != 4'b1000)))begin
			`uvm_error(get_type_name(), $sformatf("hsize/haddr/pstrb mismatch! ahbl-size:BYTE, ahbl-addr[1:0]:%d, apb-pstrb:%4b", ahbl_pkt.haddr[1], apb_pkt.pstrb))
			err_flag = 1;
		end
		//------------------------------------------
		//check  hresp and pslverr
		//------------------------------------------
		if(ahbl_pkt.hresp != apb_pkt.pslverr) begin
			`uvm_error(get_type_name(), $sformatf("hresp/pslverr mismatch hresp:[%0h], pslverr:[%0h]", ahbl_pkt.hresp, apb_pkt.pslverr ))
			err_flag = 1;
		end

		if(ahbl_pkt.hresp != apb_pkt.pslverr) begin
			`uvm_error(get_type_name(), $sformatf("hresp/pslverr mismatch hresp:[%0h], pslverr:[%0h]", ahbl_pkt.hresp, apb_pkt.pslverr ))
			err_flag = 1;
		end
		//final-display if correct
		if(err_flag)
			`uvm_error(get_type_name(), "Pkt comparing failed")
		else
			`uvm_info(get_type_name(), "Pkt comparing passed", UVM_LOW)
		#20ns;
	end

endtask:check_pkt

`uvm_error(get_type_name(), "AHB-packet and APB-packet read/write mismatch! ahb-read, apb-write")


//###############################################################
//
//  Licensed to the Apache Software Foundation (ASF) under one
//  or more contributor license agreements.  See the NOTICE file
//  distributed with this work for additional information
//  regarding copyright ownership.  The ASF licenses this file
//  to you 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.
//
//###############################################################

`ifndef _RISCV_VIP_CSR_IF_INCLUDED_
`define _RISCV_VIP_CSR_IF_INCLUDED_

`include "riscv_vip_pkg.sv"

  riscv_vip_pkg::csrs_t csrs;

endinterface

`endif

interface riscv_vip_csr_if (input clk, input rstn);