1
0
mirror of https://github.com/olofk/serv.git synced 2026-01-13 23:25:57 +00:00
olofk.serv/rtl/serv_ctrl.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

105 lines
2.2 KiB
Verilog

`default_nettype none
module serv_ctrl
(
input wire clk,
input wire i_rst,
//State
input wire i_pc_en,
input wire [4:2] i_cnt,
input wire [2:1] i_cnt_r,
input wire i_cnt_done,
//Control
input wire i_jump,
input wire i_jal_or_jalr,
input wire i_utype,
input wire i_pc_rel,
input wire i_trap,
//Data
input wire i_imm,
input wire i_buf,
input wire i_csr_pc,
output wire o_rd,
output wire o_bad_pc,
//External
output wire [31:0] o_ibus_adr,
output wire o_ibus_cyc,
input wire i_ibus_ack);
parameter RESET_PC = 32'd8;
reg en_pc_r;
wire pc_plus_4;
wire pc_plus_offset;
wire pc_plus_offset_aligned;
wire plus_4;
wire pc;
wire new_pc;
wire offset_a;
wire offset_b;
assign plus_4 = i_cnt_r[2] & (i_cnt[4:2] == 3'd0);
assign o_ibus_adr[0] = pc;
assign o_bad_pc = pc_plus_offset_aligned;
ser_add ser_add_pc_plus_4
(
.clk (clk),
.rst (i_rst),
.a (pc),
.b (plus_4),
.clr (i_cnt_done),
.q (pc_plus_4),
.o_v ());
shift_reg
#(
.LEN (32),
.INIT (RESET_PC))
pc_reg
(
.clk (clk),
.i_rst (i_rst),
.i_en (i_pc_en),
.i_d (new_pc),
.o_q (pc),
.o_par (o_ibus_adr[31:1])
);
assign new_pc = i_trap ? (i_csr_pc & en_pc_r) : i_jump ? pc_plus_offset_aligned : pc_plus_4;
assign o_rd = (i_utype & pc_plus_offset_aligned) | (pc_plus_4 & i_jal_or_jalr);
assign offset_a = i_pc_rel & pc;
assign offset_b = i_utype ? (i_imm & (i_cnt[4] | (i_cnt[3:2] == 2'b11))): i_buf;
ser_add ser_add_pc_plus_offset
(
.clk (clk),
.rst (i_rst),
.a (offset_a),
.b (offset_b),
.clr (!i_pc_en),
.q (pc_plus_offset),
.o_v ());
assign pc_plus_offset_aligned = pc_plus_offset & en_pc_r;
assign o_ibus_cyc = en_pc_r & !i_pc_en;
always @(posedge clk) begin
if (i_pc_en)
en_pc_r <= 1'b1;
else if (o_ibus_cyc & i_ibus_ack)
en_pc_r <= 1'b0;
if (i_rst) begin
en_pc_r <= 1'b1;
end
end
endmodule