mirror of
https://github.com/olofk/serv.git
synced 2026-04-29 05:25:07 +00:00
Initial commit
This commit is contained in:
17
rtl/ser_add.v
Normal file
17
rtl/ser_add.v
Normal file
@@ -0,0 +1,17 @@
|
||||
module ser_add
|
||||
(
|
||||
input clk,
|
||||
input a,
|
||||
input b,
|
||||
input clear,
|
||||
output reg q = 1'b0);
|
||||
|
||||
reg carry = 1'b0;
|
||||
wire c = carry & ~clear;
|
||||
|
||||
always @(posedge clk) begin
|
||||
q <= a ^ b ^ c;
|
||||
carry <= a&b | a&c | b&c;
|
||||
end
|
||||
|
||||
endmodule
|
||||
69
rtl/serv_alu.v
Normal file
69
rtl/serv_alu.v
Normal file
@@ -0,0 +1,69 @@
|
||||
`default_nettype none
|
||||
module serv_alu
|
||||
(
|
||||
input clk,
|
||||
input i_d,
|
||||
input i_go,
|
||||
input i_funct3_valid,
|
||||
input i_rs1,
|
||||
output o_rs_en,
|
||||
output o_rd,
|
||||
output o_rd_valid);
|
||||
|
||||
localparam [2:0]
|
||||
ADDI = 3'b000,
|
||||
SLTI = 3'b010,
|
||||
SLTIU = 3'b011,
|
||||
XORI = 3'b100,
|
||||
ORI = 3'b110,
|
||||
ANDI = 3'b111;
|
||||
|
||||
wire [2:0] funct3;
|
||||
|
||||
shift_reg #(3) shift_reg_funct3
|
||||
(
|
||||
.clk (clk),
|
||||
.i_d (i_d),
|
||||
.i_en (i_funct3_valid),
|
||||
.o_q (funct3[0]),
|
||||
.o_par (funct3[2:1]));
|
||||
|
||||
wire op_b;
|
||||
wire result_add;
|
||||
|
||||
assign op_b = i_d; //FIXME mux for rs2
|
||||
|
||||
assign o_rs_en = running;
|
||||
|
||||
ser_add ser_add
|
||||
(
|
||||
.clk (clk),
|
||||
.a (i_rs1),
|
||||
.b (op_b),
|
||||
.clear (i_go),
|
||||
.q (result_add));
|
||||
|
||||
assign o_rd = (funct3 == ADDI) ? result_add : 1'b0;
|
||||
assign o_rd_valid = (cnt > 0);
|
||||
|
||||
reg [5:0] cnt = 6'd0;
|
||||
reg done;
|
||||
reg running = 1'd0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cnt <= 6'd0;
|
||||
done <= 1'b0;
|
||||
|
||||
if (i_go)
|
||||
running <= 1'b1;
|
||||
else if (cnt == 32) begin
|
||||
running <= 1'b0;
|
||||
done <= 1'b1;
|
||||
end
|
||||
|
||||
if (running) begin
|
||||
cnt <= cnt + 1;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
131
rtl/serv_ctrl.v
Normal file
131
rtl/serv_ctrl.v
Normal file
@@ -0,0 +1,131 @@
|
||||
`default_nettype none
|
||||
module serv_ctrl
|
||||
(
|
||||
input clk,
|
||||
input i_go,
|
||||
input i_instr,
|
||||
input i_jal,
|
||||
input i_reg11,
|
||||
input i_reg2012,
|
||||
output o_reg2012_en,
|
||||
output o_rd,
|
||||
output o_rd_valid,
|
||||
output [31:0] o_pc_data,
|
||||
output reg o_pc_valid = 1'b1,
|
||||
input i_pc_ready);
|
||||
|
||||
parameter RESET_PC = 32'd8;
|
||||
|
||||
localparam [2:0]
|
||||
NULL = 3'd0,
|
||||
INSTR = 3'd1,
|
||||
REG11 = 3'd2,
|
||||
REG2012 = 3'd3,
|
||||
SIGNBIT = 3'd4;
|
||||
|
||||
wire offset;
|
||||
|
||||
reg signbit = 1'd0;
|
||||
|
||||
reg [5:0] cnt = 5'd0;
|
||||
|
||||
reg new_pc_sel = 1'b0;
|
||||
wire pc_plus_4;
|
||||
wire pc_plus_offset;
|
||||
reg pc_plus_offset_clr = 1'b0;
|
||||
|
||||
wire plus_4;
|
||||
wire pc_plus_4_clr;
|
||||
reg running = 1'b0;
|
||||
|
||||
wire new_pc;
|
||||
|
||||
reg [2:0] offset_source;
|
||||
|
||||
assign pc_plus_4_clr = (cnt == 0);
|
||||
assign plus_4 = (cnt == 2);
|
||||
|
||||
ser_add ser_add_pc_plus_4
|
||||
(
|
||||
.clk (clk),
|
||||
.a (plus_4),
|
||||
.b (o_pc_data[0]),
|
||||
.clear (pc_plus_4_clr),
|
||||
.q (pc_plus_4));
|
||||
|
||||
shift_reg
|
||||
#(
|
||||
.LEN (32),
|
||||
.INIT (RESET_PC))
|
||||
pc_reg
|
||||
(
|
||||
.clk (clk),
|
||||
.i_en (running),
|
||||
.i_d (new_pc),
|
||||
.o_q (o_pc_data[0]),
|
||||
.o_par (o_pc_data[31:1])
|
||||
);
|
||||
|
||||
assign new_pc = new_pc_sel ? pc_plus_offset : pc_plus_4;
|
||||
|
||||
assign o_rd = pc_plus_4;
|
||||
assign o_rd_valid = running & i_jal;
|
||||
|
||||
always @(cnt, i_jal, running) begin
|
||||
offset_source = NULL;
|
||||
new_pc_sel = 1'b0;
|
||||
if (i_jal) begin
|
||||
new_pc_sel = 1'b1;
|
||||
if (cnt < 10)
|
||||
offset_source = INSTR;
|
||||
else if (cnt < 11)
|
||||
offset_source = REG11;
|
||||
else if (cnt < 20)
|
||||
offset_source = REG2012;
|
||||
else
|
||||
offset_source = SIGNBIT;
|
||||
end
|
||||
end
|
||||
|
||||
wire o_reg11_en = (offset_source == REG11);
|
||||
wire o_reg2012_en = (offset_source == REG2012);
|
||||
|
||||
assign offset = (offset_source == INSTR) ? i_instr :
|
||||
(offset_source == REG11) ? i_reg11 :
|
||||
(offset_source == REG2012) ? i_reg2012 :
|
||||
(offset_source == SIGNBIT) ? signbit :
|
||||
1'b0;
|
||||
|
||||
ser_add ser_add_pc_plus_offset
|
||||
(
|
||||
.clk (clk),
|
||||
.a (o_pc_data[0]), //FIXME Need a mux before this
|
||||
.b (offset),
|
||||
.clear (pc_plus_offset_clr),
|
||||
.q (pc_plus_offset));
|
||||
|
||||
reg done = 1'b0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cnt <= 6'd0;
|
||||
done <= 1'b0;
|
||||
|
||||
if (i_go)
|
||||
running <= 1'b1;
|
||||
else if (cnt == 32) begin
|
||||
running <= 1'b0;
|
||||
done <= 1'b1;
|
||||
end
|
||||
|
||||
if (running) begin
|
||||
cnt <= cnt + 1;
|
||||
end
|
||||
|
||||
if (done)
|
||||
o_pc_valid <= 1'b1;
|
||||
if (o_pc_valid & i_pc_ready)
|
||||
o_pc_valid <= 1'b0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
68
rtl/serv_decode.v
Normal file
68
rtl/serv_decode.v
Normal file
@@ -0,0 +1,68 @@
|
||||
module serv_decode
|
||||
(
|
||||
input clk,
|
||||
input i_go,
|
||||
input i_instr,
|
||||
output o_imm_31_12,
|
||||
output o_imm_11_0,
|
||||
output o_rd,
|
||||
output o_field_rs2,
|
||||
output o_field_rs1,
|
||||
output o_funct3,
|
||||
output o_funct7,
|
||||
output o_jal,
|
||||
output o_opimm,
|
||||
output o_alu_go,
|
||||
output o_ctrl_go);
|
||||
|
||||
localparam [4:0]
|
||||
OP_OPIMM = 5'b00100,
|
||||
OP_JAL = 5'b11011;
|
||||
|
||||
|
||||
reg [8:0] barrel [0:31];
|
||||
reg [4:0] cnt = 5'd0;
|
||||
reg running = 1'b0;
|
||||
|
||||
wire opcode_valid;
|
||||
wire halt;
|
||||
|
||||
|
||||
wire [8:0] cur = barrel[cnt];
|
||||
|
||||
assign o_imm_31_12 = cur[8];
|
||||
assign o_imm_11_0 = cur[7];
|
||||
assign o_rd = cur[6];
|
||||
assign o_field_rs2 = cur[5] & (1'b0);
|
||||
assign o_field_rs1 = cur[4] & (1'b0);
|
||||
assign o_funct3 = cur[3];
|
||||
assign o_funct7 = cur[2];
|
||||
assign opcode_valid = cur[1];
|
||||
assign halt = cur[0];
|
||||
|
||||
initial begin
|
||||
$readmemb("decode.mem", barrel);
|
||||
end
|
||||
|
||||
reg [4:0] opcode = 5'd0;
|
||||
|
||||
assign o_jal = (opcode == OP_JAL);
|
||||
assign o_ctrl_go = (cnt == 19);
|
||||
assign o_opimm = (opcode == OP_OPIMM);
|
||||
assign o_alu_go = o_opimm & (cnt == 19);
|
||||
|
||||
// shift_reg #(5) shift_reg_opcode
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (opcode_valid)
|
||||
opcode <= {opcode[3:0], i_instr};
|
||||
cnt <= cnt + (i_go | running);
|
||||
if (i_go)
|
||||
running <= 1'd1;
|
||||
else if (halt) begin
|
||||
running <= 1'd0;
|
||||
cnt <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
147
rtl/serv_regfile.v
Normal file
147
rtl/serv_regfile.v
Normal file
@@ -0,0 +1,147 @@
|
||||
`default_nettype none
|
||||
module serv_regfile
|
||||
(
|
||||
input clk,
|
||||
input i_d,
|
||||
input i_field_rs1,
|
||||
input i_field_rs2,
|
||||
input i_field_rd,
|
||||
input i_rs_en,
|
||||
output o_rs1,
|
||||
output o_rs2,
|
||||
input i_rd,
|
||||
input i_rd_valid);
|
||||
|
||||
reg [31:0] rf [0:31];
|
||||
|
||||
function automatic [31:0] xreg;
|
||||
input [4:0] regnum;
|
||||
begin
|
||||
xreg = {rf[31][regnum],rf[30][regnum],rf[29][regnum],rf[28][regnum],
|
||||
rf[27][regnum],rf[26][regnum],rf[25][regnum],rf[24][regnum],
|
||||
rf[23][regnum],rf[22][regnum],rf[21][regnum],rf[20][regnum],
|
||||
rf[19][regnum],rf[18][regnum],rf[17][regnum],rf[16][regnum],
|
||||
rf[15][regnum],rf[14][regnum],rf[13][regnum],rf[12][regnum],
|
||||
rf[11][regnum],rf[10][regnum],rf[9][regnum] ,rf[8][regnum],
|
||||
rf[7][regnum] ,rf[6][regnum] ,rf[5][regnum] ,rf[4][regnum],
|
||||
rf[3][regnum] ,rf[2][regnum] ,rf[1][regnum] ,rf[0][regnum]};
|
||||
end
|
||||
endfunction // xreg
|
||||
|
||||
always @(*)
|
||||
for (i=0;i<32;i=i+1) begin
|
||||
dbg_x1[i] = rf[i][1];
|
||||
dbg_x2[i] = rf[i][2];
|
||||
dbg_x3[i] = rf[i][3];
|
||||
dbg_x4[i] = rf[i][4];
|
||||
dbg_x5[i] = rf[i][5];
|
||||
dbg_x6[i] = rf[i][6];
|
||||
dbg_x7[i] = rf[i][7];
|
||||
dbg_x8[i] = rf[i][8];
|
||||
dbg_x9[i] = rf[i][9];
|
||||
dbg_x10[i] = rf[i][10];
|
||||
dbg_x11[i] = rf[i][11];
|
||||
dbg_x12[i] = rf[i][12];
|
||||
dbg_x13[i] = rf[i][13];
|
||||
dbg_x14[i] = rf[i][14];
|
||||
dbg_x15[i] = rf[i][15];
|
||||
dbg_x16[i] = rf[i][16];
|
||||
dbg_x17[i] = rf[i][17];
|
||||
dbg_x18[i] = rf[i][18];
|
||||
dbg_x19[i] = rf[i][19];
|
||||
dbg_x20[i] = rf[i][20];
|
||||
dbg_x21[i] = rf[i][21];
|
||||
dbg_x22[i] = rf[i][22];
|
||||
dbg_x23[i] = rf[i][23];
|
||||
dbg_x24[i] = rf[i][24];
|
||||
dbg_x25[i] = rf[i][25];
|
||||
dbg_x26[i] = rf[i][26];
|
||||
dbg_x27[i] = rf[i][27];
|
||||
dbg_x28[i] = rf[i][28];
|
||||
dbg_x29[i] = rf[i][29];
|
||||
dbg_x30[i] = rf[i][30];
|
||||
dbg_x31[i] = rf[i][31];
|
||||
end
|
||||
|
||||
reg [31:0] dbg_x0 ;
|
||||
reg [31:0] dbg_x1 ;
|
||||
reg [31:0] dbg_x2 ;
|
||||
reg [31:0] dbg_x3 ;
|
||||
reg [31:0] dbg_x4 ;
|
||||
reg [31:0] dbg_x5 ;
|
||||
reg [31:0] dbg_x6 ;
|
||||
reg [31:0] dbg_x7 ;
|
||||
reg [31:0] dbg_x8 ;
|
||||
reg [31:0] dbg_x9 ;
|
||||
reg [31:0] dbg_x10;
|
||||
reg [31:0] dbg_x11;
|
||||
reg [31:0] dbg_x12;
|
||||
reg [31:0] dbg_x13;
|
||||
reg [31:0] dbg_x14;
|
||||
reg [31:0] dbg_x15;
|
||||
reg [31:0] dbg_x16;
|
||||
reg [31:0] dbg_x17;
|
||||
reg [31:0] dbg_x18;
|
||||
reg [31:0] dbg_x19;
|
||||
reg [31:0] dbg_x20;
|
||||
reg [31:0] dbg_x21;
|
||||
reg [31:0] dbg_x22;
|
||||
reg [31:0] dbg_x23;
|
||||
reg [31:0] dbg_x24;
|
||||
reg [31:0] dbg_x25;
|
||||
reg [31:0] dbg_x26;
|
||||
reg [31:0] dbg_x27;
|
||||
reg [31:0] dbg_x28;
|
||||
reg [31:0] dbg_x29;
|
||||
reg [31:0] dbg_x30;
|
||||
reg [31:0] dbg_x31;
|
||||
|
||||
|
||||
|
||||
reg [4:0] raddr = 5'd0;
|
||||
reg [4:0] waddr = 5'd0;
|
||||
reg [31:0] rs = 32'd0;
|
||||
|
||||
integer i;
|
||||
initial for (i=0; i<32; i=i+1) rf[i] = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (i_rd_valid) begin
|
||||
waddr <= waddr + 1;
|
||||
rf[waddr][rd_addr] <= i_rd;
|
||||
end
|
||||
|
||||
if (i_rs_en)
|
||||
rs <= rf[raddr];
|
||||
|
||||
end
|
||||
|
||||
wire [4:0] rs1_addr;
|
||||
wire [4:0] rs2_addr;
|
||||
wire [4:0] rd_addr;
|
||||
|
||||
shift_reg #(5) shift_reg_rs1_addr
|
||||
(.clk (clk),
|
||||
.i_en (i_field_rs1),
|
||||
.i_d (i_d),
|
||||
.o_q (rs1_addr[0]),
|
||||
.o_par (rs1_addr[4:1]));
|
||||
|
||||
shift_reg #(5) shift_reg_rs2_addr
|
||||
(.clk (clk),
|
||||
.i_en (i_field_rs2),
|
||||
.i_d (i_d),
|
||||
.o_q (rs2_addr[0]),
|
||||
.o_par (rs2_addr[4:1]));
|
||||
|
||||
shift_reg #(5) shift_reg_rd_addr
|
||||
(.clk (clk),
|
||||
.i_en (i_field_rd),
|
||||
.i_d (i_d),
|
||||
.o_q (rd_addr[0]),
|
||||
.o_par (rd_addr[4:1]));
|
||||
|
||||
assign o_rs1 = (|rs1_addr) ? rs[rs1_addr] : 1'b0;
|
||||
assign o_rs2 = (|rs2_addr) ? rs[rs2_addr] : 1'b0;
|
||||
|
||||
endmodule
|
||||
126
rtl/serv_top.v
Normal file
126
rtl/serv_top.v
Normal file
@@ -0,0 +1,126 @@
|
||||
`default_nettype none
|
||||
module serv_top
|
||||
(
|
||||
input clk,
|
||||
input [31:0] i_i_data,
|
||||
input i_i_valid,
|
||||
output reg o_i_ready = 1'b1,
|
||||
output [31:0] o_pc_data,
|
||||
output o_pc_valid,
|
||||
input i_pc_ready);
|
||||
|
||||
reg [31:0] cur_instr = 32'd0;
|
||||
reg instr;
|
||||
wire imm_31_12;
|
||||
wire imm_11_0;
|
||||
wire field_rd;
|
||||
wire field_rs1;
|
||||
wire field_rs2;
|
||||
wire funct3;
|
||||
wire funct7;
|
||||
reg decode_go = 1'b0;
|
||||
wire ctrl_go;
|
||||
wire alu_go;
|
||||
wire rs_en;
|
||||
wire rs1;
|
||||
wire rs2;
|
||||
wire rd;
|
||||
|
||||
wire ctrl_rd;
|
||||
wire ctrl_rd_valid;
|
||||
|
||||
wire alu_rd;
|
||||
wire alu_rd_valid;
|
||||
|
||||
wire funct3_valid;
|
||||
|
||||
wire jal;
|
||||
wire opimm;
|
||||
|
||||
serv_decode decode
|
||||
(
|
||||
.clk (clk),
|
||||
.i_instr (cur_instr[0]),
|
||||
.i_go (decode_go),
|
||||
.o_funct7 (funct7),
|
||||
.o_funct3 (funct3_valid),
|
||||
.o_field_rs1 (field_rs1),
|
||||
.o_field_rs2 (field_rs2),
|
||||
.o_rd (field_rd),
|
||||
.o_imm_11_0 (imm_11_0),
|
||||
.o_imm_31_12 (imm_31_12),
|
||||
.o_jal (jal),
|
||||
.o_opimm (opimm),
|
||||
.o_alu_go (alu_go),
|
||||
.o_ctrl_go (ctrl_go));
|
||||
|
||||
wire reg_2012_en_decode;
|
||||
wire reg_2012_en_ctrl;
|
||||
wire reg_2012_data;
|
||||
|
||||
wire reg_2012_en = reg_2012_en_decode | reg_2012_en_ctrl;
|
||||
|
||||
shift_reg
|
||||
#(
|
||||
.LEN (9))
|
||||
reg_2012
|
||||
(
|
||||
.clk (clk),
|
||||
.i_en (reg_2012_en),
|
||||
.i_d (cur_instr[0]),
|
||||
.o_q (reg_2012_data));
|
||||
|
||||
serv_alu alu
|
||||
(
|
||||
.clk (clk),
|
||||
.i_go (alu_go),
|
||||
.i_d (cur_instr[0]),
|
||||
.i_funct3_valid (funct3_valid),
|
||||
.i_rs1 (rs1),
|
||||
.o_rs_en (rs_en),
|
||||
.o_rd (alu_rd),
|
||||
.o_rd_valid (alu_rd_valid));
|
||||
|
||||
serv_ctrl ctrl
|
||||
(
|
||||
.clk (clk),
|
||||
.i_go (ctrl_go),
|
||||
.i_instr (cur_instr[0]),
|
||||
.i_jal (jal),
|
||||
.i_reg11 (1'b0), //FIXME
|
||||
.i_reg2012 (reg_2012_data),
|
||||
.o_reg2012_en (reg_2012_en_ctrl),
|
||||
.o_rd (ctrl_rd),
|
||||
.o_rd_valid (ctrl_rd_valid),
|
||||
.o_pc_data (o_pc_data),
|
||||
.o_pc_valid (o_pc_valid),
|
||||
.i_pc_ready (i_pc_ready));
|
||||
|
||||
serv_regfile regfile
|
||||
(
|
||||
.clk (clk),
|
||||
.i_d (cur_instr[0]),
|
||||
.i_field_rs1 (field_rs1),
|
||||
.i_field_rs2 (field_rs2),
|
||||
.i_field_rd (field_rd),
|
||||
.i_rs_en (rs_en),
|
||||
.o_rs1 (rs1),
|
||||
.o_rs2 (rs2),
|
||||
.i_rd ((ctrl_rd & ctrl_rd_valid) | (alu_rd & alu_rd_valid)),
|
||||
.i_rd_valid (ctrl_rd_valid | alu_rd_valid));
|
||||
|
||||
always @(posedge clk) begin
|
||||
decode_go <= 1'b0;
|
||||
cur_instr <= {1'b0, cur_instr[31:1]};
|
||||
|
||||
if (o_pc_valid)
|
||||
o_i_ready <= 1'b1;
|
||||
|
||||
if (i_i_valid & o_i_ready) begin
|
||||
cur_instr <= i_i_data;
|
||||
o_i_ready <= 1'b0;
|
||||
decode_go <= 1'b1;
|
||||
end
|
||||
end // always @ (posedge clk)
|
||||
|
||||
endmodule
|
||||
18
rtl/shift_reg.v
Normal file
18
rtl/shift_reg.v
Normal file
@@ -0,0 +1,18 @@
|
||||
module shift_reg
|
||||
(
|
||||
input clk,
|
||||
input i_en,
|
||||
input i_d,
|
||||
output o_q,
|
||||
output [LEN-2:0] o_par);
|
||||
|
||||
parameter LEN = 0;
|
||||
parameter INIT = 0;
|
||||
|
||||
reg [LEN-1:0] data = INIT;
|
||||
assign o_q = data[0];
|
||||
assign o_par = data[LEN-1:1];
|
||||
always @(posedge clk)
|
||||
if (i_en)
|
||||
data <= {i_d, data[LEN-1:1]};
|
||||
endmodule
|
||||
Reference in New Issue
Block a user