diff --git a/pipelined/src/fma/Makefile b/pipelined/src/fma/Makefile new file mode 100644 index 000000000..270954f72 --- /dev/null +++ b/pipelined/src/fma/Makefile @@ -0,0 +1,10 @@ +TARGET ?= fma + +# for some reason, softfloat.a needs to be symlinked to the local directory. -L isn't working +$(TARGET): $(TARGET).c Makefile + gcc -O2 -o $(TARGET) $(TARGET).c softfloat.a \ + -I../../../addins/SoftFloat-3e/source/include \ + -L../../../addins/SoftFloat-3e/build/Linux-x86_64-GCC + +clean: + rm $(TARGET) diff --git a/pipelined/src/fma/div.c b/pipelined/src/fma/div.c new file mode 100644 index 000000000..c76efab20 --- /dev/null +++ b/pipelined/src/fma/div.c @@ -0,0 +1,52 @@ +#include +#include +#include "softfloat.h" +#include "softfloat_types.h" + +int float_rounding_mode = 0; + +union dp { + unsigned short x[4]; + double y; +} X; + + +int main() +{ + uint8_t rounding_mode; + uint8_t exceptions; + + uint64_t n, d, result; + float64_t d_n, d_d, d_result; + + n = 0x3feffffffefffff6; + d = 0xffeffffffffffffe; + //n = 0x00000000400001ff; + //d = 0x3ffffdfffffffbfe; + + d_n.v = n; + d_d.v = d; + + softfloat_roundingMode = rounding_mode; + softfloat_exceptionFlags = 0; + softfloat_detectTininess = softfloat_tininess_beforeRounding; + + d_result = f64_div(d_n, d_d); + + //result = d_result.v; + //exceptions = softfloat_exceptionFlags & 0x1f; + + X.x[3] = (d_result.v & 0xffff000000000000) >> 48; + X.x[2] = (d_result.v & 0x0000ffff00000000) >> 32; + X.x[1] = (d_result.v & 0x00000000ffff0000) >> 16; + X.x[0] = (d_result.v & 0x000000000000ffff); + + printf("Number = %.4x\n", X.x[3]); + printf("Number = %.4x\n", X.x[2]); + printf("Number = %.4x\n", X.x[1]); + printf("Number = %.4x\n", X.x[0]); + printf("Number = %1.25lg\n", X.y); + + + return 0; +} diff --git a/pipelined/src/fma/fma.c b/pipelined/src/fma/fma.c new file mode 100644 index 000000000..4b7bda1fd --- /dev/null +++ b/pipelined/src/fma/fma.c @@ -0,0 +1,47 @@ +#include +#include +#include "softfloat.h" +#include "softfloat_types.h" + +int float_rounding_mode = 0; + +union sp { + unsigned short x[2]; + float y; +} X; + + +int main() +{ + uint8_t rounding_mode; + uint8_t exceptions; + + uint32_t multiplier, multiplicand, addend, result; + float32_t f_multiplier, f_multiplicand, f_addend, f_result; + + multiplier = 0xbf800000; + multiplicand = 0xbf800000; + addend = 0xffaaaaaa; + + f_multiplier.v = multiplier; + f_multiplicand.v = multiplicand; + f_addend.v = addend; + + softfloat_roundingMode = rounding_mode; + softfloat_exceptionFlags = 0; + softfloat_detectTininess = softfloat_tininess_beforeRounding; + + f_result = f32_mulAdd(f_multiplier, f_multiplicand, f_addend); + + result = f_result.v; + exceptions = softfloat_exceptionFlags & 0x1f; + + printf("%x\n", f_result.v); + + // Print out SP number + X.x[1] = (f_result.v & 0xffff0000) >> 16; + X.x[0] = (f_result.v & 0x0000ffff); + printf("Number = %f\n", X.y); + + return 0; +} diff --git a/pipelined/src/fma/fma16.sv b/pipelined/src/fma/fma16.sv new file mode 100644 index 000000000..c537baf6d --- /dev/null +++ b/pipelined/src/fma/fma16.sv @@ -0,0 +1,121 @@ +// fma16.sv +// David_Harris@hmc.edu 26 February 2022 +// 16-bit floating-point multiply-accumulate + +// Operation: general purpose multiply, add, fma, with optional negation +// If mul=1, p = x * y. Else p = x. +// If add=1, result = p + z. Else result = p. +// If negp or negz = 1, negate p or z to handle negations and subtractions +// fadd: mul = 0, add = 1, negp = negz = 0 +// fsub: mul = 0, add = 1, negp = 0, negz = 1 +// fmul: mul = 1, add = 0, negp = 0, negz = 0 +// fma: mul = 1, add = 1, negp = 0, negz = 0 + +module fma16( + input logic [15:0] x, y, z, + input logic add, mul, negp, negz, + input logic [1:0] roundmode, // 00: rz, 01: rne, 10: rp, 11: rn + output logic [15:0] result); + + logic [10:0] xm, ym, zm; + logic [4:0] xe, ye, ze; + logic xs, ys, zs; + logic zs1; // sign before optional negation + logic ps; // sign of product + + unpack unpack(x, y, z, xm, ym, zm, xe, ye, ze, xs, ys, zs1); // unpack inputs + signadj signadj(negp, negz, xs, ys, zs1, ps, zs); // handle negations + mult mult(mul, xm, ym, xe, ye, pm, pe); // p = x * y + add add(add, pm, zm, pe, ze, ps, zs, rm, re, rs); // r = z + p + postproc post(roundmode, rm, re, rs, result); // normalize, round, pack +endmodule + +module mult( + input logic mul, + input logic [10:0] xm, ym, + input logic [4:0] xe, ye, + input logic xs, ys, + output logic [21:0] pm, + output logic [5:0] pe); + + // only multiply if mul = 1 + assign pm = mul ? xm * ym : xm; // multiply mantiassas + assign pe = mul ? xe + ye : xe; +endmodule + +module add( + input logic add, + input logic [21:0] pm, + input logic [10:0] zm, + input logic [5:0] pe, + input logic [4:0] ze, + input logic ps, zs, + output logic [22:0] rm, + output logic [6:0] re, + output logic rs); + + logic [22:0] arm; + logic [6:0] are; + logic ars; + + alignshift as(pe, ze, zm, zmaligned); + condneg cnp(pm, ps, pmn); + condneg cnz(zm, zs, zmn); + + // add or pass product through + assign rm = add ? arm : pm; + assign re = add ? are : pe; + assign rs = add ? ars : ps; +); + +module postproc( + input logic [1:0] roundmode, + input logic [22:0] rm, + input logic [6:0] re, + input logic rs, + output logic [15:0] result); + + // add special case handling for zeros, NaN, Infinity +endmodule + +module signadj( + input logic negx, negz, + input logic xs, ys, zs1, + output logic ps, zs); + + assign ps = xs ^ ys ^ negx; // sign of product + assign zs = zs1 ^ negz; // +endmodule + +module unpack( + input logic [15:0] x, y, z, + output logic [10:0] xm, ym, zm, + output logic [4:0] xe, ye, ze, + output logic xs, ys, zs); + + unpacknum upx(x, xm, xe, xs); + unpacknum upy(y, ym, ye, ys); + unpacknum upz(z, zm, ze, zs); +endmodule + +module unpacknum( + input logic [15:0] num, + output logic [10:0] m, + output logic [4:0] e, + output logic s); + + logic [9:0] f; // fraction without leading 1 + logic [4:0] eb; // biased exponent + + assign {f, eb, s} = num; // pull bit fields out of floating-point number + assign m = {1'b1, f}; // prepend leading 1 to fraction + assign e = eb - 15; // remove bias from exponent +endmodule + + +// Tests: +// Every permutation for x, y, z of +// mantissa = {1.0, 1.0000000001, 1.1, 1.1111111110, 1.1111111111} +// biased exponent = {1, 2, 14, 15, 16, 21, 29, 30} +// sign = {0, 1} +// special case: [normal, 0, INF, NaN] \ No newline at end of file diff --git a/pipelined/src/fma/fma16_testgen.py b/pipelined/src/fma/fma16_testgen.py new file mode 100755 index 000000000..c3cc8d72f --- /dev/null +++ b/pipelined/src/fma/fma16_testgen.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +# fma16_testgen.py +# David_Harris@hmc.edu 26 February 2022 +# Generate test cases for 16-bit FMA + +def makeVal(val): + +def makeCase(x, y, z, mul, add, msg): + xval = makeVal(x); + yval = makeVal(y); + zval = makeVal(z); + mode = mul*2+add; # convert to hexadecimal code + expected = makeExpected(x, y, z, mul, add); + print(xval,"_", yval, "_", zval, "_", mode, "_", expected, " //", msg); + +def makeMulCase(x, y, msg): + makeCase(x, y, "0", 1, 0, msg) + +################################ +## Main program +################################ + +# Directed cases +makeMulCase("1", "1", "1 x 1"); + + +# Corner cases + +# Random cases + diff --git a/pipelined/src/fma/softfloat.a b/pipelined/src/fma/softfloat.a new file mode 120000 index 000000000..508aa0da8 --- /dev/null +++ b/pipelined/src/fma/softfloat.a @@ -0,0 +1 @@ +../../../addins/SoftFloat-3e/build/Linux-x86_64-GCC/softfloat.a \ No newline at end of file