67672 . The call to ` compile "Fibs" spec' ` in ` main ` . This will compile the Copilot
6868 specification to a Bluespec program named ` Fibs.bs ` .
6969
70- Running this program will generate three files[ ^ 1 ] :
70+ Running this program will generate five files[ ^ 1 ] :
7171
7272[ ^ 1 ] : The actual code in these files is machine-generated and somewhat
7373difficult to read. We have cleaned up the code slightly to make it easier to
@@ -127,6 +127,7 @@ understand.
127127
128128 import FibsTypes
129129 import FibsIfc
130+ import BluespecFP
130131
131132 mkFibs :: Module FibsIfc -> Module Empty
132133 mkFibs ifcMod =
@@ -179,6 +180,62 @@ understand.
179180 the structure of a module, whereas the ` ActionValue ` monad describes the
180181 behavior of a circuit at execution time.
181182
183+ * ` BluespecFP.bsv ` : A collection of floating-point operations that leverage BDPI
184+ (Bluespec's foreign-function interface). We will omit the full contents of
185+ this file for brevity, but it will look something like this:
186+
187+ ``` bluespec
188+ import FloatingPoint::*;
189+
190+ import "BDPI" function Float bs_fp_expf (Float x);
191+ import "BDPI" function Double bs_fp_exp (Double x);
192+ import "BDPI" function Float bs_fp_logf (Float x);
193+ import "BDPI" function Double bs_fp_log (Double x);
194+ ...
195+ ```
196+
197+ For more information on what this file does, see the "Floating-point numbers"
198+ section below.
199+
200+ * ` bs_fp.c ` : A collection of floating-point operations implemented in C. These
201+ functions are imported via BDPI in ` BluespecFP.bsv ` . We will omit the full
202+ contents of this file for brevity, but it will look something like this:
203+
204+ ``` bluespec
205+ #include <math.h>
206+
207+ union ui_float {
208+ unsigned int i;
209+ float f;
210+ };
211+
212+ union ull_double {
213+ unsigned long long i;
214+ double f;
215+ };
216+
217+ unsigned int bs_fp_expf(unsigned int x) {
218+ ...
219+ }
220+
221+ unsigned long long bs_fp_exp(unsigned long long x) {
222+ ...
223+ }
224+
225+ unsigned int bs_fp_logf(unsigned int x) {
226+ ...
227+ }
228+
229+ unsigned long long bs_fp_log(unsigned long long x) {
230+ ...
231+ }
232+
233+ ...
234+ ```
235+
236+ For more information on what this file does, see the "Floating-point numbers"
237+ section below.
238+
182239In a larger application, a Copilot user would instantiate ` mkFibs ` with a
183240` FibsIfc ` module that describes what should happen when the ` even ` and ` odd `
184241triggers fire. ` FibsIfc ` contains everything that the user must supply;
@@ -222,7 +279,7 @@ code generation for mkTop starts
222279Elaborated module file created: mkTop.ba
223280All packages are up to date.
224281
225- $ bsc -sim -e mkTop -o mkTop.exe
282+ $ bsc -sim -e mkTop -o mkTop.exe bs_fp.c
226283Bluesim object created: mkTop.{h,o}
227284Bluesim object created: model_mkTop.{h,o}
228285Simulation shared library created: mkTop.exe.so
@@ -657,20 +714,25 @@ the common case.
657714
658715## Floating-point numbers
659716
660- ` copilot-bluespec ` has partial support for Copilot's floating-point operations,
661- as it is limited by what operations are provided by Bluespec's standard
662- libraries. The following floating-point operations are supported :
717+ ` copilot-bluespec ` supports all of Copilot's floating-point operations with
718+ varying degrees of performance. The following floating-point operations compile
719+ directly to relatively performant circuits :
663720
664721* Basic arithmetic (` (+) ` , ` (-) ` , ` (*) ` , ` (/) ` )
665722* Equality checking (` (==) ` and ` (/=) ` )
666723* Inequality checking (` (<) ` , ` (<=) ` , ` (>) ` , and ` (>=) ` )
667724* ` abs `
668725* ` signum `
669726* ` recip `
670- * ` sqrt `
671727
672- The following floating-point operations are _ not_ supported:
728+ These operations correspond to the floating-point operations that the Bluespec
729+ standard library provides that are well tested. Unfortunately, the Bluespec
730+ standard library does not offer well-tested versions (or even _ any_ versions)
731+ of the remainder of Copilot's floating-point operations. The rest of these
732+ operations are instead implemented by using BDPI (Bluespec's foreign function
733+ interface) to interface with C code:
673734
735+ * ` sqrt `
674736* ` acos `
675737* ` asin `
676738* ` atan `
@@ -691,8 +753,102 @@ The following floating-point operations are _not_ supported:
691753* ` ceiling `
692754* ` floor `
693755
694- See https://github.com/B-Lang-org/bsc/issues/368 for further discussion on the
695- unsupported operations.
756+ Implementing these operations via C provides high confidence that they are
757+ implemented correctly, but at a somewhat steep performance penalty.
758+
759+ Because these operations need to be implemented via BDPI, ` copilot-bluespec `
760+ generates two additional files: ` BluespecFP.bsv ` (which contains the Bluespec
761+ function stubs for each function implemented via BDPI) and ` bs_fp.c ` (which
762+ contains the corresponding C function definitions). To see how this works,
763+ let us take a look at one of the BDPI'd functions, ` sqrt ` :
764+
765+ ``` bluespec
766+ import "BDPI" function Double bs_fp_sqrt (Double x);
767+ import "BDPI" function Float bs_fp_sqrtf (Float x);
768+ ```
769+
770+ This declares a Bluespec function ` bs_fp_sqrt ` that is implemented using a C
771+ function (also of the name ` bs_fp_sqrt ` ) under the hood. This takes a Bluespec
772+ ` Double ` as an argument and also returns a ` Double ` . Note that ` Double ` is not
773+ treated magically by the Bluespec compiler here. This is because any Bluespec
774+ struct can be used in BDPI (provided that the struct type implements the ` Bits `
775+ class), and Bluespec's ` Double ` is implemented as a struct with a ` Bits `
776+ instance that exactly matches the bit layout expected by IEEE-754
777+ double-precision floats. (Similarly for Bluespec's ` Float ` type.)
778+
779+ Note that at present, the ` import "BDPI" ` feature is only available when using
780+ the BSV syntax, not the BH syntax. As such, this is currently the only place
781+ where we generate BSV code.
782+
783+ The corresponding C code for ` bs_fp_sqrt(f) ` is:
784+
785+ ``` c
786+ union ull_double {
787+ unsigned long long i;
788+ double f;
789+ };
790+
791+ union ui_float {
792+ unsigned int i;
793+ float f;
794+ };
795+
796+ unsigned long long bs_fp_sqrt (unsigned long long x) {
797+ union ull_double x_u;
798+ union ull_double r_u;
799+ x_u.i = x;
800+ r_u.f = sqrt(x_u.f);
801+ return r_u.i;
802+ }
803+
804+ unsigned int bs_fp_sqrtf(unsigned int x) {
805+ union ui_float x_u;
806+ union ui_float r_u;
807+ x_u.i = x;
808+ r_u.f = sqrtf(x_u.f);
809+ return r_u.i;
810+ }
811+ ```
812+
813+ There is a lot to unpack here. Let's go through this step by step:
814+
815+ 1. The C version of `bs_fp_sqrt` takes and returns an `unsigned long long`. The
816+ use of `unsigned long long` is dictated by Bluespec itself: whenever you
817+ use a Bluespec type in BDPI that fits in exactly 64 bits, then Bluespec
818+ expects the corresponding C type to be `unsigned long long`. (You can see
819+ this for yourself by inspecting the generated `imported_BDPI_functions.h`
820+ header file.)
821+
822+ There is a similar story for `bs_fp_sqrtf`, which takes an `unsigned int`.
823+ Bluespec dictates the use of `unsigned int` when the BDPI types fits in
824+ exactly 32 bits.
825+
826+ 2. This poses something of a challenge for us, since we want the implementation
827+ of `bs_fp_sqrt` to work over `double`s, not `unsigned long long`s. To make
828+ this possible, we define a `union ull_double` type that allows easily
829+ converting an `unsigned long long` to a `double` and vice versa.
830+
831+ There is an analogous story for `ui_float`, which allows conversion to and
832+ from the `unsigned int` and `float` types.
833+
834+ 3. Finally, we perform the `sqrt(f)` function on the argument, using
835+ `ull_double`/`ui_float` as necessary to make the types work out.
836+
837+ Strictly speaking, it is only necessary to compile the generated `bs_fp.c` file
838+ if the generated Bluespec program makes use of any of the BDPI-related
839+ floating-point operations mentioned above. That being said, it doesn't hurt to
840+ compile it even if the generated Bluespec program _doesn't_ use any of them, so
841+ it's generally good practice to pass `bs_fp.c` to `bsc`.
842+
843+ Eventually, we would like to stop using BDPI in favor of native Bluespec code,
844+ which would be more performant. To do so, would we need to address the
845+ following Bluespec issues:
846+
847+ * The implementation of `sqrt` in Bluespec's standard library is buggy:
848+ https://github.com/B-Lang-org/bsc/issues/710
849+
850+ * Bluespec's standard library does not implement the remaining floating-point
851+ operations at all: https://github.com/B-Lang-org/bsc/issues/368
696852
697853## Warnings
698854
0 commit comments