Skip to content
volt
GitHub

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 block

a 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) -> void

the 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) -> never

std::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) -> void

std::bare::put_cstr

fn put_cstr(c: cstr) -> void

std::bare::put_num

fn put_num(v: u64) -> void

std::bare::volt_panic

export fn volt_panic(msg: cstr, loc: cstr) -> never

std::bare::volt_panic_str

export fn volt_panic_str(msg: str, loc: cstr) -> never

std::bare::volt_bounds

export fn volt_bounds(i: usize, len: usize, loc: cstr) -> never

std::bare::to_console

extern "C" fn to_console(ctx: void*, s: str) -> void

std::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() -> void

one core, no threads: nothing to hold

std::bare::volt_unlock_out

export fn volt_unlock_out() -> void

std::bare::volt_put

export fn volt_put(s: void*, p: cstr, n: usize) -> void

std::bare::volt_print_str

export fn volt_print_str(s: void*, t: str) -> void

std::bare::volt_rt_malloc

export fn volt_rt_malloc(n: usize) -> void*

std::bare::volt_rt_free

export fn volt_rt_free(p: void*) -> void

std::bare::volt_rt_realloc

export fn volt_rt_realloc(p: void*, n: usize) -> void*

std::bare::fmod

export fn fmod(x: f64, y: f64) -> f64

float % (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) -> f32

float % on f32

std::bare::div32::__udivdi3

export fn __udivdi3(a: u64, b: u64) -> u64

std::bare::div32::__umoddi3

export fn __umoddi3(a: u64, b: u64) -> u64

std::bare::div32::__divdi3

export fn __divdi3(a: i64, b: i64) -> i64

std::bare::div32::__moddi3

export fn __moddi3(a: i64, b: i64) -> i64

std::bare::v6m::__udivsi3

export fn __udivsi3(a: u32, b: u32) -> u32

std::bare::v6m::__umodsi3

export fn __umodsi3(a: u32, b: u32) -> u32

std::bare::v6m::__divsi3

export fn __divsi3(a: i32, b: i32) -> i32

std::bare::v6m::__modsi3

export fn __modsi3(a: i32, b: i32) -> i32

std::bare::v6m::__ashldi3

export fn __ashldi3(a: u64, s: i32) -> u64

std::bare::v6m::__lshrdi3

export fn __lshrdi3(a: u64, s: i32) -> u64

std::bare::v6m::__ashrdi3

export fn __ashrdi3(a: i64, s: i32) -> i64

std::bare::v6m::__muldi3

export fn __muldi3(a: u64, b: u64) -> u64

std::bare::v6m::__clzsi2

export fn __clzsi2(a: u32) -> i32

leading 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) -> i128

std::bare::wide128::__ashlti3

export fn __ashlti3(a: i128, s: i32) -> i128

std::bare::wide128::__lshrti3

export fn __lshrti3(a: i128, s: i32) -> i128

std::bare::wide128::__ashrti3

export fn __ashrti3(a: i128, s: i32) -> i128

std::bare::wide128::__muloti4

export fn __muloti4(a: i128, b: i128, overflow: i32*) -> i128

a * 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) -> f64

std::bare::wide128::__floattidf

export fn __floattidf(x: i128) -> f64

std::bare::wide128::__floatuntisf

export fn __floatuntisf(x: u128) -> f32

std::bare::wide128::__floattisf

export fn __floattisf(x: i128) -> f32

std::bare::wide128::__fixunsdfti

export fn __fixunsdfti(x: f64) -> u128

an 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) -> i128

std::bare::wide128::__fixunssfti

export fn __fixunssfti(x: f32) -> u128

std::bare::wide128::__fixsfti

export fn __fixsfti(x: f32) -> i128

std::bare::wide128::__udivti3

export fn __udivti3(a: u128, b: u128) -> u128

std::bare::wide128::__umodti3

export fn __umodti3(a: u128, b: u128) -> u128

std::bare::wide128::__divti3

export fn __divti3(a: i128, b: i128) -> i128

std::bare::wide128::__modti3

export fn __modti3(a: i128, b: i128) -> i128

std::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) -> i32

std::bare::mem32::bcmp

export fn bcmp(a: u8*, b: u8*, n: u32) -> i32

std::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) -> i32

std::bare::mem64::bcmp

export fn bcmp(a: u8*, b: u8*, n: usize) -> i32

std::bare::soft::b64

fn b64(v: f64) -> u64

a float's bits and back (register moves: no float instructions)

std::bare::soft::f64_of

fn f64_of(b: u64) -> f64

std::bare::soft::b32

fn b32(v: f32) -> u32

std::bare::soft::f32_of

fn f32_of(b: u32) -> f32

std::bare::soft::__adddf3

export fn __adddf3(a: f64, b: f64) -> f64

std::bare::soft::__subdf3

export fn __subdf3(a: f64, b: f64) -> f64

std::bare::soft::__muldf3

export fn __muldf3(a: f64, b: f64) -> f64

std::bare::soft::__divdf3

export fn __divdf3(a: f64, b: f64) -> f64

std::bare::soft::__negdf2

export fn __negdf2(a: f64) -> f64

std::bare::soft::__addsf3

export fn __addsf3(a: f32, b: f32) -> f32

std::bare::soft::__subsf3

export fn __subsf3(a: f32, b: f32) -> f32

std::bare::soft::__mulsf3

export fn __mulsf3(a: f32, b: f32) -> f32

std::bare::soft::__divsf3

export fn __divsf3(a: f32, b: f32) -> f32

std::bare::soft::__negsf2

export fn __negsf2(a: f32) -> f32

std::bare::soft::le64

fn le64(a: f64, b: f64) -> i32

comparisons, 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) -> i32

std::bare::soft::__eqdf2

export fn __eqdf2(a: f64, b: f64) -> i32

std::bare::soft::__nedf2

export fn __nedf2(a: f64, b: f64) -> i32

std::bare::soft::__ltdf2

export fn __ltdf2(a: f64, b: f64) -> i32

std::bare::soft::__ledf2

export fn __ledf2(a: f64, b: f64) -> i32

std::bare::soft::__gedf2

export fn __gedf2(a: f64, b: f64) -> i32

std::bare::soft::__gtdf2

export fn __gtdf2(a: f64, b: f64) -> i32

std::bare::soft::__unorddf2

export fn __unorddf2(a: f64, b: f64) -> i32

std::bare::soft::__eqsf2

export fn __eqsf2(a: f32, b: f32) -> i32

std::bare::soft::__nesf2

export fn __nesf2(a: f32, b: f32) -> i32

std::bare::soft::__ltsf2

export fn __ltsf2(a: f32, b: f32) -> i32

std::bare::soft::__lesf2

export fn __lesf2(a: f32, b: f32) -> i32

std::bare::soft::__gesf2

export fn __gesf2(a: f32, b: f32) -> i32

std::bare::soft::__gtsf2

export fn __gtsf2(a: f32, b: f32) -> i32

std::bare::soft::__unordsf2

export fn __unordsf2(a: f32, b: f32) -> i32

std::bare::soft::__extendsfdf2

export fn __extendsfdf2(a: f32) -> f64

conversions

std::bare::soft::__truncdfsf2

export fn __truncdfsf2(a: f64) -> f32

std::bare::soft::__fixdfsi

export fn __fixdfsi(a: f64) -> i32

std::bare::soft::__fixdfdi

export fn __fixdfdi(a: f64) -> i64

std::bare::soft::__fixunsdfsi

export fn __fixunsdfsi(a: f64) -> u32

std::bare::soft::__fixunsdfdi

export fn __fixunsdfdi(a: f64) -> u64

std::bare::soft::__fixsfsi

export fn __fixsfsi(a: f32) -> i32

std::bare::soft::__fixsfdi

export fn __fixsfdi(a: f32) -> i64

std::bare::soft::__fixunssfsi

export fn __fixunssfsi(a: f32) -> u32

std::bare::soft::__fixunssfdi

export fn __fixunssfdi(a: f32) -> u64

std::bare::soft::__floatsidf

export fn __floatsidf(i: i32) -> f64

std::bare::soft::__floatdidf

export fn __floatdidf(i: i64) -> f64

std::bare::soft::__floatunsidf

export fn __floatunsidf(i: u32) -> f64

std::bare::soft::__floatundidf

export fn __floatundidf(i: u64) -> f64

std::bare::soft::__floatsisf

export fn __floatsisf(i: i32) -> f32

std::bare::soft::__floatdisf

export fn __floatdisf(i: i64) -> f32

std::bare::soft::__floatunsisf

export fn __floatunsisf(i: u32) -> f32

std::bare::soft::__floatundisf

export fn __floatundisf(i: u64) -> f32

std::bare::half::of

fn of(v: u128) -> f16

std::bare::half::wide

fn wide(v: f16) -> u128

std::bare::half::__extendhfsf2

export fn __extendhfsf2(x: f16) -> f32

std::bare::half::__extendhfdf2

export fn __extendhfdf2(x: f16) -> f64

std::bare::half::__truncsfhf2

export fn __truncsfhf2(x: f32) -> f16

std::bare::half::__truncdfhf2

export fn __truncdfhf2(x: f64) -> f16

Globals

var console_sink: sink = { write: to_console, ctx: null }
val HEADER: usize = 16
var heap_top: usize = 0
var heap_limit: usize = 0
var free_blocks: block* = null