1
0
mirror of https://github.com/olofk/serv.git synced 2026-01-13 15:17:25 +00:00
olofk.serv/rtl/serv_state.v
2019-09-15 23:25:10 +02:00

154 lines
3.6 KiB
Verilog

module serv_state
(
input wire i_clk,
input wire i_rst,
input wire i_new_irq,
input wire i_rf_ready,
input wire i_take_branch,
input wire i_branch_op,
input wire i_mem_op,
input wire i_shift_op,
input wire i_slt_op,
input wire i_mem_cmd,
input wire i_e_op,
input wire i_ebreak,
input wire [4:0] i_rs1_addr,
output wire o_init,
output wire o_run,
output wire o_cnt_en,
output reg [4:0] o_cnt,
output reg [3:0] o_cnt_r,
output wire o_ctrl_pc_en,
output reg o_ctrl_jump,
output wire o_ctrl_trap,
input wire i_ctrl_misalign,
output wire o_rf_rs_en,
output wire o_alu_shamt_en,
input wire i_alu_sh_done,
output wire o_dbus_cyc,
output wire [1:0] o_mem_bytecnt,
input wire i_mem_misalign,
output reg [3:0] o_csr_mcause,
output wire o_cnt_done,
output reg o_bufreg_hold,
output wire o_csr_imm);
localparam [1:0]
IDLE = 2'd0,
INIT = 2'd1,
RUN = 2'd2,
TRAP = 2'd3;
reg [1:0] state;
reg cnt_done;
wire cnt_en;
wire running;
assign o_cnt_done = cnt_done;
//Update PC in RUN or TRAP states
assign o_ctrl_pc_en = running | o_ctrl_trap;
assign o_csr_imm = (o_cnt < 5) ? i_rs1_addr[o_cnt[2:0]] : 1'b0;
assign o_alu_shamt_en = (o_cnt < 5) & (state == INIT);
assign o_mem_bytecnt = o_cnt[4:3];
assign cnt_en = (state != IDLE);
assign o_cnt_en = cnt_en;
assign o_init = (state == INIT);
assign running = (state == RUN);
assign o_run = running;
assign o_ctrl_trap = (state == TRAP);
//slt*, branch/jump, shift, load/store
wire two_stage_op = i_slt_op | i_mem_op | i_branch_op | i_shift_op;
wire mem_misalign = i_mem_op & i_mem_misalign;
always @(posedge i_clk) begin
o_csr_mcause[3:0] <= 4'd0;
if (mem_misalign)
o_csr_mcause[3:0] <= {2'b01, i_mem_cmd, 1'b0};
if (i_e_op)
o_csr_mcause <= {!i_ebreak,3'b011};
end
reg stage_one_done;
reg pending_irq;
assign o_rf_rs_en = two_stage_op ? (state == INIT) : o_ctrl_pc_en;
assign o_dbus_cyc = (state == IDLE) & stage_one_done & i_mem_op & !mem_misalign;
always @(posedge i_clk) begin
if (state == INIT)
o_ctrl_jump <= i_take_branch;
if (state == IDLE)
o_ctrl_jump <= 1'b0;
if (i_new_irq)
pending_irq <= 1'b1;
cnt_done <= (o_cnt[4:2] == 3'b111) & o_cnt_r[2];
o_bufreg_hold <= 1'b0;
case (state)
IDLE : begin
if (i_rf_ready) begin
state <= RUN;
if (two_stage_op & !stage_one_done)
state <= INIT;
if (i_e_op | pending_irq)
state <= TRAP;
end else if (i_alu_sh_done & i_shift_op & stage_one_done)
state <= RUN;
end
INIT : begin
stage_one_done <= 1'b1;
if (cnt_done)
if (mem_misalign | (i_take_branch & i_ctrl_misalign))
state <= TRAP;
else if (i_mem_op | i_shift_op ) begin
state <= IDLE;
o_bufreg_hold <= 1'b1;
end
else
state <= RUN;
end
RUN : begin
stage_one_done <= 1'b0;
if (cnt_done)
state <= IDLE;
end
TRAP : begin
pending_irq <= 1'b0;
if (cnt_done)
state <= IDLE;
end
default : state <= IDLE;
endcase
o_cnt <= o_cnt + {4'd0,cnt_en};
if (cnt_en)
o_cnt_r <= {o_cnt_r[2:0],o_cnt_r[3]};
if (i_rst) begin
state <= IDLE;
o_cnt <= 5'd0;
pending_irq <= 1'b0;
stage_one_done <= 1'b0;
o_ctrl_jump <= 1'b0;
o_cnt_r <= 4'b0001;
end
end
endmodule