more Verilog
This commit is contained in:
parent
bd0d1e70a9
commit
3fd3b2cd64
|
@ -0,0 +1,601 @@
|
|||
`define RNE 0
|
||||
`define RNA 1
|
||||
`define RTP 2
|
||||
`define RTN 3
|
||||
`define RTZ 4
|
||||
|
||||
// Normalises a denormal number or deal with catastrophic cancelation
|
||||
|
||||
module normaliseUp(
|
||||
input [9:0] uf_exponent_in,
|
||||
input [23:0] uf_significand_in,
|
||||
output reg [9:0] uf_exponent,
|
||||
output reg [23:0] uf_significand);
|
||||
|
||||
reg [5:0] shift;
|
||||
|
||||
always @(*) begin
|
||||
shift = 0;
|
||||
|
||||
uf_exponent = uf_exponent_in;
|
||||
uf_significand = uf_significand_in;
|
||||
|
||||
`ifdef 0
|
||||
if ((0xFFFF00 & uf->significand) == 0) {
|
||||
uf->significand <<= 16;
|
||||
shift += 16;
|
||||
}
|
||||
if ((0xFF0000 & uf->significand) == 0) {
|
||||
uf->significand <<= 8;
|
||||
shift += 8;
|
||||
}
|
||||
if ((0xF00000 & uf->significand) == 0) {
|
||||
uf->significand <<= 4;
|
||||
shift += 4;
|
||||
}
|
||||
if ((0xC00000 & uf->significand) == 0) {
|
||||
uf->significand <<= 2;
|
||||
shift += 2;
|
||||
}
|
||||
if ((0x800000 & uf->significand) == 0) {
|
||||
uf->significand <<= 1;
|
||||
shift += 1;
|
||||
}
|
||||
|
||||
uf_exponent -= shift;
|
||||
`endif
|
||||
end // always
|
||||
|
||||
endmodule
|
||||
|
||||
`define BIAS 127
|
||||
|
||||
module unpack(
|
||||
input [31:0] f,
|
||||
output reg uf_nan, uf_inf, uf_zero, uf_subnormal, uf_sign,
|
||||
output reg [9:0] uf_exponent,
|
||||
output reg [23:0] uf_significand);
|
||||
|
||||
wire sign;
|
||||
wire [7:0] exponent;
|
||||
wire [22:0] significand;
|
||||
|
||||
// split up f
|
||||
assign { sign, exponent, significand } = f;
|
||||
|
||||
always @(*) begin
|
||||
uf_sign = sign;
|
||||
|
||||
if (exponent == 0) begin
|
||||
if (significand == 0) begin
|
||||
//makeZero(&uf);
|
||||
end
|
||||
|
||||
else begin
|
||||
uf_nan = 0;
|
||||
uf_inf = 0;
|
||||
uf_zero = 0;
|
||||
uf_subnormal = 1;
|
||||
|
||||
uf_exponent = -126;
|
||||
uf_significand = significand;
|
||||
|
||||
//normaliseUp(&uf);
|
||||
end
|
||||
end
|
||||
|
||||
else if (exponent == 'hff) begin
|
||||
if (significand == 0) begin
|
||||
//makeInf(&uf);
|
||||
end
|
||||
else begin
|
||||
//makeNaN(&uf);
|
||||
end
|
||||
end
|
||||
|
||||
else begin
|
||||
// Normal
|
||||
|
||||
uf_nan = 0;
|
||||
uf_inf = 0;
|
||||
uf_zero = 0;
|
||||
uf_subnormal = 0;
|
||||
|
||||
uf_exponent = exponent - `BIAS;
|
||||
uf_significand = 'h800000 | significand;
|
||||
end
|
||||
end // always
|
||||
endmodule
|
||||
|
||||
module pack(
|
||||
input uf_nan, uf_inf, uf_zero, uf_subnormal, uf_sign,
|
||||
input [9:0] uf_exponent,
|
||||
input [23:0] uf_significand,
|
||||
output [31:0] f);
|
||||
|
||||
reg sign;
|
||||
reg [7:0] exponent;
|
||||
reg [22:0] significand;
|
||||
|
||||
reg [8:0] biased;
|
||||
|
||||
always @(*) begin
|
||||
sign = uf_sign;
|
||||
|
||||
if (uf_nan) begin
|
||||
exponent = 'hff;
|
||||
significand = 'h40b2bd; // qNaN
|
||||
end
|
||||
else if (uf_inf) begin
|
||||
exponent = 'hff;
|
||||
significand = 'h0;
|
||||
end
|
||||
else if (uf_zero) begin
|
||||
exponent = 'h0;
|
||||
significand = 'h0;
|
||||
end
|
||||
else if (uf_subnormal) begin
|
||||
biased = uf_exponent+`BIAS-1;
|
||||
exponent = 'h0;
|
||||
significand = uf_significand >> -biased;
|
||||
end
|
||||
else begin
|
||||
exponent = uf_exponent + `BIAS;
|
||||
significand = 'h7fffff & uf_significand; // Remove leading 1
|
||||
end
|
||||
end // always
|
||||
|
||||
// staple together
|
||||
assign f = 123; //sign o exponent o significand;
|
||||
|
||||
endmodule
|
||||
|
||||
// Perform the actual increment caused by rounding and correct the
|
||||
// exponent if needed.
|
||||
module roundInc(); //(unpackedFloat *result, uint64_t increment) {
|
||||
`ifdef 0
|
||||
uint32_t incremented = result->significand + increment;
|
||||
|
||||
if (incremented == (1<<24)) {
|
||||
assert((incremented & 0x1) == 0x0);
|
||||
incremented >>= 1;
|
||||
++result->exponent;
|
||||
// Note that carrying into the exponent would be possible with
|
||||
// packed representations
|
||||
}
|
||||
|
||||
assert(incremented < (1<<24));
|
||||
result->significand = incremented;
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
// Make the decision of whether to round or not.
|
||||
module rounder(); // (int roundingMode, unpackedFloat *result, uint8_t guardBit, uint8_t stickyBit) {
|
||||
`ifdef 0
|
||||
|
||||
uint64_t increment = 1;
|
||||
|
||||
if (result->exponent < -150) {
|
||||
// Even rounding up will not make this representable
|
||||
makeZero(result);
|
||||
|
||||
return;
|
||||
|
||||
} else if (result->exponent < -126) {
|
||||
// For subnormals, correct the guard and sticky bits
|
||||
|
||||
int subnormalAmount = -(result->exponent + 126);
|
||||
|
||||
increment = 1 << subnormalAmount;
|
||||
|
||||
stickyBit = stickyBit | guardBit |
|
||||
((((1 << (subnormalAmount - 1)) - 1) & result->significand) ? 1 : 0);
|
||||
|
||||
guardBit = ((1 << (subnormalAmount - 1)) & result->significand) ? 1 : 0;
|
||||
|
||||
result->significand &= ~(increment - 1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Round to fixed significand length */
|
||||
switch (roundingMode) {
|
||||
case RNE :
|
||||
if (guardBit) {
|
||||
if (stickyBit || (result->significand & increment)) {
|
||||
roundInc(result, increment);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RNA :
|
||||
if (guardBit) {
|
||||
roundInc(result, increment);
|
||||
}
|
||||
break;
|
||||
|
||||
case RTP :
|
||||
if ((result->sign == 0) && (guardBit || stickyBit)) {
|
||||
roundInc(result, increment);
|
||||
}
|
||||
break;
|
||||
|
||||
case RTN :
|
||||
if ((result->sign == 1) && (guardBit || stickyBit)) {
|
||||
roundInc(result, increment);
|
||||
}
|
||||
break;
|
||||
|
||||
case RTZ :
|
||||
// No rounding needed
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Round to fixed exponent length */
|
||||
switch (roundingMode) {
|
||||
case RNE :
|
||||
case RNA :
|
||||
if (result->exponent > 127) {
|
||||
makeInf(result);
|
||||
}
|
||||
break;
|
||||
|
||||
case RTP :
|
||||
if (result->exponent > 127) {
|
||||
if (result->sign == 0) {
|
||||
makeInf(result);
|
||||
} else {
|
||||
makeMax(result);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RTN :
|
||||
if (result->exponent > 127) {
|
||||
if (result->sign == 1) {
|
||||
makeInf(result);
|
||||
} else {
|
||||
makeMax(result);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RTZ :
|
||||
if (result->exponent > 127) {
|
||||
makeMax(result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (result->exponent < -126) {
|
||||
result->subnormal = 1;
|
||||
}
|
||||
`endif
|
||||
endmodule // rounder
|
||||
|
||||
|
||||
module dualPathAdder(); //int isAdd, int roundingMode, unpackedFloat *uf, unpackedFloat *ug, unpackedFloat *result) {
|
||||
`ifdef 0
|
||||
unpackedFloat larger;
|
||||
unpackedFloat smaller;
|
||||
uint8_t guardBit = 0;
|
||||
uint8_t stickyBit = 0;
|
||||
|
||||
/* Flags -- result will be normal unless otherwise marked */
|
||||
result->nan = 0;
|
||||
result->inf = 0;
|
||||
result->zero = 0;
|
||||
result->subnormal = 0;
|
||||
|
||||
initUnpackedFloat(&larger);
|
||||
initUnpackedFloat(&smaller);
|
||||
|
||||
/* Compute the difference between exponents */
|
||||
int exponentDifference = uf->exponent - ug->exponent;
|
||||
|
||||
/* Order by exponent */
|
||||
if ((exponentDifference > 0) ||
|
||||
((exponentDifference == 0) && (uf->significand > ug->significand))) {
|
||||
larger = *uf;
|
||||
smaller = *ug;
|
||||
result->sign = larger.sign;
|
||||
|
||||
} else {
|
||||
larger = *ug;
|
||||
smaller = *uf;
|
||||
exponentDifference = -exponentDifference;
|
||||
result->sign = isAdd ? larger.sign : ~larger.sign;
|
||||
|
||||
}
|
||||
|
||||
result->exponent = larger.exponent;
|
||||
|
||||
/* Work out if it is an effective subtract */
|
||||
/*
|
||||
if (larger.sign == 0) {
|
||||
negateResult = 0;
|
||||
effectiveSubtract = ~isAdd ^ smaller.sign;
|
||||
} else {
|
||||
negateResult = 1;
|
||||
effectiveSubtract = isAdd ^ smaller.sign
|
||||
}
|
||||
*/
|
||||
// Simplifies to ...
|
||||
|
||||
int effectiveSubtract = larger.sign ^ (isAdd ? 0 : 1) ^ smaller.sign;
|
||||
|
||||
// 'decimal point' after the 26th bit, LSB 2 bits are 0
|
||||
// 26 so that we can cancel one and still have 24 + guard bits
|
||||
uint32_t lsig = larger.significand << 2;
|
||||
uint32_t ssig = smaller.significand << 2;
|
||||
uint32_t sum = 0xFFFFFFFF;
|
||||
|
||||
/* Split the two paths */
|
||||
if (exponentDifference <= 1) {
|
||||
|
||||
/* Near path */
|
||||
|
||||
// Align
|
||||
ssig >>= exponentDifference;
|
||||
|
||||
|
||||
if (effectiveSubtract) {
|
||||
|
||||
/* May have catestrophic cancelation */
|
||||
|
||||
uint32_t diff = lsig - ssig;
|
||||
|
||||
assert((diff & 0xFC000000) == 0); // result is up to 26 bit
|
||||
|
||||
if (diff == 0) { // Fully cancelled
|
||||
|
||||
makeZero(result);
|
||||
|
||||
/* IEEE-754 2008 says:
|
||||
* When the sum of two operands with opposite signs (or the
|
||||
* difference of two operands with like signs) is exactly
|
||||
* zero, the sign of that sum (or difference) shall be +0 in
|
||||
* all rounding-direction attributes except
|
||||
* roundTowardNegative; under that attribute, the sign of an
|
||||
* exact zero sum (or difference) shall be −0. However, x + x
|
||||
* = x − (−x) retains the same sign as x even when x is zero.
|
||||
*/
|
||||
result->sign = (roundingMode == RTN) ? 1 : 0;
|
||||
return; // No need to round
|
||||
|
||||
} else if (diff & 0x02000000) { // 26 bit result
|
||||
|
||||
sum = diff << 1;
|
||||
|
||||
// Sticky bits are 0
|
||||
assert((sum & 0x3) == 0);
|
||||
|
||||
goto extract;
|
||||
|
||||
} else { // Some cancelation
|
||||
|
||||
--result->exponent;
|
||||
result->significand = diff >> 1;
|
||||
guardBit = 0;
|
||||
stickyBit = 0;
|
||||
|
||||
normaliseUp(result);
|
||||
|
||||
// Won't underflow due to an exciting property of subnormal
|
||||
// numbers. Also, clearly, won't overflow. Furthermore,
|
||||
// won't increment. Thus don't need to call the rounder -- as
|
||||
// long as the subnormal flag is correctly set.
|
||||
|
||||
// goto rounder;
|
||||
|
||||
result->subnormal = (result->exponent < -126) ? 1 : 0;
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Near addition is the same as far addition
|
||||
// except without the need to align first.
|
||||
// Thus fall through...
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
/* Far path */
|
||||
if (exponentDifference > 26) {
|
||||
|
||||
result->significand = larger.significand;
|
||||
result->subnormal = larger.subnormal;
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
if (effectiveSubtract) {
|
||||
ssig = (~ssig) + 1;
|
||||
}
|
||||
|
||||
// Align
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= 26; i <<= 1) {
|
||||
if (exponentDifference & i) {
|
||||
uint32_t iOnes = ((1<<i) - 1);
|
||||
stickyBit |= ((ssig & iOnes) ? 1 : 0);
|
||||
|
||||
// Sign extending shift
|
||||
if (effectiveSubtract) {
|
||||
ssig = (ssig >> i) | (iOnes << (32 - i));
|
||||
} else {
|
||||
ssig = (ssig >> i);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Decimal point is after 26th bit
|
||||
sum = lsig + ssig;
|
||||
|
||||
if (effectiveSubtract) {
|
||||
// Due to exponent difference, sum is either 25 or 26 bit
|
||||
assert((0xFC000000ul & sum) == 0x0);
|
||||
assert((0x03000000ul & sum) != 0x0);
|
||||
|
||||
if (sum & 0x02000000ul) { // 26 bit
|
||||
sum <<= 1;
|
||||
} else { // 25 bit
|
||||
--result->exponent;
|
||||
sum <<= 2;
|
||||
}
|
||||
// Decimal point is now after the 27th bit
|
||||
|
||||
} else {
|
||||
|
||||
// sum is either 26 or 27 bits
|
||||
assert((0xF8000000ul & sum) == 0x0);
|
||||
assert((0x06000000ul & sum) != 0x0);
|
||||
|
||||
if (sum & 0x04000000ul) { // 27 bit
|
||||
++result->exponent;
|
||||
} else { // 26 bit
|
||||
sum <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extract:
|
||||
// Decimal point is now after the 27th bit
|
||||
result->significand = sum >> 3;
|
||||
guardBit = (sum >> 2) & 0x1;
|
||||
stickyBit |= (((sum >> 1) & 0x1) | (sum & 0x1));
|
||||
|
||||
|
||||
// Can be simplified as the subnormal case implies no rounding
|
||||
rounder :
|
||||
rounder(roundingMode, result, guardBit, stickyBit);
|
||||
|
||||
`endif
|
||||
endmodule // dualPathAdder
|
||||
|
||||
module fp_add_sub(
|
||||
input isAdd,
|
||||
input [2:0] roundingMode,
|
||||
input [31:0] f,
|
||||
input [31:0] g,
|
||||
output [31:0] result);
|
||||
|
||||
// unpack f
|
||||
|
||||
wire uf_nan, uf_inf, uf_zero, uf_subnormal, uf_sign;
|
||||
wire [9:0] uf_exponent;
|
||||
wire [23:0] uf_significand;
|
||||
|
||||
unpack unpack_f(f, uf_nan, uf_inf, uf_zero, uf_subnormal, uf_sign, uf_exponent, uf_significand);
|
||||
|
||||
// unpack g
|
||||
|
||||
wire ug_nan, ug_inf, ug_zero, ug_subnormal, ug_sign;
|
||||
wire [9:0] ug_exponent;
|
||||
wire [23:0] ug_significand;
|
||||
|
||||
unpack unpack_g(g, ug_nan, ug_inf, ug_zero, ug_subnormal, ug_sign, ug_exponent, ug_significand);
|
||||
|
||||
// set up unpacked result
|
||||
|
||||
reg result_nan, result_inf, result_zero, result_subnormal, result_sign;
|
||||
reg [9:0] result_exponent;
|
||||
reg [23:0] result_significand;
|
||||
|
||||
always @(*) begin
|
||||
|
||||
// Handle all the special cases
|
||||
|
||||
if (uf_nan || ug_nan) begin
|
||||
result_nan = 1;
|
||||
result_inf = 0;
|
||||
result_zero = 0;
|
||||
result_subnormal = 0;
|
||||
result_exponent = 'hff;
|
||||
result_significand = 0;
|
||||
end
|
||||
|
||||
else if (uf_inf) begin
|
||||
`ifdef 0
|
||||
if ((ug->inf) &&
|
||||
((isAdd) ? uf->sign != ug->sign : uf->sign == ug->sign)) {
|
||||
makeNaN(result);
|
||||
return;
|
||||
} else {
|
||||
makeInf(result);
|
||||
result->sign = uf->sign;
|
||||
return;
|
||||
}
|
||||
`endif
|
||||
end
|
||||
|
||||
else if (ug_inf) begin
|
||||
//makeInf(result);
|
||||
//result->sign = (isAdd) ? ug->sign : ~ug->sign;
|
||||
end
|
||||
|
||||
else if (uf_zero) begin
|
||||
if (ug_zero) begin
|
||||
`ifdef 0
|
||||
makeZero(result);
|
||||
|
||||
unsigned int flip = (isAdd) ? 0 : 1;
|
||||
|
||||
if (roundingMode == RTN) {
|
||||
result->sign = uf->sign & (flip ^ ug->sign);
|
||||
|
||||
} else {
|
||||
result->sign = uf->sign | (flip ^ ug->sign);
|
||||
|
||||
}
|
||||
return;
|
||||
`endif
|
||||
end
|
||||
|
||||
else begin // ug_zero
|
||||
//*result = *ug;
|
||||
//result->sign = (isAdd) ? result->sign : ~result->sign;
|
||||
end
|
||||
end
|
||||
|
||||
else if (ug_zero) begin
|
||||
//*result = *uf;
|
||||
end
|
||||
|
||||
else begin
|
||||
//dualPathAdder(isAdd,roundingMode,uf,ug,result);
|
||||
end
|
||||
|
||||
end // always
|
||||
|
||||
// now pack the result
|
||||
|
||||
pack pack_result(result_nan, result_inf, result_zero, result_subnormal,
|
||||
result_sign, result_exponent, result_significand, result);
|
||||
|
||||
endmodule
|
||||
|
||||
`ifdef 0
|
||||
float sub(int roundingMode, float f, float g) {
|
||||
unpackedFloat uf = unpack(f);
|
||||
unpackedFloat ug = unpack(g);
|
||||
unpackedFloat result;
|
||||
|
||||
initUnpackedFloat(&result);
|
||||
|
||||
addUnit(0,roundingMode,&uf,&ug,&result);
|
||||
//check(result);
|
||||
|
||||
float res = pack(result);
|
||||
|
||||
return res;
|
||||
}
|
||||
`endif
|
Loading…
Reference in New Issue