mirror of
https://github.com/olofk/serv.git
synced 2025-04-22 12:57:09 -04:00
M-ext complaince tests passing
This commit is contained in:
parent
4106c8d4b2
commit
d0d9c82229
1 changed files with 87 additions and 77 deletions
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue