module servile
  #(
    parameter	    reset_pc = 32'h00000000,
    parameter	    reset_strategy = "MINI",
    parameter	    rf_width = 8,
    parameter [0:0] sim = 1'b0,
    parameter [0:0] with_c = 1'b0,
    parameter [0:0] with_csr = 1'b0,
    parameter [0:0] with_mdu = 1'b0,
    //Internally calculated. Do not touch
    parameter	    regs = 32+with_csr*4,
    parameter	    rf_l2d = $clog2(regs*32/rf_width))
  (
   input wire		      i_clk,
   input wire		      i_rst,
   input wire		      i_timer_irq,

   //Memory (WB) interface
   output wire [31:0]	      o_wb_mem_adr,
   output wire [31:0]	      o_wb_mem_dat,
   output wire [3:0]	      o_wb_mem_sel,
   output wire		      o_wb_mem_we ,
   output wire		      o_wb_mem_stb,
   input wire [31:0]	      i_wb_mem_rdt,
   input wire		      i_wb_mem_ack,

   //Extension (WB) interface
   output wire [31:0]	      o_wb_ext_adr,
   output wire [31:0]	      o_wb_ext_dat,
   output wire [3:0]	      o_wb_ext_sel,
   output wire		      o_wb_ext_we ,
   output wire		      o_wb_ext_stb,
   input wire [31:0]	      i_wb_ext_rdt,
   input wire		      i_wb_ext_ack,

   //RF (SRAM) interface
   output wire [rf_l2d-1:0]   o_rf_waddr,
   output wire [rf_width-1:0] o_rf_wdata,
   output wire		      o_rf_wen,
   output wire [rf_l2d-1:0]   o_rf_raddr,
   input wire [rf_width-1:0]  i_rf_rdata,
   output wire		      o_rf_ren);



   wire [31:0] 	wb_ibus_adr;
   wire 	wb_ibus_stb;
   wire [31:0] 	wb_ibus_rdt;
   wire 	wb_ibus_ack;

   wire [31:0] 	wb_dbus_adr;
   wire [31:0] 	wb_dbus_dat;
   wire [3:0] 	wb_dbus_sel;
   wire 	wb_dbus_we;
   wire 	wb_dbus_stb;
   wire [31:0] 	wb_dbus_rdt;
   wire 	wb_dbus_ack;

   wire [31:0] 	wb_dmem_adr;
   wire [31:0] 	wb_dmem_dat;
   wire [3:0] 	wb_dmem_sel;
   wire 	wb_dmem_we;
   wire 	wb_dmem_stb;
   wire [31:0] 	wb_dmem_rdt;
   wire 	wb_dmem_ack;

   wire 		   rf_wreq;
   wire 		   rf_rreq;
   wire [$clog2(regs)-1:0] wreg0;
   wire [$clog2(regs)-1:0] wreg1;
   wire 		   wen0;
   wire 		   wen1;
   wire 		   wdata0;
   wire 		   wdata1;
   wire [$clog2(regs)-1:0] rreg0;
   wire [$clog2(regs)-1:0] rreg1;
   wire 		   rf_ready;
   wire 		   rdata0;
   wire 		   rdata1;

   wire [31:0]		   mdu_rs1;
   wire [31:0]		   mdu_rs2;
   wire [ 2:0]		   mdu_op;
   wire			   mdu_valid;
   wire [31:0]		   mdu_rd;
   wire			   mdu_ready;

   servile_mux
     #(.sim (sim))
   mux
     (.i_clk        (i_clk),
      .i_rst        (i_rst & (reset_strategy != "NONE")),

      .i_wb_cpu_adr (wb_dbus_adr),
      .i_wb_cpu_dat (wb_dbus_dat),
      .i_wb_cpu_sel (wb_dbus_sel),
      .i_wb_cpu_we  (wb_dbus_we),
      .i_wb_cpu_stb (wb_dbus_stb),
      .o_wb_cpu_rdt (wb_dbus_rdt),
      .o_wb_cpu_ack (wb_dbus_ack),

      .o_wb_mem_adr (wb_dmem_adr),
      .o_wb_mem_dat (wb_dmem_dat),
      .o_wb_mem_sel (wb_dmem_sel),
      .o_wb_mem_we  (wb_dmem_we),
      .o_wb_mem_stb (wb_dmem_stb),
      .i_wb_mem_rdt (wb_dmem_rdt),
      .i_wb_mem_ack (wb_dmem_ack),

      .o_wb_ext_adr (o_wb_ext_adr),
      .o_wb_ext_dat (o_wb_ext_dat),
      .o_wb_ext_sel (o_wb_ext_sel),
      .o_wb_ext_we  (o_wb_ext_we),
      .o_wb_ext_stb (o_wb_ext_stb),
      .i_wb_ext_rdt (i_wb_ext_rdt),
      .i_wb_ext_ack (i_wb_ext_ack));

   servile_arbiter arbiter
     (.i_wb_cpu_dbus_adr (wb_dmem_adr),
      .i_wb_cpu_dbus_dat (wb_dmem_dat),
      .i_wb_cpu_dbus_sel (wb_dmem_sel),
      .i_wb_cpu_dbus_we  (wb_dmem_we ),
      .i_wb_cpu_dbus_stb (wb_dmem_stb),
      .o_wb_cpu_dbus_rdt (wb_dmem_rdt),
      .o_wb_cpu_dbus_ack (wb_dmem_ack),

      .i_wb_cpu_ibus_adr (wb_ibus_adr),
      .i_wb_cpu_ibus_stb (wb_ibus_stb),
      .o_wb_cpu_ibus_rdt (wb_ibus_rdt),
      .o_wb_cpu_ibus_ack (wb_ibus_ack),

      .o_wb_mem_adr (o_wb_mem_adr),
      .o_wb_mem_dat (o_wb_mem_dat),
      .o_wb_mem_sel (o_wb_mem_sel),
      .o_wb_mem_we  (o_wb_mem_we ),
      .o_wb_mem_stb (o_wb_mem_stb),
      .i_wb_mem_rdt (i_wb_mem_rdt),
      .i_wb_mem_ack (i_wb_mem_ack));



   serv_rf_ram_if
     #(.width    (rf_width),
       .reset_strategy (reset_strategy),
       .csr_regs (with_csr*4))
   rf_ram_if
     (.i_clk    (i_clk),
      .i_rst    (i_rst),
      //RF IF
      .i_wreq   (rf_wreq),
      .i_rreq   (rf_rreq),
      .o_ready  (rf_ready),
      .i_wreg0  (wreg0),
      .i_wreg1  (wreg1),
      .i_wen0   (wen0),
      .i_wen1   (wen1),
      .i_wdata0 (wdata0),
      .i_wdata1 (wdata1),
      .i_rreg0  (rreg0),
      .i_rreg1  (rreg1),
      .o_rdata0 (rdata0),
      .o_rdata1 (rdata1),
      //SRAM IF
      .o_waddr  (o_rf_waddr),
      .o_wdata  (o_rf_wdata),
      .o_wen    (o_rf_wen),
      .o_raddr  (o_rf_raddr),
      .o_ren    (o_rf_ren),
      .i_rdata  (i_rf_rdata));

   generate
      if (with_mdu) begin : gen_mdu
	 mdu_top mdu_serv
	   (.i_clk       (i_clk),
	    .i_rst       (i_rst),
	    .i_mdu_rs1   (mdu_rs1),
	    .i_mdu_rs2   (mdu_rs2),
	    .i_mdu_op    (mdu_op),
	    .i_mdu_valid (mdu_valid),
	    .o_mdu_ready (mdu_ready),
	    .o_mdu_rd    (mdu_rd));
      end else begin
	 assign mdu_ready = 1'b0;
	 assign mdu_rd = 32'd0;
      end
   endgenerate

   serv_top
     #(
       .WITH_CSR       (with_csr?1:0),
       .PRE_REGISTER   (1'b1),
       .RESET_STRATEGY (reset_strategy),
       .RESET_PC       (reset_pc),
       .MDU            (with_mdu),
       .COMPRESSED     (with_c))
   cpu
     (
      .clk         (i_clk),
      .i_rst       (i_rst),
      .i_timer_irq (i_timer_irq),

`ifdef RISCV_FORMAL
      .rvfi_valid     (),
      .rvfi_order     (),
      .rvfi_insn      (),
      .rvfi_trap      (),
      .rvfi_halt      (),
      .rvfi_intr      (),
      .rvfi_mode      (),
      .rvfi_ixl       (),
      .rvfi_rs1_addr  (),
      .rvfi_rs2_addr  (),
      .rvfi_rs1_rdata (),
      .rvfi_rs2_rdata (),
      .rvfi_rd_addr   (),
      .rvfi_rd_wdata  (),
      .rvfi_pc_rdata  (),
      .rvfi_pc_wdata  (),
      .rvfi_mem_addr  (),
      .rvfi_mem_rmask (),
      .rvfi_mem_wmask (),
      .rvfi_mem_rdata (),
      .rvfi_mem_wdata (),
`endif
      //RF IF
      .o_rf_rreq   (rf_rreq),
      .o_rf_wreq   (rf_wreq),
      .i_rf_ready  (rf_ready),
      .o_wreg0     (wreg0),
      .o_wreg1     (wreg1),
      .o_wen0      (wen0),
      .o_wen1      (wen1),
      .o_wdata0    (wdata0),
      .o_wdata1    (wdata1),
      .o_rreg0     (rreg0),
      .o_rreg1     (rreg1),
      .i_rdata0    (rdata0),
      .i_rdata1    (rdata1),

      //Instruction bus
      .o_ibus_adr  (wb_ibus_adr),
      .o_ibus_cyc  (wb_ibus_stb),
      .i_ibus_rdt  (wb_ibus_rdt),
      .i_ibus_ack  (wb_ibus_ack),

      //Data bus
      .o_dbus_adr  (wb_dbus_adr),
      .o_dbus_dat  (wb_dbus_dat),
      .o_dbus_sel  (wb_dbus_sel),
      .o_dbus_we   (wb_dbus_we),
      .o_dbus_cyc  (wb_dbus_stb),
      .i_dbus_rdt  (wb_dbus_rdt),
      .i_dbus_ack  (wb_dbus_ack),

      //Extension IF
      .o_ext_rs1    (mdu_rs1),
      .o_ext_rs2    (mdu_rs2),
      .o_ext_funct3 (mdu_op),
      .i_ext_rd     (mdu_rd),
      .i_ext_ready  (mdu_ready),
      //MDU
      .o_mdu_valid  (mdu_valid));

endmodule