mirror of
https://github.com/olofk/serv.git
synced 2026-01-13 23:25:57 +00:00
258 lines
8.3 KiB
Verilog
258 lines
8.3 KiB
Verilog
module serv_decode
|
|
(
|
|
input clk,
|
|
input [31:0] i_i_rd_dat,
|
|
input i_i_rd_vld,
|
|
output reg o_i_rd_rdy = 1'b1,
|
|
output o_ctrl_en,
|
|
output o_ctrl_jump,
|
|
output o_ctrl_jalr,
|
|
output o_ctrl_auipc,
|
|
output o_rf_rd_en,
|
|
output [4:0] o_rf_rd_addr,
|
|
output o_rf_rs_en,
|
|
output [4:0] o_rf_rs1_addr,
|
|
output [4:0] o_rf_rs2_addr,
|
|
output o_alu_en,
|
|
output o_alu_init,
|
|
output o_alu_sub,
|
|
output reg o_alu_cmp_sel,
|
|
output o_alu_cmp_neg,
|
|
output reg o_alu_cmp_uns,
|
|
input i_alu_cmp,
|
|
output o_alu_shamt_en,
|
|
output o_alu_sh_signed,
|
|
output o_alu_sh_right,
|
|
output reg [2:0] o_alu_rd_sel,
|
|
output o_mem_en,
|
|
output o_mem_cmd,
|
|
output o_mem_init,
|
|
output reg o_mem_dat_valid,
|
|
input i_mem_busy,
|
|
output [2:0] o_funct3,
|
|
output reg o_imm,
|
|
output o_offset_source,
|
|
output o_op_b_source,
|
|
output [1:0] o_rd_source);
|
|
|
|
`include "serv_params.vh"
|
|
|
|
localparam [2:0]
|
|
IDLE = 3'd0,
|
|
COMPARE = 3'd1,
|
|
SH_INIT = 3'd2,
|
|
MEM_INIT = 3'd3,
|
|
MEM_WAIT = 3'd4,
|
|
RUN = 3'd5;
|
|
|
|
localparam [4:0]
|
|
OP_LOAD = 5'b00000,
|
|
OP_STORE = 5'b01000,
|
|
OP_OPIMM = 5'b00100,
|
|
OP_AUIPC = 5'b00101,
|
|
OP_OP = 5'b01100,
|
|
OP_LUI = 5'b01101,
|
|
OP_BRANCH = 5'b11000,
|
|
OP_JALR = 5'b11001,
|
|
OP_JAL = 5'b11011;
|
|
|
|
reg [2:0] state = 3'd0;
|
|
|
|
reg [4:0] cnt = 5'd0;
|
|
|
|
wire running;
|
|
wire mem_op;
|
|
wire shift_op;
|
|
|
|
assign mem_op = (opcode == OP_LOAD) | (opcode == OP_STORE);
|
|
assign shift_op = ((opcode == OP_OPIMM) & (o_funct3[1:0] == 2'b01)) |
|
|
((opcode == OP_OP ) & (o_funct3[1:0] == 2'b01));
|
|
|
|
assign o_ctrl_en = running;
|
|
assign o_ctrl_jump = (opcode == OP_JAL) |
|
|
(opcode == OP_JALR) |
|
|
((opcode == OP_BRANCH) & i_alu_cmp);
|
|
|
|
assign o_ctrl_jalr = (opcode == OP_JALR);
|
|
|
|
assign o_ctrl_auipc = (opcode == OP_AUIPC);
|
|
|
|
assign o_rf_rd_en = running &
|
|
(opcode != OP_STORE) &
|
|
(opcode != OP_BRANCH);
|
|
|
|
assign o_rf_rs_en = cnt_en /*(running & (opcode == OP_OPIMM)) |
|
|
(state == SH_INIT) |
|
|
(state == MEM_INIT)*/;
|
|
//FIXME: Change for addi?
|
|
|
|
assign o_alu_en = cnt_en;
|
|
|
|
assign o_alu_init = (state == COMPARE) |
|
|
(state == SH_INIT);
|
|
|
|
assign o_alu_sub = (opcode == OP_OP) ? i_i_rd_dat[30] /* ? 1'b1*/ :
|
|
((opcode == OP_BRANCH) & (o_funct3 == 3'b100)) ? 1'b1 :
|
|
((opcode == OP_BRANCH) & (o_funct3 == 3'b101)) ? 1'b1 :
|
|
((opcode == OP_BRANCH) & (o_funct3 == 3'b110)) ? 1'b1 :
|
|
((opcode == OP_OPIMM) & (o_funct3 == 3'b000)) ? 1'b0 :
|
|
1'bx;
|
|
|
|
|
|
assign o_alu_cmp_neg = (opcode == OP_BRANCH) & o_funct3[0];
|
|
always @(o_funct3) begin
|
|
casez (o_funct3)
|
|
3'b00? : o_alu_cmp_sel = ALU_CMP_EQ;
|
|
3'b01? : o_alu_cmp_sel = ALU_CMP_LT;
|
|
3'b1?? : o_alu_cmp_sel = ALU_CMP_LT;
|
|
default : o_alu_cmp_sel = 1'bx;
|
|
endcase
|
|
|
|
casez (o_funct3)
|
|
3'b00? : o_alu_cmp_uns = 1'b0;
|
|
3'b010 : o_alu_cmp_uns = 1'b0;
|
|
3'b011 : o_alu_cmp_uns = 1'b1;
|
|
3'b10? : o_alu_cmp_uns = 1'b0;
|
|
3'b11? : o_alu_cmp_uns = 1'b1;
|
|
default : o_alu_cmp_uns = 1'bx;
|
|
endcase
|
|
|
|
casez(o_funct3)
|
|
3'b000 : o_alu_rd_sel = ALU_RESULT_ADD;
|
|
3'b001 : o_alu_rd_sel = ALU_RESULT_SR;
|
|
3'b01? : o_alu_rd_sel = ALU_RESULT_LT;
|
|
3'b100 : o_alu_rd_sel = ALU_RESULT_XOR;
|
|
3'b101 : o_alu_rd_sel = ALU_RESULT_SR;
|
|
3'b110 : o_alu_rd_sel = ALU_RESULT_OR;
|
|
3'b111 : o_alu_rd_sel = ALU_RESULT_AND;
|
|
default : o_alu_rd_sel = 3'bxx;
|
|
endcase
|
|
end
|
|
assign o_alu_shamt_en = (state == SH_INIT) & (cnt < 5);
|
|
assign o_alu_sh_signed = i_i_rd_dat[30];
|
|
assign o_alu_sh_right = o_funct3[2];
|
|
|
|
assign o_mem_en = mem_op & cnt_en;
|
|
assign o_mem_cmd = (opcode == OP_STORE);
|
|
|
|
assign o_mem_init = (state == MEM_INIT);
|
|
|
|
assign o_rf_rd_addr = i_i_rd_dat[11:7];
|
|
assign o_funct3 = i_i_rd_dat[14:12];
|
|
assign o_rf_rs1_addr = i_i_rd_dat[19:15];
|
|
assign o_rf_rs2_addr = i_i_rd_dat[24:20];
|
|
assign o_offset_source = (opcode == OP_JAL) ? OFFSET_SOURCE_IMM :
|
|
(opcode == OP_AUIPC) ? OFFSET_SOURCE_IMM :
|
|
(opcode == OP_BRANCH) ? OFFSET_SOURCE_IMM :
|
|
(opcode == OP_JALR) ? OFFSET_SOURCE_IMM :
|
|
1'bx;
|
|
|
|
assign o_op_b_source = (opcode == OP_OPIMM) ? OP_B_SOURCE_IMM :
|
|
(opcode == OP_BRANCH) ? OP_B_SOURCE_RS2 :
|
|
(opcode == OP_OP) ? OP_B_SOURCE_RS2 :
|
|
1'bx;
|
|
|
|
always @(o_funct3, cnt)
|
|
if (o_mem_init)
|
|
o_mem_dat_valid = 1'bx;
|
|
else
|
|
casez(o_funct3[1:0])
|
|
2'b00 : o_mem_dat_valid = (cnt < 8);
|
|
2'b01 : o_mem_dat_valid = (cnt < 16);
|
|
2'b10 : o_mem_dat_valid = 1'b1;
|
|
default: o_mem_dat_valid = 1'bx;
|
|
endcase
|
|
|
|
wire [4:0] opcode = i_i_rd_dat[6:2];
|
|
|
|
|
|
assign o_rd_source = (opcode == OP_JAL) ? RD_SOURCE_CTRL :
|
|
(opcode == OP_OPIMM) ? RD_SOURCE_ALU :
|
|
(opcode == OP_OP) ? RD_SOURCE_ALU :
|
|
(opcode == OP_LUI) ? RD_SOURCE_IMM :
|
|
(opcode == OP_AUIPC) ? RD_SOURCE_CTRL :
|
|
(opcode == OP_JALR) ? RD_SOURCE_CTRL :
|
|
(opcode == OP_LOAD) ? RD_SOURCE_MEM : 2'bxx;
|
|
|
|
always @(cnt, opcode, i_i_rd_dat) begin
|
|
o_imm = 1'bx;
|
|
if (opcode == OP_JAL)
|
|
if (cnt > 19) o_imm = i_i_rd_dat[31];
|
|
else if (cnt > 11) o_imm = i_i_rd_dat[cnt];
|
|
else if (cnt > 10) o_imm = i_i_rd_dat[20];
|
|
else if (cnt > 0) o_imm = i_i_rd_dat[cnt+20];
|
|
else o_imm = 1'b0;
|
|
else if ((opcode == OP_OPIMM) | (opcode == OP_JALR))
|
|
if (cnt > 10) o_imm = i_i_rd_dat[31];
|
|
else o_imm = i_i_rd_dat[cnt+20];
|
|
else if ((opcode == OP_LUI) | (opcode == OP_AUIPC))
|
|
if (cnt > 11) o_imm = i_i_rd_dat[cnt];
|
|
else o_imm = 1'b0;
|
|
else if (opcode == OP_LOAD)
|
|
if (cnt > 10) o_imm = i_i_rd_dat[31];
|
|
else o_imm = i_i_rd_dat[cnt+20];
|
|
else if (opcode == OP_BRANCH)
|
|
if (cnt > 11) o_imm = i_i_rd_dat[31];
|
|
else if (cnt > 10) o_imm = i_i_rd_dat[7];
|
|
else if (cnt > 4) o_imm = i_i_rd_dat[cnt+20];
|
|
else if (cnt > 0) o_imm = i_i_rd_dat[cnt+7];
|
|
else o_imm = 1'b0;
|
|
else if (opcode == OP_STORE)
|
|
if (cnt > 10) o_imm = i_i_rd_dat[31];
|
|
else if (cnt > 4) o_imm = i_i_rd_dat[cnt+20];
|
|
else o_imm = i_i_rd_dat[cnt+7];
|
|
end
|
|
|
|
wire go = i_i_rd_vld & o_i_rd_rdy;
|
|
|
|
wire cnt_en =
|
|
(state == RUN) |
|
|
(state == COMPARE) |
|
|
(state == SH_INIT) |
|
|
(state == MEM_INIT);
|
|
|
|
wire cnt_done = cnt == 31;
|
|
assign running = (state == RUN);
|
|
|
|
always @(posedge clk) begin
|
|
state <= state;
|
|
case (state)
|
|
IDLE : begin
|
|
if (go)
|
|
state <= (opcode == OP_BRANCH) ? COMPARE :
|
|
(((opcode == OP_OPIMM) | (opcode == OP_OP))& (o_funct3[2:1] == 2'b01)) ? COMPARE :
|
|
mem_op ? MEM_INIT :
|
|
shift_op ? SH_INIT : RUN;
|
|
end
|
|
SH_INIT : begin
|
|
if (cnt_done)
|
|
state <= RUN;
|
|
end
|
|
COMPARE : begin
|
|
if (cnt_done)
|
|
state <= RUN;
|
|
end
|
|
MEM_INIT :
|
|
if (cnt_done)
|
|
state <= MEM_WAIT;
|
|
MEM_WAIT :
|
|
if (!i_mem_busy)
|
|
state <= RUN;
|
|
RUN : begin
|
|
if (cnt_done)
|
|
state <= IDLE;
|
|
end
|
|
default : state <= 3'bxxx;
|
|
endcase
|
|
|
|
cnt <= cnt + {4'd0,cnt_en};
|
|
|
|
if (go) begin
|
|
o_i_rd_rdy <= 1'b0;
|
|
end else if (cnt_done & (state == RUN)) begin
|
|
o_i_rd_rdy <= 1'b1;
|
|
end
|
|
end
|
|
|
|
endmodule
|