目录
踩坑记录
1、忘记修改无目的寄存器的信号
assign inst_no_dest = inst_bne | inst_beq | inst_jr | inst_sw | inst_mult | inst_multu |
inst_div | inst_divu | inst_mthi | inst_mtlo;
assign dest = dst_is_r31 ? 5'd31 :
dst_is_rt ? rt :
inst_no_dest ? 5'd0 : rd;
2、拉入reset信号初始化寄存器HI、LO
3、不同阶段间的bus宽度调整
4、除数、被除数赋值赋反了(愚蠢错误)
5、除法器状态机第一阶段需要考虑signed信号
不止op_div,src_is_signed也要考虑。因为实际上在div信号到来时,有符号除法器和无符号除法器都会收到信号。不区分符号会导致complete信号和div64_result信号的混乱。
op_div & src_is_signed
op_div & ~src_is_signed
6、HI、LO在不同指令下应该存储高32位还是低32位搞错了
代码改动
mycpu.h
`define ALU_OP 18
`define DS_TO_ES_BUS_WD 144
ID state
// Chapter5
wire src2_is_0_imm;
wire src_is_signed;
// Chapter 5 added insts
/* increase begin*/
wire inst_add;
wire inst_addi;
wire inst_sub;
wire inst_slti;
wire inst_sltiu;
wire inst_andi;
wire inst_ori;
wire inst_xori;
wire inst_sllv;
wire inst_srlv;
wire inst_srav;
wire inst_mult;
wire inst_multu;
wire inst_div;
wire inst_divu;
wire inst_mfhi;
wire inst_mflo;
wire inst_mthi;
wire inst_mtlo;
/* increase end*/
assign inst_no_dest = inst_bne | inst_beq | inst_jr | inst_sw | inst_mult | inst_multu |
inst_div | inst_divu | inst_mthi | inst_mtlo;
// Chapter5 changed
assign ds_to_es_bus = {
src_is_signed,
src2_is_0_imm, //1:1
alu_op , //124+18:124 18
load_op , //123:123
src1_is_sa , //122:122
src1_is_pc , //121:121
src2_is_imm , //120:120
src2_is_8 , //119:119
gr_we , //118:118
mem_we , //117:117
dest , //116:112
imm , //111:96
rs_value , //95 :64
rt_value , //63 :32
ds_pc //31 :0
};
// Chapter5
/* increase begin*/
assign inst_add = op_d[6'h00] & func_d[6'h20] & sa_d[5'h00];
assign inst_addi = op_d[6'h08];
assign inst_sub = op_d[6'h00] & func_d[6'h22] & sa_d[5'h00];
assign inst_slti = op_d[6'h0a];
assign inst_sltiu = op_d[6'h0b];
assign inst_andi = op_d[6'h0c];
assign inst_ori = op_d[6'h0d];
assign inst_xori = op_d[6'h0e];
assign inst_sllv = op_d[6'h00] & func_d[6'h04] & sa_d[5'h00];
assign inst_srlv = op_d[6'h00] & func_d[6'h06] & sa_d[5'h00];
assign inst_srav = op_d[6'h00] & func_d[6'h07] & sa_d[5'h00];
assign inst_mult = op_d[6'h00] & func_d[6'h18] & rd_d[5'h00] & sa_d[5'h00];
assign inst_multu = op_d[6'h00] & func_d[6'h19] & rd_d[5'h00] & sa_d[5'h00];
assign inst_div = op_d[6'h00] & func_d[6'h1a] & rd_d[5'h00] & sa_d[5'h00];
assign inst_divu = op_d[6'h00] & func_d[6'h1b] & rd_d[5'h00] & sa_d[5'h00];
assign inst_mthi = op_d[6'h00] & func_d[6'h11] & rt_d[5'h00] & rd_d[5'h00] & sa_d[5'h00];
assign inst_mtlo = op_d[6'h00] & func_d[6'h13] & rt_d[5'h00] & rd_d[5'h00] & sa_d[5'h00];
assign inst_mfhi = op_d[6'h00] & func_d[6'h10] & rs_d[5'h00] & rt_d[5'h00] & sa_d[5'h00];
assign inst_mflo = op_d[6'h00] & func_d[6'h12] & rs_d[5'h00] & rt_d[5'h00] & sa_d[5'h00];
/* increase end*/
// Chapter5
/* change begin*/
assign alu_op[ 0] = inst_addu | inst_addiu | inst_lw | inst_sw | inst_jal | inst_add | inst_addi;
assign alu_op[ 1] = inst_subu | inst_sub;
assign alu_op[ 2] = inst_slt | inst_slti;
assign alu_op[ 3] = inst_sltu | inst_sltiu;
assign alu_op[ 4] = inst_and | inst_andi;
assign alu_op[ 5] = inst_nor;
assign alu_op[ 6] = inst_or | inst_ori;
assign alu_op[ 7] = inst_xor | inst_xori;
assign alu_op[ 8] = inst_sll | inst_sllv;
assign alu_op[ 9] = inst_srl | inst_srlv;
assign alu_op[10] = inst_sra | inst_srav;
assign alu_op[11] = inst_lui;
assign alu_op[12] = inst_mult | inst_multu;
assign alu_op[13] = inst_div | inst_divu;
assign alu_op[14] = inst_mthi;
assign alu_op[15] = inst_mtlo;
assign alu_op[16] = inst_mfhi;
assign alu_op[17] = inst_mflo;
/* change end*/
// Chapter5 changed
assign load_op = inst_lw;
assign src1_is_sa = inst_sll | inst_srl | inst_sra;
assign src1_is_pc = inst_jal;
assign src2_is_imm = inst_addiu | inst_lui | inst_lw | inst_sw | inst_addi | inst_slti | inst_sltiu;
assign src2_is_0_imm = inst_andi | inst_ori | inst_xori;
assign src2_is_8 = inst_jal;
assign res_from_mem = inst_lw;
assign dst_is_r31 = inst_jal;
assign dst_is_rt = inst_addiu | inst_lui | inst_lw | inst_addi | inst_slti | inst_sltiu | inst_andi | inst_ori | inst_xori;
assign gr_we = ~inst_sw & ~inst_beq & ~inst_bne & ~inst_jr;
assign mem_we = inst_sw;
// Chapter5 increase
assign src_is_signed = inst_mult | inst_div;
EXE state
reg [31:0] HI;
reg [31:0] LO;
assign {src_is_signed,
src2_is_0_imm,
es_alu_op , //124+18:124
es_load_op , //123:123
es_src1_is_sa , //122:122
es_src1_is_pc , //121:121
es_src2_is_imm , //120:120
es_src2_is_8 , //119:119
es_gr_we , //118:118
es_mem_we , //117:117
es_dest , //116:112
es_imm , //111:96
es_rs_value , //95 :64
es_rt_value , //63 :32
es_pc //31 :0
} = ds_to_es_bus_r;
// Chapter5 increase
wire [63:0] result64;
wire complete;
wire op_div;
wire op_mthi;
wire op_mtlo;
wire op_mfhi;
wire op_mflo;
assign op_div = es_alu_op[13];
assign op_mthi = es_alu_op[14];
assign op_mtlo = es_alu_op[15];
assign op_mfhi = es_alu_op[16];
assign op_mflo = es_alu_op[17];
// Chapter5 changed
assign es_ready_go = ~op_div | complete;
// Chapter5 increase
assign es_alu_src2 = es_src2_is_imm ? {{16{es_imm[15]}}, es_imm[15:0]} :
es_src2_is_8 ? 32'd8 :
src2_is_0_imm ? {16'b0, es_imm[15:0]} :
es_rt_value;
// Chapter5 increase
always @(posedge clk or negedge reset) begin
if (reset) begin
HI <= 32'b0;
LO <= 32'b0;
end else if (complete & op_div) begin
{LO, HI} <= result64;
end else if (complete) begin
// mul
{HI, LO} <= result64;
end else if (op_mthi) begin
HI <= es_rs_value;
end else if (op_mtlo) begin
LO <= es_rs_value;
end
end
// Chapter5 increase
assign es_result = op_mfhi ? HI :
op_mflo ? LO :
es_alu_result;
alu u_alu(
.alu_op (es_alu_op ),
.alu_src1 (es_alu_src1 ),
.alu_src2 (es_alu_src2 ),
.src_is_signed (src_is_signed ),
.clk (clk ),
.reset (reset ),
.result64 (result64 ),
.complete (complete ),
.alu_result (es_alu_result )
);
ALU
module alu(
input [`ALU_OP-1:0] alu_op,
input [31:0] alu_src1,
input [31:0] alu_src2,
input src_is_signed,
input clk,
input reset,
output [31:0] alu_result,
output [63:0] result64,
output complete
);
// Chapter5
wire op_mul; //乘除法操作
wire op_div;
// Chapter5
assign op_mul = alu_op[12];
assign op_div = alu_op[13];
wire [63:0] mul64_result;
wire [63:0] div64_result;
wire [63:0] u_div64_result;
wire [63:0] s_div64_result;
// Chapter5
// wire [63:0] unsigned_prod;
// wire [63:0] signed_prod;
wire [32:0] src1;
wire [32:0] src2;
// MUL result
// assign unsigned_prod = alu_src1 * alu_src2;
// assign signed_prod = $signed(alu_src1) * $signed(alu_src2);
// 33bits mul
assign src1 = src_is_signed ? {alu_src1[31], alu_src1} : {1'b0, alu_src1};
assign src2 = src_is_signed ? {alu_src2[31], alu_src2} : {1'b0, alu_src2};
assign mul64_result = $signed(src1) * $signed(src2);
// DIV result
wire complete_udiv;
wire complete_sdiv;
u_div uut_u_div (
.clk (clk ),
.reset (reset ),
.src1 (alu_src1 [31:0]),
.src2 (alu_src2 [31:0]),
.op_div (op_div ),
.src_is_signed (src_is_signed ),
.div64_result (u_div64_result [63:0]),
.complete (complete_udiv )
);
s_div uut_s_div (
.clk (clk ),
.reset (reset ),
.src1 (alu_src1 [31:0]),
.src2 (alu_src2 [31:0]),
.op_div (op_div ),
.src_is_signed (src_is_signed ),
.div64_result (s_div64_result [63:0]),
.complete (complete_sdiv )
);
assign div64_result = src_is_signed ? s_div64_result : u_div64_result;
assign result64 = op_mul == 1'b1 ? mul64_result :
op_div == 1'b1 ? div64_result :
64'bz;
assign complete = op_mul ? 1'b1 :
src_is_signed ? complete_sdiv :
complete_udiv;
除法器模块
有符号数除法
module s_div (
input clk,
input reset,
input [31:0] src1,
input [31:0] src2,
input op_div,
input src_is_signed,
output [63:0] div64_result,
// output [31:0] s,
// output [31:0] r,
output complete
);
// DIV result
reg s_axis_divisor_tvalid;
wire s_axis_divisor_tready;
wire [31:0] s_axis_divisor_tdata;
reg s_axis_dividend_tvalid;
wire s_axis_dividend_tready;
wire [31:0] s_axis_dividend_tdata;
wire m_axis_dout_tvalid;
wire [63:0] m_axis_dout_tdata;
s_mydiv s_mydiv (
.aclk(clk),
.s_axis_divisor_tvalid (s_axis_divisor_tvalid),
.s_axis_divisor_tready (s_axis_divisor_tready),
.s_axis_divisor_tdata (s_axis_divisor_tdata),
.s_axis_dividend_tvalid (s_axis_dividend_tvalid),
.s_axis_dividend_tready (s_axis_dividend_tready),
.s_axis_dividend_tdata (s_axis_dividend_tdata),
.m_axis_dout_tvalid (m_axis_dout_tvalid),
.m_axis_dout_tdata (m_axis_dout_tdata)
);
assign s_axis_divisor_tdata = src2;
assign s_axis_dividend_tdata = src1;
parameter free = 2'b00;
parameter load_data = 2'b01;
parameter begin_div = 2'b10;
// parameter end_div = 2'b11;
reg [1:0] st_cur ;
always @(posedge clk or negedge reset) begin
if (reset) begin
st_cur <= free;
s_axis_divisor_tvalid <= 1'b0;
s_axis_dividend_tvalid <= 1'b0;
end else if (op_div) begin
case (st_cur)
free:
case (op_div & src_is_signed)
1'b1: begin
st_cur <= load_data;
s_axis_divisor_tvalid <= 1'b1;
s_axis_dividend_tvalid <= 1'b1;
end
default: st_cur <= free;
endcase
load_data:
case (s_axis_divisor_tready & s_axis_dividend_tready)
1'b1: begin
st_cur <= begin_div;
s_axis_divisor_tvalid <= 1'b0;
s_axis_dividend_tvalid <= 1'b0;
end
default: st_cur <= load_data;
endcase
begin_div:
case (m_axis_dout_tvalid)
1'b1: begin
st_cur <= free;
end
default: st_cur <= begin_div;
endcase
// end_div: begin
// st_cur <= free;
// end
default: st_cur <= free;
endcase
end
end
assign complete = m_axis_dout_tvalid;
assign div64_result = m_axis_dout_tdata;
// assign div64_result = complete? m_axis_dout_tdata : 64'bz;
endmodule
无符号数除法
module u_div (
input clk,
input reset,
input [31:0] src1,
input [31:0] src2,
input op_div,
input src_is_signed,
output [63:0] div64_result,
output complete
);
// DIV result
reg us_axis_divisor_tvalid;
wire us_axis_divisor_tready;
wire [31:0] us_axis_divisor_tdata;
reg us_axis_dividend_tvalid;
wire us_axis_dividend_tready;
wire [31:0] us_axis_dividend_tdata;
wire um_axis_dout_tvalid;
wire [63:0] um_axis_dout_tdata;
u_mydiv u_mydiv (
.aclk(clk),
.s_axis_divisor_tvalid (us_axis_divisor_tvalid),
.s_axis_divisor_tready (us_axis_divisor_tready),
.s_axis_divisor_tdata (us_axis_divisor_tdata),
.s_axis_dividend_tvalid (us_axis_dividend_tvalid),
.s_axis_dividend_tready (us_axis_dividend_tready),
.s_axis_dividend_tdata (us_axis_dividend_tdata),
.m_axis_dout_tvalid (um_axis_dout_tvalid),
.m_axis_dout_tdata (um_axis_dout_tdata)
);
assign us_axis_divisor_tdata = src2;
assign us_axis_dividend_tdata = src1;
parameter free = 2'b00;
parameter load_data = 2'b01;
parameter begin_div = 2'b10;
// parameter end_div = 2'b11;
reg [1:0] st_cur ;
always @(posedge clk or negedge reset) begin
if (reset) begin
st_cur <= free;
us_axis_divisor_tvalid <= 1'b0;
us_axis_dividend_tvalid <= 1'b0;
end else if (op_div) begin
case (st_cur)
free:
case (op_div & ~src_is_signed)
1'b1: begin
st_cur <= load_data;
us_axis_divisor_tvalid <= 1'b1;
us_axis_dividend_tvalid <= 1'b1;
end
default: st_cur <= free;
endcase
load_data:
case (us_axis_divisor_tready & us_axis_dividend_tready)
1'b1: begin
st_cur <= begin_div;
us_axis_divisor_tvalid <= 1'b0;
us_axis_dividend_tvalid <= 1'b0;
end
default: st_cur <= load_data;
endcase
begin_div:
case (um_axis_dout_tvalid)
1'b1: begin
st_cur <= free;
end
default: st_cur <= begin_div;
endcase
// end_div: begin
// st_cur <= free;
// end
default: st_cur <= free;
endcase
end
end
assign complete = um_axis_dout_tvalid;
assign div64_result = um_axis_dout_tdata;
// assign div64_result = complete? um_axis_dout_tdata : 64'bz;
endmodule