M-ext complaince tests passing

This commit is contained in:
zeeshanrafique23 2021-08-02 00:12:50 +05:00
parent 4106c8d4b2
commit d0d9c82229

View file

@ -1,6 +1,6 @@
`default_nettype none
/* Multiplication Division Unit */
/* Multiplication & Division Unit */
module mdu_top
#(
parameter WIDTH = 32
@ -14,89 +14,99 @@ module mdu_top
output wire o_mdu_ready,
output wire [WIDTH-1:0] o_mdu_rd
);
wire [31:0] rdata_a;
wire [31:0] rdata_b;
wire en_q;
reg done;
reg [63:0] result_64;
reg high;
assign rdata_a = i_mdu_rs1;
assign rdata_b = i_mdu_rs2;
assign en_q = i_mdu_valid;
wire valid = i_mdu_valid;
// START MUL //
reg [32:0] rdata_a;
reg [32:0] rdata_b;
reg [63:0] rd;
wire [31:0] mul_rd;
// Control Signals
reg mul_en;
reg mul_done;
wire mul_ready;
wire is_mul = !i_mdu_op[2];
wire unsign_mul = i_mdu_op[1];
wire sign_unsign_mul = i_mdu_op[0];
wire is_mulh = (|i_mdu_op) & is_mul;
always @(posedge i_clk) begin
if (i_rst) begin
done <= 1'b0;
result_64 <= 64'b0;
high <= 1'b0;
if (valid & is_mul) begin
mul_en <= valid;
if (unsign_mul) begin
/* verilator lint_off WIDTH */
rdata_a <= sign_unsign_mul ? $unsigned(i_mdu_rs1) : $signed({i_mdu_rs1[31],i_mdu_rs1}); //$signed(i_mdu_rs1);
rdata_b <= $unsigned(i_mdu_rs2);
end else begin
rdata_a <= $signed(i_mdu_rs1);
rdata_b <= $signed(i_mdu_rs2);
end
end else begin
done <= 1'b0;
result_64 <= 64'b0;
high <= 1'b0;
case (i_mdu_op)
3'b000: begin
if (en_q) begin // MUL
result_64 <= rdata_a * rdata_b;
done <= 1'b1;
end
end
3'b001: begin // MULH
if (en_q) begin
result_64 <= rdata_a * rdata_b;
high <= 1'b1;
done <= 1'b1;
end
end
3'b010: begin // MULHSU
if (en_q) begin
result_64 <= $signed(rdata_a) * $unsigned(rdata_b);
high <= 1'b1;
done <= 1'b1;
end
end
3'b011: begin // MULHU
if (en_q) begin
result_64 <= $unsigned(rdata_a) * $unsigned(rdata_b);
high <= 1'b1;
done <= 1'b1;
end
end
3'b100: begin // DIV
if (en_q) begin
result_64 <= {32'b0,$signed(rdata_a) / $signed(rdata_b)};
done <= 1'b1;
end
end
3'b101: begin // DIVU
if (en_q) begin
result_64 <= $unsigned(rdata_a) * $unsigned(rdata_b);
done <= 1'b1;
end
end
3'b110: begin // REM
if (en_q) begin
result_64 <= {32'b0,$signed(rdata_a) % $signed(rdata_b)};
done <= 1'b1;
end
end
3'b111: begin // REMU
if (en_q) begin
result_64 <= {32'b0,$unsigned(rdata_a) % $unsigned(rdata_b)};
done <= 1'b1;
end
end
default: begin
result_64 <= 64'b0;
end
endcase
mul_en <= 1'b0;
end
end
assign o_mdu_ready = i_mdu_valid & done;
assign o_mdu_rd = high ? result_64[63:32] : result_64[31:0];
always @(posedge i_clk) begin
if (!i_rst & is_mul & mul_en) begin
rd <= $signed(rdata_a)*$signed(rdata_b);
end
mul_done <= mul_en;
end
assign mul_ready = mul_done & valid;
assign mul_rd = is_mulh ? rd >> 32 : rd;
// DIV STARTS //
reg outsign;
reg [62:0] divisor;
reg [31:0] dividend;
reg [31:0] quotient;
reg [31:0] quotient_msk;
reg [31:0] div_rd;
reg div_ready;
reg running;
wire is_div = i_mdu_op[2] & (!i_mdu_op[1]);
wire is_rem = i_mdu_op[2] & i_mdu_op[1];
wire unsign_div_rem = i_mdu_op[0];
wire prep = valid & (is_div | is_rem) & !running & !div_ready;
always @(posedge i_clk) begin
if (i_rst)
running <= 1'b0;
else if (prep) begin
dividend <= (!unsign_div_rem & i_mdu_rs1[31]) ? -i_mdu_rs1 : i_mdu_rs1;
divisor <= ((!unsign_div_rem & i_mdu_rs2[31]) ? -i_mdu_rs2 : i_mdu_rs2) << 31;
outsign <= (!unsign_div_rem & is_div & (i_mdu_rs1[31] != i_mdu_rs2[31]) & (|i_mdu_rs2))
| (!unsign_div_rem & is_rem & i_mdu_rs1[31]);
quotient <= 32'b0;
quotient_msk <= 1 << 31;
running <= 1'b1;
div_ready <= 1'b0;
end else if (!quotient_msk && running) begin
running <= 1'b0;
div_ready <= 1'b1;
if (is_div) begin
div_rd <= outsign ? -quotient : quotient;
end else begin
div_rd <= outsign ? -dividend : dividend;
end
end else begin
div_ready <= 1'b0;
if (divisor <= dividend) begin
dividend <= dividend - divisor;
quotient <= quotient | quotient_msk;
end
divisor <= divisor >> 1;
quotient_msk <= quotient_msk >> 1;
end
end
assign o_mdu_ready = mul_ready | div_ready;
assign o_mdu_rd = is_mul ? mul_rd : div_rd;
endmodule
`default_nettype wire