data/full_repos/permissive/489147019/Flows/ASAP7/ariane136/rtl/serpent_icache.sv
1: b'%Error: data/full_repos/permissive/489147019/Flows/ASAP7/ariane136/rtl/serpent_icache.sv:27: syntax error, unexpected IDENTIFIER, expecting PACKAGE-IDENTIFIER or STRING\nimport ariane_pkg::*;\n       ^~~~~~~~~~\n%Error: Exiting due to 1 error(s)\n'
module serpent_icache  #(
    parameter logic [DCACHE_ID_WIDTH-1:0] RdTxId             = 0,
    parameter bit                         Axi64BitCompliant  = 1'b0,
    parameter logic [63:0]                CachedAddrBeg      = 64'h00_8000_0000,
    parameter logic [63:0]                CachedAddrEnd      = 64'h80_0000_0000
) (
    input  logic                      clk_i,
    input  logic                      rst_ni,

    input  logic                      flush_i,
    input  logic                      en_i,
    output logic                      miss_o,

    input  icache_areq_i_t            areq_i,
    output icache_areq_o_t            areq_o,

    input  icache_dreq_i_t            dreq_i,
    output icache_dreq_o_t            dreq_o,

    input  logic                      mem_rtrn_vld_i,
    input  icache_rtrn_t              mem_rtrn_i,
    output logic                      mem_data_req_o,
    input  logic                      mem_data_ack_i,
    output icache_req_t               mem_data_o
);


    logic                                 cache_en_d, cache_en_q;
    logic [63:0]                          vaddr_d, vaddr_q;
    logic                                 paddr_is_nc;
    logic [ICACHE_SET_ASSOC-1:0]          cl_hit;
    logic                                 cache_rden;
    logic                                 cache_wren;
    logic                                 cmp_en_d, cmp_en_q;
    logic                                 flush_d, flush_q;


    logic                                 update_lfsr;
    logic [$clog2(ICACHE_SET_ASSOC)-1:0]  inv_way;
    logic [$clog2(ICACHE_SET_ASSOC)-1:0]  rnd_way;
    logic [$clog2(ICACHE_SET_ASSOC)-1:0]  repl_way;
    logic [ICACHE_SET_ASSOC-1:0]          repl_way_oh_d, repl_way_oh_q;
    logic                                 all_ways_valid;


    logic                                 inv_en;
    logic                                 flush_en, flush_done;
    logic [ICACHE_CL_IDX_WIDTH-1:0]       flush_cnt_d, flush_cnt_q;


    logic                                 cl_we;
    logic [ICACHE_SET_ASSOC-1:0]          cl_req;
    logic [ICACHE_CL_IDX_WIDTH-1:0]       cl_index;
    logic [ICACHE_OFFSET_WIDTH-1:0]       cl_offset_d, cl_offset_q;
    logic [ICACHE_TAG_WIDTH-1:0]          cl_tag_d, cl_tag_q;
    logic [ICACHE_TAG_WIDTH-1:0]          cl_tag_rdata [ICACHE_SET_ASSOC-1:0];
    logic [ICACHE_LINE_WIDTH-1:0]         cl_rdata     [ICACHE_SET_ASSOC-1:0];
    logic [ICACHE_SET_ASSOC-1:0][FETCH_WIDTH-1:0]cl_sel;
    logic [ICACHE_SET_ASSOC-1:0]          vld_req;
    logic                                 vld_we;
    logic [ICACHE_SET_ASSOC-1:0]          vld_wdata;
    logic [ICACHE_SET_ASSOC-1:0]          vld_rdata;
    logic [ICACHE_CL_IDX_WIDTH-1:0]       vld_addr;


    typedef enum logic[2:0] {FLUSH, IDLE, READ, MISS, TLB_MISS, KILL_ATRANS, KILL_MISS} state_t;
    state_t state_d, state_q;






    assign cl_tag_d  = (areq_i.fetch_valid) ? areq_i.fetch_paddr[ICACHE_TAG_WIDTH+ICACHE_INDEX_WIDTH-1:ICACHE_INDEX_WIDTH] : cl_tag_q;


    assign paddr_is_nc = (cl_tag_d <  (CachedAddrBeg>>ICACHE_INDEX_WIDTH)) ||
                         (cl_tag_d >= (CachedAddrEnd>>ICACHE_INDEX_WIDTH)) ||
                         (!cache_en_q);


    assign dreq_o.ex = areq_i.fetch_exception;



    assign vaddr_d = (dreq_o.ready & dreq_i.req) ? dreq_i.vaddr : vaddr_q;
    assign areq_o.fetch_vaddr = {vaddr_q>>2, 2'b0};


    assign cl_index    = vaddr_d[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH];

    generate
        if(Axi64BitCompliant)begin

            assign cl_offset_d = ( dreq_o.ready & dreq_i.req)      ? {dreq_i.vaddr>>2, 2'b0} :
                                 ( paddr_is_nc  & mem_data_req_o ) ? cl_offset_q[2]<<2 :
                                                                     cl_offset_q;

            assign mem_data_o.paddr = (paddr_is_nc) ? {cl_tag_d, vaddr_q[ICACHE_INDEX_WIDTH-1:3], 3'b0} :
                                                      {cl_tag_d, vaddr_q[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH], {ICACHE_OFFSET_WIDTH{1'b0}}};
        end
        if(!Axi64BitCompliant)begin


            assign cl_offset_d = ( dreq_o.ready & dreq_i.req)      ? {dreq_i.vaddr>>2, 2'b0} :
                                                                     cl_offset_q;


            assign mem_data_o.paddr = (paddr_is_nc) ? {cl_tag_d, vaddr_q[ICACHE_INDEX_WIDTH-1:2], 2'b0} :
                                                      {cl_tag_d, vaddr_q[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH], {ICACHE_OFFSET_WIDTH{1'b0}}};
        end
    endgenerate

    assign mem_data_o.tid   = RdTxId;

    assign mem_data_o.nc    = paddr_is_nc;

    assign mem_data_o.way   = repl_way;
    assign dreq_o.vaddr     = vaddr_q;





    always_comb begin : p_fsm

        state_d      = state_q;
        cache_en_d   = cache_en_q & en_i;
        flush_en     = 1'b0;
        cmp_en_d     = 1'b0;
        cache_rden   = 1'b0;
        cache_wren   = 1'b0;
        inv_en       = 1'b0;
        flush_d      = flush_q | flush_i;


        dreq_o.ready     = 1'b0;
        areq_o.fetch_req = 1'b0;
        dreq_o.valid     = 1'b0;
        mem_data_req_o   = 1'b0;

        miss_o           = 1'b0;






        if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_INV_REQ) begin
            inv_en = 1'b1;
        end

        unique case (state_q)


            FLUSH: begin
                flush_en = 1'b1;
                if (flush_done) begin
                    state_d = IDLE;
                    flush_d = 1'b0;

                    cache_en_d = en_i;
                end
            end


            IDLE: begin

                cmp_en_d = cache_en_q;


                if (flush_d | (en_i & ~cache_en_q)) begin
                    state_d    = FLUSH;

                end else begin

                    if (~mem_rtrn_vld_i) begin
                        dreq_o.ready = 1'b1;

                        if (dreq_i.req) begin
                            cache_rden       = 1'b1;
                            state_d          = READ;
                        end
                    end
                    if (dreq_i.kill_s1) begin
                        state_d = IDLE;
                    end
                end
            end






            READ: begin
                state_d          = TLB_MISS;
                areq_o.fetch_req = '1;

                cmp_en_d    = cache_en_q;

                cache_rden  = cache_en_q;

                if (areq_i.fetch_valid) begin

                    if (flush_d) begin
                        state_d  = IDLE;

                    end else if ((|cl_hit & cache_en_q) | areq_i.fetch_exception.valid) begin
                        dreq_o.valid     = ~dreq_i.kill_s2;
                        state_d          = IDLE;




                        if (~mem_rtrn_vld_i) begin
                            dreq_o.ready     = 1'b1;
                            if (dreq_i.req) begin
                                state_d          = READ;
                            end
                        end


                        if (dreq_i.kill_s1) begin
                            state_d = IDLE;
                        end

                    end else if (dreq_i.kill_s2) begin
                        state_d = IDLE;
                    end else begin
                        cmp_en_d = 1'b0;



                        mem_data_req_o = 1'b1;
                        if (mem_data_ack_i) begin
                            miss_o         = (~paddr_is_nc);
                            state_d        = MISS;
                        end
                    end

                end else if (dreq_i.kill_s2 | flush_d) begin
                    state_d  = KILL_ATRANS;
                end
            end




            TLB_MISS: begin
                areq_o.fetch_req = '1;

                cmp_en_d = cache_en_q;

                cache_rden = cache_en_q;

                if (areq_i.fetch_valid) begin

                    if (dreq_i.kill_s2 | flush_d) begin
                        state_d  = IDLE;

                    end else if (areq_i.fetch_exception.valid) begin
                        dreq_o.valid = 1'b1;
                        state_d      = IDLE;


                    end else if (~mem_rtrn_vld_i) begin
                        state_d          = READ;
                    end

                end else if (dreq_i.kill_s2 | flush_d) begin
                    state_d  = KILL_ATRANS;
                end
            end




            MISS: begin


                if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin
                    state_d      = IDLE;

                    if (~(dreq_i.kill_s2 | flush_d)) begin
                        dreq_o.valid = 1'b1;

                        cache_wren   = ~paddr_is_nc;
                    end

                end else if (dreq_i.kill_s2 | flush_d) begin
                    state_d  = KILL_MISS;
                end
            end




            KILL_ATRANS: begin
                areq_o.fetch_req = '1;
                if (areq_i.fetch_valid) begin
                    state_d      = IDLE;
                end
            end




            KILL_MISS: begin
                if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin
                    state_d      = IDLE;
                end
            end
            default: begin

                state_d = FLUSH;
            end
        endcase
    end










    assign flush_cnt_d = (flush_done) ? '0               :
                         (flush_en)   ?  flush_cnt_q + 1 :
                                         flush_cnt_q;

    assign flush_done  = (flush_cnt_q==(ICACHE_NUM_WORDS-1));



    assign vld_addr = (flush_en)       ? flush_cnt_q        :
                      (inv_en)         ? mem_rtrn_i.inv.idx[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH] :
                                         cl_index;

    assign vld_req  = (flush_en | cache_rden)         ? '1                                    :
                      (mem_rtrn_i.inv.all & inv_en)   ? '1                                    :
                      (mem_rtrn_i.inv.vld & inv_en)   ? icache_way_bin2oh(mem_rtrn_i.inv.way) :
                                                        repl_way_oh_q;

    assign vld_wdata = (cache_wren) ? '1 : '0;

    assign vld_we    = (cache_wren | inv_en | flush_en);




    assign update_lfsr   = cache_wren & all_ways_valid;
    assign repl_way      = (all_ways_valid) ? rnd_way : inv_way;
    assign repl_way_oh_d = (cmp_en_q) ? icache_way_bin2oh(repl_way) : repl_way_oh_q;


    assign cl_req   = (cache_rden) ? '1            :
                      (cache_wren) ? repl_way_oh_q :
                                     '0;
    assign cl_we    = cache_wren;



    lzc #(
        .WIDTH ( ICACHE_SET_ASSOC )
    ) i_lzc (
        .in_i    ( ~vld_rdata     ),
        .cnt_o   ( inv_way        ),
        .empty_o ( all_ways_valid )
    );


    lfsr_8bit #(
        .WIDTH (ICACHE_SET_ASSOC)
    ) i_lfsr (
        .clk_i          ( clk_i       ),
        .rst_ni         ( rst_ni      ),
        .en_i           ( update_lfsr ),
        .refill_way_oh  (             ),
        .refill_way_bin ( rnd_way     )
    );






    logic [$clog2(ICACHE_SET_ASSOC)-1:0] hit_idx;

    generate
        for (genvar i=0;i<ICACHE_SET_ASSOC;i++) begin : g_tag_cmpsel
            assign cl_hit[i] = (cl_tag_rdata[i] == cl_tag_d) & vld_rdata[i];
            assign cl_sel[i] = cl_rdata[i][{cl_offset_q,3'b0} +: FETCH_WIDTH];
        end
    endgenerate

    lzc #(
        .WIDTH ( ICACHE_SET_ASSOC )
    ) i_lzc_hit (
        .in_i    ( cl_hit  ),
        .cnt_o   ( hit_idx ),
        .empty_o (         )
    );

    assign dreq_o.data = ( cmp_en_q ) ? cl_sel[hit_idx] :
                                        mem_rtrn_i.data[{cl_offset_q,3'b0} +: FETCH_WIDTH];






    logic [ICACHE_TAG_WIDTH:0] cl_tag_valid_rdata [ICACHE_SET_ASSOC-1:0];

    generate
        for (genvar i = 0; i < ICACHE_SET_ASSOC; i++) begin : g_sram

            sram #(

                .DATA_WIDTH ( ICACHE_TAG_WIDTH+1 ),
                .NUM_WORDS  ( ICACHE_NUM_WORDS   )
            ) tag_sram (
                .clk_i     ( clk_i                    ),
                .rst_ni    ( rst_ni                   ),
                .req_i     ( vld_req[i]               ),
                .we_i      ( vld_we                   ),
                .addr_i    ( vld_addr                 ),


                .wdata_i   ( {vld_wdata[i], cl_tag_q} ),
                .be_i      ( '1                       ),
                .rdata_o   ( cl_tag_valid_rdata[i]    )
            );

            assign cl_tag_rdata[i] = cl_tag_valid_rdata[i][ICACHE_TAG_WIDTH-1:0];
            assign vld_rdata[i]    = cl_tag_valid_rdata[i][ICACHE_TAG_WIDTH];


            sram #(
                .DATA_WIDTH ( ICACHE_LINE_WIDTH ),
                .NUM_WORDS  ( ICACHE_NUM_WORDS  )
            ) data_sram (
                .clk_i     ( clk_i               ),
                .rst_ni    ( rst_ni              ),
                .req_i     ( cl_req[i]           ),
                .we_i      ( cl_we               ),
                .addr_i    ( cl_index            ),
                .wdata_i   ( mem_rtrn_i.data     ),
                .be_i      ( '1                  ),
                .rdata_o   ( cl_rdata[i]         )
            );
        end
    endgenerate

    always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
        if(~rst_ni) begin
            cl_tag_q      <= '0;
            flush_cnt_q   <= '0;
            vaddr_q       <= '0;
            cmp_en_q      <= '0;
            cache_en_q    <= '0;
            flush_q       <= '0;
            state_q       <= IDLE;
            cl_offset_q   <= '0;
            repl_way_oh_q <= '0;
        end else begin
            cl_tag_q      <= cl_tag_d;
            flush_cnt_q   <= flush_cnt_d;
            vaddr_q       <= vaddr_d;
            cmp_en_q      <= cmp_en_d;
            cache_en_q    <= cache_en_d;
            flush_q       <= flush_d;
            state_q       <= state_d;
            cl_offset_q   <= cl_offset_d;
            repl_way_oh_q <= repl_way_oh_d;
        end
    end






`ifndef VERILATOR
  noncacheable0: assert property (
      @(posedge clk_i) disable iff (~rst_ni) paddr_is_nc |-> mem_rtrn_vld_i |-> state_q != KILL_MISS |-> mem_rtrn_i.rtype == ICACHE_IFILL_ACK |-> mem_rtrn_i.nc)
         else $fatal(1,"[l1 icache] NC paddr implies nc ifill");

  noncacheable1: assert property (
      @(posedge clk_i) disable iff (~rst_ni) mem_rtrn_vld_i |-> state_q != KILL_MISS |-> mem_rtrn_i.f4b |-> mem_rtrn_i.nc)
         else $fatal(1,"[l1 icache] 4b ifill implies NC");

  repl_inval0: assert property (
      @(posedge clk_i) disable iff (~rst_ni) cache_wren |-> ~(mem_rtrn_i.inv.all | mem_rtrn_i.inv.vld))
         else $fatal(1,"[l1 icache] cannot replace cacheline and invalidate cacheline simultaneously");

  repl_inval1: assert property (
      @(posedge clk_i) disable iff (~rst_ni) (mem_rtrn_i.inv.all | mem_rtrn_i.inv.vld) |-> ~cache_wren)
         else $fatal(1,"[l1 icache] cannot replace cacheline and invalidate cacheline simultaneously");

  invalid_state: assert property (
      @(posedge clk_i) disable iff (~rst_ni) (state_q inside {FLUSH, IDLE, READ, MISS, TLB_MISS, KILL_ATRANS, KILL_MISS}))
         else $fatal(1,"[l1 icache] fsm reached an invalid state");

  hot1: assert property (
      @(posedge clk_i) disable iff (~rst_ni) (~inv_en) |=> cmp_en_q |-> $onehot0(cl_hit))
         else $fatal(1,"[l1 icache] cl_hit signal must be hot1");

   initial begin

      assert (ICACHE_INDEX_WIDTH<=12)
        else $fatal(1,"[l1 icache] cache index width can be maximum 12bit since VM uses 4kB pages");
   end
`endif


endmodule
module serpent_icache  #(
    parameter logic [DCACHE_ID_WIDTH-1:0] RdTxId             = 0,
    parameter bit                         Axi64BitCompliant  = 1'b0,
    parameter logic [63:0]                CachedAddrBeg      = 64'h00_8000_0000,
    parameter logic [63:0]                CachedAddrEnd      = 64'h80_0000_0000
) (
    input  logic                      clk_i,
    input  logic                      rst_ni,

    input  logic                      flush_i,
    input  logic                      en_i,
    output logic                      miss_o,

    input  icache_areq_i_t            areq_i,
    output icache_areq_o_t            areq_o,

    input  icache_dreq_i_t            dreq_i,
    output icache_dreq_o_t            dreq_o,

    input  logic                      mem_rtrn_vld_i,
    input  icache_rtrn_t              mem_rtrn_i,
    output logic                      mem_data_req_o,
    input  logic                      mem_data_ack_i,
    output icache_req_t               mem_data_o
);



    logic                                 cache_en_d, cache_en_q;
    logic [63:0]                          vaddr_d, vaddr_q;
    logic                                 paddr_is_nc;
    logic [ICACHE_SET_ASSOC-1:0]          cl_hit;
    logic                                 cache_rden;
    logic                                 cache_wren;
    logic                                 cmp_en_d, cmp_en_q;
    logic                                 flush_d, flush_q;


    logic                                 update_lfsr;
    logic [$clog2(ICACHE_SET_ASSOC)-1:0]  inv_way;
    logic [$clog2(ICACHE_SET_ASSOC)-1:0]  rnd_way;
    logic [$clog2(ICACHE_SET_ASSOC)-1:0]  repl_way;
    logic [ICACHE_SET_ASSOC-1:0]          repl_way_oh_d, repl_way_oh_q;
    logic                                 all_ways_valid;


    logic                                 inv_en;
    logic                                 flush_en, flush_done;
    logic [ICACHE_CL_IDX_WIDTH-1:0]       flush_cnt_d, flush_cnt_q;


    logic                                 cl_we;
    logic [ICACHE_SET_ASSOC-1:0]          cl_req;
    logic [ICACHE_CL_IDX_WIDTH-1:0]       cl_index;
    logic [ICACHE_OFFSET_WIDTH-1:0]       cl_offset_d, cl_offset_q;
    logic [ICACHE_TAG_WIDTH-1:0]          cl_tag_d, cl_tag_q;
    logic [ICACHE_TAG_WIDTH-1:0]          cl_tag_rdata [ICACHE_SET_ASSOC-1:0];
    logic [ICACHE_LINE_WIDTH-1:0]         cl_rdata     [ICACHE_SET_ASSOC-1:0];
    logic [ICACHE_SET_ASSOC-1:0][FETCH_WIDTH-1:0]cl_sel;
    logic [ICACHE_SET_ASSOC-1:0]          vld_req;
    logic                                 vld_we;
    logic [ICACHE_SET_ASSOC-1:0]          vld_wdata;
    logic [ICACHE_SET_ASSOC-1:0]          vld_rdata;
    logic [ICACHE_CL_IDX_WIDTH-1:0]       vld_addr;


    typedef enum logic[2:0] {FLUSH, IDLE, READ, MISS, TLB_MISS, KILL_ATRANS, KILL_MISS} state_t;
    state_t state_d, state_q;






    assign cl_tag_d  = (areq_i.fetch_valid) ? areq_i.fetch_paddr[ICACHE_TAG_WIDTH+ICACHE_INDEX_WIDTH-1:ICACHE_INDEX_WIDTH] : cl_tag_q;


    assign paddr_is_nc = (cl_tag_d <  (CachedAddrBeg>>ICACHE_INDEX_WIDTH)) ||
                         (cl_tag_d >= (CachedAddrEnd>>ICACHE_INDEX_WIDTH)) ||
                         (!cache_en_q);


    assign dreq_o.ex = areq_i.fetch_exception;



    assign vaddr_d = (dreq_o.ready & dreq_i.req) ? dreq_i.vaddr : vaddr_q;
    assign areq_o.fetch_vaddr = {vaddr_q>>2, 2'b0};


    assign cl_index    = vaddr_d[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH];

    generate
        if(Axi64BitCompliant)begin

            assign cl_offset_d = ( dreq_o.ready & dreq_i.req)      ? {dreq_i.vaddr>>2, 2'b0} :
                                 ( paddr_is_nc  & mem_data_req_o ) ? cl_offset_q[2]<<2 :
                                                                     cl_offset_q;

            assign mem_data_o.paddr = (paddr_is_nc) ? {cl_tag_d, vaddr_q[ICACHE_INDEX_WIDTH-1:3], 3'b0} :
                                                      {cl_tag_d, vaddr_q[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH], {ICACHE_OFFSET_WIDTH{1'b0}}};
        end
        if(!Axi64BitCompliant)begin


            assign cl_offset_d = ( dreq_o.ready & dreq_i.req)      ? {dreq_i.vaddr>>2, 2'b0} :
                                                                     cl_offset_q;


            assign mem_data_o.paddr = (paddr_is_nc) ? {cl_tag_d, vaddr_q[ICACHE_INDEX_WIDTH-1:2], 2'b0} :
                                                      {cl_tag_d, vaddr_q[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH], {ICACHE_OFFSET_WIDTH{1'b0}}};
        end
    endgenerate

    assign mem_data_o.tid   = RdTxId;

    assign mem_data_o.nc    = paddr_is_nc;

    assign mem_data_o.way   = repl_way;
    assign dreq_o.vaddr     = vaddr_q;





    always_comb begin : p_fsm

        state_d      = state_q;
        cache_en_d   = cache_en_q & en_i;
        flush_en     = 1'b0;
        cmp_en_d     = 1'b0;
        cache_rden   = 1'b0;
        cache_wren   = 1'b0;
        inv_en       = 1'b0;
        flush_d      = flush_q | flush_i;


        dreq_o.ready     = 1'b0;
        areq_o.fetch_req = 1'b0;
        dreq_o.valid     = 1'b0;
        mem_data_req_o   = 1'b0;

        miss_o           = 1'b0;






        if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_INV_REQ) begin
            inv_en = 1'b1;
        end

        unique case (state_q)


            FLUSH: begin
                flush_en = 1'b1;
                if (flush_done) begin
                    state_d = IDLE;
                    flush_d = 1'b0;

                    cache_en_d = en_i;
                end
            end


            IDLE: begin

                cmp_en_d = cache_en_q;


                if (flush_d | (en_i & ~cache_en_q)) begin
                    state_d    = FLUSH;

                end else begin

                    if (~mem_rtrn_vld_i) begin
                        dreq_o.ready = 1'b1;

                        if (dreq_i.req) begin
                            cache_rden       = 1'b1;
                            state_d          = READ;
                        end
                    end
                    if (dreq_i.kill_s1) begin
                        state_d = IDLE;
                    end
                end
            end






            READ: begin
                state_d          = TLB_MISS;
                areq_o.fetch_req = '1;

                cmp_en_d    = cache_en_q;

                cache_rden  = cache_en_q;

                if (areq_i.fetch_valid) begin

                    if (flush_d) begin
                        state_d  = IDLE;

                    end else if ((|cl_hit & cache_en_q) | areq_i.fetch_exception.valid) begin
                        dreq_o.valid     = ~dreq_i.kill_s2;
                        state_d          = IDLE;




                        if (~mem_rtrn_vld_i) begin
                            dreq_o.ready     = 1'b1;
                            if (dreq_i.req) begin
                                state_d          = READ;
                            end
                        end


                        if (dreq_i.kill_s1) begin
                            state_d = IDLE;
                        end

                    end else if (dreq_i.kill_s2) begin
                        state_d = IDLE;
                    end else begin
                        cmp_en_d = 1'b0;



                        mem_data_req_o = 1'b1;
                        if (mem_data_ack_i) begin
                            miss_o         = (~paddr_is_nc);
                            state_d        = MISS;
                        end
                    end

                end else if (dreq_i.kill_s2 | flush_d) begin
                    state_d  = KILL_ATRANS;
                end
            end




            TLB_MISS: begin
                areq_o.fetch_req = '1;

                cmp_en_d = cache_en_q;

                cache_rden = cache_en_q;

                if (areq_i.fetch_valid) begin

                    if (dreq_i.kill_s2 | flush_d) begin
                        state_d  = IDLE;

                    end else if (areq_i.fetch_exception.valid) begin
                        dreq_o.valid = 1'b1;
                        state_d      = IDLE;


                    end else if (~mem_rtrn_vld_i) begin
                        state_d          = READ;
                    end

                end else if (dreq_i.kill_s2 | flush_d) begin
                    state_d  = KILL_ATRANS;
                end
            end




            MISS: begin


                if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin
                    state_d      = IDLE;

                    if (~(dreq_i.kill_s2 | flush_d)) begin
                        dreq_o.valid = 1'b1;

                        cache_wren   = ~paddr_is_nc;
                    end

                end else if (dreq_i.kill_s2 | flush_d) begin
                    state_d  = KILL_MISS;
                end
            end




            KILL_ATRANS: begin
                areq_o.fetch_req = '1;
                if (areq_i.fetch_valid) begin
                    state_d      = IDLE;
                end
            end




            KILL_MISS: begin
                if (mem_rtrn_vld_i && mem_rtrn_i.rtype == ICACHE_IFILL_ACK) begin
                    state_d      = IDLE;
                end
            end
            default: begin

                state_d = FLUSH;
            end
        endcase
    end










    assign flush_cnt_d = (flush_done) ? '0               :
                         (flush_en)   ?  flush_cnt_q + 1 :
                                         flush_cnt_q;

    assign flush_done  = (flush_cnt_q==(ICACHE_NUM_WORDS-1));



    assign vld_addr = (flush_en)       ? flush_cnt_q        :
                      (inv_en)         ? mem_rtrn_i.inv.idx[ICACHE_INDEX_WIDTH-1:ICACHE_OFFSET_WIDTH] :
                                         cl_index;

    assign vld_req  = (flush_en | cache_rden)         ? '1                                    :
                      (mem_rtrn_i.inv.all & inv_en)   ? '1                                    :
                      (mem_rtrn_i.inv.vld & inv_en)   ? icache_way_bin2oh(mem_rtrn_i.inv.way) :
                                                        repl_way_oh_q;

    assign vld_wdata = (cache_wren) ? '1 : '0;

    assign vld_we    = (cache_wren | inv_en | flush_en);




    assign update_lfsr   = cache_wren & all_ways_valid;
    assign repl_way      = (all_ways_valid) ? rnd_way : inv_way;
    assign repl_way_oh_d = (cmp_en_q) ? icache_way_bin2oh(repl_way) : repl_way_oh_q;


    assign cl_req   = (cache_rden) ? '1            :
                      (cache_wren) ? repl_way_oh_q :
                                     '0;
    assign cl_we    = cache_wren;



    lzc #(
        .WIDTH ( ICACHE_SET_ASSOC )
    ) i_lzc (
        .in_i    ( ~vld_rdata     ),
        .cnt_o   ( inv_way        ),
        .empty_o ( all_ways_valid )
    );


    lfsr_8bit #(
        .WIDTH (ICACHE_SET_ASSOC)
    ) i_lfsr (
        .clk_i          ( clk_i       ),
        .rst_ni         ( rst_ni      ),
        .en_i           ( update_lfsr ),
        .refill_way_oh  (             ),
        .refill_way_bin ( rnd_way     )
    );






    logic [$clog2(ICACHE_SET_ASSOC)-1:0] hit_idx;

    generate
        for (genvar i=0;i<ICACHE_SET_ASSOC;i++) begin : g_tag_cmpsel
            assign cl_hit[i] = (cl_tag_rdata[i] == cl_tag_d) & vld_rdata[i];
            assign cl_sel[i] = cl_rdata[i][{cl_offset_q,3'b0} +: FETCH_WIDTH];
        end
    endgenerate

    lzc #(
        .WIDTH ( ICACHE_SET_ASSOC )
    ) i_lzc_hit (
        .in_i    ( cl_hit  ),
        .cnt_o   ( hit_idx ),
        .empty_o (         )
    );

    assign dreq_o.data = ( cmp_en_q ) ? cl_sel[hit_idx] :
                                        mem_rtrn_i.data[{cl_offset_q,3'b0} +: FETCH_WIDTH];






    logic [ICACHE_TAG_WIDTH:0] cl_tag_valid_rdata [ICACHE_SET_ASSOC-1:0];

    generate
        for (genvar i = 0; i < ICACHE_SET_ASSOC; i++) begin : g_sram

            sram #(

                .DATA_WIDTH ( ICACHE_TAG_WIDTH+1 ),
                .NUM_WORDS  ( ICACHE_NUM_WORDS   )
            ) tag_sram (
                .clk_i     ( clk_i                    ),
                .rst_ni    ( rst_ni                   ),
                .req_i     ( vld_req[i]               ),
                .we_i      ( vld_we                   ),
                .addr_i    ( vld_addr                 ),


                .wdata_i   ( {vld_wdata[i], cl_tag_q} ),
                .be_i      ( '1                       ),
                .rdata_o   ( cl_tag_valid_rdata[i]    )
            );

            assign cl_tag_rdata[i] = cl_tag_valid_rdata[i][ICACHE_TAG_WIDTH-1:0];
            assign vld_rdata[i]    = cl_tag_valid_rdata[i][ICACHE_TAG_WIDTH];


            sram #(
                .DATA_WIDTH ( ICACHE_LINE_WIDTH ),
                .NUM_WORDS  ( ICACHE_NUM_WORDS  )
            ) data_sram (
                .clk_i     ( clk_i               ),
                .rst_ni    ( rst_ni              ),
                .req_i     ( cl_req[i]           ),
                .we_i      ( cl_we               ),
                .addr_i    ( cl_index            ),
                .wdata_i   ( mem_rtrn_i.data     ),
                .be_i      ( '1                  ),
                .rdata_o   ( cl_rdata[i]         )
            );
        end
    endgenerate

    always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
        if(~rst_ni) begin
            cl_tag_q      <= '0;
            flush_cnt_q   <= '0;
            vaddr_q       <= '0;
            cmp_en_q      <= '0;
            cache_en_q    <= '0;
            flush_q       <= '0;
            state_q       <= IDLE;
            cl_offset_q   <= '0;
            repl_way_oh_q <= '0;
        end else begin
            cl_tag_q      <= cl_tag_d;
            flush_cnt_q   <= flush_cnt_d;
            vaddr_q       <= vaddr_d;
            cmp_en_q      <= cmp_en_d;
            cache_en_q    <= cache_en_d;
            flush_q       <= flush_d;
            state_q       <= state_d;
            cl_offset_q   <= cl_offset_d;
            repl_way_oh_q <= repl_way_oh_d;
        end
    end






`ifndef VERILATOR
  noncacheable0: assert property (
      @(posedge clk_i) disable iff (~rst_ni) paddr_is_nc |-> mem_rtrn_vld_i |-> state_q != KILL_MISS |-> mem_rtrn_i.rtype == ICACHE_IFILL_ACK |-> mem_rtrn_i.nc)
         else $fatal(1,"[l1 icache] NC paddr implies nc ifill");

  noncacheable1: assert property (
      @(posedge clk_i) disable iff (~rst_ni) mem_rtrn_vld_i |-> state_q != KILL_MISS |-> mem_rtrn_i.f4b |-> mem_rtrn_i.nc)
         else $fatal(1,"[l1 icache] 4b ifill implies NC");

  repl_inval0: assert property (
      @(posedge clk_i) disable iff (~rst_ni) cache_wren |-> ~(mem_rtrn_i.inv.all | mem_rtrn_i.inv.vld))
         else $fatal(1,"[l1 icache] cannot replace cacheline and invalidate cacheline simultaneously");

  repl_inval1: assert property (
      @(posedge clk_i) disable iff (~rst_ni) (mem_rtrn_i.inv.all | mem_rtrn_i.inv.vld) |-> ~cache_wren)
         else $fatal(1,"[l1 icache] cannot replace cacheline and invalidate cacheline simultaneously");

  invalid_state: assert property (
      @(posedge clk_i) disable iff (~rst_ni) (state_q inside {FLUSH, IDLE, READ, MISS, TLB_MISS, KILL_ATRANS, KILL_MISS}))
         else $fatal(1,"[l1 icache] fsm reached an invalid state");

  hot1: assert property (
      @(posedge clk_i) disable iff (~rst_ni) (~inv_en) |=> cmp_en_q |-> $onehot0(cl_hit))
         else $fatal(1,"[l1 icache] cl_hit signal must be hot1");

   initial begin

      assert (ICACHE_INDEX_WIDTH<=12)
        else $fatal(1,"[l1 icache] cache index width can be maximum 12bit since VM uses 4kB pages");
   end
`endif


endmodule