blob: d6d659e0c41769bea3179afcf807314644cd9d04 [file] [log] [blame]
#include <stdint.h>
#include "springbok.h"
#ifndef LIBSPRINGBOK_NO_EXCEPTION_SUPPORT
extern "C" void print_csrs(void) {
uint32_t mcause;
uint32_t mepc;
uint32_t mtval;
uint32_t misa;
uint32_t mtvec;
uint32_t mhartid;
uint32_t marchid;
uint32_t mvendorid;
uint32_t mimpid;
__asm__ volatile("csrr %[MCAUSE], mcause"
: [MCAUSE] "=r"(mcause):);
__asm__ volatile("csrr %[MEPC], mepc"
: [MEPC] "=r"(mepc):);
__asm__ volatile("csrr %[MTVAL], mtval"
: [MTVAL] "=r"(mtval):);
__asm__ volatile("csrr %[MISA], misa"
: [MISA] "=r"(misa):);
__asm__ volatile("csrr %[MTVEC], mtvec"
: [MTVEC] "=r"(mtvec):);
__asm__ volatile("csrr %[MHARTID], mhartid"
: [MHARTID] "=r"(mhartid):);
__asm__ volatile("csrr %[MARCHID], marchid"
: [MARCHID] "=r"(marchid):);
__asm__ volatile("csrr %[MVENDORID], mvendorid"
: [MVENDORID] "=r"(mvendorid):);
__asm__ volatile("csrr %[MIMPID], mimpid"
: [MIMPID] "=r"(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));
}
#endif
#ifndef LIBSPRINGBOK_NO_FLOAT_SUPPORT
// 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
LOG_ERROR("float_to_str handed null buffer with non-zero length! len:%d",
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;
}
#else // defined(LIBSPRINGBOK_NO_FLOAT_SUPPORT)
extern "C" int float_to_str(const int len, char *buffer, const float value) {
// Dummy function since float support is disabled in libspringbok
LOG_ERROR("float_to_str is disabled because libspringbok was compiled without float support");
return 0;
}
#endif