`timescale 1ns/1ps
`default_nettype none
/***********************************************************************************************************************
*                                                                                *
* ANTIKERNEL                                                                                *
*                                                                                *
* Copyright (c) 2012-2024 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.                                                                                *
*                                                                                *
***********************************************************************************************************************/

/**
	@brief Gearboxes a 32-bit data stream from the transceiver to a N-bit (N > 32) data stream
 */
module Gearbox32ToN #(
	parameter			IN_WIDTH	= 32,
	parameter			OUT_WIDTH 	= 40
)(
	input wire					clk,
	input wire[IN_WIDTH-1:0]	data_in,
	input wire					valid_in,
	input wire					bitslip,

	output logic[OUT_WIDTH-1:0]	data_out	= 0,
	output logic				valid_out	= 0
);

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Rearrange the data to MSB-first bit ordering because serdes IPs are dumb, and pipeline to improve latency

	logic[IN_WIDTH-1:0] data_in_flip		= 0;
	logic				data_in_flip_valid	= 0;

	always_ff @(posedge clk) begin
		for(integer i=0; i<IN_WIDTH; i=i+1)

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// The gearbox

	localparam COMBINED_WIDTH = OUT_WIDTH + IN_WIDTH;

	//Append new data to the existing buffer
	logic[$clog2(OUT_WIDTH-1):0]		work_valid	= 0;
	logic[COMBINED_WIDTH-1:0] 			combined;
	logic[OUT_WIDTH-2:0]				workbuf		= 0;
	logic[$clog2(COMBINED_WIDTH)-1:0]	combined_valid;

	always_comb begin

		//Clear all unset bits to zero
		combined		= 0;

		//Copy working buffer
		combined[COMBINED_WIDTH-1 : IN_WIDTH+1]	= workbuf;
		combined_valid	= work_valid;

		//Add new data (left justified)
		if(data_in_flip_valid) begin
			combined[(OUT_WIDTH-work_valid) +: IN_WIDTH]	= data_in_flip;
			combined_valid									= work_valid + IN_WIDTH;
		end

		//Drop a bit if we're bitslipping
		if(bitslip)
			combined_valid	= combined_valid - 1;

	end

	always_ff @(posedge clk) begin

		valid_out	<= 0;

		//New data? If not, nothing to do
		if(data_in_flip_valid) begin

			//If we have a full output word, push it out and save the remaining data
			if(combined_valid >= OUT_WIDTH) begin
				data_out	<= combined[COMBINED_WIDTH-1:IN_WIDTH];
				valid_out	<= 1;
				workbuf		<= { combined[IN_WIDTH-1:0], {(OUT_WIDTH-IN_WIDTH-1){1'h0}} };
				work_valid	<= combined_valid - OUT_WIDTH;
			end

			//No, just register it as-is
			else begin
				workbuf		<= combined[COMBINED_WIDTH-1:IN_WIDTH+1];
				work_valid	<= combined_valid;
			end

		end

	end

endmodule

			data_in_flip[i] 	<= data_in[(IN_WIDTH-1) - i];
		data_in_flip_valid		<= valid_in;


///////////////////////////////////////////
// mux.sv
//
// Written: David_Harris@hmc.edu 9 January 2021
// Modified:
//
// Purpose: Various flavors of multiplexers
//
// A component of the CORE-V-WALLY configurable RISC-V project.
// https://github.com/openhwgroup/cvw
//
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
// may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work 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.
////////////////////////////////////////////////////////////////////////////////////////////////

/* verilator lint_off DECLFILENAME */

module mux2 #(parameter WIDTH = 8) (
  input  logic [WIDTH-1:0] d0, d1,
  input  logic             s,
  output logic [WIDTH-1:0] y);

  assign y = s ? d1 : d0;
endmodule

module mux3 #(parameter WIDTH = 8) (
  input  logic [WIDTH-1:0] d0, d1, d2,
  input  logic [1:0]       s,
  output logic [WIDTH-1:0] y);

  assign y = s[1] ? d2 : (s[0] ? d1 : d0); // exclusion-tag: mux3
endmodule

module mux4 #(parameter WIDTH = 8) (
  input  logic [WIDTH-1:0] d0, d1, d2, d3,
  input  logic [1:0]       s,
  output logic [WIDTH-1:0] y);

  assign y = s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0);
endmodule

  assign y = s[2] ? d4 : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0));
endmodule

module mux6 #(parameter WIDTH = 8) (
  input  logic [WIDTH-1:0] d0, d1, d2, d3, d4, d5,
  input  logic [2:0]       s,
  output logic [WIDTH-1:0] y);

  assign y = s[2] ? (s[0] ? d5 : d4) : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0));
endmodule // mux6

module mux7 #(parameter WIDTH = 8) (
  input  logic [WIDTH-1:0] d0, d1, d2, d3, d4, d5, d6,
  input  logic [2:0]       s,
  output logic [WIDTH-1:0] y);

  assign y = s[2] ? (s[1] ? d6 : (s[0] ? d5 : d4)) : (s[1] ? (s[0] ? d3 : d2) : (s[0] ? d1 : d0));

endmodule

/* verilator lint_on DECLFILENAME */

module mux5 #(parameter WIDTH = 8) (
  input  logic [WIDTH-1:0] d0, d1, d2, d3, d4,
  input  logic [2:0]       s,


///////////////////////////////////////////
// rconlut32.sv
//
// Written: ryan.swann@okstate.edu, james.stine@okstate.edu
// Created: 20 February 2024
//
// Purpose: rcon lookup for aes64ks1i instruction
//
// A component of the CORE-V-WALLY configurable RISC-V project.
// https://github.com/openhwgroup/cvw
//
// Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
// may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work 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 rconlut32(
  input  logic [3:0]  rd,
  output logic [31:0] rcon
);

  logic [7:0] rcon8;

  always_comb
    case(rd)
      4'h0 : rcon8 = 8'h01;
      4'h1 : rcon8 = 8'h02;
      4'h2 : rcon8 = 8'h04;
      4'h3 : rcon8 = 8'h08;
      4'h4 : rcon8 = 8'h10;
      4'h5 : rcon8 = 8'h20;
      4'h6 : rcon8 = 8'h40;
      4'h7 : rcon8 = 8'h80;
      4'h8 : rcon8 = 8'h1b;
      4'h9 : rcon8 = 8'h36;
      4'hA : rcon8 = 8'h00;

    endcase

  assign rcon = {24'b0, rcon8};
endmodule


/*********************************************************************************
Copyright (c) 2021 Wavious LLC

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.

*********************************************************************************/

`include "ddr_global_define.vh"
`include "ddr_project_define.vh"
`include "ddr_dfi_csr_defs.vh"

import ddr_global_pkg::*;

module ddr_dfi_csr #(
   parameter AWIDTH = 32,
   parameter DWIDTH = 32
) (

   input   logic                i_hclk,
   input   logic                i_hreset,
   input   logic                i_write,
   input   logic                i_read,
   input   logic [AWIDTH-1:0]   i_addr,
   input   logic [DWIDTH-1:0]   i_wdata,
   output  logic [DWIDTH-1:0]   o_rdata,
   output  logic                o_error,
   output  logic                o_ready,
   output  logic [`DDR_DFI_TOP_0_CFG_RANGE] o_dfi_top_0_cfg,
   output  logic [`DDR_DFI_DATA_BIT_ENABLE_CFG_RANGE] o_dfi_data_bit_enable_cfg,
   output  logic [`DDR_DFI_PHYFREQ_RANGE_CFG_RANGE] o_dfi_phyfreq_range_cfg,
   output  logic [`DDR_DFI_STATUS_IF_CFG_RANGE] o_dfi_status_if_cfg,
   input   logic [`DDR_DFI_STATUS_IF_STA_RANGE] i_dfi_status_if_sta,
   output  logic [`DDR_DFI_STATUS_IF_EVENT_0_CFG_RANGE] o_dfi_status_if_event_0_cfg,
   output  logic [`DDR_DFI_STATUS_IF_EVENT_1_CFG_RANGE] o_dfi_status_if_event_1_cfg,
   output  logic [`DDR_DFI_CTRLUPD_IF_CFG_RANGE] o_dfi_ctrlupd_if_cfg,
   input   logic [`DDR_DFI_CTRLUPD_IF_STA_RANGE] i_dfi_ctrlupd_if_sta,
   output  logic [`DDR_DFI_CTRLUPD_IF_EVENT_0_CFG_RANGE] o_dfi_ctrlupd_if_event_0_cfg,
   output  logic [`DDR_DFI_CTRLUPD_IF_EVENT_1_CFG_RANGE] o_dfi_ctrlupd_if_event_1_cfg,
   output  logic [`DDR_DFI_LP_CTRL_IF_CFG_RANGE] o_dfi_lp_ctrl_if_cfg,
   input   logic [`DDR_DFI_LP_CTRL_IF_STA_RANGE] i_dfi_lp_ctrl_if_sta,
   output  logic [`DDR_DFI_LP_CTRL_IF_EVENT_0_CFG_RANGE] o_dfi_lp_ctrl_if_event_0_cfg,
   output  logic [`DDR_DFI_LP_CTRL_IF_EVENT_1_CFG_RANGE] o_dfi_lp_ctrl_if_event_1_cfg,
   output  logic [`DDR_DFI_LP_DATA_IF_CFG_RANGE] o_dfi_lp_data_if_cfg,
   input   logic [`DDR_DFI_LP_DATA_IF_STA_RANGE] i_dfi_lp_data_if_sta,
   output  logic [`DDR_DFI_LP_DATA_IF_EVENT_0_CFG_RANGE] o_dfi_lp_data_if_event_0_cfg,
   output  logic [`DDR_DFI_LP_DATA_IF_EVENT_1_CFG_RANGE] o_dfi_lp_data_if_event_1_cfg,
   output  logic [`DDR_DFI_PHYUPD_IF_CFG_RANGE] o_dfi_phyupd_if_cfg,
   input   logic [`DDR_DFI_PHYUPD_IF_STA_RANGE] i_dfi_phyupd_if_sta,
   output  logic [`DDR_DFI_PHYMSTR_IF_CFG_RANGE] o_dfi_phymstr_if_cfg,
   input   logic [`DDR_DFI_PHYMSTR_IF_STA_RANGE] i_dfi_phymstr_if_sta,
   output  logic [`DDR_DFI_DEBUG_CFG_RANGE] o_dfi_debug_cfg
);

   typedef enum logic [5:0] {
      DECODE_DDR_DFI_TOP_0_CFG,
      DECODE_DDR_DFI_DATA_BIT_ENABLE_CFG,
      DECODE_DDR_DFI_PHYFREQ_RANGE_CFG,
      DECODE_DDR_DFI_STATUS_IF_CFG,
      DECODE_DDR_DFI_STATUS_IF_STA,
      DECODE_DDR_DFI_STATUS_IF_EVENT_0_CFG,
      DECODE_DDR_DFI_STATUS_IF_EVENT_1_CFG,
      DECODE_DDR_DFI_CTRLUPD_IF_CFG,
      DECODE_DDR_DFI_CTRLUPD_IF_STA,
      DECODE_DDR_DFI_CTRLUPD_IF_EVENT_0_CFG,
      DECODE_DDR_DFI_CTRLUPD_IF_EVENT_1_CFG,
      DECODE_DDR_DFI_LP_CTRL_IF_CFG,
      DECODE_DDR_DFI_LP_CTRL_IF_STA,
      DECODE_DDR_DFI_LP_CTRL_IF_EVENT_0_CFG,
      DECODE_DDR_DFI_LP_CTRL_IF_EVENT_1_CFG,
      DECODE_DDR_DFI_LP_DATA_IF_CFG,
      DECODE_DDR_DFI_LP_DATA_IF_STA,
      DECODE_DDR_DFI_LP_DATA_IF_EVENT_0_CFG,
      DECODE_DDR_DFI_LP_DATA_IF_EVENT_1_CFG,
      DECODE_DDR_DFI_PHYUPD_IF_CFG,
      DECODE_DDR_DFI_PHYUPD_IF_STA,
      DECODE_DDR_DFI_PHYMSTR_IF_CFG,
      DECODE_DDR_DFI_PHYMSTR_IF_STA,
      DECODE_DDR_DFI_DEBUG_CFG,
      DECODE_NOOP
   } DECODE_T;

   DECODE_T decode;

   assign o_ready = 1'b1;

   always_comb begin
      o_error = 1'b0;
      case (i_addr)
         `DDR_DFI_TOP_0_CFG_ADR : decode = DECODE_DDR_DFI_TOP_0_CFG;
         `DDR_DFI_DATA_BIT_ENABLE_CFG_ADR : decode = DECODE_DDR_DFI_DATA_BIT_ENABLE_CFG;
         `DDR_DFI_PHYFREQ_RANGE_CFG_ADR : decode = DECODE_DDR_DFI_PHYFREQ_RANGE_CFG;
         `DDR_DFI_STATUS_IF_CFG_ADR : decode = DECODE_DDR_DFI_STATUS_IF_CFG;
         `DDR_DFI_STATUS_IF_STA_ADR : decode = DECODE_DDR_DFI_STATUS_IF_STA;
         `DDR_DFI_STATUS_IF_EVENT_0_CFG_ADR : decode = DECODE_DDR_DFI_STATUS_IF_EVENT_0_CFG;

         `DDR_DFI_LP_CTRL_IF_CFG_ADR : decode = DECODE_DDR_DFI_LP_CTRL_IF_CFG;
         `DDR_DFI_LP_CTRL_IF_STA_ADR : decode = DECODE_DDR_DFI_LP_CTRL_IF_STA;
         `DDR_DFI_LP_CTRL_IF_EVENT_0_CFG_ADR : decode = DECODE_DDR_DFI_LP_CTRL_IF_EVENT_0_CFG;
         `DDR_DFI_LP_CTRL_IF_EVENT_1_CFG_ADR : decode = DECODE_DDR_DFI_LP_CTRL_IF_EVENT_1_CFG;
         `DDR_DFI_LP_DATA_IF_CFG_ADR : decode = DECODE_DDR_DFI_LP_DATA_IF_CFG;
         `DDR_DFI_LP_DATA_IF_STA_ADR : decode = DECODE_DDR_DFI_LP_DATA_IF_STA;
         `DDR_DFI_LP_DATA_IF_EVENT_0_CFG_ADR : decode = DECODE_DDR_DFI_LP_DATA_IF_EVENT_0_CFG;
         `DDR_DFI_LP_DATA_IF_EVENT_1_CFG_ADR : decode = DECODE_DDR_DFI_LP_DATA_IF_EVENT_1_CFG;
         `DDR_DFI_PHYUPD_IF_CFG_ADR : decode = DECODE_DDR_DFI_PHYUPD_IF_CFG;
         `DDR_DFI_PHYUPD_IF_STA_ADR : decode = DECODE_DDR_DFI_PHYUPD_IF_STA;
         `DDR_DFI_PHYMSTR_IF_CFG_ADR : decode = DECODE_DDR_DFI_PHYMSTR_IF_CFG;
         `DDR_DFI_PHYMSTR_IF_STA_ADR : decode = DECODE_DDR_DFI_PHYMSTR_IF_STA;
         `DDR_DFI_DEBUG_CFG_ADR : decode = DECODE_DDR_DFI_DEBUG_CFG;
         default : begin
            decode = DECODE_NOOP;
            o_error = 1'b1;
         end
      endcase
   end

   logic [31:0] dfi_top_0_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_top_0_cfg_q <= `DDR_DFI_TOP_0_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_TOP_0_CFG)
               dfi_top_0_cfg_q <= i_wdata;

   assign o_dfi_top_0_cfg = dfi_top_0_cfg_q & `DDR_DFI_TOP_0_CFG_MSK;

   logic [31:0] dfi_data_bit_enable_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_data_bit_enable_cfg_q <= `DDR_DFI_DATA_BIT_ENABLE_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_DATA_BIT_ENABLE_CFG)
               dfi_data_bit_enable_cfg_q <= i_wdata;

   assign o_dfi_data_bit_enable_cfg = dfi_data_bit_enable_cfg_q & `DDR_DFI_DATA_BIT_ENABLE_CFG_MSK;

   logic [31:0] dfi_phyfreq_range_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_phyfreq_range_cfg_q <= `DDR_DFI_PHYFREQ_RANGE_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_PHYFREQ_RANGE_CFG)
               dfi_phyfreq_range_cfg_q <= i_wdata;

   assign o_dfi_phyfreq_range_cfg = dfi_phyfreq_range_cfg_q & `DDR_DFI_PHYFREQ_RANGE_CFG_MSK;

   logic [31:0] dfi_status_if_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_status_if_cfg_q <= `DDR_DFI_STATUS_IF_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_STATUS_IF_CFG)
               dfi_status_if_cfg_q <= i_wdata;

   assign o_dfi_status_if_cfg = dfi_status_if_cfg_q & `DDR_DFI_STATUS_IF_CFG_MSK;

   logic [31:0] dfi_status_if_sta_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_status_if_sta_q <= `DDR_DFI_STATUS_IF_STA_POR;
      else
         dfi_status_if_sta_q <= i_dfi_status_if_sta;

   logic [31:0] dfi_status_if_event_0_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_status_if_event_0_cfg_q <= `DDR_DFI_STATUS_IF_EVENT_0_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_STATUS_IF_EVENT_0_CFG)
               dfi_status_if_event_0_cfg_q <= i_wdata;

   assign o_dfi_status_if_event_0_cfg = dfi_status_if_event_0_cfg_q & `DDR_DFI_STATUS_IF_EVENT_0_CFG_MSK;

   logic [31:0] dfi_status_if_event_1_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_status_if_event_1_cfg_q <= `DDR_DFI_STATUS_IF_EVENT_1_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_STATUS_IF_EVENT_1_CFG)
               dfi_status_if_event_1_cfg_q <= i_wdata;

   assign o_dfi_status_if_event_1_cfg = dfi_status_if_event_1_cfg_q & `DDR_DFI_STATUS_IF_EVENT_1_CFG_MSK;

   logic [31:0] dfi_ctrlupd_if_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_ctrlupd_if_cfg_q <= `DDR_DFI_CTRLUPD_IF_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_CTRLUPD_IF_CFG)
               dfi_ctrlupd_if_cfg_q <= i_wdata;

   assign o_dfi_ctrlupd_if_cfg = dfi_ctrlupd_if_cfg_q & `DDR_DFI_CTRLUPD_IF_CFG_MSK;

   logic [31:0] dfi_ctrlupd_if_sta_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_ctrlupd_if_sta_q <= `DDR_DFI_CTRLUPD_IF_STA_POR;
      else
         dfi_ctrlupd_if_sta_q <= i_dfi_ctrlupd_if_sta;

   logic [31:0] dfi_ctrlupd_if_event_0_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_ctrlupd_if_event_0_cfg_q <= `DDR_DFI_CTRLUPD_IF_EVENT_0_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_CTRLUPD_IF_EVENT_0_CFG)
               dfi_ctrlupd_if_event_0_cfg_q <= i_wdata;

   assign o_dfi_ctrlupd_if_event_0_cfg = dfi_ctrlupd_if_event_0_cfg_q & `DDR_DFI_CTRLUPD_IF_EVENT_0_CFG_MSK;

   logic [31:0] dfi_ctrlupd_if_event_1_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_ctrlupd_if_event_1_cfg_q <= `DDR_DFI_CTRLUPD_IF_EVENT_1_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_CTRLUPD_IF_EVENT_1_CFG)
               dfi_ctrlupd_if_event_1_cfg_q <= i_wdata;

   assign o_dfi_ctrlupd_if_event_1_cfg = dfi_ctrlupd_if_event_1_cfg_q & `DDR_DFI_CTRLUPD_IF_EVENT_1_CFG_MSK;

   logic [31:0] dfi_lp_ctrl_if_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_lp_ctrl_if_cfg_q <= `DDR_DFI_LP_CTRL_IF_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_LP_CTRL_IF_CFG)
               dfi_lp_ctrl_if_cfg_q <= i_wdata;

   assign o_dfi_lp_ctrl_if_cfg = dfi_lp_ctrl_if_cfg_q & `DDR_DFI_LP_CTRL_IF_CFG_MSK;

   logic [31:0] dfi_lp_ctrl_if_sta_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_lp_ctrl_if_sta_q <= `DDR_DFI_LP_CTRL_IF_STA_POR;
      else
         dfi_lp_ctrl_if_sta_q <= i_dfi_lp_ctrl_if_sta;

   logic [31:0] dfi_lp_ctrl_if_event_0_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_lp_ctrl_if_event_0_cfg_q <= `DDR_DFI_LP_CTRL_IF_EVENT_0_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_LP_CTRL_IF_EVENT_0_CFG)
               dfi_lp_ctrl_if_event_0_cfg_q <= i_wdata;

   assign o_dfi_lp_ctrl_if_event_0_cfg = dfi_lp_ctrl_if_event_0_cfg_q & `DDR_DFI_LP_CTRL_IF_EVENT_0_CFG_MSK;

   logic [31:0] dfi_lp_ctrl_if_event_1_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_lp_ctrl_if_event_1_cfg_q <= `DDR_DFI_LP_CTRL_IF_EVENT_1_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_LP_CTRL_IF_EVENT_1_CFG)
               dfi_lp_ctrl_if_event_1_cfg_q <= i_wdata;

   assign o_dfi_lp_ctrl_if_event_1_cfg = dfi_lp_ctrl_if_event_1_cfg_q & `DDR_DFI_LP_CTRL_IF_EVENT_1_CFG_MSK;

   logic [31:0] dfi_lp_data_if_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_lp_data_if_cfg_q <= `DDR_DFI_LP_DATA_IF_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_LP_DATA_IF_CFG)
               dfi_lp_data_if_cfg_q <= i_wdata;

   assign o_dfi_lp_data_if_cfg = dfi_lp_data_if_cfg_q & `DDR_DFI_LP_DATA_IF_CFG_MSK;

   logic [31:0] dfi_lp_data_if_sta_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_lp_data_if_sta_q <= `DDR_DFI_LP_DATA_IF_STA_POR;
      else
         dfi_lp_data_if_sta_q <= i_dfi_lp_data_if_sta;

   logic [31:0] dfi_lp_data_if_event_0_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_lp_data_if_event_0_cfg_q <= `DDR_DFI_LP_DATA_IF_EVENT_0_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_LP_DATA_IF_EVENT_0_CFG)
               dfi_lp_data_if_event_0_cfg_q <= i_wdata;

   assign o_dfi_lp_data_if_event_0_cfg = dfi_lp_data_if_event_0_cfg_q & `DDR_DFI_LP_DATA_IF_EVENT_0_CFG_MSK;

   logic [31:0] dfi_lp_data_if_event_1_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_lp_data_if_event_1_cfg_q <= `DDR_DFI_LP_DATA_IF_EVENT_1_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_LP_DATA_IF_EVENT_1_CFG)
               dfi_lp_data_if_event_1_cfg_q <= i_wdata;

   assign o_dfi_lp_data_if_event_1_cfg = dfi_lp_data_if_event_1_cfg_q & `DDR_DFI_LP_DATA_IF_EVENT_1_CFG_MSK;

   logic [31:0] dfi_phyupd_if_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_phyupd_if_cfg_q <= `DDR_DFI_PHYUPD_IF_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_PHYUPD_IF_CFG)
               dfi_phyupd_if_cfg_q <= i_wdata;

   assign o_dfi_phyupd_if_cfg = dfi_phyupd_if_cfg_q & `DDR_DFI_PHYUPD_IF_CFG_MSK;

   logic [31:0] dfi_phyupd_if_sta_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_phyupd_if_sta_q <= `DDR_DFI_PHYUPD_IF_STA_POR;
      else
         dfi_phyupd_if_sta_q <= i_dfi_phyupd_if_sta;

   logic [31:0] dfi_phymstr_if_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_phymstr_if_cfg_q <= `DDR_DFI_PHYMSTR_IF_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_PHYMSTR_IF_CFG)
               dfi_phymstr_if_cfg_q <= i_wdata;

   assign o_dfi_phymstr_if_cfg = dfi_phymstr_if_cfg_q & `DDR_DFI_PHYMSTR_IF_CFG_MSK;

   logic [31:0] dfi_phymstr_if_sta_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_phymstr_if_sta_q <= `DDR_DFI_PHYMSTR_IF_STA_POR;
      else
         dfi_phymstr_if_sta_q <= i_dfi_phymstr_if_sta;

   logic [31:0] dfi_debug_cfg_q;
   always_ff @( posedge i_hclk, posedge i_hreset)
      if (i_hreset)
         dfi_debug_cfg_q <= `DDR_DFI_DEBUG_CFG_POR;
      else
         if (i_write)
            if (decode == DECODE_DDR_DFI_DEBUG_CFG)
               dfi_debug_cfg_q <= i_wdata;

   assign o_dfi_debug_cfg = dfi_debug_cfg_q & `DDR_DFI_DEBUG_CFG_MSK;

   always_comb
      if (i_read)
         case (decode)
            DECODE_DDR_DFI_TOP_0_CFG : o_rdata = o_dfi_top_0_cfg;
            DECODE_DDR_DFI_DATA_BIT_ENABLE_CFG : o_rdata = o_dfi_data_bit_enable_cfg;
            DECODE_DDR_DFI_PHYFREQ_RANGE_CFG : o_rdata = o_dfi_phyfreq_range_cfg;
            DECODE_DDR_DFI_STATUS_IF_CFG : o_rdata = o_dfi_status_if_cfg;
            DECODE_DDR_DFI_STATUS_IF_STA : o_rdata = dfi_status_if_sta_q;
            DECODE_DDR_DFI_STATUS_IF_EVENT_0_CFG : o_rdata = o_dfi_status_if_event_0_cfg;
            DECODE_DDR_DFI_STATUS_IF_EVENT_1_CFG : o_rdata = o_dfi_status_if_event_1_cfg;
            DECODE_DDR_DFI_CTRLUPD_IF_CFG : o_rdata = o_dfi_ctrlupd_if_cfg;
            DECODE_DDR_DFI_CTRLUPD_IF_STA : o_rdata = dfi_ctrlupd_if_sta_q;
            DECODE_DDR_DFI_CTRLUPD_IF_EVENT_0_CFG : o_rdata = o_dfi_ctrlupd_if_event_0_cfg;
            DECODE_DDR_DFI_CTRLUPD_IF_EVENT_1_CFG : o_rdata = o_dfi_ctrlupd_if_event_1_cfg;
            DECODE_DDR_DFI_LP_CTRL_IF_CFG : o_rdata = o_dfi_lp_ctrl_if_cfg;
            DECODE_DDR_DFI_LP_CTRL_IF_STA : o_rdata = dfi_lp_ctrl_if_sta_q;
            DECODE_DDR_DFI_LP_CTRL_IF_EVENT_0_CFG : o_rdata = o_dfi_lp_ctrl_if_event_0_cfg;
            DECODE_DDR_DFI_LP_CTRL_IF_EVENT_1_CFG : o_rdata = o_dfi_lp_ctrl_if_event_1_cfg;
            DECODE_DDR_DFI_LP_DATA_IF_CFG : o_rdata = o_dfi_lp_data_if_cfg;
            DECODE_DDR_DFI_LP_DATA_IF_STA : o_rdata = dfi_lp_data_if_sta_q;
            DECODE_DDR_DFI_LP_DATA_IF_EVENT_0_CFG : o_rdata = o_dfi_lp_data_if_event_0_cfg;
            DECODE_DDR_DFI_LP_DATA_IF_EVENT_1_CFG : o_rdata = o_dfi_lp_data_if_event_1_cfg;
            DECODE_DDR_DFI_PHYUPD_IF_CFG : o_rdata = o_dfi_phyupd_if_cfg;
            DECODE_DDR_DFI_PHYUPD_IF_STA : o_rdata = dfi_phyupd_if_sta_q;
            DECODE_DDR_DFI_PHYMSTR_IF_CFG : o_rdata = o_dfi_phymstr_if_cfg;
            DECODE_DDR_DFI_PHYMSTR_IF_STA : o_rdata = dfi_phymstr_if_sta_q;
            DECODE_DDR_DFI_DEBUG_CFG : o_rdata = o_dfi_debug_cfg;
            default : o_rdata = '0;
         endcase
      else
         o_rdata = '0;

endmodule

         `DDR_DFI_STATUS_IF_EVENT_1_CFG_ADR : decode = DECODE_DDR_DFI_STATUS_IF_EVENT_1_CFG;
         `DDR_DFI_CTRLUPD_IF_CFG_ADR : decode = DECODE_DDR_DFI_CTRLUPD_IF_CFG;
         `DDR_DFI_CTRLUPD_IF_STA_ADR : decode = DECODE_DDR_DFI_CTRLUPD_IF_STA;


/*********************************************************************************
Copyright (c) 2021 Wavious LLC

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License 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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*********************************************************************************/

// The wav APB agent.
class wav_APB_agent extends uvm_agent;

  protected int id;

  `uvm_component_utils_begin(wav_APB_agent)
    `uvm_field_int(id, UVM_DEFAULT)
  `uvm_component_utils_end

  wav_APB_driver driver;
  wav_APB_sequencer sequencer;
  wav_APB_monitor monitor;

  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    monitor = wav_APB_monitor::type_id::create("monitor", this);

    if(get_is_active() == UVM_ACTIVE) begin
	 `uvm_info(get_type_name(), $psprintf("APB Agent is UVM_ACTIVE"), UVM_MEDIUM);

      driver = wav_APB_driver::type_id::create("driver", this);
    end
  endfunction

  function void set_interface(wav_APB_vif vif_a);
    if(driver != null) begin
      driver.set_interface(vif_a);
    end
    monitor.set_interface(vif_a);
  endfunction : set_interface

  function void connect_phase(uvm_phase phase);
    if(get_is_active() == UVM_ACTIVE) begin
      driver.seq_item_port.connect(sequencer.seq_item_export);
    end
  endfunction

endclass

sequencer = wav_APB_sequencer::type_id::create("sequencer", this);


`timescale 1ns/1ps
`define VERILOG
`include "defines.svh"
`undef  VERILOG

module axi_int_reg_cgra4ml #(
  localparam
    AXI_WIDTH               = `AXI_WIDTH   ,
    AXI_ID_WIDTH            = 6,
    AXI_ADDR_WIDTH          = 32,
    AXI_STRB_WIDTH          = (AXI_WIDTH/8)

) (
    input  wire                   clk,
    input  wire                   rstn,

    // Register interface
    input  logic reg_wr_en,
    output logic reg_wr_ack,
    input  logic [AXI_ADDR_WIDTH-1:0] reg_wr_addr,
    input  logic [AXI_WIDTH-1:0] reg_wr_data,
    input  logic reg_rd_en,
    output logic reg_rd_ack,
    input  logic [AXI_ADDR_WIDTH-1:0] reg_rd_addr,
    output logic [AXI_WIDTH-1:0] reg_rd_data,

    // AXI4 Master interface
    output wire [AXI_ID_WIDTH-1:0]    m_axi_awid,
    output wire [AXI_ADDR_WIDTH-1:0]  m_axi_awaddr,
    output wire [7:0]                 m_axi_awlen,
    output wire [2:0]                 m_axi_awsize,
    output wire [1:0]                 m_axi_awburst,
    output wire                       m_axi_awlock,
    output wire [3:0]                 m_axi_awcache,
    output wire [2:0]                 m_axi_awprot,
    output wire                       m_axi_awvalid,
    input  wire                       m_axi_awready,
    output wire [AXI_WIDTH   -1:0]    m_axi_wdata,
    output wire [AXI_STRB_WIDTH-1:0]  m_axi_wstrb,
    output wire                       m_axi_wlast,
    output wire                       m_axi_wvalid,
    input  wire                       m_axi_wready,
    input  wire [AXI_ID_WIDTH-1:0]    m_axi_bid,
    input  wire [1:0]                 m_axi_bresp,
    input  wire                       m_axi_bvalid,
    output wire                       m_axi_bready,
    output wire [AXI_ID_WIDTH-1:0]    m_axi_arid   ,
    output wire [AXI_ADDR_WIDTH-1:0]  m_axi_araddr ,
    output wire [7:0]                 m_axi_arlen  ,
    output wire [2:0]                 m_axi_arsize ,
    output wire [1:0]                 m_axi_arburst,
    output wire                       m_axi_arlock ,
    output wire [3:0]                 m_axi_arcache,
    output wire [2:0]                 m_axi_arprot ,
    output wire                       m_axi_arvalid,
    input  wire                       m_axi_arready,
    input  wire [AXI_ID_WIDTH-1:0]    m_axi_rid    ,
    input  wire [AXI_WIDTH   -1:0]    m_axi_rdata  ,
    input  wire [1:0]                 m_axi_rresp  ,
    input  wire                       m_axi_rlast  ,
    input  wire                       m_axi_rvalid ,
    output wire                       m_axi_rready
);

localparam
  ROWS                    = `ROWS               ,
  COLS                    = `COLS               ,
  X_BITS                  = `X_BITS             ,
  K_BITS                  = `K_BITS             ,
  Y_BITS                  = `Y_BITS             ,
  Y_OUT_BITS              = `Y_OUT_BITS         ,
  M_DATA_WIDTH_HF_CONV    = COLS  * ROWS  * Y_BITS,
  M_DATA_WIDTH_HF_CONV_DW = ROWS  * Y_BITS,
  // Full AXI
  DMA_ID_WIDTH            = AXI_ID_WIDTH-$clog2(3),
  AXI_MAX_BURST_LEN       = `AXI_MAX_BURST_LEN,
  // AXI-Lite
  AXIL_WIDTH              = 32,
  AXIL_ADDR_WIDTH         = 32,
  STRB_WIDTH              = 4,
  W_BPT                   = `W_BPT,
  OUT_ADDR_WIDTH          = 10,
  OUT_BITS                = 32,
// Parameters for controller
  SRAM_RD_DATA_WIDTH      = 256,
  SRAM_RD_DEPTH           = `MAX_N_BUNDLES,
  COUNTER_WIDTH           = 16,
  AXI_LEN_WIDTH           = 32,
  AXIL_BASE_ADDR          = `CONFIG_BASEADDR,
  TIMEOUT                 = 2, // since 0 gives error

// Alex AXI DMA RD
  AXIS_ID_WIDTH           = DMA_ID_WIDTH,
  AXIS_KEEP_ENABLE        = 1,//(AXI_WIDTH>8),
  AXIS_KEEP_WIDTH         = (AXI_WIDTH/8),//(AXI_WIDTH/8),
  AXIS_LAST_ENABLE        = 1,
  AXIS_ID_ENABLE          = 0,
  AXIS_DEST_ENABLE        = 0,
  AXIS_DEST_WIDTH         = 8,
  HEADER_WIDTH            = `HEADER_WIDTH,
  AXIS_USER_WIDTH         = HEADER_WIDTH+1,
  LEN_WIDTH               = 32,
  TAG_WIDTH               = 8,
  ENABLE_SG               = 0,
  ENABLE_UNALIGNED        = 1;

// Controller with Alex DMAs: desc signals (including od tag) and status signals
wire [AXI_ADDR_WIDTH+AXI_LEN_WIDTH-1:0] m_od_axis_write_desc_tdata;
wire m_od_axis_write_desc_tvalid;
wire m_od_axis_write_desc_tready;
wire [TAG_WIDTH-1:0] m_od_axis_write_desc_tag;
wire [TAG_WIDTH-1:0] m_os_axis_write_desc_status_tag;
wire [3:0] m_os_axis_write_desc_status_error;
wire m_os_axis_write_desc_status_valid;

wire [AXI_ADDR_WIDTH+AXI_LEN_WIDTH-1:0] m_xd_axis_write_desc_tdata;
wire [AXIS_USER_WIDTH-1:0] m_xd_axis_write_desc_tuser;
wire m_xd_axis_write_desc_tvalid;
wire m_xd_axis_write_desc_tready;

wire [AXI_ADDR_WIDTH+AXI_LEN_WIDTH-1:0] m_wd_axis_write_desc_tdata;
wire [AXIS_USER_WIDTH-1:0] m_wd_axis_write_desc_tuser;
wire m_wd_axis_write_desc_tvalid;
wire m_wd_axis_write_desc_tready;

// AXIS input & outputs to DNN engine
wire                       s_axis_pixels_tready, s_axis_pixels_skid_tready ;
wire                       s_axis_pixels_tvalid, s_axis_pixels_skid_tvalid ;
wire                       s_axis_pixels_tlast , s_axis_pixels_skid_tlast  ;
wire [AXI_WIDTH  -1:0]     s_axis_pixels_tdata , s_axis_pixels_skid_tdata  ;
wire [AXI_WIDTH/8-1:0]     s_axis_pixels_tkeep , s_axis_pixels_skid_tkeep  ;
wire [AXIS_USER_WIDTH-1:0] s_axis_pixels_tuser , s_axis_pixels_skid_tuser  ;

wire                       s_axis_weights_tready, s_axis_weights_skid_tready;
wire                       s_axis_weights_tvalid, s_axis_weights_skid_tvalid;
wire                       s_axis_weights_tlast , s_axis_weights_skid_tlast ;
wire [AXI_WIDTH  -1:0]     s_axis_weights_tdata , s_axis_weights_skid_tdata ;
wire [AXI_WIDTH/8-1:0]     s_axis_weights_tkeep , s_axis_weights_skid_tkeep ;
wire [AXIS_USER_WIDTH-1:0] s_axis_weights_tuser , s_axis_weights_skid_tuser ;

    // AND, controller monitors the axis output status
wire                    m_axis_output_tready, m_axis_output_skid_tready;
wire                    m_axis_output_tvalid, m_axis_output_skid_tvalid;
wire                    m_axis_output_tlast , m_axis_output_skid_tlast ;
wire [AXI_WIDTH   -1:0] m_axis_output_tdata , m_axis_output_skid_tdata ;
wire [AXI_WIDTH/8 -1:0] m_axis_output_tkeep , m_axis_output_skid_tkeep ;
wire [W_BPT-1:0]        m_bytes_per_transfer, m_bytes_per_transfer_skid;

wire [AXIL_ADDR_WIDTH-1:0] reg_wr_addr_ctrl = (reg_wr_addr-AXIL_BASE_ADDR) >> 2;
wire [AXIL_ADDR_WIDTH-1:0] reg_rd_addr_ctrl = (reg_rd_addr-AXIL_BASE_ADDR) >> 2;

// AXI Master Interfaces
wire [DMA_ID_WIDTH-1:0]    m_axi_s2mm_awid   , m_axi_mm2s_1_awid   , m_axi_mm2s_0_awid   ;
wire [AXI_ADDR_WIDTH-1:0]  m_axi_s2mm_awaddr , m_axi_mm2s_1_awaddr , m_axi_mm2s_0_awaddr ;
wire [7:0]                 m_axi_s2mm_awlen  , m_axi_mm2s_1_awlen  , m_axi_mm2s_0_awlen  ;
wire [2:0]                 m_axi_s2mm_awsize , m_axi_mm2s_1_awsize , m_axi_mm2s_0_awsize ;
wire [1:0]                 m_axi_s2mm_awburst, m_axi_mm2s_1_awburst, m_axi_mm2s_0_awburst;
wire                       m_axi_s2mm_awlock , m_axi_mm2s_1_awlock , m_axi_mm2s_0_awlock ;
wire [3:0]                 m_axi_s2mm_awcache, m_axi_mm2s_1_awcache, m_axi_mm2s_0_awcache;
wire [2:0]                 m_axi_s2mm_awprot , m_axi_mm2s_1_awprot , m_axi_mm2s_0_awprot ;
wire                       m_axi_s2mm_awvalid, m_axi_mm2s_1_awvalid, m_axi_mm2s_0_awvalid;
wire                       m_axi_s2mm_awready, m_axi_mm2s_1_awready, m_axi_mm2s_0_awready;
wire [AXI_WIDTH   -1:0]    m_axi_s2mm_wdata  , m_axi_mm2s_1_wdata  , m_axi_mm2s_0_wdata  ;
wire [AXI_STRB_WIDTH-1:0]  m_axi_s2mm_wstrb  , m_axi_mm2s_1_wstrb  , m_axi_mm2s_0_wstrb  ;
wire                       m_axi_s2mm_wlast  , m_axi_mm2s_1_wlast  , m_axi_mm2s_0_wlast  ;
wire                       m_axi_s2mm_wvalid , m_axi_mm2s_1_wvalid , m_axi_mm2s_0_wvalid ;
wire                       m_axi_s2mm_wready , m_axi_mm2s_1_wready , m_axi_mm2s_0_wready ;
wire [DMA_ID_WIDTH-1:0]    m_axi_s2mm_bid    , m_axi_mm2s_1_bid    , m_axi_mm2s_0_bid    ;
wire [1:0]                 m_axi_s2mm_bresp  , m_axi_mm2s_1_bresp  , m_axi_mm2s_0_bresp  ;
wire                       m_axi_s2mm_bvalid , m_axi_mm2s_1_bvalid , m_axi_mm2s_0_bvalid ;
wire                       m_axi_s2mm_bready , m_axi_mm2s_1_bready , m_axi_mm2s_0_bready ;
wire [DMA_ID_WIDTH-1:0]    m_axi_s2mm_arid   , m_axi_mm2s_1_arid   , m_axi_mm2s_0_arid   ;
wire [AXI_ADDR_WIDTH-1:0]  m_axi_s2mm_araddr , m_axi_mm2s_1_araddr , m_axi_mm2s_0_araddr ;
wire [7:0]                 m_axi_s2mm_arlen  , m_axi_mm2s_1_arlen  , m_axi_mm2s_0_arlen  ;
wire [2:0]                 m_axi_s2mm_arsize , m_axi_mm2s_1_arsize , m_axi_mm2s_0_arsize ;
wire [1:0]                 m_axi_s2mm_arburst, m_axi_mm2s_1_arburst, m_axi_mm2s_0_arburst;
wire                       m_axi_s2mm_arlock , m_axi_mm2s_1_arlock , m_axi_mm2s_0_arlock ;
wire [3:0]                 m_axi_s2mm_arcache, m_axi_mm2s_1_arcache, m_axi_mm2s_0_arcache;
wire [2:0]                 m_axi_s2mm_arprot , m_axi_mm2s_1_arprot , m_axi_mm2s_0_arprot ;
wire                       m_axi_s2mm_arvalid, m_axi_mm2s_1_arvalid, m_axi_mm2s_0_arvalid;
wire                       m_axi_s2mm_arready, m_axi_mm2s_1_arready, m_axi_mm2s_0_arready;
wire [DMA_ID_WIDTH-1:0]    m_axi_s2mm_rid    , m_axi_mm2s_1_rid    , m_axi_mm2s_0_rid    ;
wire [AXI_WIDTH   -1:0]    m_axi_s2mm_rdata  , m_axi_mm2s_1_rdata  , m_axi_mm2s_0_rdata  ;
wire [1:0]                 m_axi_s2mm_rresp  , m_axi_mm2s_1_rresp  , m_axi_mm2s_0_rresp  ;
wire                       m_axi_s2mm_rlast  , m_axi_mm2s_1_rlast  , m_axi_mm2s_0_rlast  ;
wire                       m_axi_s2mm_rvalid , m_axi_mm2s_1_rvalid , m_axi_mm2s_0_rvalid ;
wire                       m_axi_s2mm_rready , m_axi_mm2s_1_rready , m_axi_mm2s_0_rready ;

assign {m_axi_mm2s_1_awid   , m_axi_mm2s_0_awid   } = 0; // i
assign {m_axi_mm2s_1_awaddr , m_axi_mm2s_0_awaddr } = 0; // i
assign {m_axi_mm2s_1_awlen  , m_axi_mm2s_0_awlen  } = 0; // i
assign {m_axi_mm2s_1_awsize , m_axi_mm2s_0_awsize } = 0; // i
assign {m_axi_mm2s_1_awburst, m_axi_mm2s_0_awburst} = 0; // i
assign {m_axi_mm2s_1_awlock , m_axi_mm2s_0_awlock } = 0; // i
assign {m_axi_mm2s_1_awcache, m_axi_mm2s_0_awcache} = 0; // i
assign {m_axi_mm2s_1_awprot , m_axi_mm2s_0_awprot } = 0; // i
assign {m_axi_mm2s_1_awvalid, m_axi_mm2s_0_awvalid} = 0; // i
assign {m_axi_mm2s_1_wdata  , m_axi_mm2s_0_wdata  } = 0; // i
assign {m_axi_mm2s_1_wstrb  , m_axi_mm2s_0_wstrb  } = 0; // i
assign {m_axi_mm2s_1_wlast  , m_axi_mm2s_0_wlast  } = 0; // i
assign {m_axi_mm2s_1_wvalid , m_axi_mm2s_0_wvalid } = 0; // i
assign {m_axi_mm2s_1_bready , m_axi_mm2s_0_bready } = 0; // i
assign m_axi_s2mm_arid    = 0; // i
assign m_axi_s2mm_araddr  = 0; // i
assign m_axi_s2mm_arlen   = 0; // i
assign m_axi_s2mm_arsize  = 0; // i
assign m_axi_s2mm_arburst = 0; // i
assign m_axi_s2mm_arlock  = 0; // i
assign m_axi_s2mm_arcache = 0; // i
assign m_axi_s2mm_arprot  = 0; // i
assign m_axi_s2mm_arvalid = 0; // i
assign m_axi_s2mm_rready  = 0; // i

dma_controller #(
    .SRAM_RD_DATA_WIDTH(SRAM_RD_DATA_WIDTH),
    .SRAM_RD_DEPTH(SRAM_RD_DEPTH),
    .COUNTER_WIDTH(COUNTER_WIDTH),
    .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
    .AXIS_USER_WIDTH(AXIS_USER_WIDTH),
    .AXI_DATA_WIDTH(AXIL_WIDTH),
    .AXI_LEN_WIDTH(AXI_LEN_WIDTH),
    .AXI_TAG_WIDTH(TAG_WIDTH)
) CONTROLLER (
    .clk(clk),
    .rstn(rstn),
    .reg_wr_en(reg_wr_en),
    .reg_wr_ack(reg_wr_ack),
    .reg_wr_addr(reg_wr_addr_ctrl[AXI_ADDR_WIDTH-1:0]),
    .reg_wr_data(reg_wr_data),
    .reg_rd_en(reg_rd_en),
    .reg_rd_ack(reg_rd_ack),
    .reg_rd_addr(reg_rd_addr_ctrl[AXI_ADDR_WIDTH-1:0]),
    .reg_rd_data(reg_rd_data),
    .o_ready(m_axis_output_skid_tready),
    .o_valid(m_axis_output_skid_tvalid),
    .o_last(m_axis_output_skid_tlast),
    .o_bpt(m_bytes_per_transfer_skid),
    .os_tag(m_os_axis_write_desc_status_tag),
    .os_error(m_os_axis_write_desc_status_error),
    .os_valid(m_os_axis_write_desc_status_valid),
    .m_od_addr(m_od_axis_write_desc_tdata[AXI_ADDR_WIDTH-1:0]),
    .m_od_len(m_od_axis_write_desc_tdata[AXI_ADDR_WIDTH+AXI_LEN_WIDTH-1:AXI_ADDR_WIDTH]),
    .m_od_valid(m_od_axis_write_desc_tvalid),
    .m_od_ready(m_od_axis_write_desc_tready),
    .m_od_tag(m_od_axis_write_desc_tag),
    .m_xd_addr(m_xd_axis_write_desc_tdata[AXI_ADDR_WIDTH-1:0]),
    .m_xd_user(m_xd_axis_write_desc_tuser),
    .m_xd_len(m_xd_axis_write_desc_tdata[AXI_ADDR_WIDTH+AXI_LEN_WIDTH-1:AXI_ADDR_WIDTH]),
    .m_xd_valid(m_xd_axis_write_desc_tvalid),
    .m_xd_ready(m_xd_axis_write_desc_tready),
    .m_wd_addr(m_wd_axis_write_desc_tdata[AXI_ADDR_WIDTH-1:0]),
    .m_wd_user(m_wd_axis_write_desc_tuser),
    .m_wd_len((m_wd_axis_write_desc_tdata[AXI_ADDR_WIDTH+AXI_LEN_WIDTH-1:AXI_ADDR_WIDTH])),
    .m_wd_valid(m_wd_axis_write_desc_tvalid),
    .m_wd_ready(m_wd_axis_write_desc_tready)
);

dnn_engine #(
    .ROWS(ROWS),
    .COLS(COLS),
    .X_BITS(X_BITS),
    .K_BITS(K_BITS),
    .Y_BITS(Y_BITS),
    .Y_OUT_BITS(Y_OUT_BITS),
    .HEADER_WIDTH(HEADER_WIDTH),
    .M_DATA_WIDTH_HF_CONV(M_DATA_WIDTH_HF_CONV),
    .M_DATA_WIDTH_HF_CONV_DW(M_DATA_WIDTH_HF_CONV_DW),
    .AXI_WIDTH(AXI_WIDTH),
    .W_BPT(W_BPT),
    .OUT_ADDR_WIDTH(OUT_ADDR_WIDTH),
    .OUT_BITS(OUT_BITS)
) ENGINE (
    .aclk(clk),
    .aresetn(rstn),
    .s_axis_pixels_tready(s_axis_pixels_tready),
    .s_axis_pixels_tvalid(s_axis_pixels_tvalid),
    .s_axis_pixels_tlast(s_axis_pixels_tlast),
    .s_axis_pixels_tdata(s_axis_pixels_tdata),
    .s_axis_pixels_tuser(s_axis_pixels_tuser),
    .s_axis_pixels_tkeep(s_axis_pixels_tkeep),
    .s_axis_weights_tready(s_axis_weights_tready),
    .s_axis_weights_tvalid(s_axis_weights_tvalid),
    .s_axis_weights_tlast(s_axis_weights_tlast),
    .s_axis_weights_tdata(s_axis_weights_tdata),
    .s_axis_weights_tuser(s_axis_weights_tuser),
    .s_axis_weights_tkeep(s_axis_weights_tkeep),
    .m_axis_tready(m_axis_output_tready),
    .m_axis_tvalid(m_axis_output_tvalid),
    .m_axis_tlast(m_axis_output_tlast),
    .m_axis_tdata(m_axis_output_tdata),
    .m_axis_tkeep(m_axis_output_tkeep),
    .m_bytes_per_transfer(m_bytes_per_transfer)
);

skid_buffer #(
  .WIDTH(AXI_WIDTH + AXI_WIDTH/8 + AXIS_USER_WIDTH + 1)
  ) SKID_X (
  .clk     (clk ),
  .rstn    (rstn),
  .s_ready (s_axis_pixels_skid_tready ),
  .s_valid (s_axis_pixels_skid_tvalid ),
  .s_data  ({s_axis_pixels_skid_tdata, s_axis_pixels_skid_tuser, s_axis_pixels_skid_tkeep, s_axis_pixels_skid_tlast}),
  .m_ready (s_axis_pixels_tready      ),
  .m_valid (s_axis_pixels_tvalid      ),
  .m_data  ({s_axis_pixels_tdata,      s_axis_pixels_tuser,      s_axis_pixels_tkeep,      s_axis_pixels_tlast     })
);

skid_buffer #(
  .WIDTH(AXI_WIDTH + AXI_WIDTH/8 + AXIS_USER_WIDTH + 1)
  ) SKID_W (
  .clk     (clk ),
  .rstn    (rstn),
  .s_ready (s_axis_weights_skid_tready ),
  .s_valid (s_axis_weights_skid_tvalid ),
  .s_data  ({s_axis_weights_skid_tdata, s_axis_weights_skid_tuser, s_axis_weights_skid_tkeep, s_axis_weights_skid_tlast}),
  .m_ready (s_axis_weights_tready      ),
  .m_valid (s_axis_weights_tvalid      ),
  .m_data  ({s_axis_weights_tdata,      s_axis_weights_tuser,      s_axis_weights_tkeep,      s_axis_weights_tlast     })
);

skid_buffer #(
  .WIDTH(AXI_WIDTH + AXI_WIDTH/8 + W_BPT + 1)
  ) SKID_Y (
  .clk     (clk ),
  .rstn    (rstn),
  .s_ready (m_axis_output_tready),
  .s_valid (m_axis_output_tvalid),
  .s_data  ({m_axis_output_tdata,      m_axis_output_tkeep,      m_bytes_per_transfer,        m_axis_output_tlast     }),
  .m_ready (m_axis_output_skid_tready),
  .m_valid (m_axis_output_skid_tvalid),
  .m_data  ({m_axis_output_skid_tdata, m_axis_output_skid_tkeep, m_bytes_per_transfer_skid,   m_axis_output_skid_tlast})
);

wire m_axi_mm2s_0_arvalid_masked = m_axi_mm2s_0_arvalid && s_axis_pixels_skid_tready;
wire m_axi_mm2s_0_arready_masked = m_axi_mm2s_0_arready && s_axis_pixels_skid_tready;

alex_axi_dma_rd #(
    .AXI_DATA_WIDTH(AXI_WIDTH   ),
    .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
    .AXI_STRB_WIDTH(AXI_STRB_WIDTH),
    .AXI_ID_WIDTH(DMA_ID_WIDTH),
    .AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
    .AXIS_DATA_WIDTH(AXI_WIDTH),
    .AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
    .AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
    .AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
    .AXIS_ID_ENABLE(AXIS_ID_ENABLE),
    .AXIS_ID_WIDTH(AXIS_ID_WIDTH),
    .AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
    .AXIS_DEST_WIDTH(AXIS_DEST_WIDTH),
    .AXIS_USER_ENABLE(1),
    .AXIS_USER_WIDTH(AXIS_USER_WIDTH),
    .LEN_WIDTH(LEN_WIDTH),
    .TAG_WIDTH(TAG_WIDTH),
    .ENABLE_SG(ENABLE_SG),
    .ENABLE_UNALIGNED(ENABLE_UNALIGNED),
    .AXI_ID(1)
) PIXEL_DMA (
    .clk(clk),
    .rstn(rstn),
    .s_axis_read_desc_tdata(m_xd_axis_write_desc_tdata),
    .s_axis_read_desc_tag({TAG_WIDTH{1'b0}}),
    .s_axis_read_desc_tid({DMA_ID_WIDTH{1'b0}}),
    .s_axis_read_desc_tdest({AXIS_DEST_WIDTH{1'b0}}),
    .s_axis_read_desc_tuser(m_xd_axis_write_desc_tuser),
    .s_axis_read_desc_tvalid(m_xd_axis_write_desc_tvalid),
    .s_axis_read_desc_tready(m_xd_axis_write_desc_tready),
    .m_axis_read_desc_status_tag(),
    .m_axis_read_desc_status_error(),
    .m_axis_read_desc_status_valid(),
    .m_axis_read_data_tdata(s_axis_pixels_skid_tdata),
    .m_axis_read_data_tkeep(s_axis_pixels_skid_tkeep),
    .m_axis_read_data_tvalid(s_axis_pixels_skid_tvalid),
    .m_axis_read_data_tready(s_axis_pixels_skid_tready),
    .m_axis_read_data_tlast(s_axis_pixels_skid_tlast),
    .m_axis_read_data_tid(),
    .m_axis_read_data_tdest(),
    .m_axis_read_data_tuser(s_axis_pixels_skid_tuser),
    .m_axi_arid(m_axi_mm2s_0_arid),
    .m_axi_araddr(m_axi_mm2s_0_araddr),
    .m_axi_arlen(m_axi_mm2s_0_arlen),
    .m_axi_arsize(m_axi_mm2s_0_arsize),
    .m_axi_arburst(m_axi_mm2s_0_arburst),
    .m_axi_arlock(m_axi_mm2s_0_arlock),
    .m_axi_arcache(m_axi_mm2s_0_arcache),
    .m_axi_arprot(m_axi_mm2s_0_arprot),
    .m_axi_arvalid(m_axi_mm2s_0_arvalid),
    .m_axi_arready(m_axi_mm2s_0_arready_masked),
    .m_axi_rid(m_axi_mm2s_0_rid),
    .m_axi_rdata(m_axi_mm2s_0_rdata),
    .m_axi_rresp(m_axi_mm2s_0_rresp),
    .m_axi_rlast(m_axi_mm2s_0_rlast),
    .m_axi_rvalid(m_axi_mm2s_0_rvalid),
    .m_axi_rready(m_axi_mm2s_0_rready),
    .enable(1'b1)
);

wire m_axi_mm2s_1_arvalid_masked = m_axi_mm2s_1_arvalid && s_axis_weights_skid_tready;
wire m_axi_mm2s_1_arready_masked = m_axi_mm2s_1_arready && s_axis_weights_skid_tready;

alex_axi_dma_rd #(
    .AXI_DATA_WIDTH(AXI_WIDTH   ),
    .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
    .AXI_STRB_WIDTH(AXI_STRB_WIDTH),
    .AXI_ID_WIDTH(DMA_ID_WIDTH),
    .AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
    .AXIS_DATA_WIDTH(AXI_WIDTH),
    .AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
    .AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
    .AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
    .AXIS_ID_ENABLE(AXIS_ID_ENABLE),
    .AXIS_ID_WIDTH(AXIS_ID_WIDTH),
    .AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
    .AXIS_DEST_WIDTH(AXIS_DEST_WIDTH),
    .AXIS_USER_ENABLE(1),
    .AXIS_USER_WIDTH(AXIS_USER_WIDTH),
    .LEN_WIDTH(LEN_WIDTH),
    .TAG_WIDTH(TAG_WIDTH),
    .ENABLE_SG(ENABLE_SG),
    .ENABLE_UNALIGNED(ENABLE_UNALIGNED),
    .AXI_ID(2)
) WEIGHTS_DMA (
    .clk(clk),
    .rstn(rstn),
    .s_axis_read_desc_tdata(m_wd_axis_write_desc_tdata),

    .s_axis_read_desc_tid({DMA_ID_WIDTH{1'b0}}),
    .s_axis_read_desc_tdest({AXIS_DEST_WIDTH{1'b0}}),
    .s_axis_read_desc_tuser(m_wd_axis_write_desc_tuser),
    .s_axis_read_desc_tvalid(m_wd_axis_write_desc_tvalid),
    .s_axis_read_desc_tready(m_wd_axis_write_desc_tready),
    .m_axis_read_desc_status_tag(),
    .m_axis_read_desc_status_error(),
    .m_axis_read_desc_status_valid(),
    .m_axis_read_data_tdata(s_axis_weights_skid_tdata),
    .m_axis_read_data_tkeep(s_axis_weights_skid_tkeep),
    .m_axis_read_data_tvalid(s_axis_weights_skid_tvalid),
    .m_axis_read_data_tready(s_axis_weights_skid_tready),
    .m_axis_read_data_tlast(s_axis_weights_skid_tlast),
    .m_axis_read_data_tid(),
    .m_axis_read_data_tdest(),
    .m_axis_read_data_tuser(s_axis_weights_skid_tuser),
    .m_axi_arid(m_axi_mm2s_1_arid),
    .m_axi_araddr(m_axi_mm2s_1_araddr),
    .m_axi_arlen(m_axi_mm2s_1_arlen),
    .m_axi_arsize(m_axi_mm2s_1_arsize),
    .m_axi_arburst(m_axi_mm2s_1_arburst),
    .m_axi_arlock(m_axi_mm2s_1_arlock),
    .m_axi_arcache(m_axi_mm2s_1_arcache),
    .m_axi_arprot(m_axi_mm2s_1_arprot),
    .m_axi_arvalid(m_axi_mm2s_1_arvalid),
    .m_axi_arready(m_axi_mm2s_1_arready_masked),
    .m_axi_rid(m_axi_mm2s_1_rid),
    .m_axi_rdata(m_axi_mm2s_1_rdata),
    .m_axi_rresp(m_axi_mm2s_1_rresp),
    .m_axi_rlast(m_axi_mm2s_1_rlast),
    .m_axi_rvalid(m_axi_mm2s_1_rvalid),
    .m_axi_rready(m_axi_mm2s_1_rready),
    .enable(1'b1)
);

alex_axi_dma_wr #(
    .AXI_DATA_WIDTH(AXI_WIDTH   ),
    .AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
    .AXI_STRB_WIDTH(AXI_STRB_WIDTH),
    .AXI_ID_WIDTH(DMA_ID_WIDTH),
    .AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
    .AXIS_DATA_WIDTH(AXI_WIDTH),
    .AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
    .AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
    .AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
    .AXIS_ID_ENABLE(AXIS_ID_ENABLE),
    .AXIS_ID_WIDTH(AXIS_ID_WIDTH),
    .AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
    .AXIS_DEST_WIDTH(AXIS_DEST_WIDTH),
    .AXIS_USER_ENABLE(0),
    .AXIS_USER_WIDTH(AXIS_USER_WIDTH),
    .LEN_WIDTH(LEN_WIDTH),
    .TAG_WIDTH(TAG_WIDTH),
    .ENABLE_SG(ENABLE_SG),
    .ENABLE_UNALIGNED(ENABLE_UNALIGNED),
    .AXI_ID(3)
) OUT_DMA (
    .clk(clk),
    .rstn(rstn),
    .s_axis_write_desc_tdata(m_od_axis_write_desc_tdata),
    .s_axis_write_desc_tag(m_od_axis_write_desc_tag),
    .s_axis_write_desc_tvalid(m_od_axis_write_desc_tvalid),
    .s_axis_write_desc_tready(m_od_axis_write_desc_tready),
    .m_axis_write_desc_status_len(),
    .m_axis_write_desc_status_tag(m_os_axis_write_desc_status_tag),
    .m_axis_write_desc_status_id(),
    .m_axis_write_desc_status_dest(),
    .m_axis_write_desc_status_user(),
    .m_axis_write_desc_status_error(m_os_axis_write_desc_status_error),
    .m_axis_write_desc_status_valid(m_os_axis_write_desc_status_valid),
    .s_axis_write_data_tdata(m_axis_output_skid_tdata),
    .s_axis_write_data_tkeep(m_axis_output_skid_tkeep),
    .s_axis_write_data_tvalid(m_axis_output_skid_tvalid),
    .s_axis_write_data_tready(m_axis_output_skid_tready),
    .s_axis_write_data_tlast(m_axis_output_skid_tlast),
    .s_axis_write_data_tid(),
    .s_axis_write_data_tdest(),
    .s_axis_write_data_tuser(),
    .m_axi_awid(m_axi_s2mm_awid),
    .m_axi_awaddr(m_axi_s2mm_awaddr),
    .m_axi_awlen(m_axi_s2mm_awlen),
    .m_axi_awsize(m_axi_s2mm_awsize),
    .m_axi_awburst(m_axi_s2mm_awburst),
    .m_axi_awlock(m_axi_s2mm_awlock),
    .m_axi_awcache(m_axi_s2mm_awcache),
    .m_axi_awprot(m_axi_s2mm_awprot),
    .m_axi_awvalid(m_axi_s2mm_awvalid),
    .m_axi_awready(m_axi_s2mm_awready),
    .m_axi_wdata(m_axi_s2mm_wdata),
    .m_axi_wstrb(m_axi_s2mm_wstrb),
    .m_axi_wlast(m_axi_s2mm_wlast),
    .m_axi_wvalid(m_axi_s2mm_wvalid),
    .m_axi_wready(m_axi_s2mm_wready),
    .m_axi_bid(m_axi_s2mm_bid),
    .m_axi_bresp(m_axi_s2mm_bresp),
    .m_axi_bvalid(m_axi_s2mm_bvalid),
    .m_axi_bready(m_axi_s2mm_bready),
    .enable(1'b1),
    .abort(1'b0)
);

localparam S_COUNT = 3;
localparam M_COUNT = 1;

axi_crossbar #(
  .S_COUNT         (S_COUNT                       ),
  .M_COUNT         (M_COUNT                       ),
  .DATA_WIDTH      (AXI_WIDTH                     ),
  .ADDR_WIDTH      (AXI_ADDR_WIDTH                ),
  .STRB_WIDTH      (AXI_STRB_WIDTH                ),
  .S_ID_WIDTH      (DMA_ID_WIDTH                  ),
  .M_ID_WIDTH      (AXI_ID_WIDTH                  ),
  // .AWUSER_ENABLE   (0                             ),
  // .AWUSER_WIDTH    (1                             ),
  // .WUSER_ENABLE    (0                             ),
  // .WUSER_WIDTH     (1                             ),
  // .BUSER_ENABLE    (0                             ),
  // .BUSER_WIDTH     (1                             ),
  // .ARUSER_ENABLE   (0                             ),
  // .ARUSER_WIDTH    (1                             ),
  // .RUSER_ENABLE    (0                             ),
  // .RUSER_WIDTH     (1                             ),
  // .S_THREADS       ({S_COUNT{32'd2}}              ),
  // .S_ACCEPT        ({S_COUNT{32'd16}}             ),
  .M_REGIONS       (1                             ),
  .M_BASE_ADDR     (0                             ),
  .M_ADDR_WIDTH    (AXI_ADDR_WIDTH                ),
  // .M_CONNECT_READ  ({M_COUNT{{S_COUNT{1'b1}}}}    ),
  // .M_CONNECT_WRITE ({M_COUNT{{S_COUNT{1'b1}}}}    ),
  // .M_ISSUE         ({M_COUNT{32'd4}}              ),
  // .M_SECURE        ({M_COUNT{1'b0}}               ),
  .S_AW_REG_TYPE   ({S_COUNT{2'd2}}               ),
  .S_W_REG_TYPE    ({S_COUNT{2'd2}}               ),
  .S_B_REG_TYPE    ({S_COUNT{2'd2}}               ),
  .S_AR_REG_TYPE   ({S_COUNT{2'd2}}               ),
  .S_R_REG_TYPE    ({S_COUNT{2'd2}}               ),
  .M_AW_REG_TYPE   ({M_COUNT{2'd2}}               ),
  .M_W_REG_TYPE    ({M_COUNT{2'd2}}               ),
  .M_B_REG_TYPE    ({M_COUNT{2'd2}}               ),
  .M_AR_REG_TYPE   ({M_COUNT{2'd2}}               ),
  .M_R_REG_TYPE    ({M_COUNT{2'd2}}               )
) AXI_INTC (
  .clk           (clk),
  .rstn          (rstn),

  .s_axi_awqos   (0),
  .s_axi_awuser  (0),
  .s_axi_wuser   (0),
  .s_axi_buser   (),
  .s_axi_arqos   (0),
  .s_axi_aruser  (0),
  .s_axi_ruser   (),

  .m_axi_awqos   (),
  .m_axi_awuser  (),
  .m_axi_wuser   (),
  .m_axi_buser   (),
  .m_axi_arqos   (),
  .m_axi_aruser  (),
  .m_axi_ruser   (0),
  .m_axi_awregion(),
  .m_axi_arregion(),

  .s_axi_awid    ({m_axi_s2mm_awid   , m_axi_mm2s_1_awid   , m_axi_mm2s_0_awid   }), // i
  .s_axi_awaddr  ({m_axi_s2mm_awaddr , m_axi_mm2s_1_awaddr , m_axi_mm2s_0_awaddr }), // i
  .s_axi_awlen   ({m_axi_s2mm_awlen  , m_axi_mm2s_1_awlen  , m_axi_mm2s_0_awlen  }), // i
  .s_axi_awsize  ({m_axi_s2mm_awsize , m_axi_mm2s_1_awsize , m_axi_mm2s_0_awsize }), // i
  .s_axi_awburst ({m_axi_s2mm_awburst, m_axi_mm2s_1_awburst, m_axi_mm2s_0_awburst}), // i
  .s_axi_awlock  ({m_axi_s2mm_awlock , m_axi_mm2s_1_awlock , m_axi_mm2s_0_awlock }), // i
  .s_axi_awcache ({m_axi_s2mm_awcache, m_axi_mm2s_1_awcache, m_axi_mm2s_0_awcache}), // i
  .s_axi_awprot  ({m_axi_s2mm_awprot , m_axi_mm2s_1_awprot , m_axi_mm2s_0_awprot }), // i
  .s_axi_awvalid ({m_axi_s2mm_awvalid, m_axi_mm2s_1_awvalid, m_axi_mm2s_0_awvalid}), // i
  .s_axi_awready ({m_axi_s2mm_awready, m_axi_mm2s_1_awready, m_axi_mm2s_0_awready}), // o
  .s_axi_wdata   ({m_axi_s2mm_wdata  , m_axi_mm2s_1_wdata  , m_axi_mm2s_0_wdata  }), // i
  .s_axi_wstrb   ({m_axi_s2mm_wstrb  , m_axi_mm2s_1_wstrb  , m_axi_mm2s_0_wstrb  }), // i
  .s_axi_wlast   ({m_axi_s2mm_wlast  , m_axi_mm2s_1_wlast  , m_axi_mm2s_0_wlast  }), // i
  .s_axi_wvalid  ({m_axi_s2mm_wvalid , m_axi_mm2s_1_wvalid , m_axi_mm2s_0_wvalid }), // i
  .s_axi_wready  ({m_axi_s2mm_wready , m_axi_mm2s_1_wready , m_axi_mm2s_0_wready }), // o
  .s_axi_bid     ({m_axi_s2mm_bid    , m_axi_mm2s_1_bid    , m_axi_mm2s_0_bid    }), // o
  .s_axi_bresp   ({m_axi_s2mm_bresp  , m_axi_mm2s_1_bresp  , m_axi_mm2s_0_bresp  }), // o
  .s_axi_bvalid  ({m_axi_s2mm_bvalid , m_axi_mm2s_1_bvalid , m_axi_mm2s_0_bvalid }), // o
  .s_axi_bready  ({m_axi_s2mm_bready , m_axi_mm2s_1_bready , m_axi_mm2s_0_bready }), // i
  .s_axi_arid    ({m_axi_s2mm_arid   , m_axi_mm2s_1_arid   , m_axi_mm2s_0_arid   }), // i
  .s_axi_araddr  ({m_axi_s2mm_araddr , m_axi_mm2s_1_araddr , m_axi_mm2s_0_araddr }), // i
  .s_axi_arlen   ({m_axi_s2mm_arlen  , m_axi_mm2s_1_arlen  , m_axi_mm2s_0_arlen  }), // i
  .s_axi_arsize  ({m_axi_s2mm_arsize , m_axi_mm2s_1_arsize , m_axi_mm2s_0_arsize }), // i
  .s_axi_arburst ({m_axi_s2mm_arburst, m_axi_mm2s_1_arburst, m_axi_mm2s_0_arburst}), // i
  .s_axi_arlock  ({m_axi_s2mm_arlock , m_axi_mm2s_1_arlock , m_axi_mm2s_0_arlock }), // i
  .s_axi_arcache ({m_axi_s2mm_arcache, m_axi_mm2s_1_arcache, m_axi_mm2s_0_arcache}), // i
  .s_axi_arprot  ({m_axi_s2mm_arprot , m_axi_mm2s_1_arprot , m_axi_mm2s_0_arprot }), // i
  .s_axi_arvalid ({m_axi_s2mm_arvalid, m_axi_mm2s_1_arvalid_masked, m_axi_mm2s_0_arvalid_masked}), // i
  .s_axi_arready ({m_axi_s2mm_arready, m_axi_mm2s_1_arready, m_axi_mm2s_0_arready}), // o
  .s_axi_rid     ({m_axi_s2mm_rid    , m_axi_mm2s_1_rid    , m_axi_mm2s_0_rid    }), // o
  .s_axi_rdata   ({m_axi_s2mm_rdata  , m_axi_mm2s_1_rdata  , m_axi_mm2s_0_rdata  }), // o
  .s_axi_rresp   ({m_axi_s2mm_rresp  , m_axi_mm2s_1_rresp  , m_axi_mm2s_0_rresp  }), // o
  .s_axi_rlast   ({m_axi_s2mm_rlast  , m_axi_mm2s_1_rlast  , m_axi_mm2s_0_rlast  }), // o
  .s_axi_rvalid  ({m_axi_s2mm_rvalid , m_axi_mm2s_1_rvalid , m_axi_mm2s_0_rvalid }), // o
  .s_axi_rready  ({m_axi_s2mm_rready , m_axi_mm2s_1_rready , m_axi_mm2s_0_rready }), // i

  .m_axi_awid    (m_axi_awid   ), // o
  .m_axi_awaddr  (m_axi_awaddr ), // o
  .m_axi_awlen   (m_axi_awlen  ), // o
  .m_axi_awsize  (m_axi_awsize ), // o
  .m_axi_awburst (m_axi_awburst), // o
  .m_axi_awlock  (m_axi_awlock ), // o
  .m_axi_awcache (m_axi_awcache), // o
  .m_axi_awprot  (m_axi_awprot ), // o
  .m_axi_awvalid (m_axi_awvalid), // o
  .m_axi_awready (m_axi_awready), // i
  .m_axi_wdata   (m_axi_wdata  ), // o
  .m_axi_wstrb   (m_axi_wstrb  ), // o
  .m_axi_wlast   (m_axi_wlast  ), // o
  .m_axi_wvalid  (m_axi_wvalid ), // o
  .m_axi_wready  (m_axi_wready ), // i
  .m_axi_bid     (m_axi_bid    ), // i
  .m_axi_bresp   (m_axi_bresp  ), // i
  .m_axi_bvalid  (m_axi_bvalid ), // i
  .m_axi_bready  (m_axi_bready ), // o
  .m_axi_arid    (m_axi_arid   ), // o
  .m_axi_araddr  (m_axi_araddr ), // o
  .m_axi_arlen   (m_axi_arlen  ), // o
  .m_axi_arsize  (m_axi_arsize ), // o
  .m_axi_arburst (m_axi_arburst), // o
  .m_axi_arlock  (m_axi_arlock ), // o
  .m_axi_arcache (m_axi_arcache), // o
  .m_axi_arprot  (m_axi_arprot ), // o
  .m_axi_arvalid (m_axi_arvalid), // o
  .m_axi_arready (m_axi_arready), // i
  .m_axi_rid     (m_axi_rid    ), // i
  .m_axi_rdata   (m_axi_rdata  ), // i
  .m_axi_rresp   (m_axi_rresp  ), // i
  .m_axi_rlast   (m_axi_rlast  ), // i
  .m_axi_rvalid  (m_axi_rvalid ), // i
  .m_axi_rready  (m_axi_rready )  // o
);

endmodule


// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Primitive block for generating CIP interrupts in peripherals.
//
// This block generates both the level-triggered wired interrupt signal intr_o and also updates
// the value of the INTR_STATE register. Together, the signal and register make up the two
// externally-visible indications of of the interrupt state.
//
// This assumes the existence of three external controller registers, which
// interface with this module via the standard reggen reg2hw/hw2reg signals. The 3 registers are:
// - INTR_ENABLE : enables/masks the output of INTR_STATE as the intr_o signal
// - INTR_STATE  : the current state of the interrupt (may be RO or W1C depending on "IntrT")
// - INTR_TEST   : sw-access-only register which asserts the interrupt for testing purposes

module prim_intr_hw # (
  // This module can be instantiated once per interrupt field (Width == 1), or
  // "bussified" with all fields of the interrupt vector (Width == $width(vec)).
  parameter int unsigned Width = 1,
  parameter bit          FlopOutput = 1,

  // As the wired interrupt signal intr_o is a level-triggered interrupt, the upstream consumer sw
  // has two options to make forward progress when this signal is asserted:
  // - Mask the interrupt, by setting INTR_ENABLE = 1'b0 or masking/enabling at an upstream
  //   consumer.
  // - Interact with the peripheral in some user-defined way that clears the signal.
  // To make this user-defined interaction ergonomic from a SW-perspective, we have defined
  // two common patterns for typical interrupt-triggering events, *Status* and *Event*.
  // - *Event* is useful for capturing a momentary assertion of the input signal.
  //   - INTR_STATE/intr_o is set to '1 upon the event occurring.
  //   - INTR_STATE/intr_o remain set until software writes-1-to-clear to INTR_STATE.
  // - *Status* captures a persistent conditional assertion that requires intervention to de-assert.
  //   - Until the root cause is alleviated, the interrupt output (while enabled) is continuously
  //     asserted.
  //   - INTR_STATE for *status* interrupts is RO (it simply presents the raw HW input signal).
  //   - If the root_cause is cleared, INTR_STATE/intr_o also clears automatically.
  // More details about the interrupt type distinctions can be found in the comportability docs.
  parameter              IntrT = "Event" // Event or Status
) (
  // event
  input  clk_i,
  input  rst_ni,
  input  [Width-1:0]  event_intr_i,

  // register interface
  input  [Width-1:0]  reg2hw_intr_enable_q_i,
  input  [Width-1:0]  reg2hw_intr_test_q_i,
  input               reg2hw_intr_test_qe_i,
  input  [Width-1:0]  reg2hw_intr_state_q_i,
  output              hw2reg_intr_state_de_o,
  output [Width-1:0]  hw2reg_intr_state_d_o,

  // outgoing interrupt
  output logic [Width-1:0]  intr_o
);

  logic [Width-1:0] status; // incl. test

  if (IntrT == "Event") begin : g_intr_event
    logic  [Width-1:0]    new_event;
    assign new_event =
               (({Width{reg2hw_intr_test_qe_i}} & reg2hw_intr_test_q_i) | event_intr_i);
    assign hw2reg_intr_state_de_o = |new_event;
    // for scalar interrupts, this resolves to '1' with new event
    // for vector interrupts, new events are OR'd in to existing interrupt state
    assign hw2reg_intr_state_d_o  =  new_event | reg2hw_intr_state_q_i;

    assign status = reg2hw_intr_state_q_i ;
  end : g_intr_event
  else if (IntrT == "Status") begin : g_intr_status

    end

    // TODO: In Status type, INTR_STATE is better to be external type and RO.
    assign hw2reg_intr_state_de_o = 1'b 1; // always represent the status
    assign hw2reg_intr_state_d_o  = event_intr_i | test_q;

    assign status = event_intr_i | test_q;

    // To make the timing same to event type, status signal does not use CSR.q,
    // rather the input of the CSR.
    logic unused_reg2hw;
    assign unused_reg2hw = ^reg2hw_intr_state_q_i;
  end : g_intr_status

  if (FlopOutput == 1) begin : gen_flop_intr_output
    // flop the interrupt output
    always_ff @(posedge clk_i or negedge rst_ni) begin
      if (!rst_ni) begin
        intr_o <= '0;
      end else begin
        intr_o <= status & reg2hw_intr_enable_q_i;
      end
    end

  end else begin : gen_intr_passthrough_output
    logic unused_clk;
    logic unused_rst_n;
    assign unused_clk = clk_i;
    assign unused_rst_n = rst_ni;
    assign intr_o = reg2hw_intr_state_q_i & reg2hw_intr_enable_q_i;
  end

  `ASSERT_INIT(IntrTKind_A, IntrT inside {"Event", "Status"})

endmodule

    logic [Width-1:0] test_q; // Storing test. Cleared by SW

    always_ff @(posedge clk_i or negedge rst_ni) begin


/*

  parameter int pCODE          = 8 ;
  parameter int pN             = 1 ;
  parameter int pLLR_W         = 1 ;
  parameter int pLLR_BY_CYCLE  = 1 ;
  parameter int pNODE_W        = 1 ;
  parameter int pNODE_BY_CYCLE = 1 ;
  parameter int pTAG_W         = 1 ;
  parameter int pUSE_SC_MODE   = 0 ;

  logic                     gsfc_ldpc_dec_mem__iclk                                                 ;
  logic                     gsfc_ldpc_dec_mem__ireset                                               ;
  logic                     gsfc_ldpc_dec_mem__iclkena                                              ;
  logic      [pTAG_W-1 : 0] gsfc_ldpc_dec_mem__irtag                                                ;
  mem_addr_t                gsfc_ldpc_dec_mem__iraddr       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  mem_sela_t                gsfc_ldpc_dec_mem__irsela       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  logic                     gsfc_ldpc_dec_mem__irmask       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  logic      [pTAG_W-1 : 0] gsfc_ldpc_dec_mem__ortag                                                ;
  logic                     gsfc_ldpc_dec_mem__ormask       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  node_t                    gsfc_ldpc_dec_mem__ordat        [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  node_state_t              gsfc_ldpc_dec_mem__orstate      [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  logic                     gsfc_ldpc_dec_mem__iwrite                                               ;
  mem_addr_t                gsfc_ldpc_dec_mem__iwaddr       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  mem_sela_t                gsfc_ldpc_dec_mem__iwsela       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  logic                     gsfc_ldpc_dec_mem__iwmask       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  node_t                    gsfc_ldpc_dec_mem__iwdat        [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  logic                     gsfc_ldpc_dec_mem__iwrite_state                                         ;
  node_state_t              gsfc_ldpc_dec_mem__iwstate      [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;

  gsfc_ldpc_dec_mem
  #(
    .pCODE          ( pCODE          ) ,
    .pN             ( pN             ) ,
    .pLLR_W         ( pLLR_W         ) ,
    .pLLR_BY_CYCLE  ( pLLR_BY_CYCLE  ) ,
    .pNODE_W        ( pNODE_W        ) ,
    .pNODE_BY_CYCLE ( pNODE_BY_CYCLE ) ,
    .pTAG_W         ( pTAG_W         ) ,
    .pUSE_SC_MODE   ( pUSE_SC_MODE   )
  )
  gsfc_ldpc_dec_mem
  (
    .iclk         ( gsfc_ldpc_dec_mem__iclk         ) ,
    .ireset       ( gsfc_ldpc_dec_mem__ireset       ) ,
    .iclkena      ( gsfc_ldpc_dec_mem__iclkena      ) ,
    .irtag        ( gsfc_ldpc_dec_mem__irtag        ) ,
    .iraddr       ( gsfc_ldpc_dec_mem__iraddr       ) ,
    .irsela       ( gsfc_ldpc_dec_mem__irsela       ) ,
    .irmask       ( gsfc_ldpc_dec_mem__irmask       ) ,
    .ortag        ( gsfc_ldpc_dec_mem__ortag        ) ,
    .ormask       ( gsfc_ldpc_dec_mem__ormask       ) ,
    .ordat        ( gsfc_ldpc_dec_mem__ordat        ) ,
    .orstate      ( gsfc_ldpc_dec_mem__orstate      ) ,
    .iwrite       ( gsfc_ldpc_dec_mem__iwrite       ) ,
    .iwaddr       ( gsfc_ldpc_dec_mem__iwaddr       ) ,
    .iwsela       ( gsfc_ldpc_dec_mem__iwsela       ) ,
    .iwmask       ( gsfc_ldpc_dec_mem__iwmask       ) ,
    .iwdat        ( gsfc_ldpc_dec_mem__iwdat        ) ,
    .iwrite_state ( gsfc_ldpc_dec_mem__iwrite_state ) ,
    .iwstate      ( gsfc_ldpc_dec_mem__iwstate      )
  );

  assign gsfc_ldpc_dec_mem__iclk    = '0 ;
  assign gsfc_ldpc_dec_mem__ireset  = '0 ;
  assign gsfc_ldpc_dec_mem__iclkena = '0 ;
  assign gsfc_ldpc_dec_mem__irtag   = '0 ;
  assign gsfc_ldpc_dec_mem__iraddr  = '0 ;
  assign gsfc_ldpc_dec_mem__irsela  = '0 ;
  assign gsfc_ldpc_dec_mem__irmask  = '0 ;
  assign gsfc_ldpc_dec_mem__iwrite  = '0 ;
  assign gsfc_ldpc_dec_mem__iwaddr  = '0 ;
  assign gsfc_ldpc_dec_mem__iwsela  = '0 ;
  assign gsfc_ldpc_dec_mem__iwmask  = '0 ;
  assign gsfc_ldpc_dec_mem__iwdat   = '0 ;

*/

//
// Project       : GSFC ldpc (7154, 8176)
// Author        : Shekhalev Denis (des00)
// Workfile      : gsfc_ldpc_dec_mem.sv
// Description   : Special shift ram array for LDPC parallel decoding
//

module gsfc_ldpc_dec_mem
(
  iclk         ,
  ireset       ,
  iclkena      ,
  //
  irtag        ,
  iraddr       ,
  irsela       ,
  irmask       ,
  ortag        ,
  ormask       ,
  ordat        ,
  orstate      ,
  //
  iwrite       ,
  iwaddr       ,
  iwsela       ,
  iwmask       ,
  iwdat        ,
  //
  iwrite_state ,
  iwstate
);

  parameter int pTAG_W = 2;

  `include "../gsfc_ldpc_parameters.svh"
  `include "gsfc_ldpc_dec_parameters.svh"

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  input  logic                       iclk                                                 ;
  input  logic                       ireset                                               ;
  input  logic                       iclkena                                              ;
  //
  input  logic        [pTAG_W-1 : 0] irtag                                                ;
  input  mem_addr_t                  iraddr       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;

  input  logic                       irmask       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;  // reserved
  output logic        [pTAG_W-1 : 0] ortag                                                ;
  output logic                       ormask       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;  // reserved
  output node_t                      ordat        [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  output node_state_t                orstate      [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  //
  input  logic                       iwrite                                               ;
  input  mem_addr_t                  iwaddr       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  input  mem_sela_t                  iwsela       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  input  logic                       iwmask       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;  // reserved
  input  node_t                      iwdat        [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;
  //
  input  logic                       iwrite_state                                         ;
  input  node_state_t                iwstate      [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

`ifdef MODEL_TECH
  bit   [pNODE_W-1 : 0] mem [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE][2**cADDR_W];
`endif

  logic                 write;
  mem_addr_t            waddr    [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];
  node_t                wdat     [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];

  logic  [pTAG_W-1 : 0] rtag_r1                                         ;
  mem_sela_t            rsela_r1 [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];
  logic                 rmask_r1 [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];

  mem_addr_t            raddr    [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];

  logic  [pTAG_W-1 : 0] rtag_r0                                         ;
  mem_sela_t            rsela_r0 [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];
  logic                 rmask_r0 [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];

  logic  [pTAG_W-1 : 0] rtag                                            ;
  mem_sela_t            rsela    [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];
  logic                 rmask    [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];
  node_t                rdat     [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE];

  // state bits packed to "single" ram
  logic                                                                  write_state;
  mem_addr_t                                                             waddr_state;
  node_state_t [pC-1:0][pW-1 : 0][pLLR_BY_CYCLE-1:0][pNODE_BY_CYCLE-1:0] wstate;

  mem_addr_t                                                             raddr_state;
  node_state_t [pC-1:0][pW-1 : 0][pLLR_BY_CYCLE-1:0][pNODE_BY_CYCLE-1:0] rstate;

  //------------------------------------------------------------------------------------------------------
  // write muxed data : take 2 cycle
  //------------------------------------------------------------------------------------------------------

  always_ff @(posedge iclk) begin
    mem_sela_t tsela;
    //
    if (iclkena) begin
      write       <= iwrite;
      waddr       <= iwaddr;
      write_state <= (pUSE_SC_MODE & iwrite_state);
      waddr_state <= iwaddr[0][0][0][0];
      for (int c = 0; c < pC; c++) begin
        for (int w = 0; w < pW; w++) begin
          for (int llra = 0; llra < pLLR_BY_CYCLE; llra++) begin
            for (int n = 0; n < pNODE_BY_CYCLE; n++) begin
              tsela = iwsela[c][w][llra][n];
              //
              wdat[c][w][llra][n] <= iwdat[c][w][tsela][n];
              //
              if (pUSE_SC_MODE) begin
                wstate[c][w][llra][n]  <= iwstate[c][w][llra][n];
              end // sc_mode
            end // n
          end // llra
        end // w
      end // c
    end // iclkena
  end

  //------------------------------------------------------------------------------------------------------
  // read masked data : take 4 cycles
  //------------------------------------------------------------------------------------------------------

  always_ff @(posedge iclk) begin
    mem_sela_t tsela;
    //
    if (iclkena) begin
      // + 1
       rtag_r1    <= irtag;
      rsela_r1    <= irsela;
      rmask_r1    <= irmask;
      raddr       <= iraddr;
      raddr_state <= iraddr[0][0][0][0];
      // + 2 : read ram
       rtag_r0    <=  rtag_r1;
      rsela_r0    <= rsela_r1;
      rmask_r0    <= rmask_r1;
      // + 3 : read ram
      rtag        <=  rtag_r0;
      rsela       <= rsela_r0;
      rmask       <= rmask_r0;
      // + 4
      ortag       <= rtag;
      ormask      <= rmask;
      for (int c = 0; c < pC; c++) begin
        for (int w = 0; w < pW; w++) begin
          for (int n = 0; n < pNODE_BY_CYCLE; n++) begin
            for (int llra = 0; llra < pLLR_BY_CYCLE; llra++) begin
              tsela = rsela[c][w][llra][n];
              //
              ordat[c][w][llra][n] <= rdat[c][w][tsela][n];
              //
              if (pUSE_SC_MODE) begin
                orstate[c][w][llra][n] <= rstate[c][w][llra][n];
              end // sc
            end // llra
          end // n
        end // w
      end // c
    end
  end

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  generate
    genvar gc, gw, gllra, gn;
    for (gc = 0; gc < pC; gc++) begin : mem_c_inst
      for (gw = 0; gw < pW; gw++) begin : mem_w_inst
        for (gllra = 0; gllra < pLLR_BY_CYCLE; gllra++) begin : mem_llra_inst
          for (gn = 0; gn < pNODE_BY_CYCLE; gn++) begin : mem_n_inst
            codec_mem_block
            #(
              .pADDR_W ( cADDR_W ) ,
              .pDAT_W  ( pNODE_W ) ,
              .pPIPE   ( 1       )
            )
            memb
            (
              .iclk    ( iclk    ) ,
              .ireset  ( ireset  ) ,
              .iclkena ( iclkena ) ,
              //
              .iwrite  ( write                     ) ,
              .iwaddr  ( waddr [gc][gw][gllra][gn] ) ,
              .iwdat   ( wdat  [gc][gw][gllra][gn] ) ,
              //
              .iraddr  ( raddr [gc][gw][gllra][gn] ) ,
              .ordat   ( rdat  [gc][gw][gllra][gn] )
            );
            //
`ifdef MODEL_TECH
            assign mem[gc][gw][gllra][gn] = memb.mem;
`endif
          end // n
        end // llra
      end // w
    end // c
  endgenerate

  //------------------------------------------------------------------------------------------------------
  // for vnode states can use single ram, because it use on vertical step with linear access (!!!)
  //------------------------------------------------------------------------------------------------------

  generate
    if (pUSE_SC_MODE) begin : state_mem

      codec_mem_block
      #(
        .pADDR_W ( cADDR_W                                                ) ,
        .pDAT_W  ( pW*pC*pLLR_BY_CYCLE*pNODE_BY_CYCLE*$bits(node_state_t) ) ,
        .pPIPE   ( 1                                                      )
      )
      mem
      (
        .iclk    ( iclk    ) ,
        .ireset  ( ireset  ) ,
        .iclkena ( iclkena ) ,
        //
        .iwrite  ( write_state ) ,
        .iwaddr  ( waddr_state ) ,
        .iwdat   ( wstate      ) ,
        //
        .iraddr  ( raddr_state ) ,
        .ordat   ( rstate      )
      );

    end
    else begin

      assign rstate = '0;

    end
  endgenerate

endmodule

input  mem_sela_t                  irsela       [pC][pW][pLLR_BY_CYCLE][pNODE_BY_CYCLE] ;


    }
  };

  //
  // 2D min-sum normalization factors for all coderates
  //  v-step/h-step normalization is cNORM_BY_8_FACTOR/8

  localparam int cNORM_FACTOR = 6;


// 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.

/*
 * cluster_clock_gate.sv
 * Davide Rossi <davide.rossi@unibo.it>
 * Antonio Pullini <pullinia@iis.ee.ethz.ch>
 * Igor Loi <igor.loi@unibo.it>
 * Francesco Conti <fconti@iis.ee.ethz.ch>
 */

 module cluster_clock_gate
#(
  parameter NB_CORES = 4
) (
  input  logic                clk_i,
  input  logic                rstn_i,
  input  logic                test_mode_i,
  input  logic                cluster_cg_en_i,
  input  logic                cluster_int_busy_i,
  input  logic [NB_CORES-1:0] cores_busy_i,
  input  logic                events_i,
  input  logic                incoming_req_i,
  output logic                isolate_cluster_o,

  assign isolate_cluster_o = r_clockgate;

  assign s_somebusy = cluster_int_busy_i | ( |cores_busy_i);

  assign s_clockenable = ~(&r_clockgate);

  always_ff @(posedge clk_i or negedge rstn_i)
  begin : proc_evnt_sync
    if(~rstn_i) begin
      r_events_sync <= 0;
    end else begin
      r_events_sync <= {r_events_sync[0],events_i};
    end
  end

  always_ff @(posedge clk_i or negedge rstn_i)
  begin
    if(~rstn_i) begin
      r_clockgate <= 0;
    end
    else begin
      if(!s_somebusy && !incoming_req_i && !r_events_sync[1])
        r_clockgate <= {r_clockgate[2:0],cluster_cg_en_i};
      else
        r_clockgate <= {r_clockgate[2:0],1'b0};
    end
  end

  cluster_clock_gating u_clkgate_cluster (
    .clk_o     ( cluster_clk_o ),
    .clk_i     ( clk_i         ),
    .en_i      ( s_clockenable ),
    .test_en_i ( test_mode_i   )
  );

endmodule

  output logic                cluster_clk_o

);

  logic s_somebusy;


// Copyright 2014-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.

module register_file_1w_multi_port_read
#(
    parameter ADDR_WIDTH    = 5,
    parameter DATA_WIDTH    = 32,

    parameter N_READ        = 2,
    parameter N_WRITE       = 1
)

    // Write port
    input  logic                                   WriteEnable,
    input  logic [ADDR_WIDTH-1:0]                  WriteAddr,
    input  logic [DATA_WIDTH-1:0]                  WriteData
);

    localparam    NUM_WORDS = 2**ADDR_WIDTH;

    // Read address register, located at the input of the address decoder
    logic [N_READ-1:0][ADDR_WIDTH-1:0]             RAddrRegxDP;
    logic [N_READ-1:0][NUM_WORDS-1:0]              RAddrOneHotxD;

    logic [DATA_WIDTH-1:0]                         MemContentxDP[NUM_WORDS];

    logic [NUM_WORDS-1:0]                          WAddrOneHotxD;
    logic [NUM_WORDS-1:0]                          ClocksxC;
    logic [DATA_WIDTH-1:0]                         WDataIntxD;

    logic                                          clk_int;

    int unsigned i;
    int unsigned k;

    genvar       x;
    genvar       z;

    cluster_clock_gating CG_WE_GLOBAL
    (
        .clk_o     ( clk_int        ),
        .en_i      ( WriteEnable    ),
        .test_en_i ( test_en_i      ),
        .clk_i     ( clk            )
    );

    //-----------------------------------------------------------------------------
    //-- READ : Read address register
    //-----------------------------------------------------------------------------

    generate
        for(z=0; z<N_READ; z++ )
        begin
            always_ff @(posedge clk)
            begin : p_RAddrReg
                if(rst_n == 1'b0)
                begin
                    RAddrRegxDP[z] <= '0;
                end
                else
                begin
                    if( ReadEnable[z] )
                        RAddrRegxDP[z] <= ReadAddr[z];
                end
            end

    //-----------------------------------------------------------------------------
    //-- READ : Read address decoder RAD
    //-----------------------------------------------------------------------------
            always @(*)
            begin : p_RAD
              RAddrOneHotxD[z] = '0;
              RAddrOneHotxD[z][RAddrRegxDP[z]] = 1'b1;
            end
            assign ReadData[z] = MemContentxDP[RAddrRegxDP[z]];

        end
    endgenerate

    //-----------------------------------------------------------------------------
    //-- WRITE : Write Address Decoder (WAD), combinatorial process
    //-----------------------------------------------------------------------------
    always_comb
    begin : p_WAD
      for(i=0; i<NUM_WORDS; i++)
      begin : p_WordIter
            if ( (WriteEnable == 1'b1 ) && (WriteAddr == i) )
              WAddrOneHotxD[i] = 1'b1;
            else
              WAddrOneHotxD[i] = 1'b0;
      end
    end

    //-----------------------------------------------------------------------------
    //-- WRITE : Clock gating (if integrated clock-gating cells are available)
    //-----------------------------------------------------------------------------
    generate
        for(x=0; x<NUM_WORDS; x++)
        begin : CG_CELL_WORD_ITER
                cluster_clock_gating CG_Inst
                (
                  .clk_o     ( ClocksxC[x]      ),
                  .en_i      ( WAddrOneHotxD[x] ),
                  .test_en_i ( 1'b0             ), // test Enable is not affecting those cells
                  .clk_i     ( clk_int          )
                );
        end
    endgenerate

    //-----------------------------------------------------------------------------
    // WRITE : SAMPLE INPUT DATA
    //---------------------------------------------------------------------------
    always_ff @(posedge clk)
    begin : sample_waddr
        if(rst_n == 1'b0)
        begin
            WDataIntxD <= '0;
        end
        else
        begin
            if(WriteEnable )
              WDataIntxD <= WriteData;
        end
    end

    //-----------------------------------------------------------------------------
    //-- WRITE : Write operation
    //-----------------------------------------------------------------------------
    //-- Generate M = WORDS sequential processes, each of which describes one
    //-- word of the memory. The processes are synchronized with the clocks
    //-- ClocksxC(i), i = 0, 1, ..., M-1
    //-- Use active low, i.e. transparent on low latches as storage elements
    //-- Data is sampled on rising clock edge

    always_latch
    begin : latch_wdata
      for(k=0; k<NUM_WORDS; k++)
        begin : w_WordIter
            if( ClocksxC[k] == 1'b1)
              MemContentxDP[k] <= WDataIntxD;
        end
    end

endmodule

(
    input  logic                                   clk,
    input  logic                                   rst_n,
    input  logic                                   test_en_i,


/*********************************************************************************
Copyright (c) 2021 Wavious LLC

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.

*********************************************************************************/

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

// Macros and helper code for using assertions.
//  - Provides default clk and rst options to simplify code
//  - Provides boiler plate template for common assertions

`ifndef PRIM_ASSERT_SV
`define PRIM_ASSERT_SV

`ifdef UVM
  // report assertion error with UVM if compiled
  package assert_rpt_pkg;
    import uvm_pkg::*;
    `include "uvm_macros.svh"
    function void assert_rpt(string msg);
      `uvm_error("ASSERT FAILED", msg)
    endfunction
  endpackage
`endif

///////////////////
// Helper macros //
///////////////////

// Default clk and reset signals used by assertion macros below.

`define ASSERT_DEFAULT_RST !rst_ni

// Converts an arbitrary block of code into a Verilog string
`define PRIM_STRINGIFY(__x) `"__x`"

// The basic helper macros are actually defined in "implementation headers". The macros should do
// the same thing in each case (except for the dummy flavour), but in a way that the respective
// tools support.
//
// If the tool supports assertions in some form, we also define INC_ASSERT (which can be used to
// hide signal definitions that are only used for assertions).
//
// The list of basic macros supported is:
//
//  ASSERT_I:     Immediate assertion. Note that immediate assertions are sensitive to simulation
//                glitches.
//
//  ASSERT_INIT:  Assertion in initial block. Can be used for things like parameter checking.
//
//  ASSERT_FINAL: Assertion in final block. Can be used for things like queues being empty at end of
//                sim, all credits returned at end of sim, state machines in idle at end of sim.
//
//  ASSERT:       Assert a concurrent property directly. It can be called as a module (or
//                interface) body item.
//
//                Note: We use (__rst !== '0) in the disable iff statements instead of (__rst ==
//                '1). This properly disables the assertion in cases when reset is X at the
//                beginning of a simulation. For that case, (reset == '1) does not disable the
//                assertion.
//
//  ASSERT_NEVER: Assert a concurrent property NEVER happens
//
//  ASSERT_KNOWN: Assert that signal has a known value (each bit is either '0' or '1') after reset.
//                It can be called as a module (or interface) body item.
//
//  COVER:        Cover a concurrent property
//
//  ASSUME:       Assume a concurrent property
//
//  ASSUME_I:     Assume an immediate property

`ifdef VERILATOR
 `include "prim_assert_dummy_macros.svh"
`elsif SYNTHESIS
 `include "prim_assert_dummy_macros.svh"
`elsif YOSYS
 `include "prim_assert_yosys_macros.svh"
 `define INC_ASSERT
`else
 `include "prim_assert_standard_macros.svh"
 `define INC_ASSERT
`endif

//////////////////////////////
// Complex assertion macros //
//////////////////////////////

// Assert that signal is an active-high pulse with pulse length of 1 clock cycle
`define ASSERT_PULSE(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
  `ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst)

// Assert that a property is true only when an enable signal is set.  It can be called as a module
// (or interface) body item.
`define ASSERT_IF(__name, __prop, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
  `ASSERT(__name, (__enable) |-> (__prop), __clk, __rst)

// Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is
// set.  It can be called as a module (or interface) body item.
`define ASSERT_KNOWN_IF(__name, __sig, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
  `ASSERT_KNOWN(__name``KnownEnable, __enable, __clk, __rst)                                               \
  `ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst)

//////////////////////////////////
// For formal verification only //
//////////////////////////////////

// Note that the existing set of ASSERT macros specified above shall be used for FPV,
// thereby ensuring that the assertions are evaluated during DV simulations as well.

// ASSUME_FPV
// Assume a concurrent property during formal verification only.
`define ASSUME_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef FPV_ON                                                                                \
   `ASSUME(__name, __prop, __clk, __rst)                                                     \
`endif

// ASSUME_I_FPV
// Assume a concurrent property during formal verification only.
`define ASSUME_I_FPV(__name, __prop) \
`ifdef FPV_ON                        \
   `ASSUME_I(__name, __prop)         \
`endif

// COVER_FPV
// Cover a concurrent property during formal verification
`define COVER_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef FPV_ON                                                                               \
   `COVER(__name, __prop, __clk, __rst)                                                     \
`endif

`endif // PRIM_ASSERT_SV


/*********************************************************************************
Copyright (c) 2021 Wavious LLC

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.

*********************************************************************************/

`include "ddr_global_define.vh"
`include "ddr_project_define.vh"
`include "ddr_dfi_csr_defs.vh"

import ddr_global_pkg::*;

module ddr_dfi_ahb_csr #(
   parameter AWIDTH = 32,
   parameter DWIDTH = 32
) (

   input   logic                i_hclk,
   input   logic                i_hreset,
   input   logic [AWIDTH-1:0]   i_haddr,
   input   logic                i_hwrite,
   input   logic                i_hsel,
   input   logic [DWIDTH-1:0]   i_hwdata,
   input   logic [1:0]          i_htrans,
   input   logic [2:0]          i_hsize,
   input   logic [2:0]          i_hburst,
   input   logic                i_hreadyin,
   output  logic                o_hready,
   output  logic [DWIDTH-1:0]   o_hrdata,
   output  logic [1:0]          o_hresp,
   output  logic [`DDR_DFI_TOP_0_CFG_RANGE] o_dfi_top_0_cfg,
   output  logic [`DDR_DFI_DATA_BIT_ENABLE_CFG_RANGE] o_dfi_data_bit_enable_cfg,
   output  logic [`DDR_DFI_PHYFREQ_RANGE_CFG_RANGE] o_dfi_phyfreq_range_cfg,
   output  logic [`DDR_DFI_STATUS_IF_CFG_RANGE] o_dfi_status_if_cfg,
   input   logic [`DDR_DFI_STATUS_IF_STA_RANGE] i_dfi_status_if_sta,
   output  logic [`DDR_DFI_STATUS_IF_EVENT_0_CFG_RANGE] o_dfi_status_if_event_0_cfg,
   output  logic [`DDR_DFI_STATUS_IF_EVENT_1_CFG_RANGE] o_dfi_status_if_event_1_cfg,
   output  logic [`DDR_DFI_CTRLUPD_IF_CFG_RANGE] o_dfi_ctrlupd_if_cfg,
   input   logic [`DDR_DFI_CTRLUPD_IF_STA_RANGE] i_dfi_ctrlupd_if_sta,
   output  logic [`DDR_DFI_CTRLUPD_IF_EVENT_0_CFG_RANGE] o_dfi_ctrlupd_if_event_0_cfg,
   output  logic [`DDR_DFI_CTRLUPD_IF_EVENT_1_CFG_RANGE] o_dfi_ctrlupd_if_event_1_cfg,
   output  logic [`DDR_DFI_LP_CTRL_IF_CFG_RANGE] o_dfi_lp_ctrl_if_cfg,
   input   logic [`DDR_DFI_LP_CTRL_IF_STA_RANGE] i_dfi_lp_ctrl_if_sta,
   output  logic [`DDR_DFI_LP_CTRL_IF_EVENT_0_CFG_RANGE] o_dfi_lp_ctrl_if_event_0_cfg,
   output  logic [`DDR_DFI_LP_CTRL_IF_EVENT_1_CFG_RANGE] o_dfi_lp_ctrl_if_event_1_cfg,
   output  logic [`DDR_DFI_LP_DATA_IF_CFG_RANGE] o_dfi_lp_data_if_cfg,
   input   logic [`DDR_DFI_LP_DATA_IF_STA_RANGE] i_dfi_lp_data_if_sta,
   output  logic [`DDR_DFI_LP_DATA_IF_EVENT_0_CFG_RANGE] o_dfi_lp_data_if_event_0_cfg,
   output  logic [`DDR_DFI_LP_DATA_IF_EVENT_1_CFG_RANGE] o_dfi_lp_data_if_event_1_cfg,
   output  logic [`DDR_DFI_PHYUPD_IF_CFG_RANGE] o_dfi_phyupd_if_cfg,
   input   logic [`DDR_DFI_PHYUPD_IF_STA_RANGE] i_dfi_phyupd_if_sta,
   output  logic [`DDR_DFI_PHYMSTR_IF_CFG_RANGE] o_dfi_phymstr_if_cfg,
   input   logic [`DDR_DFI_PHYMSTR_IF_STA_RANGE] i_dfi_phymstr_if_sta,
   output  logic [`DDR_DFI_DEBUG_CFG_RANGE] o_dfi_debug_cfg
);

   logic                slv_write;
   logic                slv_read;
   logic                slv_error;
   logic [AWIDTH-1:0]   slv_addr;
   logic [DWIDTH-1:0]   slv_wdata;
   logic [DWIDTH-1:0]   slv_rdata;
   logic                slv_ready;

   ddr_ahb_slave #(
      .AWIDTH(AWIDTH),
      .DWIDTH(DWIDTH)
   ) ahb_slave (
      .i_hclk     (i_hclk),
      .i_hreset   (i_hreset),
      .i_haddr    (i_haddr),
      .i_hwrite   (i_hwrite),
      .i_hsel     (i_hsel),
      .i_hwdata   (i_hwdata),
      .i_htrans   (i_htrans),
      .i_hsize    (i_hsize),
      .i_hburst   (i_hburst),
      .i_hreadyin (i_hreadyin),
      .o_hready   (o_hready),
      .o_hrdata   (o_hrdata),
      .o_hresp    (o_hresp),
      .o_write    (slv_write),
      .o_read     (slv_read),
      .o_wdata    (slv_wdata),
      .o_addr     (slv_addr),
      .i_rdata    (slv_rdata),
      .i_error    (slv_error),
      .i_ready    (slv_ready)

      .i_hreset (i_hreset),
      .i_write  (slv_write),
      .i_read   (slv_read),
      .i_wdata  (slv_wdata),
      .i_addr   (slv_addr),
      .o_rdata  (slv_rdata),
      .o_error  (slv_error),
      .o_ready  (slv_ready),
      .o_dfi_top_0_cfg (o_dfi_top_0_cfg),
      .o_dfi_data_bit_enable_cfg (o_dfi_data_bit_enable_cfg),
      .o_dfi_phyfreq_range_cfg (o_dfi_phyfreq_range_cfg),
      .o_dfi_status_if_cfg (o_dfi_status_if_cfg),
      .i_dfi_status_if_sta (i_dfi_status_if_sta),
      .o_dfi_status_if_event_0_cfg (o_dfi_status_if_event_0_cfg),
      .o_dfi_status_if_event_1_cfg (o_dfi_status_if_event_1_cfg),
      .o_dfi_ctrlupd_if_cfg (o_dfi_ctrlupd_if_cfg),
      .i_dfi_ctrlupd_if_sta (i_dfi_ctrlupd_if_sta),
      .o_dfi_ctrlupd_if_event_0_cfg (o_dfi_ctrlupd_if_event_0_cfg),
      .o_dfi_ctrlupd_if_event_1_cfg (o_dfi_ctrlupd_if_event_1_cfg),
      .o_dfi_lp_ctrl_if_cfg (o_dfi_lp_ctrl_if_cfg),
      .i_dfi_lp_ctrl_if_sta (i_dfi_lp_ctrl_if_sta),
      .o_dfi_lp_ctrl_if_event_0_cfg (o_dfi_lp_ctrl_if_event_0_cfg),
      .o_dfi_lp_ctrl_if_event_1_cfg (o_dfi_lp_ctrl_if_event_1_cfg),
      .o_dfi_lp_data_if_cfg (o_dfi_lp_data_if_cfg),
      .i_dfi_lp_data_if_sta (i_dfi_lp_data_if_sta),
      .o_dfi_lp_data_if_event_0_cfg (o_dfi_lp_data_if_event_0_cfg),
      .o_dfi_lp_data_if_event_1_cfg (o_dfi_lp_data_if_event_1_cfg),
      .o_dfi_phyupd_if_cfg (o_dfi_phyupd_if_cfg),
      .i_dfi_phyupd_if_sta (i_dfi_phyupd_if_sta),
      .o_dfi_phymstr_if_cfg (o_dfi_phymstr_if_cfg),
      .i_dfi_phymstr_if_sta (i_dfi_phymstr_if_sta),
      .o_dfi_debug_cfg (o_dfi_debug_cfg)
   );

endmodule

   );

   ddr_dfi_csr #(
      .AWIDTH(AWIDTH),


// Copyright 2015-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.

module dc_data_buffer
#(
    parameter DATA_WIDTH   = 32,
    parameter BUFFER_DEPTH = 8
)(
    input  logic                      clk,
    input  logic                      rstn,
    input  logic                      write_enable,
    input  logic  [BUFFER_DEPTH-1:0]  write_pointer,
    input  logic  [DATA_WIDTH-1:0]    write_data,
    input  logic  [BUFFER_DEPTH-1:0]  read_pointer,
    output logic  [DATA_WIDTH-1:0]    read_data
);

    logic [BUFFER_DEPTH-1:0][DATA_WIDTH-1:0]       data;
    logic  [$clog2(BUFFER_DEPTH)-1:0]  write_pointer_bin;
    logic  [$clog2(BUFFER_DEPTH)-1:0]  read_pointer_bin;

    onehot_to_bin #(.ONEHOT_WIDTH(BUFFER_DEPTH)) WPRT_OH_BIN (.onehot(write_pointer), .bin(write_pointer_bin));
    onehot_to_bin #(.ONEHOT_WIDTH(BUFFER_DEPTH)) RPRT_OH_BIN (.onehot(read_pointer),  .bin(read_pointer_bin));

    always_ff @(posedge clk, negedge rstn)
    begin: read_write_data
        if (rstn == 1'b0)
                data <= '0;
        else

            if (write_enable)
                data[write_pointer_bin] <= write_data;
    end