/*
   Copyright 2013 Ray Salemi

   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.
*/
class coverage;

   virtual tinyalu_bfm bfm;

   byte         unsigned        A;
   byte         unsigned        B;
   operation_t  op_set;

   covergroup op_cov;

      coverpoint op_set {
         bins single_cycle[] = {[add_op : xor_op], rst_op,no_op};
         bins multi_cycle = {mul_op};

         bins opn_rst[] = ([add_op:mul_op] => rst_op);
         bins rst_opn[] = (rst_op => [add_op:mul_op]);

         bins sngl_mul[] = ([add_op:xor_op],no_op => mul_op);
         bins mul_sngl[] = (mul_op => [add_op:xor_op], no_op);

         bins twoops[] = ([add_op:mul_op] [* 2]);
         bins manymult = (mul_op [* 3:5]);

      }

   endgroup

   covergroup zeros_or_ones_on_ops;

      all_ops : coverpoint op_set {
         ignore_bins null_ops = {rst_op, no_op};}

      a_leg: coverpoint A {
         bins zeros = {'h00};
         bins others= {['h01:'hFE]};
         bins ones  = {'hFF};
      }

      b_leg: coverpoint B {
         bins zeros = {'h00};
         bins others= {['h01:'hFE]};
         bins ones  = {'hFF};
      }

      op_00_FF:  cross a_leg, b_leg, all_ops {
         bins add_00 = binsof (all_ops) intersect {add_op} &&
                       (binsof (a_leg.zeros) || binsof (b_leg.zeros));

         bins add_FF = binsof (all_ops) intersect {add_op} &&
                       (binsof (a_leg.ones) || binsof (b_leg.ones));

         bins and_00 = binsof (all_ops) intersect {and_op} &&

         bins and_FF = binsof (all_ops) intersect {and_op} &&
                       (binsof (a_leg.ones) || binsof (b_leg.ones));

         bins xor_00 = binsof (all_ops) intersect {xor_op} &&
<TARGET>

         bins xor_FF = binsof (all_ops) intersect {xor_op} &&
                       (binsof (a_leg.ones) || binsof (b_leg.ones));

         bins mul_00 = binsof (all_ops) intersect {mul_op} &&
                       (binsof (a_leg.zeros) || binsof (b_leg.zeros));

         bins mul_FF = binsof (all_ops) intersect {mul_op} &&
                       (binsof (a_leg.ones) || binsof (b_leg.ones));

         bins mul_max = binsof (all_ops) intersect {mul_op} &&
                        (binsof (a_leg.ones) && binsof (b_leg.ones));

         ignore_bins others_only =
                                  binsof(a_leg.others) && binsof(b_leg.others);

      }

endgroup

   function new (virtual tinyalu_bfm b);
     op_cov = new();
     zeros_or_ones_on_ops = new();
     bfm = b;
   endfunction : new

   task execute();
      forever begin  : sampling_block
         @(negedge bfm.clk);
         A = bfm.A;
         B = bfm.B;
         op_set = bfm.op_set;
         op_cov.sample();
         zeros_or_ones_on_ops.sample();
      end : sampling_block
   endtask : execute

endclass : coverage


/*
   Copyright 2013 Ray Salemi

   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.
*/
class consumer extends uvm_component;
   `uvm_component_utils(consumer);

   uvm_get_port #(int) get_port_h;
   int shared;

   function void build_phase(uvm_phase phase);
      get_port_h = new("get_port_h", this);
   endfunction : build_phase

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

   task run_phase(uvm_phase phase);
      forever begin
         get_port_h.get(shared);
         $display("Received: %0d", shared);
      end


`include "uvm_macros.svh"
import uvm_pkg::*;

class rpting extends uvm_component;

  `uvm_component_utils(rpting)

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

  task run();

    uvm_report_info(get_full_name(),
    "This is information 1",UVM_NONE,`__FILE__,`__LINE__);

    uvm_report_info(get_full_name(),
    "This is information 2",UVM_LOW);

    uvm_report_info(get_full_name(),
    "This is information 3",150);

    uvm_report_info(get_full_name(),
    "This is information 4",UVM_MEDIUM);

    uvm_report_warning(get_full_name(),
    "Warning Messgae from rpting",UVM_LOW);

    uvm_report_error(get_full_name(),
    "Error Message from rpting \n\n",UVM_LOW);
  endtask

endclass

module top;

rpting rpt1;
rpting rpt2;
rpting rpt3;

initial begin
  rpt1 = new("rpt1",null);
  rpt2 = new("rpt2",null);
  rpt3 = new("rpt3",null);

  // display the howmany error message in console
  rpt3.set_report_severity_action(UVM_ERROR,UVM_DISPLAY);

  run_test();
end
endmodule

  //Do nohing when error message occured
  rpt1.set_report_severity_action(UVM_ERROR,UVM_NO_ACTION);


class env extends uvm_env;
  `uvm_component_utils(env)

    super.new(inst,c);
  endfunction

  agent a;

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    a = agent::type_id::create("AGENT",this);
  endfunction

endclass

function new(input string inst = "ENV", uvm_component c);


/////////////////////////////////////////////////////////////////////////////////////
//
//Copyright 2020  Li Xinbing
//
//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.
//
/////////////////////////////////////////////////////////////////////////////////////

//THis module manages instruction memory request. There are 3 methods to change PC.
//1--- jump_vld/jump_pc: System jump to PC
//2--- branch_vld/branch_pc: branch to PC
//3--- buffer_free: Keep fetching instructions

`include "define.v"
module instrman
(
    input                           clk,
	input                           rst,

    output                          imem_req,
	output `N(`XLEN)                imem_addr,
	input                           imem_resp,
	input  `N(`BUS_WID)             imem_rdata,
	input                           imem_err,

	input                           jump_vld,
	input  `N(`XLEN)                jump_pc,
	input                           branch_vld,
	input  `N(`XLEN)                branch_pc,
	input                           buffer_free,

	output                          imem_vld,
	output `N(`BUS_WID)             imem_instr,
	output                          imem_status

);

    //---------------------------------------------------------------------------
    //signal defination
    //---------------------------------------------------------------------------
	reg `N(`XLEN)   pc;
	reg             req_sent;
	reg             instr_verified;

    //---------------------------------------------------------------------------
    //statements description
    //---------------------------------------------------------------------------

    wire             reload_vld = jump_vld|branch_vld;
	wire `N(`XLEN)    reload_pc = ( jump_vld ? jump_pc : branch_pc ) & ( {`XLEN{1'b1}}<<1 );
	wire `N(`XLEN)   fetch_addr = reload_vld ? reload_pc : pc;

	//imem_addr
	`FFx(pc,0)
	if ( imem_req )
	    pc <= fetch_addr + 4*`BUS_LEN;
	else if ( reload_vld )
	    pc <= reload_pc;
	else;

	//imem_req
	wire             request_go = buffer_free|reload_vld;

	//if req_sent is 0, request_go can be asserted any time, if it is 1, only when imem_resp is OK.
	`FFx(req_sent,1'b0)
	if ( ~req_sent|imem_resp )
	    req_sent <= request_go;
	else;

	assign             imem_req = request_go & ( ~req_sent|imem_resp );

	//rdata could be cancelled by "reload_vld"
	`FFx(instr_verified,1'b0)
	if ( imem_req )
	    instr_verified <= 1'b1;
	else if ( reload_vld|imem_resp )
	    instr_verified <= 1'b0;
	else;

	assign             imem_vld = instr_verified & imem_resp;
	assign           imem_instr = imem_rdata;
	assign          imem_status = imem_err;

endmodule

assign            imem_addr = fetch_addr & `PC_ALIGN;


/// Copyright by Syntacore LLC © 2016-2018. See LICENSE for details
/// @file       <scr1_pipe_idu.sv>
/// @brief      Instruction Decoder Unit (IDU)
///

`include "scr1_memif.svh"
`include "scr1_arch_types.svh"
`include "scr1_riscv_isa_decoding.svh"
`include "scr1_arch_description.svh"

module scr1_pipe_idu
(
`ifdef SCR1_SIM_ENV
    input   logic                           rst_n,
    input   logic                           clk,
`endif // SCR1_SIM_ENV

    // IFU <-> IDU interface
    output  logic                           idu2ifu_rdy,            // IDU ready for new data
    input   logic [`SCR1_IMEM_DWIDTH-1:0]   ifu2idu_instr,          // IFU instruction
    input   logic                           ifu2idu_imem_err,       // Instruction access fault exception
    input   logic                           ifu2idu_err_rvi_hi,     // 1 - imem fault when trying to fetch second half of an unaligned RVI instruction
    input   logic                           ifu2idu_vd,             // IFU request

    // IDU <-> EXU interface
    output  logic                           idu2exu_req,            // IDU request
    output  type_scr1_exu_cmd_s             idu2exu_cmd,            // IDU command
    output  logic                           idu2exu_use_rs1,        // Instruction uses rs1
    output  logic                           idu2exu_use_rs2,        // Instruction uses rs2
    output  logic                           idu2exu_use_rd,         // Instruction uses rd
    output  logic                           idu2exu_use_imm,        // Instruction uses immediate
    input   logic                           exu2idu_rdy             // EXU ready for new data
);

//-------------------------------------------------------------------------------
// Local parameters declaration
//-------------------------------------------------------------------------------
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_ZERO_ADDR   = 5'd0;
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_RA_ADDR     = 5'd1;
localparam [SCR1_GPR_FIELD_WIDTH-1:0] SCR1_MPRF_SP_ADDR     = 5'd2;

//-------------------------------------------------------------------------------
// Local signals declaration
//-------------------------------------------------------------------------------

logic [`SCR1_IMEM_DWIDTH-1:0]       instr;
type_scr1_instr_type_e              instr_type;
type_scr1_rvi_opcode_e              rvi_opcode;
logic                               rvi_illegal;
logic [2:0]                         funct3;
logic [6:0]                         funct7;
logic [11:0]                        funct12;
logic [4:0]                         shamt;
`ifdef SCR1_RVC_EXT
logic                               rvc_illegal;
`endif  // SCR1_RVC_EXT
`ifdef SCR1_RVE_EXT
logic                               rve_illegal;
`endif  // SCR1_RVE_EXT

//-------------------------------------------------------------------------------
// Decode
//-------------------------------------------------------------------------------

assign idu2ifu_rdy  = exu2idu_rdy;
assign idu2exu_req  = ifu2idu_vd;
assign instr        = ifu2idu_instr;

// RVI / RVC
assign instr_type   = type_scr1_instr_type_e'(instr[1:0]);

// RVI / RVC fields
assign rvi_opcode   = type_scr1_rvi_opcode_e'(instr[6:2]);                          // RVI
assign funct3       = (instr_type == SCR1_INSTR_RVI) ? instr[14:12] : instr[15:13]; // RVI / RVC
assign funct7       = instr[31:25];                                                 // RVI
assign funct12      = instr[31:20];                                                 // RVI (SYSTEM)
assign shamt        = instr[24:20];                                                 // RVI

// RV32I(MC) decode
always_comb begin
    // Defaults
    idu2exu_cmd.instr_rvc   = 1'b0;
    idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
    idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_NONE;
    idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_PC_IMM;
    idu2exu_cmd.lsu_cmd     = SCR1_LSU_CMD_NONE;
    idu2exu_cmd.csr_op      = SCR1_CSR_OP_REG;
    idu2exu_cmd.csr_cmd     = SCR1_CSR_CMD_NONE;
    idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_NONE;
    idu2exu_cmd.jump_req    = 1'b0;
    idu2exu_cmd.branch_req  = 1'b0;
    idu2exu_cmd.mret_req    = 1'b0;
    idu2exu_cmd.fencei_req  = 1'b0;
    idu2exu_cmd.wfi_req     = 1'b0;
    idu2exu_cmd.rs1_addr    = '0;
    idu2exu_cmd.rs2_addr    = '0;
    idu2exu_cmd.rd_addr     = '0;
    idu2exu_cmd.imm         = '0;
    idu2exu_cmd.exc_req     = 1'b0;
    idu2exu_cmd.exc_code    = SCR1_EXC_CODE_INSTR_MISALIGN;
    // Clock gating
    idu2exu_use_rs1         = 1'b0;
    idu2exu_use_rs2         = 1'b0;
    idu2exu_use_rd          = 1'b0;
    idu2exu_use_imm         = 1'b0;

    rvi_illegal             = 1'b0;
`ifdef SCR1_RVE_EXT
    rve_illegal             = 1'b0;
`endif  // SCR1_RVE_EXT
`ifdef SCR1_RVC_EXT
    rvc_illegal             = 1'b0;
`endif  // SCR1_RVC_EXT

    // Check for IMEM access fault
    if (ifu2idu_imem_err) begin
        idu2exu_cmd.exc_req     = 1'b1;
        idu2exu_cmd.exc_code    = SCR1_EXC_CODE_INSTR_ACCESS_FAULT;
        idu2exu_cmd.instr_rvc   = ifu2idu_err_rvi_hi;
    end else begin  // no imem fault
        case (instr_type)
            SCR1_INSTR_RVI  : begin
                idu2exu_cmd.rs1_addr    = instr[19:15];
                idu2exu_cmd.rs2_addr    = instr[24:20];
                idu2exu_cmd.rd_addr     = instr[11:7];
                case (rvi_opcode)
                    SCR1_OPCODE_AUIPC           : begin
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_PC_IMM;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_SUM2;
                        idu2exu_cmd.imm         = {instr[31:12], 12'b0};
`ifdef SCR1_RVE_EXT
                        if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_AUIPC

                    SCR1_OPCODE_LUI             : begin
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IMM;
                        idu2exu_cmd.imm         = {instr[31:12], 12'b0};
`ifdef SCR1_RVE_EXT
                        if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_LUI

                    SCR1_OPCODE_JAL             : begin
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_PC_IMM;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_INC_PC;
                        idu2exu_cmd.jump_req    = 1'b1;
                        idu2exu_cmd.imm         = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0};
`ifdef SCR1_RVE_EXT
                        if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_JAL

                    SCR1_OPCODE_LOAD            : begin
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_REG_IMM;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_LSU;
                        idu2exu_cmd.imm         = {{21{instr[31]}}, instr[30:20]};
                        case (funct3)
                            3'b000  : idu2exu_cmd.lsu_cmd = SCR1_LSU_CMD_LB;
                            3'b001  : idu2exu_cmd.lsu_cmd = SCR1_LSU_CMD_LH;
                            3'b010  : idu2exu_cmd.lsu_cmd = SCR1_LSU_CMD_LW;
                            3'b100  : idu2exu_cmd.lsu_cmd = SCR1_LSU_CMD_LBU;
                            3'b101  : idu2exu_cmd.lsu_cmd = SCR1_LSU_CMD_LHU;
                            default : rvi_illegal = 1'b1;
                        endcase // funct3
`ifdef SCR1_RVE_EXT
                        if (instr[11] | instr[19])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_LOAD

                    SCR1_OPCODE_STORE           : begin
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rs2         = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_REG_IMM;
                        idu2exu_cmd.imm         = {{21{instr[31]}}, instr[30:25], instr[11:7]};
                        case (funct3)
                            3'b000  : idu2exu_cmd.lsu_cmd = SCR1_LSU_CMD_SB;
                            3'b001  : idu2exu_cmd.lsu_cmd = SCR1_LSU_CMD_SH;
                            3'b010  : idu2exu_cmd.lsu_cmd = SCR1_LSU_CMD_SW;
                            default : rvi_illegal = 1'b1;
                        endcase // funct3
`ifdef SCR1_RVE_EXT
                        if (instr[19] | instr[24])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_STORE

                    SCR1_OPCODE_OP              : begin
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rs2         = 1'b1;
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                        case (funct7)
                            7'b0000000 : begin
                                case (funct3)
                                    3'b000  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_ADD;
                                    3'b001  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_SLL;
                                    3'b010  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_SUB_LT;
                                    3'b011  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_SUB_LTU;
                                    3'b100  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_XOR;
                                    3'b101  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_SRL;
                                    3'b110  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_OR;
                                    3'b111  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_AND;
                                endcase // funct3
                            end // 7'b0000000

                            7'b0100000 : begin
                                case (funct3)
                                    3'b000  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_SUB;
                                    3'b101  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_SRA;
                                    default : rvi_illegal = 1'b1;
                                endcase // funct3
                            end // 7'b0100000
`ifdef SCR1_RVM_EXT
                            7'b0000001 : begin
                                case (funct3)
                                    3'b000  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_MUL;
                                    3'b001  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_MULH;
                                    3'b010  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_MULHSU;
                                    3'b011  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_MULHU;
                                    3'b100  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_DIV;
                                    3'b101  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_DIVU;
                                    3'b110  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_REM;
                                    3'b111  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_REMU;
                                endcase // funct3
                            end // 7'b0000001
`endif  // SCR1_RVM_EXT
                            default : rvi_illegal = 1'b1;
                        endcase // funct7
`ifdef SCR1_RVE_EXT
                        if (instr[11] | instr[19] | instr[24])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_OP

                    SCR1_OPCODE_OP_IMM          : begin
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.imm         = {{21{instr[31]}}, instr[30:20]};
                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_IMM;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                        case (funct3)
                            3'b000  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_ADD;        // ADDI
                            3'b010  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_SUB_LT;     // SLTI
                            3'b011  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_SUB_LTU;    // SLTIU
                            3'b100  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_XOR;        // XORI
                            3'b110  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_OR;         // ORI
                            3'b111  : idu2exu_cmd.ialu_cmd  = SCR1_IALU_CMD_AND;        // ANDI
                            3'b001  : begin
                                case (funct7)
                                    7'b0000000  : begin
                                        // SLLI
                                        idu2exu_cmd.imm         = `SCR1_XLEN'(shamt);   // zero-extend
                                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SLL;
                                    end
                                    default     : rvi_illegal   = 1'b1;
                                endcase // funct7
                            end
                            3'b101  : begin
                                case (funct7)
                                    7'b0000000  : begin
                                        // SRLI
                                        idu2exu_cmd.imm         = `SCR1_XLEN'(shamt);   // zero-extend
                                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SRL;
                                    end
                                    7'b0100000  : begin
                                        // SRAI
                                        idu2exu_cmd.imm         = `SCR1_XLEN'(shamt);   // zero-extend
                                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SRA;
                                    end
                                    default     : rvi_illegal   = 1'b1;
                                endcase // funct7
                            end
                        endcase // funct3
`ifdef SCR1_RVE_EXT
                        if (instr[11] | instr[19])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_OP_IMM

                    SCR1_OPCODE_MISC_MEM    : begin
                        case (funct3)
                            3'b000  : begin
                                if (~|{instr[31:28], instr[19:15], instr[11:7]}) begin
                                    // FENCE = NOP
                                end
                                else rvi_illegal = 1'b1;
                            end
                            3'b001  : begin
                                if (~|{instr[31:15], instr[11:7]}) begin
                                    // FENCE.I
                                    idu2exu_cmd.fencei_req    = 1'b1;
                                end
                                else rvi_illegal = 1'b1;
                            end
                            default : rvi_illegal = 1'b1;
                        endcase // funct3
                    end // SCR1_OPCODE_MISC_MEM

                    SCR1_OPCODE_BRANCH          : begin
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rs2         = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.imm         = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0};
                        idu2exu_cmd.branch_req  = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_PC_IMM;
                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                        case (funct3)
                            3'b000  : idu2exu_cmd.ialu_cmd = SCR1_IALU_CMD_SUB_EQ;
                            3'b001  : idu2exu_cmd.ialu_cmd = SCR1_IALU_CMD_SUB_NE;
                            3'b100  : idu2exu_cmd.ialu_cmd = SCR1_IALU_CMD_SUB_LT;
                            3'b101  : idu2exu_cmd.ialu_cmd = SCR1_IALU_CMD_SUB_GE;
                            3'b110  : idu2exu_cmd.ialu_cmd = SCR1_IALU_CMD_SUB_LTU;
                            3'b111  : idu2exu_cmd.ialu_cmd = SCR1_IALU_CMD_SUB_GEU;
                            default : rvi_illegal = 1'b1;
                        endcase // funct3
`ifdef SCR1_RVE_EXT
                        if (instr[19] | instr[24])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_BRANCH

                    SCR1_OPCODE_JALR        : begin
                        idu2exu_use_rs1     = 1'b1;
                        idu2exu_use_rd      = 1'b1;
                        idu2exu_use_imm     = 1'b1;
                        case (funct3)
                            3'b000  : begin
                                // JALR
                                idu2exu_cmd.sum2_op   = SCR1_SUM2_OP_REG_IMM;
                                idu2exu_cmd.rd_wb_sel = SCR1_RD_WB_INC_PC;
                                idu2exu_cmd.jump_req  = 1'b1;
                                idu2exu_cmd.imm       = {{21{instr[31]}}, instr[30:20]};
                            end
                            default : rvi_illegal = 1'b1;
                        endcase
`ifdef SCR1_RVE_EXT
                        if (instr[11] | instr[19])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end // SCR1_OPCODE_JALR

                    SCR1_OPCODE_SYSTEM      : begin
                        idu2exu_use_rd      = 1'b1;
                        idu2exu_use_imm     = 1'b1;
                        idu2exu_cmd.imm     = `SCR1_XLEN'({funct3, instr[31:20]});      // {funct3, CSR address}
                        case (funct3)
                            3'b000  : begin
                                idu2exu_use_rd    = 1'b0;
                                idu2exu_use_imm   = 1'b0;
                                case ({instr[19:15], instr[11:7]})
                                    10'd0 : begin
                                        case (funct12)
                                            12'h000 : begin
                                                // ECALL
                                                idu2exu_cmd.exc_req     = 1'b1;
                                                idu2exu_cmd.exc_code    = SCR1_EXC_CODE_ECALL_M;
                                            end
                                            12'h001 : begin
                                                // EBREAK
                                                idu2exu_cmd.exc_req     = 1'b1;
                                                idu2exu_cmd.exc_code    = SCR1_EXC_CODE_BREAKPOINT;
                                            end
                                            12'h302 : begin
                                                // MRET
                                                idu2exu_cmd.mret_req    = 1'b1;
                                            end
                                            12'h105 : begin
                                                // WFI
                                                idu2exu_cmd.wfi_req     = 1'b1;
                                            end
                                            default : rvi_illegal = 1'b1;
                                        endcase // funct12
                                    end
                                    default : rvi_illegal = 1'b1;
                                endcase // {instr[19:15], instr[11:7]}
                            end
                            3'b001  : begin
                                // CSRRW
                                idu2exu_use_rs1             = 1'b1;
                                idu2exu_cmd.rd_wb_sel       = SCR1_RD_WB_CSR;
                                idu2exu_cmd.csr_cmd         = SCR1_CSR_CMD_WRITE;
                                idu2exu_cmd.csr_op          = SCR1_CSR_OP_REG;
`ifdef SCR1_RVE_EXT
                                if (instr[11] | instr[19])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end
                            3'b010  : begin
                                // CSRRS
                                idu2exu_use_rs1             = 1'b1;
                                idu2exu_cmd.rd_wb_sel       = SCR1_RD_WB_CSR;
                                idu2exu_cmd.csr_cmd         = SCR1_CSR_CMD_SET;
                                idu2exu_cmd.csr_op          = SCR1_CSR_OP_REG;
`ifdef SCR1_RVE_EXT
                                if (instr[11] | instr[19])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end
                            3'b011  : begin
                                // CSRRC
                                idu2exu_use_rs1             = 1'b1;
                                idu2exu_cmd.rd_wb_sel       = SCR1_RD_WB_CSR;
                                idu2exu_cmd.csr_cmd         = SCR1_CSR_CMD_CLEAR;
                                idu2exu_cmd.csr_op          = SCR1_CSR_OP_REG;
`ifdef SCR1_RVE_EXT
                                if (instr[11] | instr[19])  rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end
                            3'b101  : begin
                                // CSRRWI
                                idu2exu_use_rs1             = 1'b1;             // zimm
                                idu2exu_cmd.rd_wb_sel       = SCR1_RD_WB_CSR;
                                idu2exu_cmd.csr_cmd         = SCR1_CSR_CMD_WRITE;
                                idu2exu_cmd.csr_op          = SCR1_CSR_OP_IMM;
`ifdef SCR1_RVE_EXT
                                if (instr[11])              rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end
                            3'b110  : begin
                                // CSRRSI
                                idu2exu_use_rs1             = 1'b1;             // zimm
                                idu2exu_cmd.rd_wb_sel       = SCR1_RD_WB_CSR;
                                idu2exu_cmd.csr_cmd         = SCR1_CSR_CMD_SET;
                                idu2exu_cmd.csr_op          = SCR1_CSR_OP_IMM;
`ifdef SCR1_RVE_EXT
                                if (instr[11])              rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end
                            3'b111  : begin
                                // CSRRCI
                                idu2exu_use_rs1             = 1'b1;             // zimm
                                idu2exu_cmd.rd_wb_sel       = SCR1_RD_WB_CSR;
                                idu2exu_cmd.csr_cmd         = SCR1_CSR_CMD_CLEAR;
                                idu2exu_cmd.csr_op          = SCR1_CSR_OP_IMM;
`ifdef SCR1_RVE_EXT
                                if (instr[11])              rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end
                            default : rvi_illegal = 1'b1;
                        endcase // funct3
                    end // SCR1_OPCODE_SYSTEM

                    default : begin
                        rvi_illegal = 1'b1;
                    end
                endcase // rvi_opcode
            end // SCR1_INSTR_RVI

`ifdef SCR1_RVC_EXT

            // Quadrant 0
            SCR1_INSTR_RVC0 : begin
                idu2exu_cmd.instr_rvc   = 1'b1;
                idu2exu_use_rs1         = 1'b1;
                idu2exu_use_imm         = 1'b1;
                case (funct3)
                    3'b000  : begin
                        if (~|instr[12:5])      rvc_illegal = 1'b1;
                        // C.ADDI4SPN
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_ADD;
                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_IMM;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                        idu2exu_cmd.rs1_addr    = SCR1_MPRF_SP_ADDR;
                        idu2exu_cmd.rd_addr     = {2'b01, instr[4:2]};
                        idu2exu_cmd.imm         = {22'd0, instr[10:7], instr[12:11], instr[5], instr[6], 2'b00};
                    end
                    3'b010  : begin
                        // C.LW
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_REG_IMM;
                        idu2exu_cmd.lsu_cmd     = SCR1_LSU_CMD_LW;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_LSU;
                        idu2exu_cmd.rs1_addr    = {2'b01, instr[9:7]};
                        idu2exu_cmd.rd_addr     = {2'b01, instr[4:2]};
                        idu2exu_cmd.imm         = {25'd0, instr[5], instr[12:10], instr[6], 2'b00};
                    end
                    3'b110  : begin
                        // C.SW
                        idu2exu_use_rs2         = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_REG_IMM;
                        idu2exu_cmd.lsu_cmd     = SCR1_LSU_CMD_SW;
                        idu2exu_cmd.rs1_addr    = {2'b01, instr[9:7]};
                        idu2exu_cmd.rs2_addr    = {2'b01, instr[4:2]};
                        idu2exu_cmd.imm         = {25'd0, instr[5], instr[12:10], instr[6], 2'b00};
                    end
                    default : begin
                        rvc_illegal = 1'b1;
                    end
                endcase // funct3
            end // Quadrant 0

            // Quadrant 1
            SCR1_INSTR_RVC1 : begin
                idu2exu_cmd.instr_rvc   = 1'b1;
                idu2exu_use_rd          = 1'b1;
                idu2exu_use_imm         = 1'b1;
                case (funct3)
                    3'b000  : begin
                        // C.ADDI / C.NOP
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_ADD;
                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_IMM;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                        idu2exu_cmd.rs1_addr    = instr[11:7];
                        idu2exu_cmd.rd_addr     = instr[11:7];
                        idu2exu_cmd.imm         = {{27{instr[12]}}, instr[6:2]};
`ifdef SCR1_RVE_EXT
                        if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end
                    3'b001  : begin
                        // C.JAL
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_PC_IMM;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_INC_PC;
                        idu2exu_cmd.jump_req    = 1'b1;
                        idu2exu_cmd.rd_addr     = SCR1_MPRF_RA_ADDR;
                        idu2exu_cmd.imm         = {{21{instr[12]}}, instr[8], instr[10:9], instr[6], instr[7], instr[2], instr[11], instr[5:3], 1'b0};
                    end
                    3'b010  : begin
                        // C.LI
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IMM;
                        idu2exu_cmd.rd_addr     = instr[11:7];
                        idu2exu_cmd.imm         = {{27{instr[12]}}, instr[6:2]};
`ifdef SCR1_RVE_EXT
                        if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end
                    3'b011  : begin
                        if (~|{instr[12], instr[6:2]}) rvc_illegal = 1'b1;
                        if (instr[11:7] == SCR1_MPRF_SP_ADDR) begin
                            // C.ADDI16SP
                            idu2exu_use_rs1         = 1'b1;
                            idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_ADD;
                            idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_IMM;
                            idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                            idu2exu_cmd.rs1_addr    = SCR1_MPRF_SP_ADDR;
                            idu2exu_cmd.rd_addr     = SCR1_MPRF_SP_ADDR;
                            idu2exu_cmd.imm         = {{23{instr[12]}}, instr[4:3], instr[5], instr[2], instr[6], 4'd0};
                        end else begin
                            // C.LUI
                            idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IMM;
                            idu2exu_cmd.rd_addr     = instr[11:7];
                            idu2exu_cmd.imm         = {{15{instr[12]}}, instr[6:2], 12'd0};
`ifdef SCR1_RVE_EXT
                            if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                        end
                    end
                    3'b100  : begin
                        idu2exu_cmd.rs1_addr    = {2'b01, instr[9:7]};
                        idu2exu_cmd.rd_addr     = {2'b01, instr[9:7]};
                        idu2exu_cmd.rs2_addr    = {2'b01, instr[4:2]};
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rd          = 1'b1;
                        case (instr[11:10])
                            2'b00   : begin
                                if (instr[12])          rvc_illegal = 1'b1;
                                // C.SRLI
                                idu2exu_use_imm         = 1'b1;
                                idu2exu_cmd.imm         = {27'd0, instr[6:2]};
                                idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SRL;
                                idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_IMM;
                                idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                            end
                            2'b01   : begin
                                if (instr[12])          rvc_illegal = 1'b1;
                                // C.SRAI
                                idu2exu_use_imm         = 1'b1;

                                idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SRA;
                                idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_IMM;
                                idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                            end
                            2'b10   : begin
                                // C.ANDI
                                idu2exu_use_imm         = 1'b1;
                                idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_AND;
                                idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_IMM;
                                idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                                idu2exu_cmd.imm         = {{27{instr[12]}}, instr[6:2]};
                            end
                            2'b11   : begin
                                idu2exu_use_rs2         = 1'b1;
                                case ({instr[12], instr[6:5]})
                                    3'b000  : begin
                                        // C.SUB
                                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SUB;
                                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                                    end
                                    3'b001  : begin
                                        // C.XOR
                                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_XOR;
                                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                                    end
                                    3'b010  : begin
                                        // C.OR
                                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_OR;
                                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                                    end
                                    3'b011  : begin
                                        // C.AND
                                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_AND;
                                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                                    end
                                    default : begin
                                        rvc_illegal = 1'b1;
                                    end
                                endcase // {instr[12], instr[6:5]}
                            end
                        endcase // instr[11:10]
                    end // funct3 == 3'b100
                    3'b101  : begin
                        // C.J
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_PC_IMM;
                        idu2exu_cmd.jump_req    = 1'b1;
                        idu2exu_cmd.imm         = {{21{instr[12]}}, instr[8], instr[10:9], instr[6], instr[7], instr[2], instr[11], instr[5:3], 1'b0};
                    end
                    3'b110  : begin
                        // C.BEQZ
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rs2         = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SUB_EQ;
                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_PC_IMM;
                        idu2exu_cmd.branch_req  = 1'b1;
                        idu2exu_cmd.rs1_addr    = {2'b01, instr[9:7]};
                        idu2exu_cmd.rs2_addr    = SCR1_MPRF_ZERO_ADDR;
                        idu2exu_cmd.imm         = {{24{instr[12]}}, instr[6:5], instr[2], instr[11:10], instr[4:3], 1'b0};
                    end
                    3'b111  : begin
                        // C.BNEZ
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rs2         = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SUB_NE;
                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_PC_IMM;
                        idu2exu_cmd.branch_req  = 1'b1;
                        idu2exu_cmd.rs1_addr    = {2'b01, instr[9:7]};
                        idu2exu_cmd.rs2_addr    = SCR1_MPRF_ZERO_ADDR;
                        idu2exu_cmd.imm         = {{24{instr[12]}}, instr[6:5], instr[2], instr[11:10], instr[4:3], 1'b0};
                    end
                endcase // funct3
            end // Quadrant 1

            // Quadrant 2
            SCR1_INSTR_RVC2 : begin
                idu2exu_cmd.instr_rvc   = 1'b1;
                idu2exu_use_rs1         = 1'b1;
                case (funct3)
                    3'b000  : begin
                        if (instr[12])          rvc_illegal = 1'b1;
                        // C.SLLI
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.rs1_addr    = instr[11:7];
                        idu2exu_cmd.rd_addr     = instr[11:7];
                        idu2exu_cmd.imm         = {27'd0, instr[6:2]};
                        idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_SLL;
                        idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_IMM;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
`ifdef SCR1_RVE_EXT
                        if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end
                    3'b010  : begin
                        if (~|instr[11:7])      rvc_illegal = 1'b1;
                        // C.LWSP
                        idu2exu_use_rd          = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_REG_IMM;
                        idu2exu_cmd.lsu_cmd     = SCR1_LSU_CMD_LW;
                        idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_LSU;
                        idu2exu_cmd.rs1_addr    = SCR1_MPRF_SP_ADDR;
                        idu2exu_cmd.rd_addr     = instr[11:7];
                        idu2exu_cmd.imm         = {24'd0, instr[3:2], instr[12], instr[6:4], 2'b00};
`ifdef SCR1_RVE_EXT
                        if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end
                    3'b100  : begin
                        if (~instr[12]) begin
                            if (|instr[6:2]) begin
                                // C.MV
                                idu2exu_use_rs2         = 1'b1;
                                idu2exu_use_rd          = 1'b1;
                                idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_ADD;
                                idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                                idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                                idu2exu_cmd.rs1_addr    = SCR1_MPRF_ZERO_ADDR;
                                idu2exu_cmd.rs2_addr    = instr[6:2];
                                idu2exu_cmd.rd_addr     = instr[11:7];
`ifdef SCR1_RVE_EXT
                                if (instr[11]|instr[6]) rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end else begin
                                if (~|instr[11:7])      rvc_illegal = 1'b1;
                                // C.JR
                                idu2exu_use_imm         = 1'b1;
                                idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_REG_IMM;
                                idu2exu_cmd.jump_req    = 1'b1;
                                idu2exu_cmd.rs1_addr    = instr[11:7];
                                idu2exu_cmd.imm         = 0;
`ifdef SCR1_RVE_EXT
                                if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end
                        end else begin  // instr[12] == 1
                            if (~|instr[11:2]) begin
                                // C.EBREAK
                                idu2exu_cmd.exc_req     = 1'b1;
                                idu2exu_cmd.exc_code    = SCR1_EXC_CODE_BREAKPOINT;
                            end else if (~|instr[6:2]) begin
                                // C.JALR
                                idu2exu_use_rs1         = 1'b1;
                                idu2exu_use_rd          = 1'b1;
                                idu2exu_use_imm         = 1'b1;
                                idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_REG_IMM;
                                idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_INC_PC;
                                idu2exu_cmd.jump_req    = 1'b1;
                                idu2exu_cmd.rs1_addr    = instr[11:7];
                                idu2exu_cmd.rd_addr     = SCR1_MPRF_RA_ADDR;
                                idu2exu_cmd.imm         = 0;
`ifdef SCR1_RVE_EXT
                                if (instr[11])          rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end else begin
                                // C.ADD
                                idu2exu_use_rs1         = 1'b1;
                                idu2exu_use_rs2         = 1'b1;
                                idu2exu_use_rd          = 1'b1;
                                idu2exu_cmd.ialu_cmd    = SCR1_IALU_CMD_ADD;
                                idu2exu_cmd.ialu_op     = SCR1_IALU_OP_REG_REG;
                                idu2exu_cmd.rd_wb_sel   = SCR1_RD_WB_IALU;
                                idu2exu_cmd.rs1_addr    = instr[11:7];
                                idu2exu_cmd.rs2_addr    = instr[6:2];
                                idu2exu_cmd.rd_addr     = instr[11:7];
`ifdef SCR1_RVE_EXT
                                if (instr[11]|instr[6]) rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                            end
                        end // instr[12] == 1
                    end
                    3'b110  : begin
                        // C.SWSP
                        idu2exu_use_rs1         = 1'b1;
                        idu2exu_use_rs2         = 1'b1;
                        idu2exu_use_imm         = 1'b1;
                        idu2exu_cmd.sum2_op     = SCR1_SUM2_OP_REG_IMM;
                        idu2exu_cmd.lsu_cmd     = SCR1_LSU_CMD_SW;
                        idu2exu_cmd.rs1_addr    = SCR1_MPRF_SP_ADDR;
                        idu2exu_cmd.rs2_addr    = instr[6:2];
                        idu2exu_cmd.imm         = {24'd0, instr[8:7], instr[12:9], 2'b00};
`ifdef SCR1_RVE_EXT
                        if (instr[6])           rve_illegal = 1'b1;
`endif  // SCR1_RVE_EXT
                    end
                    default : begin
                        rvc_illegal = 1'b1;
                    end
                endcase // funct3
            end // Quadrant 2

            default         : begin
            end
`else   // SCR1_RVC_EXT
            default         : begin
                idu2exu_cmd.instr_rvc   = 1'b1;
                rvi_illegal             = 1'b1;
            end
`endif  // SCR1_RVC_EXT
        endcase // instr_type
    end // no imem fault

    // At this point the instruction is fully decoded
    // given that no imem fault has happened

    // Check illegal instruction
    if (
    rvi_illegal
`ifdef SCR1_RVC_EXT
    | rvc_illegal
`endif
`ifdef SCR1_RVE_EXT
    | rve_illegal
`endif
    ) begin
        idu2exu_cmd.ialu_cmd        = SCR1_IALU_CMD_NONE;
        idu2exu_cmd.lsu_cmd         = SCR1_LSU_CMD_NONE;
        idu2exu_cmd.csr_cmd         = SCR1_CSR_CMD_NONE;
        idu2exu_cmd.rd_wb_sel       = SCR1_RD_WB_NONE;
        idu2exu_cmd.jump_req        = 1'b0;
        idu2exu_cmd.branch_req      = 1'b0;
        idu2exu_cmd.mret_req        = 1'b0;
        idu2exu_cmd.fencei_req      = 1'b0;
        idu2exu_cmd.wfi_req         = 1'b0;

        idu2exu_use_rs1             = 1'b0;
        idu2exu_use_rs2             = 1'b0;
        idu2exu_use_rd              = 1'b0;

`ifndef SCR1_MTVAL_ILLEGAL_INSTR_EN
        idu2exu_use_imm             = 1'b0;
`else // SCR1_MTVAL_ILLEGAL_INSTR_EN
        idu2exu_use_imm             = 1'b1;
        idu2exu_cmd.imm             = instr;
`endif // SCR1_MTVAL_ILLEGAL_INSTR_EN

        idu2exu_cmd.exc_req         = 1'b1;
        idu2exu_cmd.exc_code        = SCR1_EXC_CODE_ILLEGAL_INSTR;
    end

end // RV32I(MC) decode

`ifdef SCR1_SIM_ENV
`ifndef VERILATOR
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------

// X checks

SCR1_SVA_IDU_XCHECK : assert property (
    @(negedge clk) disable iff (~rst_n)
    !$isunknown({ifu2idu_vd, exu2idu_rdy})
    ) else $error("IDU Error: unknown values");

SCR1_SVA_IDU_XCHECK2 : assert property (
    @(negedge clk) disable iff (~rst_n)
    ifu2idu_vd |-> !$isunknown({ifu2idu_imem_err, (ifu2idu_imem_err ? 0 : ifu2idu_instr)})
    ) else $error("IDU Error: unknown values");

// Behavior checks

SCR1_SVA_IDU_IALU_CMD_RANGE : assert property (
    @(negedge clk) disable iff (~rst_n)
    (ifu2idu_vd & ~ifu2idu_imem_err) |->
    ((idu2exu_cmd.ialu_cmd >= SCR1_IALU_CMD_NONE) &
    (idu2exu_cmd.ialu_cmd <=
`ifdef SCR1_RVM_EXT
                            SCR1_IALU_CMD_REMU
`else
                            SCR1_IALU_CMD_SRA
`endif // SCR1_RVM_EXT
        ))
    ) else $error("IDU Error: IALU_CMD out of range");

`endif // VERILATOR
`endif // SCR1_SIM_ENV

endmodule : scr1_pipe_idu

idu2exu_cmd.imm         = {27'd0, instr[6:2]};


// ============================================================================
// Amazon FPGA Hardware Development Kit
//
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Amazon Software License (the "License"). You may not use
// this file except in compliance with the License. A copy of the License is
// located at
//
//    http://aws.amazon.com/asl/
//
// or in the "license" file accompanying this file. This file is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or
// implied. See the License for the specific language governing permissions and
// limitations under the License.
// ============================================================================

// SDE PCIS Accumulator

module sde_ps_acc #(parameter PCIS_DATA_WIDTH = 512,
                    parameter PCIS_ADDR_WIDTH = 64,
                    parameter ACC_WIDTH = 64,
                    parameter ACC_WIDTH_DW = ACC_WIDTH >> 5,
                    parameter START_ADDR = 64'd0,
		    parameter LIMITED_SUPPORT = 1
                   )
   (
    input                            clk,
    input                            rst_n,

    output logic                     ooo_error,
    output logic                     unalin_error,

    // PS FSM to PCIS-ACC Block
    input                            pcis_req_wr,
    input [PCIS_ADDR_WIDTH-1:0]      pcis_req_addr,

    // PCIS Write Data Bus
    input [PCIS_DATA_WIDTH-1:0]      pcis_wdata,
    input [(PCIS_DATA_WIDTH>>3)-1:0] pcis_wstrb,
    input                            pcis_wlast,
    input                            pcis_wvalid,
    output logic                     pcis_wready,

    // PCIS-ACC to Slave
    output logic                     acc_wr_req,
    output logic [ACC_WIDTH-1:0]     acc_wdata,
    input                            acc_ack

    );

   localparam PCIS_ADDR_BYTE_IDX_WIDTH = $clog2(PCIS_DATA_WIDTH>>3);
   localparam PCIS_ADDR_DW_IDX_WIDTH = PCIS_ADDR_BYTE_IDX_WIDTH - 2;
   localparam ACC_DW_IDX_WIDTH = $clog2(ACC_WIDTH_DW) + 1;
   localparam ACC_MAX_DW_IDX_WIDTH = ACC_DW_IDX_WIDTH > PCIS_ADDR_DW_IDX_WIDTH ? ACC_DW_IDX_WIDTH : PCIS_ADDR_DW_IDX_WIDTH;

if (LIMITED_SUPPORT == 0) begin

   // Following logic supports any DW length of data coming on pcis_wdata and any address alignment. But at increased resource utilization.
   logic [PCIS_ADDR_DW_IDX_WIDTH:0] pcis_wr_num_dw_d;
   logic [PCIS_ADDR_DW_IDX_WIDTH:0] pcis_wr_num_dw_q;
   logic                            pcis_first_q;
   logic [PCIS_DATA_WIDTH-1:0]      pcis_wdata_q;
   logic                            pcis_wvalid_q;

   logic [ACC_MAX_DW_IDX_WIDTH:0]   acc_in_dw_cnt_remain;
   logic                            acc_out_transmit;
   logic [ACC_DW_IDX_WIDTH:0]       acc_out_num_dw_needed;
   logic [ACC_MAX_DW_IDX_WIDTH:0]   acc_num_dw_to_accumulate;
   logic [ACC_DW_IDX_WIDTH:0]       acc_wr_num_dw_d;
   logic                            acc_out_stall;
   logic [ACC_WIDTH-1:0]            acc_in_wdata_acc;
   logic [ACC_WIDTH-1:0]            acc_in_wdata_d;
   logic [ACC_DW_IDX_WIDTH:0]       acc_wr_num_dw;

   always @(posedge clk)
     if (!rst_n) begin
        pcis_first_q <= 1;
        pcis_wdata_q <= '{default:'0};
        pcis_wr_num_dw_q <= 0;
        pcis_wvalid_q <= 0;
     end
     else begin
        pcis_first_q <= pcis_wvalid & pcis_wready & pcis_wlast ? 1'b1 :
                        pcis_wvalid & pcis_wready ? 1'b0 : pcis_first_q;

        pcis_wdata_q <= pcis_wvalid && ~pcis_wvalid_q && pcis_first_q ? pcis_wdata >> {pcis_req_addr[PCIS_ADDR_BYTE_IDX_WIDTH-1:0], 3'b000} :
                        pcis_wvalid && ~pcis_wvalid_q ? pcis_wdata :
                        pcis_wvalid_q && ~acc_out_stall ? (pcis_wdata_q >> {acc_num_dw_to_accumulate, 5'd0}) :
                        pcis_wdata_q;

        pcis_wr_num_dw_q <= pcis_wvalid && ~pcis_wvalid_q && pcis_first_q ? pcis_wr_num_dw_d - pcis_req_addr[PCIS_ADDR_BYTE_IDX_WIDTH-1:2] :
                            pcis_wvalid && ~pcis_wvalid_q ? pcis_wr_num_dw_d :
                            pcis_wvalid_q && ~acc_out_stall ? pcis_wr_num_dw_q - acc_num_dw_to_accumulate :
                            pcis_wr_num_dw_q;

        pcis_wvalid_q <= ~pcis_wvalid_q & pcis_wvalid & pcis_req_wr ? 1'b1 :
                         pcis_wvalid_q & ~acc_out_stall & (pcis_wr_num_dw_q == acc_num_dw_to_accumulate) ? 1'b0 :
                         pcis_wvalid_q;

     end
   assign pcis_wready = pcis_req_wr & ~pcis_wvalid_q;

   // Number of bytes in the input that are not transmitted/are remaining to be sent
   assign acc_in_dw_cnt_remain = pcis_wr_num_dw_q; // Zero extend if required

   assign acc_out_transmit = (acc_wr_num_dw >= ACC_WIDTH_DW);

   // Number of total bytes still needed
   assign acc_out_num_dw_needed = acc_out_transmit ? ACC_WIDTH_DW : ACC_WIDTH_DW - acc_wr_num_dw;

   // Number of bytes to accumulate in this clock
   assign acc_num_dw_to_accumulate = (acc_in_dw_cnt_remain > acc_out_num_dw_needed) ? acc_out_num_dw_needed : acc_in_dw_cnt_remain;

   // Number of bytes in the output
   assign acc_wr_num_dw_d = acc_out_transmit & pcis_wvalid_q ? acc_num_dw_to_accumulate :
                            acc_out_transmit ? 0 :
                            pcis_wvalid_q ? acc_wr_num_dw + acc_num_dw_to_accumulate : acc_wr_num_dw;

   // Output should stall if request is outstanding and there is an ack
   assign acc_out_stall = acc_wr_req & ~acc_ack;

   // Case1 : Accumulate
   always_comb
     for (int dw_idx = 0; dw_idx < ACC_WIDTH_DW; dw_idx++) begin
        if (dw_idx < acc_wr_num_dw)
          acc_in_wdata_acc[dw_idx*32 +: 32] = acc_wdata[dw_idx*32 +: 32];
        else
          acc_in_wdata_acc[dw_idx*32 +: 32] = pcis_wdata_q[(dw_idx - acc_wr_num_dw)*32 +: 32];
     end

   // Output data
   assign acc_in_wdata_d =  acc_out_transmit & pcis_wvalid_q ? pcis_wdata_q[ACC_WIDTH-1:0] :
                            pcis_wvalid_q ? acc_in_wdata_acc :
                            acc_wdata;

   always @(posedge clk)
     if (!rst_n) begin
        acc_wr_num_dw <= 0;
        acc_wr_req <= 0;
        acc_wdata <= '{default:'0};
     end
     else begin
        acc_wr_num_dw <= ~acc_out_stall ? acc_wr_num_dw_d : acc_wr_num_dw;
        acc_wr_req <= ~acc_out_stall ? (acc_wr_num_dw_d == ACC_WIDTH_DW) : acc_wr_req;
        acc_wdata <= ~acc_out_stall ? acc_in_wdata_d : acc_wdata;
     end // else: !if(!rst_n)

   logic [PCIS_ADDR_WIDTH-1:0] pcis_req_addr_q;

   always @(posedge clk)
     if (!rst_n) begin
        pcis_req_addr_q <= 0;
        ooo_error <= 0;
        unalin_error <= 0;
     end
     else begin
        pcis_req_addr_q <= pcis_req_wr ? pcis_req_addr : pcis_req_addr_q;
        ooo_error <= ~ooo_error & pcis_req_wr & (pcis_req_addr_q > pcis_req_addr) & (pcis_req_addr != START_ADDR);
        unalin_error <= ~unalin_error & pcis_req_wr & (pcis_req_addr[5:0] != 6'd0);
     end

end // if (LIMITED_SUPPORT == 0)

else begin

   // Following logic assumes these:
   // 1. Always 64Byte aligned address coming on pcis_addr from host.
   // 2. The MSB 256 bits on pcis_wdata bus should NOT contain any valid descriptors. Only pcis_wdata[255:0] is used.
   // 3. Only supports 1DW, 4DW or 8DW coming on pcis_wdata from the host.
   logic [PCIS_ADDR_DW_IDX_WIDTH:0] pcis_wr_num_dw_d;
   logic [PCIS_ADDR_DW_IDX_WIDTH:0] pcis_wr_num_dw_q;
   logic                            pcis_first_q;

   localparam PCIS_WDATAQ_WIDTH = (PCIS_DATA_WIDTH <= 256) ? PCIS_DATA_WIDTH : 256;
   logic [PCIS_WDATAQ_WIDTH-1:0]    pcis_wdata_q;

   logic                            pcis_wvalid_q;

   logic [ACC_MAX_DW_IDX_WIDTH:0]   acc_in_dw_cnt_remain;
   logic                            acc_out_transmit;
   logic [ACC_DW_IDX_WIDTH:0]       acc_out_num_dw_needed;
   logic [ACC_MAX_DW_IDX_WIDTH:0]   acc_num_dw_to_accumulate;
   logic [ACC_DW_IDX_WIDTH:0]       acc_wr_num_dw_d;
   logic                            acc_out_stall;
   logic [ACC_WIDTH-1:0]            acc_in_wdata_acc;
   logic [ACC_WIDTH-1:0]            acc_in_wdata_d;
   logic [ACC_DW_IDX_WIDTH:0]       acc_wr_num_dw;

   always_comb begin
     pcis_wr_num_dw_d = '0;
     for (int dw_idx = 0; dw_idx < (PCIS_DATA_WIDTH>>5)/2; dw_idx++) //(512/32)/2=8
       if ((pcis_wstrb[dw_idx*4]) && (dw_idx == 0 || dw_idx == 3 || dw_idx == 7))
         pcis_wr_num_dw_d = dw_idx + 1; //Supported DW= 1DW, 4DW and 8DW
   end

   always @(posedge clk)
     if (!rst_n) begin
        pcis_first_q <= 1;
        pcis_wdata_q <= '{default:'0};
        pcis_wr_num_dw_q <= 0;
        pcis_wvalid_q <= 0;
     end
     else begin
        pcis_first_q <= pcis_wvalid & pcis_wready & pcis_wlast ? 1'b1 :
                        pcis_wvalid & pcis_wready ? 1'b0 : pcis_first_q;

	pcis_wdata_q <= pcis_wvalid && ~pcis_wvalid_q ? pcis_wdata : //assuming the addr will always be 64 Byte aligned.
                        pcis_wvalid_q && ~acc_out_stall ? (pcis_wdata_q >> {acc_num_dw_to_accumulate, 5'd0}) :
                        pcis_wdata_q;

	pcis_wr_num_dw_q <= pcis_wvalid && ~pcis_wvalid_q ? pcis_wr_num_dw_d :
                            pcis_wvalid_q && ~acc_out_stall ? pcis_wr_num_dw_q - acc_num_dw_to_accumulate :
                            pcis_wr_num_dw_q;

        pcis_wvalid_q <= ~pcis_wvalid_q & pcis_wvalid & pcis_req_wr ? 1'b1 :
                         pcis_wvalid_q & ~acc_out_stall & (pcis_wr_num_dw_q == acc_num_dw_to_accumulate) ? 1'b0 :
                         pcis_wvalid_q;

     end
   assign pcis_wready = pcis_req_wr & ~pcis_wvalid_q;

   // Number of bytes in the input that are not transmitted/are remaining to be sent
   assign acc_in_dw_cnt_remain = pcis_wr_num_dw_q; // Zero extend if required

   assign acc_out_transmit = (acc_wr_num_dw >= ACC_WIDTH_DW);

   // Number of total bytes still needed
   assign acc_out_num_dw_needed = acc_out_transmit ? ACC_WIDTH_DW : ACC_WIDTH_DW - acc_wr_num_dw;

   // Number of bytes to accumulate in this clock
   assign acc_num_dw_to_accumulate = (acc_in_dw_cnt_remain > acc_out_num_dw_needed) ? acc_out_num_dw_needed : acc_in_dw_cnt_remain;

   // Number of bytes in the output
   assign acc_wr_num_dw_d = acc_out_transmit & pcis_wvalid_q ? acc_num_dw_to_accumulate :
                            acc_out_transmit ? 0 :
                            pcis_wvalid_q ? acc_wr_num_dw + acc_num_dw_to_accumulate : acc_wr_num_dw;

   // Output should stall if request is outstanding and there is an ack
   assign acc_out_stall = acc_wr_req & ~acc_ack;

   // Case1 : Accumulate
   always_comb
     for (int dw_idx = 0; dw_idx < ACC_WIDTH_DW; dw_idx++) begin
        if (dw_idx < acc_wr_num_dw)
          acc_in_wdata_acc[dw_idx*32 +: 32] = acc_wdata[dw_idx*32 +: 32];
        else
          acc_in_wdata_acc[dw_idx*32 +: 32] = pcis_wdata_q[(dw_idx - acc_wr_num_dw)*32 +: 32];
     end

   // Output data
   assign acc_in_wdata_d =  acc_out_transmit & pcis_wvalid_q ? pcis_wdata_q[ACC_WIDTH-1:0] :
                            pcis_wvalid_q ? acc_in_wdata_acc :
                            acc_wdata;

   always @(posedge clk)
     if (!rst_n) begin
        acc_wr_num_dw <= 0;
        acc_wr_req <= 0;
        acc_wdata <= '{default:'0};
     end
     else begin
        acc_wr_num_dw <= ~acc_out_stall ? acc_wr_num_dw_d : acc_wr_num_dw;
        acc_wr_req <= ~acc_out_stall ? (acc_wr_num_dw_d == ACC_WIDTH_DW) : acc_wr_req;
        acc_wdata <= ~acc_out_stall ? acc_in_wdata_d : acc_wdata;
     end // else: !if(!rst_n)

   logic [PCIS_ADDR_WIDTH-1:0] pcis_req_addr_q;

   always @(posedge clk)
     if (!rst_n) begin
        pcis_req_addr_q <= 0;
        ooo_error <= 0;
        unalin_error <= 0;
     end
     else begin
        pcis_req_addr_q <= pcis_req_wr ? pcis_req_addr : pcis_req_addr_q;
        ooo_error <= ~ooo_error & pcis_req_wr & (pcis_req_addr_q > pcis_req_addr) & (pcis_req_addr != START_ADDR);
	unalin_error <= ~unalin_error & pcis_req_wr & (pcis_req_addr[5:0] != 6'd0);
     end
end // else: !if(LIMITED_SUPPORT == 0)

endmodule // sde_ps_acc

   always_comb begin
     pcis_wr_num_dw_d = '0;
     for (int dw_idx = 0; dw_idx < (PCIS_DATA_WIDTH>>5); dw_idx++)


`pragma protect begin_protected
`pragma protect version = 2
`pragma protect encrypt_agent = "XILINX"
`pragma protect encrypt_agent_info = "Xilinx Encryption Tool 2024.1"
`pragma protect begin_commonblock
`pragma protect control error_handling="delegated"
`pragma protect end_commonblock
`pragma protect begin_toolblock
`pragma protect rights_digest_method="sha256"
`pragma protect key_keyowner = "Xilinx", key_keyname= "xilinxt_2023_11", key_method = "rsa", key_block
ggChurdwlpDo+c3r72vww66WLYqwoSIJB01y+PZCdhF9m2d6lRnKQde8A07aS5xHvHkaZvOnowUg
hkAQmJ58EGegOuasc3KqiVIuQthPnHsYrB1DzUAyka9IpTzlmRWR83SRwDQth4oTk09VWjrIAgcf
vE21JEsucJBdKTGabFupsyduPrzQ2X+qRSKuZCB7KSAwRazhqwD/crr8j0LBb9wLMfM76C6R5xIv
z9wVbsUrmAsdYmwsmyj9xoermIiz7d0IgaZTS3gd4fcjr8bguTPumE56slkA9rwaYnH0oFoQyk2b
/X950yBxdR2DvLFrXX2eeppYqb38yG7fr2/row==

`pragma protect control xilinx_configuration_visible = "false"
`pragma protect control xilinx_enable_modification = "false"
`pragma protect control xilinx_enable_probing = "false"
`pragma protect end_toolblock="0aas+Vn9A0FSJkLyqzmaTb9r5JFW2IeLsGZpnU2RJQY="
`pragma protect data_method = "AES128-CBC"
`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 7680)
`pragma protect data_block
eDCTkwSao/NstfGiF/AZPSt+6N8lzQtCNDgv995UbAc044t4zwLdNY1CB3SXoDRM+lWAm2yqAyWA
BZE3QaIs+ylTd8FBvPDg/FvxhTr2tkJ/Yyp49PI/AWVJGUZE66o9ZCj1Mo9Ol6MpYfrFxDFHvoqp
Zsr3zsF8hpB9sZuiYhG28jVZFVUL0kY+QwQqwsVq43o4b1remsHmqg1VPS4cPTPNx7sSr3QdjTA8
PTqJoQgM5HS4zVuqXwGNMSUz38MB6jneQKzDZ5FXj6CVWS1LR5+SQb8oR2SW/iVBmpAekT6PbFeA
njLLgrY64gJsH3rNNvY/M7Dht1mbLwUbTtD+6OgXyvZ0GoM0UL6Q1EIk6QjG2OJNbTHoiKNgDeL1
hqD3bCQ4DuJTPfKZ9eEnLcItJ+RWFkUU2IBFdZIhYdRApRtdApbJJnzFBGW1nxPb6nIssLOo2Cu5
6YpQmJjKYnNDtAG06qI2HmOrDSKP35hAugQdg3iTDWvezSYYdhfznoR2u3j4kb1G0HnxfK0IUkaI
bh1wnorDVpFWXc66lFHPyZu8oA+gdCCa06DVDQWPRTTrZdYiPAGqjCqi43ephupA5octOBb5hIPi
GWpUnARLg23NpoW91vMhH0T+CB6o2R/jhWxPwGkhamLsWKlwZmmiqwk6cycAl/limjFdOJUjmv7j
qI5rFeDS2g+gj5OUQxnSWUBWGcvwDtj6O92c1NHt6S82/PsIJq16ScmwoWt9aUzHbXux1/lGuEvE
PzOBmZskCkg+MYp7d/gEhj8BBTpQp2Fm6SQXM8nVcLHHYOUnMfPoDJqloccY5c3DpU5Nj5l+Z+wF
twN7QBeBEbee259GnaWGfFyc/foneN17Rcpm9g7p/KOXYEaVk/kF8ZYwETaZWQrNbzm06erq9KcG
d6YB2vzKovyHD4XJ6LQlEHUwk4EMKpOHYE2WsfeU9nWMQK2lSrOn/3hloktj+Fppkf28bnVPmmNd
WoFhKNS7t/3mYpSKxtcju76feb92UkJdlYZQnKypEFeYwfvq8ZFS0CmStWr7vuuWKRkNRKPtNzu1
4T4rcgRmawfrcYijVNnpY6q0k9wwK9sHz4I5cn/nr1s4MqQpozaPzyGhZPCXI0NXce6GGpYEk/FV


/**
 *
 * Name:
 *   bp_cce_spec_bits.sv
 *
 * Description:
 *   This module contains the metadata required for speculative memory accesses.
 *
 *   These bits are stored in flops and may be read asynchronously.
 *
 *   The width of address into bsg_hash_bank is log2(cce_way_groups_p), where cce_way_groups_p
 *   is the total number of way groups in the system.
 *   num_way_groups_p is the number of way groups managed by this CCE (or that number
 *   plus one in the event that there is not an even number of way groups per CCE).
 *
 */

`include "bp_common_defines.svh"
`include "bp_me_defines.svh"

module bp_cce_spec_bits
  import bp_common_pkg::*;
  import bp_me_pkg::*;
  #(parameter `BSG_INV_PARAM(num_way_groups_p)
    , parameter `BSG_INV_PARAM(cce_way_groups_p)
    , parameter `BSG_INV_PARAM(num_cce_p)
    , parameter `BSG_INV_PARAM(paddr_width_p)
    , parameter `BSG_INV_PARAM(addr_offset_p)

    // Derived parameters
    , localparam lg_num_way_groups_lp     = `BSG_SAFE_CLOG2(num_way_groups_p)
    , localparam lg_cce_way_groups_lp     = `BSG_SAFE_CLOG2(cce_way_groups_p)

  )
  (input                                                          clk_i
   , input                                                        reset_i

   // Write port
   , input                                                        w_v_i
   , input [paddr_width_p-1:0]                                    w_addr_i
   , input                                                        w_addr_bypass_hash_i

   , input                                                        spec_v_i
   , input                                                        squash_v_i
   , input                                                        fwd_mod_v_i
   , input                                                        state_v_i
   , input bp_cce_spec_s                                          spec_i

   // Read port
   , input                                                        r_v_i
   , input [paddr_width_p-1:0]                                    r_addr_i
   , input                                                        r_addr_bypass_hash_i

   , output bp_cce_spec_s                                         spec_o

  );

  // Address to way group hashing
  logic [hash_idx_width_lp-1:0] r_wg_lo, w_wg_lo;
  wire [lg_cce_way_groups_lp-1:0] r_addr_rev = {<< {r_addr_i[addr_offset_p+:lg_cce_way_groups_lp]}};
  wire [lg_cce_way_groups_lp-1:0] w_addr_rev = {<< {w_addr_i[addr_offset_p+:lg_cce_way_groups_lp]}};
  logic [lg_num_way_groups_lp-1:0] r_wg, w_wg;

  bsg_hash_bank
    #(.banks_p(num_cce_p) // number of CCE's to spread way groups over
      ,.width_p(lg_cce_way_groups_lp) // width of address input
      )
    r_addr_hash
     (.i(r_addr_rev)
      ,.bank_o()
      ,.index_o(r_wg_lo)
      );

  bsg_hash_bank
    #(.banks_p(num_cce_p) // number of CCE's to spread way groups over
      ,.width_p(lg_cce_way_groups_lp) // width of address input
      )
    w_addr_hash
     (.i(w_addr_rev)
      ,.bank_o()
      ,.index_o(w_wg_lo)
      );

  assign r_wg = (r_addr_bypass_hash_i) ? r_addr_i[0+:lg_num_way_groups_lp]
                                       : r_wg_lo[0+:lg_num_way_groups_lp];
  assign w_wg = (w_addr_bypass_hash_i) ? w_addr_i[0+:lg_num_way_groups_lp]
                                       : w_wg_lo[0+:lg_num_way_groups_lp];

  // speculation metadata bits
  bp_cce_spec_s [num_way_groups_p-1:0] spec_bits_r, spec_bits_n;

  always_ff @(posedge clk_i) begin
    if (reset_i) begin
      spec_bits_r <= '0;
    end else begin
      spec_bits_r <= spec_bits_n;
    end
  end

  always_comb begin
    if (reset_i) begin
      spec_bits_n = '0;
    end else begin
      spec_bits_n = spec_bits_r;
      if (w_v_i) begin
        if (spec_v_i) begin
          spec_bits_n[w_wg].spec = spec_i.spec;
        end
        if (squash_v_i) begin
          spec_bits_n[w_wg].squash = spec_i.squash;
        end
        if (fwd_mod_v_i) begin
          spec_bits_n[w_wg].fwd_mod = spec_i.fwd_mod;
        end
        if (state_v_i) begin
          spec_bits_n[w_wg].state = spec_i.state;
        end
      end
    end
  end

  // Output
  wire unused0 = r_v_i;
  assign spec_o = spec_bits_r[r_wg];

endmodule

`BSG_ABSTRACT_MODULE(bp_cce_spec_bits)

, localparam hash_idx_width_lp = $clog2((2**lg_cce_way_groups_lp+num_cce_p-1)/num_cce_p)


/**
 *
 * bp_core_tile.v
 *
 */

`include "bp_common_defines.svh"
`include "bp_be_defines.svh"
`include "bp_me_defines.svh"
`include "bp_top_defines.svh"
`include "bsg_cache.svh"
`include "bsg_noc_links.svh"

module bp_core_tile
 import bp_common_pkg::*;
 import bp_be_pkg::*;
 import bp_me_pkg::*;
 import bp_top_pkg::*;
 import bsg_cache_pkg::*;
 import bsg_noc_pkg::*;
 import bsg_wormhole_router_pkg::*;
 #(parameter bp_params_e bp_params_p = e_bp_default_cfg
   `declare_bp_proc_params(bp_params_p)
   `declare_bp_bedrock_if_widths(paddr_width_p, lce_id_width_p, cce_id_width_p, did_width_p, lce_assoc_p)

   , localparam cfg_bus_width_lp = `bp_cfg_bus_width(vaddr_width_p, hio_width_p, core_id_width_p, cce_id_width_p, lce_id_width_p, did_width_p)

   // Wormhole parameters
   , localparam coh_noc_ral_link_width_lp = `bsg_ready_and_link_sif_width(coh_noc_flit_width_p)
   , localparam dma_noc_ral_link_width_lp = `bsg_ready_and_link_sif_width(dma_noc_flit_width_p)
   )
  (input                                                      clk_i
   , input                                                    rt_clk_i
   , input                                                    reset_i

   // Memory side connection
   , input [mem_noc_did_width_p-1:0]                          my_did_i
   , input [mem_noc_did_width_p-1:0]                          host_did_i
   , input [coh_noc_cord_width_p-1:0]                         my_cord_i

   , input [coh_noc_ral_link_width_lp-1:0]                    lce_req_link_i
   , output logic [coh_noc_ral_link_width_lp-1:0]             lce_req_link_o

   , input [coh_noc_ral_link_width_lp-1:0]                    lce_cmd_link_i
   , output logic [coh_noc_ral_link_width_lp-1:0]             lce_cmd_link_o

   , input [coh_noc_ral_link_width_lp-1:0]                    lce_fill_link_i
   , output logic [coh_noc_ral_link_width_lp-1:0]             lce_fill_link_o

   , input [coh_noc_ral_link_width_lp-1:0]                    lce_resp_link_i
   , output logic [coh_noc_ral_link_width_lp-1:0]             lce_resp_link_o

   , output logic [dma_noc_ral_link_width_lp-1:0]             dma_link_o
   , input [dma_noc_ral_link_width_lp-1:0]                    dma_link_i
   );

  `declare_bp_cfg_bus_s(vaddr_width_p, hio_width_p, core_id_width_p, cce_id_width_p, lce_id_width_p, did_width_p);
  `declare_bp_bedrock_if(paddr_width_p, lce_id_width_p, cce_id_width_p, did_width_p, lce_assoc_p);
  `declare_bsg_ready_and_link_sif_s(coh_noc_flit_width_p, bp_coh_ready_and_link_s);
  `declare_bsg_ready_and_link_sif_s(dma_noc_flit_width_p, bp_dma_ready_and_link_s);

  // Reset
  logic reset_r;
  always_ff @(posedge clk_i)
    reset_r <= reset_i;

  // LCE-CCE coherence network links
  `bp_cast_i(bp_coh_ready_and_link_s, lce_req_link);
  `bp_cast_o(bp_coh_ready_and_link_s, lce_req_link);
  `bp_cast_i(bp_coh_ready_and_link_s, lce_cmd_link);
  `bp_cast_o(bp_coh_ready_and_link_s, lce_cmd_link);
  `bp_cast_i(bp_coh_ready_and_link_s, lce_fill_link);
  `bp_cast_o(bp_coh_ready_and_link_s, lce_fill_link);
  `bp_cast_i(bp_coh_ready_and_link_s, lce_resp_link);
  `bp_cast_o(bp_coh_ready_and_link_s, lce_resp_link);

  // Core-side LCE-CCE network connections
  bp_bedrock_lce_req_header_s [1:0] lce_req_header_lo;
  logic [1:0][bedrock_fill_width_p-1:0] lce_req_data_lo;
  logic [1:0] lce_req_v_lo, lce_req_ready_and_li;
  logic [1:0][coh_noc_cord_width_p-1:0] lce_req_dst_cord_lo;
  logic [1:0][coh_noc_cid_width_p-1:0] lce_req_dst_cid_lo;

  bp_bedrock_lce_cmd_header_s [1:0] lce_cmd_header_li;
  logic [1:0][bedrock_fill_width_p-1:0] lce_cmd_data_li;
  logic [1:0] lce_cmd_v_li, lce_cmd_ready_and_lo;

  bp_bedrock_lce_fill_header_s [1:0] lce_fill_header_li;
  logic [1:0][bedrock_fill_width_p-1:0] lce_fill_data_li;
  logic [1:0] lce_fill_v_li, lce_fill_ready_and_lo;

  bp_bedrock_lce_fill_header_s [1:0] lce_fill_header_lo;
  logic [1:0][bedrock_fill_width_p-1:0] lce_fill_data_lo;
  logic [1:0] lce_fill_v_lo, lce_fill_ready_and_li;
  logic [1:0][coh_noc_cord_width_p-1:0] lce_fill_dst_cord_lo;
  logic [1:0][coh_noc_cid_width_p-1:0] lce_fill_dst_cid_lo;

  bp_bedrock_lce_resp_header_s [1:0] lce_resp_header_lo;
  logic [1:0][bedrock_fill_width_p-1:0] lce_resp_data_lo;
  logic [1:0] lce_resp_v_lo, lce_resp_ready_and_li;
  logic [1:0][coh_noc_cord_width_p-1:0] lce_resp_dst_cord_lo;
  logic [1:0][coh_noc_cid_width_p-1:0] lce_resp_dst_cid_lo;

  // CCE-side LCE-CCE BedRock network
  bp_bedrock_lce_req_header_s lce_req_header_li;
  logic [bedrock_fill_width_p-1:0] lce_req_data_li;
  logic lce_req_v_li, lce_req_ready_and_lo;

  bp_bedrock_lce_resp_header_s lce_resp_header_li;
  logic [bedrock_fill_width_p-1:0] lce_resp_data_li;
  logic lce_resp_v_li, lce_resp_ready_and_lo;

  bp_bedrock_lce_cmd_header_s lce_cmd_header_lo;
  logic [bedrock_fill_width_p-1:0] lce_cmd_data_lo;
  logic lce_cmd_v_lo, lce_cmd_ready_and_li;
  logic [coh_noc_cord_width_p-1:0] lce_cmd_dst_cord_lo;
  logic [coh_noc_cid_width_p-1:0] lce_cmd_dst_cid_lo;

  // LCE-CCE network links - unconcentrated
  bp_coh_ready_and_link_s [1:0] lce_req_link_li, lce_req_link_lo;
  bp_coh_ready_and_link_s [1:0] lce_cmd_link_li, lce_cmd_link_lo;
  bp_coh_ready_and_link_s [1:0] lce_fill_link_li, lce_fill_link_lo;
  bp_coh_ready_and_link_s [1:0] lce_resp_link_li, lce_resp_link_lo;

  bp_coh_ready_and_link_s cce_lce_req_link_lo;
  bp_coh_ready_and_link_s cce_lce_resp_link_lo;

  // stub unused CCE link connections
  // CCE does not send requests
  assign cce_lce_req_link_lo.v = '0;
  assign cce_lce_req_link_lo.data = '0;
  // CCE does not send responses
  assign cce_lce_resp_link_lo.v = '0;
  assign cce_lce_resp_link_lo.data = '0;

  for (genvar i = 0; i < 2; i++) begin : lce

    // LCE request from LCE
    bp_me_cce_id_to_cord
     #(.bp_params_p(bp_params_p))
     req_router_cord
      (.cce_id_i(lce_req_header_lo[i].payload.dst_id)
       ,.cce_cord_o(lce_req_dst_cord_lo[i])
       ,.cce_cid_o(lce_req_dst_cid_lo[i])
       );

    bp_me_stream_to_wormhole
     #(.bp_params_p(bp_params_p)
       ,.flit_width_p(coh_noc_flit_width_p)
       ,.cord_width_p(coh_noc_cord_width_p)
       ,.len_width_p(coh_noc_len_width_p)
       ,.cid_width_p(coh_noc_cid_width_p)
       ,.pr_hdr_width_p(lce_req_header_width_lp)
       ,.pr_payload_width_p(lce_req_payload_width_lp)
       ,.pr_stream_mask_p(lce_req_stream_mask_gp)
       ,.pr_data_width_p(bedrock_fill_width_p)
       )
     lce_req_stream_to_wh
     (.clk_i(clk_i)
      ,.reset_i(reset_r)

      ,.pr_hdr_i(lce_req_header_lo[i])
      ,.pr_data_i(lce_req_data_lo[i])
      ,.pr_v_i(lce_req_v_lo[i])
      ,.pr_ready_and_o(lce_req_ready_and_li[i])
      ,.dst_cord_i(lce_req_dst_cord_lo[i])
      ,.dst_cid_i(lce_req_dst_cid_lo[i])

      ,.link_data_o(lce_req_link_lo[i].data)
      ,.link_v_o(lce_req_link_lo[i].v)
      ,.link_ready_and_i(lce_req_link_li[i].ready_and_rev)
      );
    // LCE does not receive requests
    assign lce_req_link_lo[i].ready_and_rev = 1'b0;

    // LCE command to LCE
    bp_me_wormhole_to_stream
     #(.bp_params_p(bp_params_p)
       ,.flit_width_p(coh_noc_flit_width_p)
       ,.cord_width_p(coh_noc_cord_width_p)
       ,.len_width_p(coh_noc_len_width_p)
       ,.cid_width_p(coh_noc_cid_width_p)
       ,.pr_hdr_width_p(lce_cmd_header_width_lp)
       ,.pr_payload_width_p(lce_cmd_payload_width_lp)
       ,.pr_stream_mask_p(lce_cmd_stream_mask_gp)
       ,.pr_data_width_p(bedrock_fill_width_p)
       )
     lce_cmd_wh_to_stream
     (.clk_i(clk_i)
      ,.reset_i(reset_r)

      ,.link_data_i(lce_cmd_link_li[i].data)
      ,.link_v_i(lce_cmd_link_li[i].v)
      ,.link_ready_and_o(lce_cmd_link_lo[i].ready_and_rev)

      ,.pr_hdr_o(lce_cmd_header_li[i])
      ,.pr_data_o(lce_cmd_data_li[i])
      ,.pr_v_o(lce_cmd_v_li[i])
      ,.pr_ready_and_i(lce_cmd_ready_and_lo[i])
      );
    // LCE does not send commands
    assign lce_cmd_link_lo[i].v = '0;
    assign lce_cmd_link_lo[i].data = '0;

    // LCE fill to LCE
    bp_me_wormhole_to_stream
     #(.bp_params_p(bp_params_p)
       ,.flit_width_p(coh_noc_flit_width_p)
       ,.cord_width_p(coh_noc_cord_width_p)
       ,.len_width_p(coh_noc_len_width_p)
       ,.cid_width_p(coh_noc_cid_width_p)
       ,.pr_hdr_width_p(lce_fill_header_width_lp)
       ,.pr_payload_width_p(lce_fill_payload_width_lp)
       ,.pr_stream_mask_p(lce_fill_stream_mask_gp)
       ,.pr_data_width_p(bedrock_fill_width_p)
       )
     lce_fill_wh_to_stream
     (.clk_i(clk_i)
      ,.reset_i(reset_r)

      ,.link_data_i(lce_fill_link_li[i].data)
      ,.link_v_i(lce_fill_link_li[i].v)
      ,.link_ready_and_o(lce_fill_link_lo[i].ready_and_rev)

      ,.pr_hdr_o(lce_fill_header_li[i])
      ,.pr_data_o(lce_fill_data_li[i])
      ,.pr_v_o(lce_fill_v_li[i])
      ,.pr_ready_and_i(lce_fill_ready_and_lo[i])
      );

    // LCE fill from LCE
    bp_me_lce_id_to_cord
     #(.bp_params_p(bp_params_p))
     fill_router_cord
      (.lce_id_i(lce_fill_header_lo[i].payload.dst_id)
       ,.lce_cord_o(lce_fill_dst_cord_lo[i])
       ,.lce_cid_o(lce_fill_dst_cid_lo[i])
       );

    bp_me_stream_to_wormhole
     #(.bp_params_p(bp_params_p)
       ,.flit_width_p(coh_noc_flit_width_p)
       ,.cord_width_p(coh_noc_cord_width_p)
       ,.len_width_p(coh_noc_len_width_p)
       ,.cid_width_p(coh_noc_cid_width_p)
       ,.pr_hdr_width_p(lce_fill_header_width_lp)
       ,.pr_payload_width_p(lce_fill_payload_width_lp)
       ,.pr_stream_mask_p(lce_fill_stream_mask_gp)
       ,.pr_data_width_p(bedrock_fill_width_p)
       )
     lce_fill_stream_to_wh
     (.clk_i(clk_i)
      ,.reset_i(reset_r)

      ,.pr_hdr_i(lce_fill_header_lo[i])
      ,.pr_data_i(lce_fill_data_lo[i])
      ,.pr_v_i(lce_fill_v_lo[i])
      ,.pr_ready_and_o(lce_fill_ready_and_li[i])
      ,.dst_cord_i(lce_fill_dst_cord_lo[i])
      ,.dst_cid_i(lce_fill_dst_cid_lo[i])

      ,.link_data_o(lce_fill_link_lo[i].data)
      ,.link_v_o(lce_fill_link_lo[i].v)
      ,.link_ready_and_i(lce_fill_link_li[i].ready_and_rev)
      );

    // LCE Response from LCE
    bp_me_cce_id_to_cord
     #(.bp_params_p(bp_params_p))
     resp_router_cord
      (.cce_id_i(lce_resp_header_lo[i].payload.dst_id)
       ,.cce_cord_o(lce_resp_dst_cord_lo[i])
       ,.cce_cid_o(lce_resp_dst_cid_lo[i])
       );

    bp_me_stream_to_wormhole
     #(.bp_params_p(bp_params_p)
       ,.flit_width_p(coh_noc_flit_width_p)
       ,.cord_width_p(coh_noc_cord_width_p)
       ,.len_width_p(coh_noc_len_width_p)
       ,.cid_width_p(coh_noc_cid_width_p)
       ,.pr_hdr_width_p(lce_resp_header_width_lp)
       ,.pr_payload_width_p(lce_resp_payload_width_lp)
       ,.pr_stream_mask_p(lce_resp_stream_mask_gp)
       ,.pr_data_width_p(bedrock_fill_width_p)
       )
     lce_resp_stream_to_wh
     (.clk_i(clk_i)
      ,.reset_i(reset_r)

      ,.pr_hdr_i(lce_resp_header_lo[i])
      ,.pr_data_i(lce_resp_data_lo[i])
      ,.pr_v_i(lce_resp_v_lo[i])
      ,.pr_ready_and_o(lce_resp_ready_and_li[i])
      ,.dst_cord_i(lce_resp_dst_cord_lo[i])
      ,.dst_cid_i(lce_resp_dst_cid_lo[i])

      ,.link_data_o(lce_resp_link_lo[i].data)
      ,.link_v_o(lce_resp_link_lo[i].v)
      ,.link_ready_and_i(lce_resp_link_li[i].ready_and_rev)
      );
    // LCE does not receive responses
    assign lce_resp_link_lo[i].ready_and_rev = 1'b0;

  end // lce to WH network connections

  // LCE to CCE request
  bp_me_wormhole_to_stream
   #(.bp_params_p(bp_params_p)
     ,.flit_width_p(coh_noc_flit_width_p)
     ,.cord_width_p(coh_noc_cord_width_p)
     ,.len_width_p(coh_noc_len_width_p)
     ,.cid_width_p(coh_noc_cid_width_p)
     ,.pr_hdr_width_p(lce_req_header_width_lp)
     ,.pr_payload_width_p(lce_req_payload_width_lp)
     ,.pr_stream_mask_p(lce_req_stream_mask_gp)
     ,.pr_data_width_p(bedrock_fill_width_p)
     )
   lce_req_wh_to_stream
   (.clk_i(clk_i)
    ,.reset_i(reset_r)

    ,.link_data_i(lce_req_link_cast_i.data)
    ,.link_v_i(lce_req_link_cast_i.v)
    ,.link_ready_and_o(cce_lce_req_link_lo.ready_and_rev)

    ,.pr_hdr_o(lce_req_header_li)
    ,.pr_data_o(lce_req_data_li)
    ,.pr_v_o(lce_req_v_li)

    );

  // CCE to LCE command
  bp_me_lce_id_to_cord
   #(.bp_params_p(bp_params_p))
   cmd_router_cord
    (.lce_id_i(lce_cmd_header_lo.payload.dst_id)
     ,.lce_cord_o(lce_cmd_dst_cord_lo)
     ,.lce_cid_o(lce_cmd_dst_cid_lo)
     );

  bp_me_stream_to_wormhole
   #(.bp_params_p(bp_params_p)
     ,.flit_width_p(coh_noc_flit_width_p)
     ,.cord_width_p(coh_noc_cord_width_p)
     ,.len_width_p(coh_noc_len_width_p)
     ,.cid_width_p(coh_noc_cid_width_p)
     ,.pr_hdr_width_p(lce_cmd_header_width_lp)
     ,.pr_payload_width_p(lce_cmd_payload_width_lp)
     ,.pr_stream_mask_p(lce_cmd_stream_mask_gp)
     ,.pr_data_width_p(bedrock_fill_width_p)
     )
   lce_cmd_stream_to_wh
   (.clk_i(clk_i)
    ,.reset_i(reset_r)

    ,.pr_hdr_i(lce_cmd_header_lo)
    ,.pr_data_i(lce_cmd_data_lo)
    ,.pr_v_i(lce_cmd_v_lo)
    ,.pr_ready_and_o(lce_cmd_ready_and_li)
    ,.dst_cord_i(lce_cmd_dst_cord_lo)
    ,.dst_cid_i(lce_cmd_dst_cid_lo)

    ,.link_data_o(lce_cmd_link_cast_o.data)
    ,.link_v_o(lce_cmd_link_cast_o.v)
    ,.link_ready_and_i(lce_cmd_link_cast_i.ready_and_rev)
    );

  // LCE to CCE response
  bp_me_wormhole_to_stream
   #(.bp_params_p(bp_params_p)
     ,.flit_width_p(coh_noc_flit_width_p)
     ,.cord_width_p(coh_noc_cord_width_p)
     ,.len_width_p(coh_noc_len_width_p)
     ,.cid_width_p(coh_noc_cid_width_p)
     ,.pr_hdr_width_p(lce_resp_header_width_lp)
     ,.pr_payload_width_p(lce_resp_payload_width_lp)
     ,.pr_stream_mask_p(lce_resp_stream_mask_gp)
     ,.pr_data_width_p(bedrock_fill_width_p)
     )
   lce_resp_wh_to_stream
   (.clk_i(clk_i)
    ,.reset_i(reset_r)

    ,.link_data_i(lce_resp_link_cast_i.data)
    ,.link_v_i(lce_resp_link_cast_i.v)
    ,.link_ready_and_o(cce_lce_resp_link_lo.ready_and_rev)

    ,.pr_hdr_o(lce_resp_header_li)
    ,.pr_data_o(lce_resp_data_li)
    ,.pr_v_o(lce_resp_v_li)
    ,.pr_ready_and_i(lce_resp_ready_and_lo)
    );

  // LCE-CCE Network Concentrators

  bp_coh_ready_and_link_s req_concentrated_link_li, req_concentrated_link_lo;
  bp_coh_ready_and_link_s cmd_concentrated_link_li, cmd_concentrated_link_lo;
  bp_coh_ready_and_link_s fill_concentrated_link_li, fill_concentrated_link_lo;
  bp_coh_ready_and_link_s resp_concentrated_link_li, resp_concentrated_link_lo;

  assign req_concentrated_link_li = lce_req_link_cast_i;
  assign lce_req_link_cast_o = '{data          : req_concentrated_link_lo.data
                                 ,v            : req_concentrated_link_lo.v
                                 ,ready_and_rev: cce_lce_req_link_lo.ready_and_rev
                                 };
  bsg_wormhole_concentrator_in
   #(.flit_width_p(coh_noc_flit_width_p)
     ,.len_width_p(coh_noc_len_width_p)
     ,.num_in_p(2)
     ,.cord_width_p(coh_noc_cord_width_p)
     ,.hold_on_valid_p(1)
     )
   req_concentrator
    (.clk_i(clk_i)
     ,.reset_i(reset_r)

     ,.links_v_i({lce_req_link_lo[1].v, lce_req_link_lo[0].v})
     ,.links_data_i({lce_req_link_lo[1].data, lce_req_link_lo[0].data})
     ,.links_ready_and_rev_o({lce_req_link_li[1].ready_and_rev, lce_req_link_li[0].ready_and_rev})

     ,.concentrated_link_v_o(req_concentrated_link_lo.v)
     ,.concentrated_link_data_o(req_concentrated_link_lo.data)
     ,.concentrated_link_ready_and_rev_i(req_concentrated_link_li.ready_and_rev)
     );
  assign lce_req_link_li[1].v = 1'b0;
  assign lce_req_link_li[0].v = 1'b0;
  assign lce_req_link_li[1].data = '0;
  assign lce_req_link_li[0].data = '0;
  assign req_concentrated_link_lo.ready_and_rev = 1'b0;

  assign cmd_concentrated_link_li = lce_cmd_link_cast_i;
  assign lce_cmd_link_cast_o.ready_and_rev = cmd_concentrated_link_lo.ready_and_rev;
  bsg_wormhole_concentrator_out
   #(.flit_width_p(coh_noc_flit_width_p)
     ,.len_width_p(coh_noc_len_width_p)
     ,.cid_width_p(coh_noc_cid_width_p)
     ,.num_in_p(2)
     ,.cord_width_p(coh_noc_cord_width_p)
     ,.hold_on_valid_p(1)
     )
   cmd_concentrator
    (.clk_i(clk_i)
     ,.reset_i(reset_r)

     ,.links_v_o({lce_cmd_link_li[1].v, lce_cmd_link_li[0].v})
     ,.links_data_o({lce_cmd_link_li[1].data, lce_cmd_link_li[0].data})
     ,.links_ready_and_rev_i({lce_cmd_link_lo[1].ready_and_rev, lce_cmd_link_lo[0].ready_and_rev})

     ,.concentrated_link_v_i(cmd_concentrated_link_li.v)
     ,.concentrated_link_data_i(cmd_concentrated_link_li.data)
     ,.concentrated_link_ready_and_rev_o(cmd_concentrated_link_lo.ready_and_rev)
     );
  assign lce_cmd_link_li[1].ready_and_rev = 1'b0;
  assign lce_cmd_link_li[0].ready_and_rev = 1'b0;
  assign cmd_concentrated_link_lo.v = 1'b0;
  assign cmd_concentrated_link_lo.data = '0;

  assign fill_concentrated_link_li = lce_fill_link_cast_i;
  assign lce_fill_link_cast_o = fill_concentrated_link_lo;
  bsg_wormhole_concentrator
   #(.flit_width_p(coh_noc_flit_width_p)
     ,.len_width_p(coh_noc_len_width_p)
     ,.cid_width_p(coh_noc_cid_width_p)
     ,.num_in_p(2)
     ,.cord_width_p(coh_noc_cord_width_p)
     ,.hold_on_valid_p(1)
     )
   fill_concentrator
    (.clk_i(clk_i)
     ,.reset_i(reset_r)

     ,.links_i(lce_fill_link_lo)
     ,.links_o(lce_fill_link_li)

     ,.concentrated_link_i(fill_concentrated_link_li)
     ,.concentrated_link_o(fill_concentrated_link_lo)
     );

  assign resp_concentrated_link_li = lce_resp_link_cast_i;
  assign lce_resp_link_cast_o = '{data          : resp_concentrated_link_lo.data
                                  ,v            : resp_concentrated_link_lo.v
                                  ,ready_and_rev: cce_lce_resp_link_lo.ready_and_rev
                                  };
  bsg_wormhole_concentrator_in
   #(.flit_width_p(coh_noc_flit_width_p)
     ,.len_width_p(coh_noc_len_width_p)
     ,.num_in_p(2)
     ,.cord_width_p(coh_noc_cord_width_p)
     ,.hold_on_valid_p(1)
     )
   resp_concentrator
    (.clk_i(clk_i)
     ,.reset_i(reset_r)

     ,.links_v_i({lce_resp_link_lo[1].v, lce_resp_link_lo[0].v})
     ,.links_data_i({lce_resp_link_lo[1].data, lce_resp_link_lo[0].data})
     ,.links_ready_and_rev_o({lce_resp_link_li[1].ready_and_rev, lce_resp_link_li[0].ready_and_rev})

     ,.concentrated_link_v_o(resp_concentrated_link_lo.v)
     ,.concentrated_link_data_o(resp_concentrated_link_lo.data)
     ,.concentrated_link_ready_and_rev_i(resp_concentrated_link_li.ready_and_rev)
     );
  assign lce_resp_link_li[1].v = 1'b0;
  assign lce_resp_link_li[0].v = 1'b0;
  assign lce_resp_link_li[1].data = '0;
  assign lce_resp_link_li[0].data = '0;
  assign resp_concentrated_link_lo.ready_and_rev = 1'b0;

  // Processor
  bp_cfg_bus_s cfg_bus_lo;
  logic cce_ucode_v_lo;
  logic cce_ucode_w_lo;
  logic [cce_pc_width_p-1:0] cce_ucode_addr_lo;
  logic [cce_instr_width_gp-1:0] cce_ucode_data_lo, cce_ucode_data_li;

  bp_bedrock_mem_fwd_header_s mem_fwd_header_lo;
  logic [bedrock_fill_width_p-1:0] mem_fwd_data_lo;
  logic mem_fwd_v_lo, mem_fwd_ready_and_li;
  bp_bedrock_mem_rev_header_s mem_rev_header_li;
  logic [bedrock_fill_width_p-1:0] mem_rev_data_li;
  logic mem_rev_v_li, mem_rev_ready_and_lo;

  `declare_bsg_cache_dma_pkt_s(daddr_width_p, l2_block_size_in_words_p);
  bsg_cache_dma_pkt_s [l2_dmas_p-1:0] dma_pkt_lo;
  logic [l2_dmas_p-1:0] dma_pkt_v_lo, dma_pkt_yumi_li;
  logic [l2_dmas_p-1:0][l2_fill_width_p-1:0] dma_data_li;
  logic [l2_dmas_p-1:0] dma_data_v_li, dma_data_ready_and_lo;
  logic [l2_dmas_p-1:0][l2_fill_width_p-1:0] dma_data_lo;
  logic [l2_dmas_p-1:0] dma_data_v_lo, dma_data_yumi_li;
  bp_core
   #(.bp_params_p(bp_params_p))
   core
    (.clk_i(clk_i)
     ,.rt_clk_i(rt_clk_i)
     ,.reset_i(reset_r)

     ,.my_did_i(my_did_i)
     ,.host_did_i(host_did_i)
     ,.my_cord_i(my_cord_i)

     ,.cfg_bus_o(cfg_bus_lo)
     ,.cce_ucode_v_o(cce_ucode_v_lo)
     ,.cce_ucode_w_o(cce_ucode_w_lo)
     ,.cce_ucode_addr_o(cce_ucode_addr_lo)
     ,.cce_ucode_data_o(cce_ucode_data_lo)
     ,.cce_ucode_data_i(cce_ucode_data_li)

     ,.lce_req_header_o(lce_req_header_lo)
     ,.lce_req_data_o(lce_req_data_lo)
     ,.lce_req_v_o(lce_req_v_lo)
     ,.lce_req_ready_and_i(lce_req_ready_and_li)

     ,.lce_cmd_header_i(lce_cmd_header_li)
     ,.lce_cmd_data_i(lce_cmd_data_li)
     ,.lce_cmd_v_i(lce_cmd_v_li)
     ,.lce_cmd_ready_and_o(lce_cmd_ready_and_lo)

     ,.lce_resp_header_o(lce_resp_header_lo)
     ,.lce_resp_data_o(lce_resp_data_lo)
     ,.lce_resp_v_o(lce_resp_v_lo)
     ,.lce_resp_ready_and_i(lce_resp_ready_and_li)

     ,.lce_fill_header_i(lce_fill_header_li)
     ,.lce_fill_data_i(lce_fill_data_li)
     ,.lce_fill_v_i(lce_fill_v_li)
     ,.lce_fill_ready_and_o(lce_fill_ready_and_lo)

     ,.lce_fill_header_o(lce_fill_header_lo)
     ,.lce_fill_data_o(lce_fill_data_lo)
     ,.lce_fill_v_o(lce_fill_v_lo)
     ,.lce_fill_ready_and_i(lce_fill_ready_and_li)

     ,.mem_fwd_header_i(mem_fwd_header_lo)
     ,.mem_fwd_data_i(mem_fwd_data_lo)
     ,.mem_fwd_v_i(mem_fwd_v_lo)
     ,.mem_fwd_ready_and_o(mem_fwd_ready_and_li)

     ,.mem_rev_header_o(mem_rev_header_li)
     ,.mem_rev_data_o(mem_rev_data_li)
     ,.mem_rev_v_o(mem_rev_v_li)
     ,.mem_rev_ready_and_i(mem_rev_ready_and_lo)

     ,.dma_pkt_o(dma_pkt_lo)
     ,.dma_pkt_v_o(dma_pkt_v_lo)
     ,.dma_pkt_ready_and_i(dma_pkt_yumi_li)

     ,.dma_data_i(dma_data_li)
     ,.dma_data_v_i(dma_data_v_li)
     ,.dma_data_ready_and_o(dma_data_ready_and_lo)

     ,.dma_data_o(dma_data_lo)
     ,.dma_data_v_o(dma_data_v_lo)
     ,.dma_data_ready_and_i(dma_data_yumi_li)
     );

  // CCE: Cache Coherence Engine
  bp_cce_wrapper
   #(.bp_params_p(bp_params_p))
   cce
    (.clk_i(clk_i)
     ,.reset_i(reset_r)

     ,.cfg_bus_i(cfg_bus_lo)

     ,.ucode_v_i(cce_ucode_v_lo)
     ,.ucode_w_i(cce_ucode_w_lo)
     ,.ucode_addr_i(cce_ucode_addr_lo)
     ,.ucode_data_i(cce_ucode_data_lo)
     ,.ucode_data_o(cce_ucode_data_li)

     // LCE-CCE Interface
     // BedRock Burst protocol: ready&valid
     ,.lce_req_header_i(lce_req_header_li)
     ,.lce_req_data_i(lce_req_data_li)
     ,.lce_req_v_i(lce_req_v_li)
     ,.lce_req_ready_and_o(lce_req_ready_and_lo)

     ,.lce_resp_header_i(lce_resp_header_li)
     ,.lce_resp_data_i(lce_resp_data_li)
     ,.lce_resp_v_i(lce_resp_v_li)
     ,.lce_resp_ready_and_o(lce_resp_ready_and_lo)

     ,.lce_cmd_header_o(lce_cmd_header_lo)
     ,.lce_cmd_data_o(lce_cmd_data_lo)
     ,.lce_cmd_v_o(lce_cmd_v_lo)
     ,.lce_cmd_ready_and_i(lce_cmd_ready_and_li)

     // CCE-MEM Interface
     // BedRock Burst protocol: ready&valid
     ,.mem_rev_header_i(mem_rev_header_li)
     ,.mem_rev_data_i(mem_rev_data_li)
     ,.mem_rev_v_i(mem_rev_v_li)
     ,.mem_rev_ready_and_o(mem_rev_ready_and_lo)

     ,.mem_fwd_header_o(mem_fwd_header_lo)
     ,.mem_fwd_data_o(mem_fwd_data_lo)
     ,.mem_fwd_v_o(mem_fwd_v_lo)
     ,.mem_fwd_ready_and_i(mem_fwd_ready_and_li)
     );

  bp_dma_ready_and_link_s [l2_dmas_p-1:0] dma_link_lo, dma_link_li;
  for (genvar i = 0; i < l2_dmas_p; i++)
    begin : dma
      wire [dma_noc_cord_width_p-1:0] cord_li = my_cord_i[coh_noc_x_cord_width_p+:dma_noc_y_cord_width_p];
      wire [dma_noc_cid_width_p-1:0]   cid_li = i;

      bsg_cache_dma_to_wormhole
       #(.dma_addr_width_p(daddr_width_p)
         ,.dma_burst_len_p(l2_block_size_in_fill_p)
         ,.dma_mask_width_p(l2_block_size_in_words_p)

         ,.wh_flit_width_p(dma_noc_flit_width_p)
         ,.wh_cid_width_p(dma_noc_cid_width_p)
         ,.wh_len_width_p(dma_noc_len_width_p)
         ,.wh_cord_width_p(dma_noc_cord_width_p)
         )
       dma2wh
        (.clk_i(clk_i)
         ,.reset_i(reset_r)

         ,.dma_pkt_i(dma_pkt_lo[i])
         ,.dma_pkt_v_i(dma_pkt_v_lo[i])
         ,.dma_pkt_yumi_o(dma_pkt_yumi_li[i])

         ,.dma_data_o(dma_data_li[i])
         ,.dma_data_v_o(dma_data_v_li[i])
         ,.dma_data_ready_and_i(dma_data_ready_and_lo[i])

         ,.dma_data_i(dma_data_lo[i])
         ,.dma_data_v_i(dma_data_v_lo[i])
         ,.dma_data_yumi_o(dma_data_yumi_li[i])

         ,.wh_link_sif_i(dma_link_li[i])
         ,.wh_link_sif_o(dma_link_lo[i])

         ,.my_wh_cord_i(cord_li)
         ,.my_wh_cid_i(cid_li)
         // TODO: Parameterizable?
         ,.dest_wh_cord_i('1)
         ,.dest_wh_cid_i('0)
         );
    end

  bsg_wormhole_concentrator
   #(.flit_width_p(dma_noc_flit_width_p)
     ,.len_width_p(dma_noc_len_width_p)
     ,.cid_width_p(dma_noc_cid_width_p)
     ,.cord_width_p(dma_noc_cord_width_p)
     ,.num_in_p(l2_dmas_p)
     ,.hold_on_valid_p(1)
     )
   dma_concentrate
    (.clk_i(clk_i)
     ,.reset_i(reset_r)

     ,.links_i(dma_link_lo)
     ,.links_o(dma_link_li)

     ,.concentrated_link_o(dma_link_o)
     ,.concentrated_link_i(dma_link_i)
     );

endmodule