mirror of
https://github.com/olofk/serv.git
synced 2026-01-13 23:25:57 +00:00
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
105 lines
2.2 KiB
Verilog
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
|