module e203_clk_ctrl (
  input  clk,        // clock
  input  rst_n,      // async reset
  input  test_mode,  // test mode 

  // The cgstop is coming from CSR (0xBFE mcgstop)'s filed 0
  // // This register is our self-defined CSR register to disable the 
      // automaticall clock gating for CPU logics for debugging purpose
  input  core_cgstop,

  // The Top always on clk and rst
  output clk_aon,



  input  core_ifu_active,
  input  core_exu_active,
  input  core_lsu_active,
  input  core_biu_active,
  `ifdef E203_HAS_ITCM
  input  itcm_active,
  output itcm_ls,
  `endif
  `ifdef E203_HAS_DTCM
  input  dtcm_active,
  output dtcm_ls,
  `endif
    // The core's clk and rst
  output clk_core_ifu,
  output clk_core_exu,
  output clk_core_lsu,
  output clk_core_biu,

    // The ITCM/DTCM clk and rst
  `ifdef E203_HAS_ITCM
  output clk_itcm,
  `endif
  `ifdef E203_HAS_DTCM
  output clk_dtcm,
  `endif

  input  core_wfi
);

  // The CSR control bit CGSTOP will override the automatical clock gating here for special debug purpose

      // The IFU is always actively fetching unless it is WFI to override it
  wire ifu_clk_en = core_cgstop | (core_ifu_active & (~core_wfi));
      // The EXU, LSU and BIU module's clock gating does not need to check
      //  WFI because it may have request from external agent
      //  and also, it actually will automactically become inactive regardess
      //  currently is WFI or not, hence we dont need WFI here
  wire exu_clk_en = core_cgstop | (core_exu_active);
  wire lsu_clk_en = core_cgstop | (core_lsu_active);
  wire biu_clk_en = core_cgstop | (core_biu_active);




  e203_clkgate u_ifu_clkgate(
    .clk_in   (clk        ),
    .test_mode(test_mode  ),
    .clock_en (ifu_clk_en),
    .clk_out  (clk_core_ifu)
  );

  e203_clkgate u_exu_clkgate(
    .clk_in   (clk        ),
    .test_mode(test_mode  ),
    .clock_en (exu_clk_en),
    .clk_out  (clk_core_exu)
  );

  e203_clkgate u_lsu_clkgate(
    .clk_in   (clk        ),
    .test_mode(test_mode  ),
    .clock_en (lsu_clk_en),
    .clk_out  (clk_core_lsu)
  );

  e203_clkgate u_biu_clkgate(
    .clk_in   (clk        ),
    .test_mode(test_mode  ),
    .clock_en (biu_clk_en),
    .clk_out  (clk_core_biu)
  );

  `ifdef E203_HAS_ITCM
      // The ITCM and DTCM Ctrl module's clock gating does not need to check
      //  WFI because it may have request from external agent
      //  and also, it actually will automactically become inactive regardess
      //  currently is WFI or not, hence we dont need WFI here
  wire itcm_active_r;
  sirv_gnrl_dffr #(1)itcm_active_dffr(itcm_active, itcm_active_r, clk, rst_n);
  wire itcm_clk_en = core_cgstop | itcm_active | itcm_active_r;
  assign itcm_ls = ~itcm_clk_en;

  e203_clkgate u_itcm_clkgate(
    .clk_in   (clk        ),
    .test_mode(test_mode  ),
    .clock_en (itcm_clk_en),
    .clk_out  (clk_itcm)
  );
  `endif

  `ifdef E203_HAS_DTCM
  wire dtcm_active_r;
  sirv_gnrl_dffr #(1)dtcm_active_dffr(dtcm_active, dtcm_active_r, clk, rst_n);
  wire dtcm_clk_en = core_cgstop | dtcm_active | dtcm_active_r;
  assign dtcm_ls = ~dtcm_clk_en;

  e203_clkgate u_dtcm_clkgate(
    .clk_in   (clk        ),
    .test_mode(test_mode  ),
    .clock_en (dtcm_clk_en),
    .clk_out  (clk_dtcm)
  );
  `endif


  // The Top always on clk and rst
  assign clk_aon = clk;

endmodule