more Verilog

This commit is contained in:
Daniel Kroening 2014-03-26 10:41:15 +00:00
parent bd0d1e70a9
commit 3fd3b2cd64
1 changed files with 601 additions and 0 deletions

View File

@ -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