67
67
2 . The call to ` compile "Fibs" spec' ` in ` main ` . This will compile the Copilot
68
68
specification to a Bluespec program named ` Fibs.bs ` .
69
69
70
- Running this program will generate three files[ ^ 1 ] :
70
+ Running this program will generate five files[ ^ 1 ] :
71
71
72
72
[ ^ 1 ] : The actual code in these files is machine-generated and somewhat
73
73
difficult to read. We have cleaned up the code slightly to make it easier to
@@ -127,6 +127,7 @@ understand.
127
127
128
128
import FibsTypes
129
129
import FibsIfc
130
+ import BluespecFP
130
131
131
132
mkFibs :: Module FibsIfc -> Module Empty
132
133
mkFibs ifcMod =
@@ -179,6 +180,62 @@ understand.
179
180
the structure of a module, whereas the ` ActionValue ` monad describes the
180
181
behavior of a circuit at execution time.
181
182
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
+
182
239
In a larger application, a Copilot user would instantiate ` mkFibs ` with a
183
240
` FibsIfc ` module that describes what should happen when the ` even ` and ` odd `
184
241
triggers fire. ` FibsIfc ` contains everything that the user must supply;
@@ -222,7 +279,7 @@ code generation for mkTop starts
222
279
Elaborated module file created: mkTop.ba
223
280
All packages are up to date.
224
281
225
- $ bsc -sim -e mkTop -o mkTop.exe
282
+ $ bsc -sim -e mkTop -o mkTop.exe bs_fp.c
226
283
Bluesim object created: mkTop.{h,o}
227
284
Bluesim object created: model_mkTop.{h,o}
228
285
Simulation shared library created: mkTop.exe.so
@@ -657,20 +714,25 @@ the common case.
657
714
658
715
## Floating-point numbers
659
716
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 :
663
720
664
721
* Basic arithmetic (` (+) ` , ` (-) ` , ` (*) ` , ` (/) ` )
665
722
* Equality checking (` (==) ` and ` (/=) ` )
666
723
* Inequality checking (` (<) ` , ` (<=) ` , ` (>) ` , and ` (>=) ` )
667
724
* ` abs `
668
725
* ` signum `
669
726
* ` recip `
670
- * ` sqrt `
671
727
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:
673
734
735
+ * ` sqrt `
674
736
* ` acos `
675
737
* ` asin `
676
738
* ` atan `
@@ -691,8 +753,102 @@ The following floating-point operations are _not_ supported:
691
753
* ` ceiling `
692
754
* ` floor `
693
755
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
696
852
697
853
## Warnings
698
854
0 commit comments