1
0
mirror of https://github.com/olofk/serv.git synced 2026-02-24 15:37:38 +00:00
Files
olofk.serv/rtl/serv_top.v
Olof Kindgren 75decc8251 Bring back old immediate decoder
This was originally thrown out since it was slow and cost too much
resources. Due to other changes in the core, it is now cheaper
than the other one
2019-10-29 21:54:22 +01:00

448 lines
12 KiB
Verilog

`default_nettype none
module serv_top
(
input wire clk,
input wire i_rst,
input wire i_timer_irq,
`ifdef RISCV_FORMAL
output reg rvfi_valid = 1'b0,
output reg [63:0] rvfi_order = 64'd0,
output reg [31:0] rvfi_insn = 32'd0,
output reg rvfi_trap = 1'b0,
output reg rvfi_halt = 1'b0,
output reg rvfi_intr = 1'b0,
output reg [1:0] rvfi_mode = 2'b11,
output reg [1:0] rvfi_ixl = 2'b01,
output reg [4:0] rvfi_rs1_addr,
output reg [4:0] rvfi_rs2_addr,
output reg [31:0] rvfi_rs1_rdata,
output reg [31:0] rvfi_rs2_rdata,
output reg [4:0] rvfi_rd_addr,
output reg [31:0] rvfi_rd_wdata,
output reg [31:0] rvfi_pc_rdata,
output reg [31:0] rvfi_pc_wdata,
output reg [31:0] rvfi_mem_addr,
output reg [3:0] rvfi_mem_rmask,
output reg [3:0] rvfi_mem_wmask,
output reg [31:0] rvfi_mem_rdata,
output reg [31:0] rvfi_mem_wdata,
`endif
output wire [31:0] o_ibus_adr,
output wire o_ibus_cyc,
input wire [31:0] i_ibus_rdt,
input wire i_ibus_ack,
output wire [31:0] o_dbus_adr,
output wire [31:0] o_dbus_dat,
output wire [3:0] o_dbus_sel,
output wire o_dbus_we ,
output wire o_dbus_cyc,
input wire [31:0] i_dbus_rdt,
input wire i_dbus_ack);
`include "serv_params.vh"
wire [4:0] rd_addr;
wire [4:0] rs1_addr;
wire [4:0] rs2_addr;
wire take_branch;
wire e_op;
wire ebreak;
wire branch_op;
wire mem_op;
wire shift_op;
wire slt_op;
wire rd_alu_en;
wire rd_csr_en;
wire ctrl_rd;
wire alu_rd;
wire mem_rd;
wire csr_rd;
wire rd;
wire ctrl_pc_en;
wire jump;
wire jalr;
wire jal_or_jalr;
wire utype;
wire mret;
wire imm;
wire trap;
wire pc_rel;
wire init;
wire run;
wire cnt_en;
wire [4:0] cnt;
wire [3:0] cnt_r;
wire cnt_done;
wire bufreg_hold;
wire bufreg_rs1_en;
wire bufreg_imm_en;
wire bufreg_loop;
wire bufreg_q;
wire alu_sub;
wire [1:0] alu_bool_op;
wire alu_cmp_eq;
wire alu_cmp_uns;
wire alu_cmp;
wire alu_shamt_en;
wire alu_sh_signed;
wire alu_sh_right;
wire alu_sh_done;
wire [1:0] alu_rd_sel;
wire rf_rreq;
wire rf_wreq;
wire rf_ready;
wire rs1;
wire rs2;
wire rd_en;
wire op_b_source;
wire op_b;
wire mem_signed;
wire mem_word;
wire mem_half;
wire [1:0] mem_bytecnt;
wire mem_misalign;
wire bad_pc;
wire csr_mstatus_en;
wire csr_mie_en;
wire csr_mcause_en;
wire [1:0] csr_source;
wire csr_imm;
wire csr_d_sel;
wire csr_en;
wire [1:0] csr_addr;
wire csr_pc;
parameter RESET_PC = 32'd8;
wire new_irq;
wire [1:0] lsb;
wire [31:0] bufreg_out;
serv_state state
(
.i_clk (clk),
.i_rst (i_rst),
.i_new_irq (new_irq),
.i_dbus_ack (i_dbus_ack),
.i_ibus_ack (i_ibus_ack),
.o_rf_rreq (rf_rreq),
.o_rf_wreq (rf_wreq),
.i_rf_ready (rf_ready),
.i_take_branch (take_branch),
.i_branch_op (branch_op),
.i_mem_op (mem_op),
.i_shift_op (shift_op),
.i_slt_op (slt_op),
.i_e_op (e_op),
.i_rs1_addr (rs1_addr),
.o_init (init),
.o_run (run),
.o_cnt_en (cnt_en),
.o_cnt (cnt),
.o_cnt_r (cnt_r),
.o_cnt_done (cnt_done),
.o_bufreg_hold (bufreg_hold),
.o_ctrl_pc_en (ctrl_pc_en),
.o_ctrl_jump (jump),
.o_ctrl_trap (trap),
.i_ctrl_misalign(lsb[1]),
.o_alu_shamt_en (alu_shamt_en),
.i_alu_sh_done (alu_sh_done),
.o_dbus_cyc (o_dbus_cyc),
.o_mem_bytecnt (mem_bytecnt),
.i_mem_misalign (mem_misalign),
.o_csr_imm (csr_imm));
wire bufreg_clr_lsb;
serv_decode decode
(
.clk (clk),
//Input
.i_cnt_en (cnt_en),
.i_cnt_done (cnt_done),
.i_wb_rdt (i_ibus_rdt),
.i_wb_en (o_ibus_cyc & i_ibus_ack),
.i_alu_cmp (alu_cmp),
//To state
.o_take_branch (take_branch),
.o_e_op (e_op),
.o_ebreak (ebreak),
.o_branch_op (branch_op),
.o_mem_op (mem_op),
.o_shift_op (shift_op),
.o_slt_op (slt_op),
//To bufreg
.o_bufreg_loop (bufreg_loop),
.o_bufreg_rs1_en (bufreg_rs1_en),
.o_bufreg_imm_en (bufreg_imm_en),
.o_bufreg_clr_lsb (bufreg_clr_lsb),
//To ctrl
.o_ctrl_jalr (jalr),
.o_ctrl_jal_or_jalr (jal_or_jalr),
.o_ctrl_utype (utype),
.o_ctrl_pc_rel (pc_rel),
.o_ctrl_mret (mret),
//To alu
.o_alu_sub (alu_sub),
.o_alu_bool_op (alu_bool_op),
.o_alu_cmp_eq (alu_cmp_eq),
.o_alu_cmp_uns (alu_cmp_uns),
.o_alu_sh_signed (alu_sh_signed),
.o_alu_sh_right (alu_sh_right),
.o_alu_rd_sel (alu_rd_sel),
//To RF
.o_rf_rd_en (rd_en),
.o_rf_rd_addr (rd_addr),
.o_rf_rs1_addr (rs1_addr),
.o_rf_rs2_addr (rs2_addr),
//To mem IF
.o_mem_cmd (o_dbus_we),
.o_mem_signed (mem_signed),
.o_mem_word (mem_word),
.o_mem_half (mem_half),
//To CSR
.o_csr_en (csr_en),
.o_csr_addr (csr_addr),
.o_csr_mstatus_en (csr_mstatus_en),
.o_csr_mie_en (csr_mie_en),
.o_csr_mcause_en (csr_mcause_en),
.o_csr_source (csr_source),
.o_csr_d_sel (csr_d_sel),
//To top
.o_imm (imm),
.o_op_b_source (op_b_source),
.o_rd_csr_en (rd_csr_en),
.o_rd_alu_en (rd_alu_en));
assign o_dbus_adr = {bufreg_out[31:2], 2'b00};
serv_bufreg bufreg
(
.i_clk (clk),
.i_rst (i_rst),
.i_cnt (cnt[4:2]),
.i_cnt_r (cnt_r[1:0]),
.i_en (!bufreg_hold),
.i_init (init),
.i_loop (bufreg_loop),
.i_rs1 (rs1),
.i_rs1_en (bufreg_rs1_en),
.i_imm (imm),
.i_imm_en (bufreg_imm_en),
.i_clr_lsb (bufreg_clr_lsb),
.o_lsb (lsb),
.o_reg (bufreg_out),
.o_q (bufreg_q));
serv_ctrl
#(.RESET_PC (RESET_PC))
ctrl
(
.clk (clk),
.i_rst (i_rst),
//State
.i_pc_en (ctrl_pc_en),
.i_cnt (cnt[4:2]),
.i_cnt_r (cnt_r[2:1]),
.i_cnt_done (cnt_done),
//Control
.i_jump (jump),
.i_jal_or_jalr (jal_or_jalr),
.i_utype (utype),
.i_pc_rel (pc_rel),
.i_trap (trap | mret),
//Data
.i_imm (imm),
.i_buf (bufreg_q),
.i_csr_pc (csr_pc),
.o_rd (ctrl_rd),
.o_bad_pc (bad_pc),
//External
.o_ibus_adr (o_ibus_adr),
.o_ibus_cyc (o_ibus_cyc),
.i_ibus_ack (i_ibus_ack));
assign rd = (ctrl_rd ) |
(rd_alu_en & alu_rd ) |
(csr_rd & rd_csr_en) |
(mem_rd);
assign op_b = (op_b_source == OP_B_SOURCE_IMM) ? imm : rs2;
serv_alu alu
(
.clk (clk),
.i_rst (i_rst),
.i_en (cnt_en),
.i_rs1 (rs1),
.i_op_b (op_b),
.i_buf (bufreg_q),
.i_init (init),
.i_cnt_done (cnt_done),
.i_sub (alu_sub),
.i_bool_op (alu_bool_op),
.i_cmp_eq (alu_cmp_eq),
.i_cmp_uns (alu_cmp_uns),
.o_cmp (alu_cmp),
.i_shamt_en (alu_shamt_en),
.i_sh_right (alu_sh_right),
.i_sh_signed (alu_sh_signed),
.o_sh_done (alu_sh_done),
.i_rd_sel (alu_rd_sel),
.o_rd (alu_rd));
wire csr_in;
wire rf_csr_out;
serv_mpram regfile
(
.i_clk (clk),
.i_rst (i_rst),
.i_run (run),
//Trap interface
.i_trap (trap),
.i_mret (mret),
.i_mepc (o_ibus_adr[0]),
.i_mtval (mem_misalign ? bufreg_q : bad_pc),
.o_csr_pc (csr_pc),
//CSR write port
.i_csr_en (csr_en),
.i_csr_addr (csr_addr),
.i_csr (csr_in),
//RD write port
.i_rd_wen (rd_en & (|rd_addr)),
.i_rd_waddr (rd_addr),
.i_rd (rd),
.i_rreq (rf_rreq),
.i_wreq (rf_wreq),
.o_rgnt (rf_ready),
//RS1 read port
.i_rs1_raddr (rs1_addr),
.o_rs1 (rs1),
//RS2 read port
.i_rs2_raddr (rs2_addr),
.o_rs2 (rs2),
//CSR read port
.o_csr (rf_csr_out));
serv_mem_if mem_if
(
.i_clk (clk),
.i_rst (i_rst),
.i_en (cnt_en),
.i_init (init),
.i_mem_op (mem_op),
.i_signed (mem_signed),
.i_word (mem_word),
.i_half (mem_half),
.i_bytecnt (mem_bytecnt),
.i_rs2 (rs2),
.o_rd (mem_rd),
.i_lsb (lsb),
.o_misalign (mem_misalign),
//External interface
.o_wb_dat (o_dbus_dat),
.o_wb_sel (o_dbus_sel),
.i_wb_rdt (i_dbus_rdt),
.i_wb_ack (i_dbus_ack));
serv_csr csr
(
.i_clk (clk),
.i_run (run),
.i_cnt (cnt[4:2]),
.i_cnt_r (cnt_r[3:2]),
.i_e_op (e_op),
.i_ebreak (ebreak),
.i_mem_cmd (o_dbus_we),
.i_mem_misalign (mem_misalign),
.i_rf_csr_out (rf_csr_out),
.o_csr_in (csr_in),
.i_mtip (i_timer_irq),
.o_new_irq (new_irq),
.i_mstatus_en (csr_mstatus_en),
.i_mie_en (csr_mie_en ),
.i_mcause_en (csr_mcause_en ),
.i_csr_source (csr_source),
.i_trap (trap),
.i_d (csr_d_sel ? csr_imm : rs1),
.o_q (csr_rd));
`ifdef RISCV_FORMAL
reg [31:0] pc = RESET_PC;
wire rs_en = (branch_op|mem_op|shift_op|slt_op) ? init : ctrl_pc_en;
always @(posedge clk) begin
rvfi_valid <= cnt_done & ctrl_pc_en & !i_rst;
rvfi_order <= rvfi_order + {63'd0,rvfi_valid};
if (o_ibus_cyc & i_ibus_ack)
rvfi_insn <= i_ibus_rdt;
if (rd_en)
rvfi_rd_wdata <= {rd,rvfi_rd_wdata[31:1]};
if (cnt_done & ctrl_pc_en) begin
rvfi_pc_rdata <= pc;
if (!rd_en)
rvfi_rd_addr <= 5'd0;
if (!rd_en | !(|rd_addr))
rvfi_rd_wdata <= 32'd0;
end
rvfi_trap <= trap;
if (rvfi_valid) begin
rvfi_trap <= 1'b0;
pc <= rvfi_pc_wdata;
end
rvfi_halt <= 1'b0;
rvfi_intr <= 1'b0;
rvfi_mode <= 2'd3;
rvfi_ixl = 2'd1;
if (rf_ready) begin
rvfi_rs1_addr <= rs1_addr;
rvfi_rs2_addr <= rs2_addr;
rvfi_rd_addr <= rd_addr;
end
if (rs_en) begin
rvfi_rs1_rdata <= {rs1,rvfi_rs1_rdata[31:1]};
rvfi_rs2_rdata <= {rs2,rvfi_rs2_rdata[31:1]};
end
if (i_dbus_ack) begin
rvfi_mem_addr <= o_dbus_adr;
rvfi_mem_rmask <= o_dbus_we ? 4'b0000 : o_dbus_sel;
rvfi_mem_wmask <= o_dbus_we ? o_dbus_sel : 4'b0000;
rvfi_mem_rdata <= i_dbus_rdt;
rvfi_mem_wdata <= o_dbus_dat;
end
if (i_ibus_ack) begin
rvfi_mem_rmask <= 4'b0000;
rvfi_mem_wmask <= 4'b0000;
end
end
/* verilator lint_off COMBDLY */
always @(o_ibus_adr)
rvfi_pc_wdata <= o_ibus_adr;
/* verilator lint_on COMBDLY */
`endif
endmodule