Merge "Adding a new function to print floats without external deps"
diff --git a/hello_vec/Makefile b/hello_vec/Makefile
index 14b7d19..fcae97d 100644
--- a/hello_vec/Makefile
+++ b/hello_vec/Makefile
@@ -29,7 +29,7 @@
CC := ${SHODANROOTDIR}/cache/toolchain_vp/bin/riscv32-unknown-elf-gcc
CPP := ${SHODANROOTDIR}/cache/toolchain_vp/bin/riscv32-unknown-elf-g++
-${BUILDDIR}/hello_vec.elf: ${BUILDDIR}/main.o ${BUILDDIR}/springbok_gloss.o ${BUILDDIR}/crt0.o
+${BUILDDIR}/hello_vec.elf: ${BUILDDIR}/main.o ${BUILDDIR}/springbok_gloss.o ${BUILDDIR}/springbok.o ${BUILDDIR}/crt0.o
mkdir -p $(dir $@)
${CPP} ${CXXFLAGS} ${CPPFLAGS} $^ ${LDFLAGS} -o $@
@cat ${BUILDDIR}/hello_vec.map | awk '/\.heap/ {printf("%16s: %13s\n", "heap (reserved)", int(strtonum($$3)/1024) " KB")} /\.stack/ {printf("%16s: %13s\n", "stack (reserved)", int(strtonum($$3)/1024) " KB")}'
@@ -42,6 +42,10 @@
mkdir -p $(dir $@)
${CPP} ${CXXFLAGS} ${CPPFLAGS} -c $< -o $@
+${BUILDDIR}/springbok.o: ${ROOTDIR}/springbok/springbok.cpp ${MAKEFILE_LIST}
+ mkdir -p $(dir $@)
+ ${CPP} ${CXXFLAGS} ${CPPFLAGS} -c $< -o $@
+
${BUILDDIR}/crt0.o: ${ROOTDIR}/springbok/crt0.s ${MAKEFILE_LIST}
mkdir -p $(dir $@)
${CC} ${CXXFLAGS} ${CFLAGS} -c $< -o $@
diff --git a/hello_vec/main.cpp b/hello_vec/main.cpp
index 598adec..0fd0e01 100644
--- a/hello_vec/main.cpp
+++ b/hello_vec/main.cpp
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <springbok_intrinsics.h>
+#include <springbok.h>
class ExampleStatic {
public:
@@ -37,5 +38,12 @@
printf("%s(%d): Hello printf!\n", __PRETTY_FUNCTION__, __LINE__);
+ const float sorta_pi = 3.141592653589f;
+ int chars_needed = float_to_str(0, NULL, sorta_pi);
+ char *buffer = new char[chars_needed];
+ float_to_str(chars_needed, buffer, sorta_pi);
+ printf("Pi is ~%s, %d characters printed\n", buffer, chars_needed);
+ delete[] buffer;
+
return thingy[0] + thingy[1] + thingy[2] + thingy[3] + exampleStatic.value;
}
diff --git a/springbok/include/springbok.h b/springbok/include/springbok.h
index 80905a7..a0a9d06 100644
--- a/springbok/include/springbok.h
+++ b/springbok/include/springbok.h
@@ -32,4 +32,6 @@
#define LOG_NOISY(msg, args...) \
SIMLOG(noisy, LOG_FMT msg, LOG_ARGS(NOISY_TAG), ##args)
+extern "C" int float_to_str(const int len, char *buffer, const float value);
+
#endif
diff --git a/springbok/springbok.cpp b/springbok/springbok.cpp
index 678e196..95c3941 100644
--- a/springbok/springbok.cpp
+++ b/springbok/springbok.cpp
@@ -1,3 +1,4 @@
+#include <stdint.h>
#include "springbok.h"
extern "C" void print_csrs(void) {
@@ -28,13 +29,195 @@
: [MVENDORID] "=r"(mvendorid):);
__asm__ volatile("csrr %[MIMPID], mimpid"
: [MIMPID] "=r"(mimpid):);
- LOG_ERROR("MCAUSE:\t\t0x%08X", mcause);
- LOG_ERROR("MEPC:\t\t0x%08X", mepc);
- LOG_ERROR("MTVAL:\t\t0x%08X", mtval);
- LOG_ERROR("MISA:\t\t0x%08X", misa);
- LOG_ERROR("MTVEC:\t\t0x%08X", mtvec);
- LOG_ERROR("MHARTID:\t\t0x%08X", mhartid);
- LOG_ERROR("MARCHID:\t\t0x%08X", marchid);
- LOG_ERROR("MVENDORID:\t0x%08X", mvendorid);
- LOG_ERROR("MIMPID:\t\t0x%08X", mimpid);
+ LOG_ERROR("MCAUSE:\t\t0x%08X", static_cast<unsigned int>(mcause));
+ LOG_ERROR("MEPC:\t\t0x%08X", static_cast<unsigned int>(mepc));
+ LOG_ERROR("MTVAL:\t\t0x%08X", static_cast<unsigned int>(mtval));
+ LOG_ERROR("MISA:\t\t0x%08X", static_cast<unsigned int>(misa));
+ LOG_ERROR("MTVEC:\t\t0x%08X", static_cast<unsigned int>(mtvec));
+ LOG_ERROR("MHARTID:\t\t0x%08X", static_cast<unsigned int>(mhartid));
+ LOG_ERROR("MARCHID:\t\t0x%08X", static_cast<unsigned int>(marchid));
+ LOG_ERROR("MVENDORID:\t0x%08X", static_cast<unsigned int>(mvendorid));
+ LOG_ERROR("MIMPID:\t\t0x%08X", static_cast<unsigned int>(mimpid));
}
+
+// Helper function for float_to_str. Copies a string into the output buffer.
+static void print_str(char *buffer, const int len, int *l, const char *str) {
+ for (int i = 0; str[i] != '\0'; i++) {
+ if (*l < len) {
+ buffer[*l] = str[i];
+ }
+ (*l)++;
+ }
+}
+
+// Helper function for float_to_str. Copies a fixed-point decimal number up to
+// 16 digits long into the output buffer.
+static void print_fp_num(char *buffer, const int len, int *l, uint64_t abs_value,
+ const bool negative, const int fixed_point) {
+ uint8_t digits[16];
+ int i;
+
+ for(i = 0; i < 16; i++) {
+ digits[i] = abs_value % 10;
+ abs_value /= 10;
+ }
+ for(i = 15; i > fixed_point; i--) {
+ if (digits[i]) {
+ break;
+ }
+ }
+ if (negative) {
+ if ((*l) < len) {
+ buffer[*l] = '-';
+ }
+ (*l)++;
+ }
+ for(; i >= 0; i--) {
+ if(i == fixed_point-1) {
+ if((*l) < len) {
+ buffer[*l] = '.';
+ }
+ (*l)++;
+ }
+ if((*l) < len) {
+ buffer[*l] = digits[i] + '0';
+ }
+ (*l)++;
+ }
+}
+
+// This function converts a floating point value into a string. It doesn't rely
+// on any external library functions to do so, including string manipulation
+// functions. It's (probably) not good enough for production and may have bugs.
+// Always prints at least 7 significant figures, which is just slightly less
+// precise than single precision.
+//
+// Usage:
+// [Code]
+// int main(void) {
+// const float sorta_pi = 3.141592653589f;
+// int chars_needed = float_to_str(0, NULL, sorta_pi);
+// char *buffer = new char[chars_needed];
+// float_to_str(chars_needed, buffer, sorta_pi);
+// printf("Pi is ~%s, %d characters printed\n", buffer, chars_needed);
+// delete[] buffer;
+// return 0;
+// }
+//
+// [Output]
+// Pi is 3.141592, 9 characters printed
+extern "C" int float_to_str(const int len, char *buffer, const float value) {
+ if (buffer == NULL && len != 0) {
+ // Bad inputs
+ springbok_simprint(SPRINGBOK_SIMPRINT_ERROR, "float_to_str handed null buffer with non-zero length! len:", len);
+ return 0;
+ }
+
+ int l = 0;
+
+ union {
+ float value;
+ uint32_t raw;
+ } conv = { .value = value };
+
+ const uint32_t raw_v = conv.raw;
+ const uint32_t raw_absv = raw_v & UINT32_C(0x7FFFFFFF);
+ const float absv = value < 0? -value : value;
+
+ if (raw_absv > UINT32_C(0x7F800000)) {
+ // NaN
+ print_str(buffer, len, &l, "[NaN]");
+
+ } else if (raw_absv == UINT32_C(0x7F800000)) {
+ // Infinity
+ if (value > 0) {
+ print_str(buffer, len, &l, "[+INF]");
+ } else {
+ print_str(buffer, len, &l, "[-INF]");
+ }
+
+ } else if (absv >= 1.f && absv < 10000000.f) {
+ // Convert to 7.6 decimal fixed point and print
+ print_fp_num(buffer, len, &l, static_cast<uint64_t>(absv * 1000000.f), value < 0, 6);
+
+ } else if (absv > 0) {
+ // Scientific notation
+
+ // The powers of ten from 10^-45 to 10^38 rounded downward and cast to
+ // binary32. Each stored value holds the property of being the next value
+ // lower or equal to the associated power of ten.
+ const uint32_t kRawBucketStart[84] = {
+ 0x00000000, 0x00000007, 0x00000047, 0x000002c9, 0x00001be0, 0x000116c2, 0x000ae397, 0x006ce3ee,
+ 0x02081cea, 0x03aa2424, 0x0554ad2d, 0x0704ec3c, 0x08a6274b, 0x0a4fb11e, 0x0c01ceb3, 0x0da2425f,
+ 0x0f4ad2f7, 0x10fd87b5, 0x129e74d1, 0x14461206, 0x15f79687, 0x179abe14, 0x19416d9a, 0x1af1c900,
+ 0x1c971da0, 0x1e3ce508, 0x1fec1e4a, 0x219392ee, 0x233877aa, 0x24e69594, 0x26901d7c, 0x283424dc,
+ 0x29e12e13, 0x2b8cbccc, 0x2d2febff, 0x2edbe6fe, 0x3089705f, 0x322bcc77, 0x33d6bf94, 0x358637bd,
+ 0x3727c5ac, 0x38d1b717, 0x3a83126e, 0x3c23d70a, 0x3dcccccc, 0x3f7fffff, 0x411fffff, 0x42c7ffff,
+ 0x4479ffff, 0x461c3fff, 0x47c34fff, 0x497423ff, 0x4b18967f, 0x4cbebc1f, 0x4e6e6b27, 0x501502f8,
+ 0x51ba43b7, 0x5368d4a5, 0x551184e7, 0x56b5e620, 0x58635fa9, 0x5a0e1bc9, 0x5bb1a2bc, 0x5d5e0b6b,
+ 0x5f0ac723, 0x60ad78eb, 0x6258d726, 0x64078678, 0x65a96816, 0x6753c21b, 0x69045951, 0x6aa56fa5,
+ 0x6c4ecb8f, 0x6e013f39, 0x6fa18f07, 0x7149f2c9, 0x72fc6f7c, 0x749dc5ad, 0x76453719, 0x77f684df,
+ 0x799a130b, 0x7b4097ce, 0x7cf0bdc2, 0x7e967699,
+ };
+ // The inverse powers of ten from 10^45 to 10^-38. The 32 values from each
+ // edge are scaled up and down by 2^32 to keep them from becoming
+ // denormalized or infinity. Since this is a power of 2, it will not affect
+ // numerical accuracy.
+ const uint32_t kRawBucketScale[84] = {
+ 0x7a335dbf, 0x788f7e32, 0x76e596b7, 0x7537abc6, 0x7392efd1, 0x71eb194f, 0x703c143f, 0x6e967699,
+ 0x6cf0bdc2, 0x6b4097cf, 0x699a130c, 0x67f684df, 0x66453719, 0x649dc5ae, 0x62fc6f7c, 0x6149f2ca,
+ 0x5fa18f08, 0x5e013f3a, 0x5c4ecb8f, 0x5aa56fa6, 0x59045952, 0x5753c21c, 0x55a96816, 0x54078678,
+ 0x5258d726, 0x50ad78ec, 0x4f0ac723, 0x4d5e0b6b, 0x4bb1a2bc, 0x4a0e1bca, 0x48635faa, 0x46b5e621,
+ 0x551184e7, 0x5368d4a5, 0x51ba43b7, 0x501502f9, 0x4e6e6b28, 0x4cbebc20, 0x4b189680, 0x49742400,
+ 0x47c35000, 0x461c4000, 0x447a0000, 0x42c80000, 0x41200000, 0x3f800000, 0x3dcccccd, 0x3c23d70b,
+ 0x3a83126f, 0x38d1b718, 0x3727c5ad, 0x358637be, 0x43d6bf95, 0x422bcc78, 0x40897060, 0x3edbe6ff,
+ 0x3d2febff, 0x3b8cbccc, 0x39e12e13, 0x383424dd, 0x36901d7d, 0x34e69595, 0x333877aa, 0x319392ef,
+ 0x2fec1e4a, 0x2e3ce509, 0x2c971da1, 0x2af1c900, 0x29416d9a, 0x279abe15, 0x25f79687, 0x24461206,
+ 0x229e74d2, 0x20fd87b5, 0x1f4ad2f8, 0x1da24260, 0x1c01ceb3, 0x1a4fb11f, 0x18a6274b, 0x1704ec3d,
+ 0x1554ad2e, 0x13aa2425, 0x12081cea, 0x1059c7dc,
+ };
+ const float *bucket_start = reinterpret_cast<const float*>(kRawBucketStart);
+ const float *bucket_scale = reinterpret_cast<const float*>(kRawBucketScale);
+
+ // Search and find the first smaller power of 10.
+ int e;
+ for(e = 38; e >= -45; e--) {
+ if (bucket_start[e+45] < absv) {
+ break;
+ }
+ }
+ const int abs_e = e < 0 ? -e : e;
+
+ // Prescale by 2^32 if the power of 10 is too large or small.
+ float scaled_absv = absv;
+ if (e < -45+32) {
+ scaled_absv *= 4294967296.f; // exactly 2^32
+ } else if (e >= 39-32) {
+ scaled_absv *= 0.00000000023283064365386962890625; // exactly 2^-32
+ }
+
+ // Scale by the inverse power of 10. The scales by 2^32 will cancel out
+ // and provide a value in the range of [1, 10).
+ scaled_absv *= bucket_scale[e+45];
+
+ // Print as a signed 1.6 decimal fixed-point value with signed exponent.
+ print_fp_num(buffer, len, &l, static_cast<uint64_t>(scaled_absv * 1000000.f), value < 0, 6);
+ print_str(buffer, len, &l, "e");
+ print_fp_num(buffer, len, &l, abs_e, e < 0, 0);
+
+ } else {
+ // Exactly 0
+ print_fp_num(buffer, len, &l, 0, false, 0);
+ }
+
+ // Add a null terminator, even if there isn't room.
+ if (l < len) {
+ buffer[l] = '\0';
+ } else if (len > 0) {
+ buffer[len-1] = '\0';
+ }
+ l++;
+
+ // Return the number of characters needed for display.
+ return l;
+}