std::bare
Std on bare metal (voltc --target ..-none): the runtime the compiler's code calls, in Volt instead of C. Panics, bounds and printing go to the board's volt_console_write; the program ends in the board's volt_exit (voltc's start code has defaults for both). Memory comes from a heap between the linker script's __heap_start and __heap_end. It also gives what LLVM calls for copies, fills, 64-bit division and floating point on 32-bit cores (and division, 64-bit shifts and multiplies on a Cortex-M0), which a C library and libgcc would.
Source: std/bare.volt
Types
struct std::bare::sink
struct sink| Field | |
|---|---|
write: extern "C" fn(void*, str) -> void | |
ctx: void* |
struct std::bare::block
struct blocka block's header: its whole size, and while it's free the next free block
| Field | |
|---|---|
size: usize | |
next: block* |
Functions
std::bare::volt_hook_console_write
extern "C" fn volt_hook_console_write(p: u8*, n: usize) -> voidthe board's hooks (voltc's start code jumps from these names to volt_console_write and volt_exit, which the program defines), and the heap's bounds from the linker script
std::bare::volt_hook_exit
extern "C" fn volt_hook_exit(code: i32) -> neverstd::bare::volt_heap_start
extern "C" fn volt_heap_start() -> u8*std::bare::volt_heap_end
extern "C" fn volt_heap_end() -> u8*std::bare::volt_heap_grow
extern "C" fn volt_heap_grow(more: usize) -> u8*WebAssembly's memory grows: at least more bytes past the end, the new end returned
std::bare::put
fn put(s: str) -> voidstd::bare::put_cstr
fn put_cstr(c: cstr) -> voidstd::bare::put_num
fn put_num(v: u64) -> voidstd::bare::volt_panic
export fn volt_panic(msg: cstr, loc: cstr) -> neverstd::bare::volt_panic_str
export fn volt_panic_str(msg: str, loc: cstr) -> neverstd::bare::volt_bounds
export fn volt_bounds(i: usize, len: usize, loc: cstr) -> neverstd::bare::to_console
extern "C" fn to_console(ctx: void*, s: str) -> voidstd::bare::volt_stdout
export fn volt_stdout() -> void*std::bare::volt_stderr
export fn volt_stderr() -> void*std::bare::volt_lock_out
export fn volt_lock_out() -> voidone core, no threads: nothing to hold
std::bare::volt_unlock_out
export fn volt_unlock_out() -> voidstd::bare::volt_put
export fn volt_put(s: void*, p: cstr, n: usize) -> voidstd::bare::volt_print_str
export fn volt_print_str(s: void*, t: str) -> voidstd::bare::volt_rt_malloc
export fn volt_rt_malloc(n: usize) -> void*std::bare::volt_rt_free
export fn volt_rt_free(p: void*) -> voidstd::bare::volt_rt_realloc
export fn volt_rt_realloc(p: void*, n: usize) -> void*std::bare::fmod
export fn fmod(x: f64, y: f64) -> f64float % (LLVM's frem), which LLVM makes a call to the C library's fmod or fmodf
std::bare::fmodf
export fn fmodf(x: f32, y: f32) -> f32float % on f32
std::bare::div32::__udivdi3
export fn __udivdi3(a: u64, b: u64) -> u64std::bare::div32::__umoddi3
export fn __umoddi3(a: u64, b: u64) -> u64std::bare::div32::__divdi3
export fn __divdi3(a: i64, b: i64) -> i64std::bare::div32::__moddi3
export fn __moddi3(a: i64, b: i64) -> i64std::bare::v6m::__udivsi3
export fn __udivsi3(a: u32, b: u32) -> u32std::bare::v6m::__umodsi3
export fn __umodsi3(a: u32, b: u32) -> u32std::bare::v6m::__divsi3
export fn __divsi3(a: i32, b: i32) -> i32std::bare::v6m::__modsi3
export fn __modsi3(a: i32, b: i32) -> i32std::bare::v6m::__ashldi3
export fn __ashldi3(a: u64, s: i32) -> u64std::bare::v6m::__lshrdi3
export fn __lshrdi3(a: u64, s: i32) -> u64std::bare::v6m::__ashrdi3
export fn __ashrdi3(a: i64, s: i32) -> i64std::bare::v6m::__muldi3
export fn __muldi3(a: u64, b: u64) -> u64std::bare::v6m::__clzsi2
export fn __clzsi2(a: u32) -> i32leading zeros, which LLVM calls for @clz (the Cortex-M0 has no CLZ; softfloat's rem128 uses it): halving, no @clz here, which would call this
std::bare::wide128::__multi3
export fn __multi3(a: i128, b: i128) -> i128std::bare::wide128::__ashlti3
export fn __ashlti3(a: i128, s: i32) -> i128std::bare::wide128::__lshrti3
export fn __lshrti3(a: i128, s: i32) -> i128std::bare::wide128::__ashrti3
export fn __ashrti3(a: i128, s: i32) -> i128std::bare::wide128::__muloti4
export fn __muloti4(a: i128, b: i128, overflow: i32*) -> i128a * b with *overflow set when it doesn't fit in an i128 (checked multiplies in debug builds)
std::bare::wide128::__floatuntidf
export fn __floatuntidf(x: u128) -> f64std::bare::wide128::__floattidf
export fn __floattidf(x: i128) -> f64std::bare::wide128::__floatuntisf
export fn __floatuntisf(x: u128) -> f32std::bare::wide128::__floattisf
export fn __floattisf(x: i128) -> f32std::bare::wide128::__fixunsdfti
export fn __fixunsdfti(x: f64) -> u128an f64 truncated toward zero to a u128 (0 below zero or for NaN, the largest past it)
std::bare::wide128::__fixdfti
export fn __fixdfti(x: f64) -> i128std::bare::wide128::__fixunssfti
export fn __fixunssfti(x: f32) -> u128std::bare::wide128::__fixsfti
export fn __fixsfti(x: f32) -> i128std::bare::wide128::__udivti3
export fn __udivti3(a: u128, b: u128) -> u128std::bare::wide128::__umodti3
export fn __umodti3(a: u128, b: u128) -> u128std::bare::wide128::__divti3
export fn __divti3(a: i128, b: i128) -> i128std::bare::wide128::__modti3
export fn __modti3(a: i128, b: i128) -> i128std::bare::mem32::memcpy
export fn memcpy(d: u8*, s: u8*, n: u32) -> u8*std::bare::mem32::memmove
export fn memmove(d: u8*, s: u8*, n: u32) -> u8*std::bare::mem32::memset
export fn memset(d: u8*, c: i32, n: u32) -> u8*std::bare::mem32::memcmp
export fn memcmp(a: u8*, b: u8*, n: u32) -> i32std::bare::mem32::bcmp
export fn bcmp(a: u8*, b: u8*, n: u32) -> i32std::bare::mem64::memcpy
export fn memcpy(d: u8*, s: u8*, n: usize) -> u8*std::bare::mem64::memmove
export fn memmove(d: u8*, s: u8*, n: usize) -> u8*std::bare::mem64::memset
export fn memset(d: u8*, c: i32, n: usize) -> u8*std::bare::mem64::memcmp
export fn memcmp(a: u8*, b: u8*, n: usize) -> i32std::bare::mem64::bcmp
export fn bcmp(a: u8*, b: u8*, n: usize) -> i32std::bare::soft::b64
fn b64(v: f64) -> u64a float's bits and back (register moves: no float instructions)
std::bare::soft::f64_of
fn f64_of(b: u64) -> f64std::bare::soft::b32
fn b32(v: f32) -> u32std::bare::soft::f32_of
fn f32_of(b: u32) -> f32std::bare::soft::__adddf3
export fn __adddf3(a: f64, b: f64) -> f64std::bare::soft::__subdf3
export fn __subdf3(a: f64, b: f64) -> f64std::bare::soft::__muldf3
export fn __muldf3(a: f64, b: f64) -> f64std::bare::soft::__divdf3
export fn __divdf3(a: f64, b: f64) -> f64std::bare::soft::__negdf2
export fn __negdf2(a: f64) -> f64std::bare::soft::__addsf3
export fn __addsf3(a: f32, b: f32) -> f32std::bare::soft::__subsf3
export fn __subsf3(a: f32, b: f32) -> f32std::bare::soft::__mulsf3
export fn __mulsf3(a: f32, b: f32) -> f32std::bare::soft::__divsf3
export fn __divsf3(a: f32, b: f32) -> f32std::bare::soft::__negsf2
export fn __negsf2(a: f32) -> f32std::bare::soft::le64
fn le64(a: f64, b: f64) -> i32comparisons, as libgcc's: <0, 0 or >0 like a - b; a NaN gives 1 to eq/ne/lt/le, -1 to ge/gt, so each comparison comes out false
std::bare::soft::ge64
fn ge64(a: f64, b: f64) -> i32std::bare::soft::__eqdf2
export fn __eqdf2(a: f64, b: f64) -> i32std::bare::soft::__nedf2
export fn __nedf2(a: f64, b: f64) -> i32std::bare::soft::__ltdf2
export fn __ltdf2(a: f64, b: f64) -> i32std::bare::soft::__ledf2
export fn __ledf2(a: f64, b: f64) -> i32std::bare::soft::__gedf2
export fn __gedf2(a: f64, b: f64) -> i32std::bare::soft::__gtdf2
export fn __gtdf2(a: f64, b: f64) -> i32std::bare::soft::__unorddf2
export fn __unorddf2(a: f64, b: f64) -> i32std::bare::soft::__eqsf2
export fn __eqsf2(a: f32, b: f32) -> i32std::bare::soft::__nesf2
export fn __nesf2(a: f32, b: f32) -> i32std::bare::soft::__ltsf2
export fn __ltsf2(a: f32, b: f32) -> i32std::bare::soft::__lesf2
export fn __lesf2(a: f32, b: f32) -> i32std::bare::soft::__gesf2
export fn __gesf2(a: f32, b: f32) -> i32std::bare::soft::__gtsf2
export fn __gtsf2(a: f32, b: f32) -> i32std::bare::soft::__unordsf2
export fn __unordsf2(a: f32, b: f32) -> i32std::bare::soft::__extendsfdf2
export fn __extendsfdf2(a: f32) -> f64conversions
std::bare::soft::__truncdfsf2
export fn __truncdfsf2(a: f64) -> f32std::bare::soft::__fixdfsi
export fn __fixdfsi(a: f64) -> i32std::bare::soft::__fixdfdi
export fn __fixdfdi(a: f64) -> i64std::bare::soft::__fixunsdfsi
export fn __fixunsdfsi(a: f64) -> u32std::bare::soft::__fixunsdfdi
export fn __fixunsdfdi(a: f64) -> u64std::bare::soft::__fixsfsi
export fn __fixsfsi(a: f32) -> i32std::bare::soft::__fixsfdi
export fn __fixsfdi(a: f32) -> i64std::bare::soft::__fixunssfsi
export fn __fixunssfsi(a: f32) -> u32std::bare::soft::__fixunssfdi
export fn __fixunssfdi(a: f32) -> u64std::bare::soft::__floatsidf
export fn __floatsidf(i: i32) -> f64std::bare::soft::__floatdidf
export fn __floatdidf(i: i64) -> f64std::bare::soft::__floatunsidf
export fn __floatunsidf(i: u32) -> f64std::bare::soft::__floatundidf
export fn __floatundidf(i: u64) -> f64std::bare::soft::__floatsisf
export fn __floatsisf(i: i32) -> f32std::bare::soft::__floatdisf
export fn __floatdisf(i: i64) -> f32std::bare::soft::__floatunsisf
export fn __floatunsisf(i: u32) -> f32std::bare::soft::__floatundisf
export fn __floatundisf(i: u64) -> f32std::bare::half::of
fn of(v: u128) -> f16std::bare::half::wide
fn wide(v: f16) -> u128std::bare::half::__extendhfsf2
export fn __extendhfsf2(x: f16) -> f32std::bare::half::__extendhfdf2
export fn __extendhfdf2(x: f16) -> f64std::bare::half::__truncsfhf2
export fn __truncsfhf2(x: f32) -> f16std::bare::half::__truncdfhf2
export fn __truncdfhf2(x: f64) -> f16Globals
var console_sink: sink = { write: to_console, ctx: null }val HEADER: usize = 16var heap_top: usize = 0var heap_limit: usize = 0var free_blocks: block* = null