data/full_repos/permissive/197264840/rtl/core/frv_pipeline_writeback.v
1: b'%Error: data/full_repos/permissive/197264840/rtl/core/frv_pipeline_writeback.v:112: Cannot find include file: frv_common.vh\n`include "frv_common.vh" \n         ^~~~~~~~~~~~~~~\n        ... Looked in:\n             data/full_repos/permissive/197264840/rtl/core,data/full_repos/permissive/197264840/frv_common.vh\n             data/full_repos/permissive/197264840/rtl/core,data/full_repos/permissive/197264840/frv_common.vh.v\n             data/full_repos/permissive/197264840/rtl/core,data/full_repos/permissive/197264840/frv_common.vh.sv\n             frv_common.vh\n             frv_common.vh.v\n             frv_common.vh.sv\n             obj_dir/frv_common.vh\n             obj_dir/frv_common.vh.v\n             obj_dir/frv_common.vh.sv\n%Error: Exiting due to 1 error(s)\n'
module frv_pipeline_writeback (

input              g_clk           ,
input              g_resetn        ,

`ifdef RVFI
output [NRET        - 1 : 0] rvfi_valid     ,
output [NRET *   64 - 1 : 0] rvfi_order     ,
output [NRET * ILEN - 1 : 0] rvfi_insn      ,
output [NRET        - 1 : 0] rvfi_trap      ,
output [NRET        - 1 : 0] rvfi_halt      ,
output [NRET        - 1 : 0] rvfi_intr      ,
output [NRET * 2    - 1 : 0] rvfi_mode      ,

output [NRET *    5 - 1 : 0] rvfi_rs1_addr  ,
output [NRET *    5 - 1 : 0] rvfi_rs2_addr  ,
output [NRET * XLEN - 1 : 0] rvfi_rs1_rdata ,
output [NRET * XLEN - 1 : 0] rvfi_rs2_rdata ,
output [NRET *    5 - 1 : 0] rvfi_rd_addr   ,
output [NRET * XLEN - 1 : 0] rvfi_rd_wdata  ,

output [NRET * XLEN - 1 : 0] rvfi_pc_rdata  ,
output [NRET * XLEN - 1 : 0] rvfi_pc_wdata  ,

output [NRET * XLEN  - 1: 0] rvfi_mem_addr  ,
output [NRET * XLEN/8- 1: 0] rvfi_mem_rmask ,
output [NRET * XLEN/8- 1: 0] rvfi_mem_wmask ,
output [NRET * XLEN  - 1: 0] rvfi_mem_rdata ,
output [NRET * XLEN  - 1: 0] rvfi_mem_wdata ,

input  wire [XL:0] rvfi_s4_rs1_rdata,
input  wire [XL:0] rvfi_s4_rs2_rdata,
input  wire [ 4:0] rvfi_s4_rs1_addr ,
input  wire [ 4:0] rvfi_s4_rs2_addr ,
input  wire [XL:0] rvfi_s4_mem_wdata,
`endif

input  wire [ 4:0] s4_rd           ,
input  wire [XL:0] s4_opr_a        ,
input  wire [XL:0] s4_opr_b        ,
input  wire [ 4:0] s4_uop          ,
input  wire [ 4:0] s4_fu           ,
input  wire        s4_trap         ,
input  wire [ 1:0] s4_size         ,
input  wire [31:0] s4_instr        ,
output wire        s4_busy         ,
input  wire        s4_valid        ,

output wire [ 4:0] fwd_s4_rd       ,
output wire [XL:0] fwd_s4_wdata    ,
output wire        fwd_s4_load     ,
output wire        fwd_s4_csr      ,

output wire        gpr_wen         ,
output wire [ 4:0] gpr_rd          ,
output wire [XL:0] gpr_wdata       ,

input  wire        int_trap_req    ,
input  wire [ 5:0] int_trap_cause  ,
output wire        int_trap_ack    ,

output wire        trap_cpu        ,
output wire        trap_int        ,
output wire [ 5:0] trap_cause      ,
output wire [XL:0] trap_mtval      ,
output wire [XL:0] trap_pc         ,

output wire        exec_mret       ,

input  wire [XL:0] csr_mepc        ,
input  wire [XL:0] csr_mtvec       ,

output wire [XL:0] trs_pc          ,
output wire [31:0] trs_instr       ,
output wire        trs_valid       ,

output wire        csr_en          ,
output wire        csr_wr          ,
output wire        csr_wr_set      ,
output wire        csr_wr_clr      ,
output wire [11:0] csr_addr        ,
output wire [XL:0] csr_wdata       ,
input  wire [XL:0] csr_rdata       ,

output wire        cf_req          ,
output wire [XL:0] cf_target       ,
input  wire        cf_ack          ,

output wire        hold_lsu_req    ,

input  wire [31:0] mmio_rdata      ,
input  wire        mmio_error      ,

input  wire        dmem_recv       ,
output wire        dmem_ack        ,
input  wire        dmem_error      ,
input  wire [XL:0] dmem_rdata

);



`include "frv_common.vh"


parameter FRV_PC_RESET_VALUE = 32'h8000_0000;

wire  pipe_progress = s4_valid && !s4_busy;

assign s4_busy = fu_cfu && cfu_busy ||
                (cf_req && !cf_ack) ||
                 fu_lsu && lsu_busy ;



assign hold_lsu_req = cf_req || lsu_busy || trap_int;





reg  [XL:0] s4_pc;
wire [XL:0] pc_plus_isize = s4_pc + {29'b0, s4_size,1'b0};

wire [XL:0] n_s4_pc       = cf_req && !trap_int ? cf_target      :
                                cfu_tgt_ld_opra ? s4_opr_a       :
                                                  pc_plus_isize  ;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        s4_pc <= FRV_PC_RESET_VALUE;
    end else if(trap_int && cf_req && cf_ack) begin
        s4_pc <= cf_target;
    end else if(pipe_progress || (cf_req && cf_ack)) begin
        s4_pc <= n_s4_pc;
    end
end





wire fu_alu = s4_fu[P_FU_ALU];
wire fu_mul = s4_fu[P_FU_MUL];
wire fu_lsu = s4_fu[P_FU_LSU];
wire fu_cfu = s4_fu[P_FU_CFU];
wire fu_csr = s4_fu[P_FU_CSR];





wire        alu_gpr_wen     = fu_alu;
wire [XL:0] alu_gpr_wdata   = s4_opr_a;





wire        mul_gpr_wen     = fu_mul;
wire [XL:0] mul_gpr_wdata   = s4_opr_a;





reg csr_done;

wire n_csr_done = !pipe_progress && (csr_done || csr_en);

always @(posedge g_clk) begin
    if(!g_resetn) begin
        csr_done <= 1'b0;
    end else begin
        csr_done <= n_csr_done;
    end
end

assign      csr_en          = fu_csr && !csr_done;
assign      csr_wr          = fu_csr && s4_uop[CSR_WRITE];
assign      csr_wr_set      = fu_csr && s4_uop[CSR_SET  ];
assign      csr_wr_clr      = fu_csr && s4_uop[CSR_CLEAR];
assign      csr_addr        = s4_opr_b[11:0];
assign      csr_wdata       = s4_opr_a;

wire        csr_read        = fu_csr && s4_uop[CSR_READ];

wire        csr_gpr_wen     = csr_read && !csr_done;
wire [XL:0] csr_gpr_wdata   = csr_rdata;






wire cfu_pt_c   = fu_cfu && s4_uop == CFU_PT_C ;
wire cfu_pt_w   = fu_cfu && s4_uop == CFU_PT_W ;
wire cfu_pnt_c  = fu_cfu && s4_uop == CFU_PNT_C;
wire cfu_pnt_w  = fu_cfu && s4_uop == CFU_PNT_W;

wire cfu_pred_wrong     = cfu_pt_w || cfu_pnt_w;
wire cfu_pred_correct   = cfu_pt_c || cfu_pnt_c;


wire cfu_uop_link   = fu_cfu && s4_uop == CFU_LINK;



wire cfu_tgt_reg    = fu_cfu && (s4_uop == CFU_JALR || s4_uop == CFU_LINK);
wire cfu_tgt_direct = fu_cfu &&  s4_uop == CFU_JALI ;
wire cfu_cf_taken   = cfu_pred_wrong || (cfu_tgt_reg && !cfu_uop_link);

wire cfu_tgt_ld_opra= cfu_tgt_reg || cfu_tgt_direct || cfu_pt_c || cfu_pnt_w;
wire cfu_tgt_ld_npc =                                  cfu_pt_w || cfu_pnt_c;


wire cfu_ebreak     = fu_cfu && s4_uop == CFU_EBREAK;
wire cfu_ecall      = fu_cfu && s4_uop == CFU_ECALL ;


wire cfu_trap       = cfu_ebreak || cfu_ecall;

wire cfu_mret       = fu_cfu &&  s4_uop == CFU_MRET ;



assign exec_mret    = cfu_mret && pipe_progress;


wire cfu_tgt_trap   = cfu_trap || s4_trap || lsu_trap || trap_int;


wire cfu_link       = fu_cfu && (s4_uop == CFU_JALI     ||
                                 s4_uop == CFU_JALR     ||
                                 s4_uop == CFU_LINK     );



wire   cf_req_noint = cfu_cf_taken || cfu_trap || cfu_mret || s4_trap ||
                      lsu_trap     ;


assign cf_req       = cf_req_noint || trap_int  ;


wire cfu_finish_now = cf_req && cf_ack;

wire [31:0] cf_target_noint = 
    {XLEN{cfu_tgt_ld_opra}}  & s4_opr_a      |
    {XLEN{cfu_tgt_ld_npc }}  & pc_plus_isize |
    {XLEN{cfu_tgt_reg    }}  & s4_opr_a      |
    {XLEN{cfu_mret       }}  & csr_mepc      ;


assign cf_target    = 
          cfu_tgt_trap    ? csr_mtvec : cf_target_noint;


reg     cfu_done;
wire    n_cfu_done = !pipe_progress && (cfu_done || cfu_finish_now) ;


wire    cfu_busy = fu_cfu && 
                   !(cfu_done || cfu_finish_now) &&
                   (cfu_cf_taken ||cfu_trap || cfu_mret);

always @(posedge g_clk) if(!g_resetn) begin
    cfu_done <= 1'b0;
end else begin
    cfu_done <= n_cfu_done;
end


wire cfu_gpr_wen = cfu_link;


wire [XL:0] cfu_gpr_wdata = pc_plus_isize;








wire        lsu_mmio        = fu_lsu    && s4_opr_a[4];



wire        lsu_txn_recv    = lsu_load               &&
                              dmem_recv && dmem_ack  &&
                              lsu_rsp_expected       ;




wire        n_lsu_rsp_seen  = 
    !pipe_progress && (lsu_rsp_seen || lsu_mmio || (dmem_recv && dmem_ack));

reg         lsu_rsp_seen;




wire        lsu_rsp_expected= fu_lsu && !lsu_rsp_seen && !lsu_mmio;



assign      dmem_ack    = lsu_rsp_expected;

wire        lsu_gpr_wen     = (lsu_txn_recv && !dmem_error ||
                               lsu_mmio     && !mmio_error  ) &&
                              !lsu_rsp_seen &&  lsu_load       ;

wire [XL:0] lsu_gpr_wdata   = lsu_rdata;

wire        lsu_load    = fu_lsu && s4_uop[LSU_LOAD];
wire        lsu_store   = fu_lsu && s4_uop[LSU_STORE]   ;
wire        lsu_byte    = s4_uop[2:1] == LSU_BYTE;
wire        lsu_half    = s4_uop[2:1] == LSU_HALF;
wire        lsu_word    = s4_uop[2:1] == LSU_WORD;
wire        lsu_signed  = s4_uop[LSU_SIGNED]  ;
wire [XL:0] lsu_addr    = s4_opr_b;



wire [ 3:0] lsu_strb    = s4_opr_a[3:0];



wire        lsu_busy    =
    fu_lsu && !(
        lsu_rsp_seen || (dmem_recv && dmem_ack) || lsu_mmio
    );

wire [31:0] mem_rdata = lsu_mmio ? mmio_rdata : dmem_rdata;



wire [ 7: 0] rdata_b0 =
    {8{lsu_strb[0]                       }} & mem_rdata[ 7: 0] |
    {8{lsu_byte && lsu_addr[1:0] == 2'b01}} & mem_rdata[15: 8] |
    {8{lsu_byte && lsu_addr[1:0] == 2'b10}} & mem_rdata[23:16] |
    {8{lsu_half && lsu_addr[  1] == 1'b1 }} & mem_rdata[23:16] |
    {8{lsu_byte && lsu_addr[1:0] == 2'b11}} & mem_rdata[31:24] ;

wire [ 7: 0] rdata_b1 =
    {8{lsu_byte && lsu_signed            }} & {8{rdata_b0[7] }} |
    {8{lsu_half && lsu_addr[  1] == 1'b0 }} &  mem_rdata[15: 8] |
    {8{lsu_word                          }} &  mem_rdata[15: 8] |
    {8{lsu_half && lsu_addr[  1] == 1'b1 }} &  mem_rdata[31:24] ;

wire [15: 0] rdata_h1 =
    {16{lsu_byte && lsu_signed           }} & {16{rdata_b1[7]}} |
    {16{lsu_half && lsu_signed           }} & {16{rdata_b1[7]}} |
    {16{lsu_word                         }} &  mem_rdata[31:16] ;


wire [XL:0] lsu_rdata   = {rdata_h1,rdata_b1,rdata_b0};



wire        lsu_b_error = lsu_rsp_expected && dmem_error && dmem_recv ||
                          lsu_mmio         && mmio_error              ;

wire        lsu_trap    = lsu_b_error;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        lsu_rsp_seen <= 1'b0;
    end else begin
        lsu_rsp_seen <= n_lsu_rsp_seen;
    end
end





assign gpr_rd   = s4_rd;

assign gpr_wen  = !s4_trap &&
    (csr_gpr_wen || alu_gpr_wen || lsu_gpr_wen ||
     cfu_gpr_wen || mul_gpr_wen );

assign gpr_wdata= {32{csr_gpr_wen}} & csr_gpr_wdata |
                  {32{alu_gpr_wen}} & alu_gpr_wdata |
                  {32{lsu_gpr_wen}} & lsu_gpr_wdata |
                  {32{cfu_gpr_wen}} & cfu_gpr_wdata |
                  {32{mul_gpr_wen}} & mul_gpr_wdata ;

assign fwd_s4_rd    = gpr_rd;
assign fwd_s4_wdata = gpr_wdata;
assign fwd_s4_load  = fu_lsu && lsu_load;
assign fwd_s4_csr   = fu_csr;






reg    trap_int_pending;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        trap_int_pending <= 1'b0;
    end else if(trap_int_pending) begin
        trap_int_pending <= !(cf_req && cf_ack);
    end else begin
        trap_int_pending <= int_trap_req && !pipe_progress;
    end
end


assign int_trap_ack = 1'b0;


assign trap_cpu   = cfu_trap || lsu_trap || s4_trap;


assign trap_int   = (int_trap_req || trap_int_pending) &&
                    !trap_cpu && !lsu_rsp_expected;

assign trap_cause =
    lsu_b_error && lsu_load     ? TRAP_LDACCESS :
    lsu_b_error && lsu_store    ? TRAP_STACCESS :
    cfu_ebreak                  ? TRAP_BREAKPT  :
    cfu_ecall                   ?   TRAP_ECALLM :
    trap_int                    ? int_trap_cause:
                                  s4_opr_a[5:0] ;


assign trap_mtval = 32'b0   ;

assign trap_pc    = s4_pc   ;





assign trs_pc   = s4_pc;
assign trs_instr= s4_instr;





assign trs_valid= 
    |s4_size && ((s4_valid && !s4_busy) || (cf_req && cf_ack && !cfu_done));













`ifdef RVFI

reg  [63:0] rvfi_order_counter;
wire [63:0] n_rvfi_order_counter = rvfi_order_counter + 1;

assign rvfi_order = rvfi_order_counter;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        rvfi_order_counter <= 0;
    end else if(rvfi_valid) begin
        rvfi_order_counter <= n_rvfi_order_counter;
    end
end





reg [ 4:0] saved_gpr_waddr;
reg [XL:0] saved_gpr_wdata;
reg        use_saved_gpr_wdata;

wire       n_use_saved_gpr_wdata =
    !pipe_progress && (use_saved_gpr_wdata || gpr_wen);

always @(posedge g_clk) begin
    if(!g_resetn) begin
        use_saved_gpr_wdata <= 1'b0;
    end else begin
        use_saved_gpr_wdata <= n_use_saved_gpr_wdata;
    end
end

always @(posedge g_clk) begin
    if(!g_resetn) begin
        saved_gpr_wdata <= 0;
        saved_gpr_waddr <= 0;
    end else if(gpr_wen) begin
        saved_gpr_wdata <= gpr_wdata;
        saved_gpr_waddr <= gpr_rd   ;
    end
end




reg [XL:0] saved_mem_rdata;
reg        use_saved_mem_rdata;

wire       n_use_saved_mem_rdata =
    !pipe_progress && (use_saved_mem_rdata || (dmem_recv && dmem_ack));

always @(posedge g_clk) begin
    if(!g_resetn) begin
        use_saved_mem_rdata <= 1'b0;
    end else begin
        use_saved_mem_rdata <= n_use_saved_mem_rdata;
    end
end

always @(posedge g_clk) begin
    if(!g_resetn) begin
        saved_mem_rdata <= 0;
    end else if(dmem_recv && dmem_ack) begin
        saved_mem_rdata <= dmem_rdata;
    end
end




reg  intr_tracker;
wire n_intr_tracker = trap_int || intr_tracker;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        intr_tracker <= 1'b0;
    end else if(intr_tracker) begin
        intr_tracker <= !pipe_progress;
    end else if(pipe_progress) begin
        intr_tracker <= n_intr_tracker;
    end
end



always @(posedge g_clk) begin
    assume(!mmio_error);
end

assign rvfi_valid = trs_valid;
assign rvfi_insn  = trs_instr;
assign rvfi_trap  = trap_cpu ;
assign rvfi_intr  = intr_tracker;

assign rvfi_rs1_addr = rvfi_s4_rs1_addr ;
assign rvfi_rs2_addr = rvfi_s4_rs2_addr ;
assign rvfi_rs1_rdata= rvfi_s4_rs1_rdata;
assign rvfi_rs2_rdata= rvfi_s4_rs2_rdata;

assign rvfi_rd_addr  = use_saved_gpr_wdata ? saved_gpr_waddr :
                       gpr_wen             ? gpr_rd          : 0;
assign rvfi_rd_wdata = |s4_rd && !trap_cpu ?
                       (use_saved_gpr_wdata ? saved_gpr_wdata : gpr_wdata) : 0;

assign rvfi_pc_rdata = trs_pc   ; 
assign rvfi_pc_wdata = n_s4_pc  ;

assign rvfi_mem_addr = {s4_opr_b[XL:2], 2'b00} ;
assign rvfi_mem_rmask= fu_lsu && lsu_load  ? lsu_strb : 4'b0000 ;
assign rvfi_mem_wmask= fu_lsu && lsu_store ? lsu_strb : 4'b0000 ;
assign rvfi_mem_rdata= lsu_mmio            ? mmio_rdata      :
                       use_saved_mem_rdata ? saved_mem_rdata :
                                             dmem_rdata;
assign rvfi_mem_wdata= rvfi_s4_mem_wdata;


assign rvfi_halt  = 0;
assign rvfi_mode  = 0;

`endif

endmodule
module frv_pipeline_writeback (

input              g_clk           ,
input              g_resetn        ,

`ifdef RVFI
output [NRET        - 1 : 0] rvfi_valid     ,
output [NRET *   64 - 1 : 0] rvfi_order     ,
output [NRET * ILEN - 1 : 0] rvfi_insn      ,
output [NRET        - 1 : 0] rvfi_trap      ,
output [NRET        - 1 : 0] rvfi_halt      ,
output [NRET        - 1 : 0] rvfi_intr      ,
output [NRET * 2    - 1 : 0] rvfi_mode      ,

output [NRET *    5 - 1 : 0] rvfi_rs1_addr  ,
output [NRET *    5 - 1 : 0] rvfi_rs2_addr  ,
output [NRET * XLEN - 1 : 0] rvfi_rs1_rdata ,
output [NRET * XLEN - 1 : 0] rvfi_rs2_rdata ,
output [NRET *    5 - 1 : 0] rvfi_rd_addr   ,
output [NRET * XLEN - 1 : 0] rvfi_rd_wdata  ,

output [NRET * XLEN - 1 : 0] rvfi_pc_rdata  ,
output [NRET * XLEN - 1 : 0] rvfi_pc_wdata  ,

output [NRET * XLEN  - 1: 0] rvfi_mem_addr  ,
output [NRET * XLEN/8- 1: 0] rvfi_mem_rmask ,
output [NRET * XLEN/8- 1: 0] rvfi_mem_wmask ,
output [NRET * XLEN  - 1: 0] rvfi_mem_rdata ,
output [NRET * XLEN  - 1: 0] rvfi_mem_wdata ,

input  wire [XL:0] rvfi_s4_rs1_rdata,
input  wire [XL:0] rvfi_s4_rs2_rdata,
input  wire [ 4:0] rvfi_s4_rs1_addr ,
input  wire [ 4:0] rvfi_s4_rs2_addr ,
input  wire [XL:0] rvfi_s4_mem_wdata,
`endif

input  wire [ 4:0] s4_rd           ,
input  wire [XL:0] s4_opr_a        ,
input  wire [XL:0] s4_opr_b        ,
input  wire [ 4:0] s4_uop          ,
input  wire [ 4:0] s4_fu           ,
input  wire        s4_trap         ,
input  wire [ 1:0] s4_size         ,
input  wire [31:0] s4_instr        ,
output wire        s4_busy         ,
input  wire        s4_valid        ,

output wire [ 4:0] fwd_s4_rd       ,
output wire [XL:0] fwd_s4_wdata    ,
output wire        fwd_s4_load     ,
output wire        fwd_s4_csr      ,

output wire        gpr_wen         ,
output wire [ 4:0] gpr_rd          ,
output wire [XL:0] gpr_wdata       ,

input  wire        int_trap_req    ,
input  wire [ 5:0] int_trap_cause  ,
output wire        int_trap_ack    ,

output wire        trap_cpu        ,
output wire        trap_int        ,
output wire [ 5:0] trap_cause      ,
output wire [XL:0] trap_mtval      ,
output wire [XL:0] trap_pc         ,

output wire        exec_mret       ,

input  wire [XL:0] csr_mepc        ,
input  wire [XL:0] csr_mtvec       ,

output wire [XL:0] trs_pc          ,
output wire [31:0] trs_instr       ,
output wire        trs_valid       ,

output wire        csr_en          ,
output wire        csr_wr          ,
output wire        csr_wr_set      ,
output wire        csr_wr_clr      ,
output wire [11:0] csr_addr        ,
output wire [XL:0] csr_wdata       ,
input  wire [XL:0] csr_rdata       ,

output wire        cf_req          ,
output wire [XL:0] cf_target       ,
input  wire        cf_ack          ,

output wire        hold_lsu_req    ,

input  wire [31:0] mmio_rdata      ,
input  wire        mmio_error      ,

input  wire        dmem_recv       ,
output wire        dmem_ack        ,
input  wire        dmem_error      ,
input  wire [XL:0] dmem_rdata

);




`include "frv_common.vh"


parameter FRV_PC_RESET_VALUE = 32'h8000_0000;

wire  pipe_progress = s4_valid && !s4_busy;

assign s4_busy = fu_cfu && cfu_busy ||
                (cf_req && !cf_ack) ||
                 fu_lsu && lsu_busy ;



assign hold_lsu_req = cf_req || lsu_busy || trap_int;





reg  [XL:0] s4_pc;
wire [XL:0] pc_plus_isize = s4_pc + {29'b0, s4_size,1'b0};

wire [XL:0] n_s4_pc       = cf_req && !trap_int ? cf_target      :
                                cfu_tgt_ld_opra ? s4_opr_a       :
                                                  pc_plus_isize  ;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        s4_pc <= FRV_PC_RESET_VALUE;
    end else if(trap_int && cf_req && cf_ack) begin
        s4_pc <= cf_target;
    end else if(pipe_progress || (cf_req && cf_ack)) begin
        s4_pc <= n_s4_pc;
    end
end





wire fu_alu = s4_fu[P_FU_ALU];
wire fu_mul = s4_fu[P_FU_MUL];
wire fu_lsu = s4_fu[P_FU_LSU];
wire fu_cfu = s4_fu[P_FU_CFU];
wire fu_csr = s4_fu[P_FU_CSR];





wire        alu_gpr_wen     = fu_alu;
wire [XL:0] alu_gpr_wdata   = s4_opr_a;





wire        mul_gpr_wen     = fu_mul;
wire [XL:0] mul_gpr_wdata   = s4_opr_a;





reg csr_done;

wire n_csr_done = !pipe_progress && (csr_done || csr_en);

always @(posedge g_clk) begin
    if(!g_resetn) begin
        csr_done <= 1'b0;
    end else begin
        csr_done <= n_csr_done;
    end
end

assign      csr_en          = fu_csr && !csr_done;
assign      csr_wr          = fu_csr && s4_uop[CSR_WRITE];
assign      csr_wr_set      = fu_csr && s4_uop[CSR_SET  ];
assign      csr_wr_clr      = fu_csr && s4_uop[CSR_CLEAR];
assign      csr_addr        = s4_opr_b[11:0];
assign      csr_wdata       = s4_opr_a;

wire        csr_read        = fu_csr && s4_uop[CSR_READ];

wire        csr_gpr_wen     = csr_read && !csr_done;
wire [XL:0] csr_gpr_wdata   = csr_rdata;






wire cfu_pt_c   = fu_cfu && s4_uop == CFU_PT_C ;
wire cfu_pt_w   = fu_cfu && s4_uop == CFU_PT_W ;
wire cfu_pnt_c  = fu_cfu && s4_uop == CFU_PNT_C;
wire cfu_pnt_w  = fu_cfu && s4_uop == CFU_PNT_W;

wire cfu_pred_wrong     = cfu_pt_w || cfu_pnt_w;
wire cfu_pred_correct   = cfu_pt_c || cfu_pnt_c;


wire cfu_uop_link   = fu_cfu && s4_uop == CFU_LINK;



wire cfu_tgt_reg    = fu_cfu && (s4_uop == CFU_JALR || s4_uop == CFU_LINK);
wire cfu_tgt_direct = fu_cfu &&  s4_uop == CFU_JALI ;
wire cfu_cf_taken   = cfu_pred_wrong || (cfu_tgt_reg && !cfu_uop_link);

wire cfu_tgt_ld_opra= cfu_tgt_reg || cfu_tgt_direct || cfu_pt_c || cfu_pnt_w;
wire cfu_tgt_ld_npc =                                  cfu_pt_w || cfu_pnt_c;


wire cfu_ebreak     = fu_cfu && s4_uop == CFU_EBREAK;
wire cfu_ecall      = fu_cfu && s4_uop == CFU_ECALL ;


wire cfu_trap       = cfu_ebreak || cfu_ecall;

wire cfu_mret       = fu_cfu &&  s4_uop == CFU_MRET ;



assign exec_mret    = cfu_mret && pipe_progress;


wire cfu_tgt_trap   = cfu_trap || s4_trap || lsu_trap || trap_int;


wire cfu_link       = fu_cfu && (s4_uop == CFU_JALI     ||
                                 s4_uop == CFU_JALR     ||
                                 s4_uop == CFU_LINK     );



wire   cf_req_noint = cfu_cf_taken || cfu_trap || cfu_mret || s4_trap ||
                      lsu_trap     ;


assign cf_req       = cf_req_noint || trap_int  ;


wire cfu_finish_now = cf_req && cf_ack;

wire [31:0] cf_target_noint = 
    {XLEN{cfu_tgt_ld_opra}}  & s4_opr_a      |
    {XLEN{cfu_tgt_ld_npc }}  & pc_plus_isize |
    {XLEN{cfu_tgt_reg    }}  & s4_opr_a      |
    {XLEN{cfu_mret       }}  & csr_mepc      ;


assign cf_target    = 
          cfu_tgt_trap    ? csr_mtvec : cf_target_noint;


reg     cfu_done;
wire    n_cfu_done = !pipe_progress && (cfu_done || cfu_finish_now) ;


wire    cfu_busy = fu_cfu && 
                   !(cfu_done || cfu_finish_now) &&
                   (cfu_cf_taken ||cfu_trap || cfu_mret);

always @(posedge g_clk) if(!g_resetn) begin
    cfu_done <= 1'b0;
end else begin
    cfu_done <= n_cfu_done;
end


wire cfu_gpr_wen = cfu_link;


wire [XL:0] cfu_gpr_wdata = pc_plus_isize;








wire        lsu_mmio        = fu_lsu    && s4_opr_a[4];



wire        lsu_txn_recv    = lsu_load               &&
                              dmem_recv && dmem_ack  &&
                              lsu_rsp_expected       ;




wire        n_lsu_rsp_seen  = 
    !pipe_progress && (lsu_rsp_seen || lsu_mmio || (dmem_recv && dmem_ack));

reg         lsu_rsp_seen;




wire        lsu_rsp_expected= fu_lsu && !lsu_rsp_seen && !lsu_mmio;



assign      dmem_ack    = lsu_rsp_expected;

wire        lsu_gpr_wen     = (lsu_txn_recv && !dmem_error ||
                               lsu_mmio     && !mmio_error  ) &&
                              !lsu_rsp_seen &&  lsu_load       ;

wire [XL:0] lsu_gpr_wdata   = lsu_rdata;

wire        lsu_load    = fu_lsu && s4_uop[LSU_LOAD];
wire        lsu_store   = fu_lsu && s4_uop[LSU_STORE]   ;
wire        lsu_byte    = s4_uop[2:1] == LSU_BYTE;
wire        lsu_half    = s4_uop[2:1] == LSU_HALF;
wire        lsu_word    = s4_uop[2:1] == LSU_WORD;
wire        lsu_signed  = s4_uop[LSU_SIGNED]  ;
wire [XL:0] lsu_addr    = s4_opr_b;



wire [ 3:0] lsu_strb    = s4_opr_a[3:0];



wire        lsu_busy    =
    fu_lsu && !(
        lsu_rsp_seen || (dmem_recv && dmem_ack) || lsu_mmio
    );

wire [31:0] mem_rdata = lsu_mmio ? mmio_rdata : dmem_rdata;



wire [ 7: 0] rdata_b0 =
    {8{lsu_strb[0]                       }} & mem_rdata[ 7: 0] |
    {8{lsu_byte && lsu_addr[1:0] == 2'b01}} & mem_rdata[15: 8] |
    {8{lsu_byte && lsu_addr[1:0] == 2'b10}} & mem_rdata[23:16] |
    {8{lsu_half && lsu_addr[  1] == 1'b1 }} & mem_rdata[23:16] |
    {8{lsu_byte && lsu_addr[1:0] == 2'b11}} & mem_rdata[31:24] ;

wire [ 7: 0] rdata_b1 =
    {8{lsu_byte && lsu_signed            }} & {8{rdata_b0[7] }} |
    {8{lsu_half && lsu_addr[  1] == 1'b0 }} &  mem_rdata[15: 8] |
    {8{lsu_word                          }} &  mem_rdata[15: 8] |
    {8{lsu_half && lsu_addr[  1] == 1'b1 }} &  mem_rdata[31:24] ;

wire [15: 0] rdata_h1 =
    {16{lsu_byte && lsu_signed           }} & {16{rdata_b1[7]}} |
    {16{lsu_half && lsu_signed           }} & {16{rdata_b1[7]}} |
    {16{lsu_word                         }} &  mem_rdata[31:16] ;


wire [XL:0] lsu_rdata   = {rdata_h1,rdata_b1,rdata_b0};



wire        lsu_b_error = lsu_rsp_expected && dmem_error && dmem_recv ||
                          lsu_mmio         && mmio_error              ;

wire        lsu_trap    = lsu_b_error;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        lsu_rsp_seen <= 1'b0;
    end else begin
        lsu_rsp_seen <= n_lsu_rsp_seen;
    end
end





assign gpr_rd   = s4_rd;

assign gpr_wen  = !s4_trap &&
    (csr_gpr_wen || alu_gpr_wen || lsu_gpr_wen ||
     cfu_gpr_wen || mul_gpr_wen );

assign gpr_wdata= {32{csr_gpr_wen}} & csr_gpr_wdata |
                  {32{alu_gpr_wen}} & alu_gpr_wdata |
                  {32{lsu_gpr_wen}} & lsu_gpr_wdata |
                  {32{cfu_gpr_wen}} & cfu_gpr_wdata |
                  {32{mul_gpr_wen}} & mul_gpr_wdata ;

assign fwd_s4_rd    = gpr_rd;
assign fwd_s4_wdata = gpr_wdata;
assign fwd_s4_load  = fu_lsu && lsu_load;
assign fwd_s4_csr   = fu_csr;






reg    trap_int_pending;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        trap_int_pending <= 1'b0;
    end else if(trap_int_pending) begin
        trap_int_pending <= !(cf_req && cf_ack);
    end else begin
        trap_int_pending <= int_trap_req && !pipe_progress;
    end
end


assign int_trap_ack = 1'b0;


assign trap_cpu   = cfu_trap || lsu_trap || s4_trap;


assign trap_int   = (int_trap_req || trap_int_pending) &&
                    !trap_cpu && !lsu_rsp_expected;

assign trap_cause =
    lsu_b_error && lsu_load     ? TRAP_LDACCESS :
    lsu_b_error && lsu_store    ? TRAP_STACCESS :
    cfu_ebreak                  ? TRAP_BREAKPT  :
    cfu_ecall                   ?   TRAP_ECALLM :
    trap_int                    ? int_trap_cause:
                                  s4_opr_a[5:0] ;


assign trap_mtval = 32'b0   ;

assign trap_pc    = s4_pc   ;





assign trs_pc   = s4_pc;
assign trs_instr= s4_instr;





assign trs_valid= 
    |s4_size && ((s4_valid && !s4_busy) || (cf_req && cf_ack && !cfu_done));













`ifdef RVFI

reg  [63:0] rvfi_order_counter;
wire [63:0] n_rvfi_order_counter = rvfi_order_counter + 1;

assign rvfi_order = rvfi_order_counter;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        rvfi_order_counter <= 0;
    end else if(rvfi_valid) begin
        rvfi_order_counter <= n_rvfi_order_counter;
    end
end





reg [ 4:0] saved_gpr_waddr;
reg [XL:0] saved_gpr_wdata;
reg        use_saved_gpr_wdata;

wire       n_use_saved_gpr_wdata =
    !pipe_progress && (use_saved_gpr_wdata || gpr_wen);

always @(posedge g_clk) begin
    if(!g_resetn) begin
        use_saved_gpr_wdata <= 1'b0;
    end else begin
        use_saved_gpr_wdata <= n_use_saved_gpr_wdata;
    end
end

always @(posedge g_clk) begin
    if(!g_resetn) begin
        saved_gpr_wdata <= 0;
        saved_gpr_waddr <= 0;
    end else if(gpr_wen) begin
        saved_gpr_wdata <= gpr_wdata;
        saved_gpr_waddr <= gpr_rd   ;
    end
end




reg [XL:0] saved_mem_rdata;
reg        use_saved_mem_rdata;

wire       n_use_saved_mem_rdata =
    !pipe_progress && (use_saved_mem_rdata || (dmem_recv && dmem_ack));

always @(posedge g_clk) begin
    if(!g_resetn) begin
        use_saved_mem_rdata <= 1'b0;
    end else begin
        use_saved_mem_rdata <= n_use_saved_mem_rdata;
    end
end

always @(posedge g_clk) begin
    if(!g_resetn) begin
        saved_mem_rdata <= 0;
    end else if(dmem_recv && dmem_ack) begin
        saved_mem_rdata <= dmem_rdata;
    end
end




reg  intr_tracker;
wire n_intr_tracker = trap_int || intr_tracker;

always @(posedge g_clk) begin
    if(!g_resetn) begin
        intr_tracker <= 1'b0;
    end else if(intr_tracker) begin
        intr_tracker <= !pipe_progress;
    end else if(pipe_progress) begin
        intr_tracker <= n_intr_tracker;
    end
end



always @(posedge g_clk) begin
    assume(!mmio_error);
end

assign rvfi_valid = trs_valid;
assign rvfi_insn  = trs_instr;
assign rvfi_trap  = trap_cpu ;
assign rvfi_intr  = intr_tracker;

assign rvfi_rs1_addr = rvfi_s4_rs1_addr ;
assign rvfi_rs2_addr = rvfi_s4_rs2_addr ;
assign rvfi_rs1_rdata= rvfi_s4_rs1_rdata;
assign rvfi_rs2_rdata= rvfi_s4_rs2_rdata;

assign rvfi_rd_addr  = use_saved_gpr_wdata ? saved_gpr_waddr :
                       gpr_wen             ? gpr_rd          : 0;
assign rvfi_rd_wdata = |s4_rd && !trap_cpu ?
                       (use_saved_gpr_wdata ? saved_gpr_wdata : gpr_wdata) : 0;

assign rvfi_pc_rdata = trs_pc   ; 
assign rvfi_pc_wdata = n_s4_pc  ;

assign rvfi_mem_addr = {s4_opr_b[XL:2], 2'b00} ;
assign rvfi_mem_rmask= fu_lsu && lsu_load  ? lsu_strb : 4'b0000 ;
assign rvfi_mem_wmask= fu_lsu && lsu_store ? lsu_strb : 4'b0000 ;
assign rvfi_mem_rdata= lsu_mmio            ? mmio_rdata      :
                       use_saved_mem_rdata ? saved_mem_rdata :
                                             dmem_rdata;
assign rvfi_mem_wdata= rvfi_s4_mem_wdata;


assign rvfi_halt  = 0;
assign rvfi_mode  = 0;

`endif

endmodule