gcc: Implement ROM/OS calls

Co-authored-by: Lua MacDougall <lua@foxgirl.dev>
This commit is contained in:
Ry 2023-02-06 19:50:50 -08:00
parent 04aeba8eb0
commit eec12a9e9a
4 changed files with 1146 additions and 1 deletions

View File

@ -6,9 +6,13 @@ How does this work?
- `rv2fox` converts the generated RISC-V assembly to fox32 assembly
- `fox32asm` makes an FXF binary
## Generating bindings.c
bindings.kts is a little Kotlin script which generates bindings.c.
Ensure you have Kotlin installed on your system, then run `./bindings.kts > bindings.c`
## TODO:
- commandline argument passing
- calls out of C, into the ROM
- testcase sha256 program that hashes the ROM
- rust support: `rustc --emit asm --target riscv32im-unknown-none-elf test.rs -O`

629
gcc/bindings.c Normal file
View File

@ -0,0 +1,629 @@
#pragma once
#include "call.h"
// fox32rom definitions
// system jump table
static inline void get_rom_version(void) {
call(0xF0040000);
}
static inline void system_vsync_handler(void) {
call(0xF0040004);
}
static inline void get_mouse_position(void) {
call(0xF0040008);
}
static inline void new_event(void) {
call(0xF004000C);
}
static inline void wait_for_event(void) {
call(0xF0040010);
}
static inline void get_next_event(void) {
call(0xF0040014);
}
static inline void panic(void) {
call(0xF0040018);
}
static inline void get_mouse_button(void) {
call(0xF004001C);
}
static inline void scancode_to_ascii(void) {
call(0xF0040020);
}
static inline void shift_pressed(void) {
call(0xF0040024);
}
static inline void shift_released(void) {
call(0xF0040028);
}
static inline void caps_pressed(void) {
call(0xF004002C);
}
static inline void poweroff(void) {
call(0xF0040030);
}
// generic drawing jump table
static inline void draw_str_generic(void) {
call(0xF0041000);
}
static inline void draw_format_str_generic(void) {
call(0xF0041004);
}
static inline void draw_decimal_generic(void) {
call(0xF0041008);
}
static inline void draw_hex_generic(void) {
call(0xF004100C);
}
static inline void draw_font_tile_generic(void) {
call(0xF0041010);
}
static inline void draw_tile_generic(void) {
call(0xF0041014);
}
static inline void set_tilemap(void) {
call(0xF0041018);
}
static inline void draw_pixel_generic(void) {
call(0xF004101C);
}
static inline void draw_filled_rectangle_generic(void) {
call(0xF0041020);
}
static inline void get_tilemap(void) {
call(0xF0041024);
}
// background jump table
static inline void fill_background(
unsigned int color
) {
parameter(0, color);
call(0xF0042000);
}
static inline unsigned int draw_str_to_background(
unsigned char* str,
unsigned int x,
unsigned int y,
unsigned int foreground_color,
unsigned int background_color
) {
unsigned int result_1;
parameter(0, str);
parameter(1, x);
parameter(2, y);
parameter(3, foreground_color);
parameter(4, background_color);
call(0xF0042004);
ret(1, result_1);
return result_1;
}
static inline unsigned int draw_format_str_to_background(
unsigned char* str,
unsigned int x,
unsigned int y,
unsigned int foreground_color,
unsigned int background_color,
unsigned int format_value_0,
unsigned int format_value_1,
unsigned int format_value_2,
unsigned int format_value_3,
unsigned int format_value_4,
unsigned int format_value_5
) {
unsigned int result_1;
parameter(0, str);
parameter(1, x);
parameter(2, y);
parameter(3, foreground_color);
parameter(4, background_color);
parameter(10, format_value_0);
parameter(11, format_value_1);
parameter(12, format_value_2);
parameter(13, format_value_3);
parameter(14, format_value_4);
parameter(15, format_value_5);
call(0xF0042008);
ret(1, result_1);
return result_1;
}
static inline unsigned int draw_decimal_to_background(
unsigned int value,
unsigned int x,
unsigned int y,
unsigned int foreground_color,
unsigned int background_color
) {
unsigned int result_1;
parameter(0, value);
parameter(1, x);
parameter(2, y);
parameter(3, foreground_color);
parameter(4, background_color);
call(0xF004200C);
ret(1, result_1);
return result_1;
}
static inline unsigned int draw_hex_to_background(
unsigned int value,
unsigned int x,
unsigned int y,
unsigned int foreground_color,
unsigned int background_color
) {
unsigned int result_1;
parameter(0, value);
parameter(1, x);
parameter(2, y);
parameter(3, foreground_color);
parameter(4, background_color);
call(0xF0042010);
ret(1, result_1);
return result_1;
}
static inline void draw_font_tile_to_background(
unsigned int tile,
unsigned int x,
unsigned int y,
unsigned int foreground_color,
unsigned int background_color
) {
parameter(0, tile);
parameter(1, x);
parameter(2, y);
parameter(3, foreground_color);
parameter(4, background_color);
call(0xF0042014);
}
static inline void draw_tile_to_background(
unsigned int tile,
unsigned int x,
unsigned int y
) {
parameter(0, tile);
parameter(1, x);
parameter(2, y);
call(0xF0042018);
}
static inline void draw_pixel_to_background(
unsigned int x,
unsigned int y,
unsigned int color
) {
parameter(0, x);
parameter(1, y);
parameter(2, color);
call(0xF004201C);
}
static inline void draw_filled_rectangle_to_background(
unsigned int x,
unsigned int y,
unsigned int width,
unsigned int height,
unsigned int color
) {
parameter(0, x);
parameter(1, y);
parameter(2, width);
parameter(3, height);
parameter(4, color);
call(0xF0042020);
}
// overlay jump table
static inline void fill_overlay(void) {
call(0xF0043000);
}
static inline void draw_str_to_overlay(void) {
call(0xF0043004);
}
static inline void draw_format_str_to_overlay(void) {
call(0xF0043008);
}
static inline void draw_decimal_to_overlay(void) {
call(0xF004300C);
}
static inline void draw_hex_to_overlay(void) {
call(0xF0043010);
}
static inline void draw_font_tile_to_overlay(void) {
call(0xF0043014);
}
static inline void draw_tile_to_overlay(void) {
call(0xF0043018);
}
static inline void draw_pixel_to_overlay(void) {
call(0xF004301C);
}
static inline void draw_filled_rectangle_to_overlay(void) {
call(0xF0043020);
}
static inline void check_if_overlay_covers_position(void) {
call(0xF0043024);
}
static inline void check_if_enabled_overlay_covers_position(void) {
call(0xF0043028);
}
static inline void enable_overlay(void) {
call(0xF004302C);
}
static inline void disable_overlay(void) {
call(0xF0043030);
}
static inline void move_overlay(void) {
call(0xF0043034);
}
static inline void resize_overlay(void) {
call(0xF0043038);
}
static inline void set_overlay_framebuffer_pointer(void) {
call(0xF004303C);
}
static inline void get_unused_overlay(void) {
call(0xF0043040);
}
static inline void make_coordinates_relative_to_overlay(void) {
call(0xF0043044);
}
// menu bar jump table
static inline void enable_menu_bar(void) {
call(0xF0044000);
}
static inline void disable_menu_bar(void) {
call(0xF0044004);
}
static inline void menu_bar_click_event(void) {
call(0xF0044008);
}
static inline void clear_menu_bar(void) {
call(0xF004400C);
}
static inline void draw_menu_bar_root_items(void) {
call(0xF0044010);
}
static inline void draw_menu_items(void) {
call(0xF0044014);
}
static inline void close_menu(void) {
call(0xF0044018);
}
static inline void menu_update_event(void) {
call(0xF004401C);
}
// disk jump table
static inline void read_sector(void) {
call(0xF0045000);
}
static inline void write_sector(void) {
call(0xF0045004);
}
static inline void ryfs_open(void) {
call(0xF0045008);
}
static inline void ryfs_seek(void) {
call(0xF004500C);
}
static inline void ryfs_read(void) {
call(0xF0045010);
}
static inline void ryfs_read_whole_file(void) {
call(0xF0045014);
}
static inline void ryfs_get_size(void) {
call(0xF0045018);
}
static inline void ryfs_get_file_list(void) {
call(0xF004501C);
}
static inline void ryfs_tell(void) {
call(0xF0045020);
}
static inline void ryfs_write(void) {
call(0xF0045024);
}
// memory copy/compare jump table
static inline void copy_memory_bytes(void) {
call(0xF0046000);
}
static inline void copy_memory_words(void) {
call(0xF0046004);
}
static inline void copy_string(void) {
call(0xF0046008);
}
static inline void compare_memory_bytes(void) {
call(0xF004600C);
}
static inline void compare_memory_words(void) {
call(0xF0046010);
}
static inline void compare_string(void) {
call(0xF0046014);
}
static inline void string_length(void) {
call(0xF0046018);
}
// integer jump table
static inline void string_to_int(void) {
call(0xF0047000);
}
// audio jump table
static inline void play_audio(void) {
call(0xF0048000);
}
static inline void stop_audio(void) {
call(0xF0048004);
}
// random number jump table
static inline unsigned int random(void) {
unsigned int result_0;
call(0xF0049000);
ret(0, result_0);
return result_0;
}
static inline unsigned int random_range(
unsigned int minimum,
unsigned int maximum
) {
unsigned int result_0;
parameter(1, minimum);
parameter(2, maximum);
call(0xF0049004);
ret(0, result_0);
return result_0;
}
// keys
#define KEY_CTRL 0x0000001D
#define KEY_LSHIFT 0x0000002A
#define KEY_RSHIFT 0x00000036
#define KEY_CAPS 0x0000003A
// fox32os definitions
// system jump table
static inline void get_os_version(void) {
call(0x00000810);
}
// FXF jump table
static inline void parse_fxf_binary(void) {
call(0x00000910);
}
// task jump table
static inline void new_task(void) {
call(0x00000A10);
}
static inline void yield_task(void) {
call(0x00000A14);
}
static inline void end_current_task(void) {
call(0x00000A18);
}
static inline void get_current_task_id(void) {
call(0x00000A1C);
}
static inline void get_unused_task_id(void) {
call(0x00000A20);
}
static inline void is_task_id_used(void) {
call(0x00000A24);
}
// memory jump table
static inline void allocate_memory(void) {
call(0x00000B10);
}
static inline void free_memory(void) {
call(0x00000B14);
}
// window jump table
static inline void new_window(void) {
call(0x00000C10);
}
static inline void destroy_window(void) {
call(0x00000C14);
}
static inline void new_window_event(void) {
call(0x00000C18);
}
static inline void get_next_window_event(void) {
call(0x00000C1C);
}
static inline void draw_title_bar_to_window(void) {
call(0x00000C20);
}
static inline void move_window(void) {
call(0x00000C24);
}
static inline void fill_window(void) {
call(0x00000C28);
}
static inline void get_window_overlay_number(void) {
call(0x00000C2C);
}
static inline void start_dragging_window(void) {
call(0x00000C30);
}
static inline void new_messagebox(void) {
call(0x00000C34);
}
static inline void get_active_window_struct(void) {
call(0x00000C38);
}
// VFS jump table
static inline void open(void) {
call(0x00000D10);
}
static inline void seek(void) {
call(0x00000D14);
}
static inline void tell(void) {
call(0x00000D18);
}
static inline void read(void) {
call(0x00000D1C);
}
static inline void write(void) {
call(0x00000D20);
}
// widget jump table
static inline void draw_widgets_to_window(void) {
call(0x00000E10);
}
static inline void handle_widget_click(void) {
call(0x00000E14);
}
// event types
#define EVENT_TYPE_MOUSE_CLICK 0x00000000
#define EVENT_TYPE_MOUSE_RELEASE 0x00000001
#define EVENT_TYPE_KEY_DOWN 0x00000002
#define EVENT_TYPE_KEY_UP 0x00000003
#define EVENT_TYPE_MENU_BAR_CLICK 0x00000004
#define EVENT_TYPE_MENU_UPDATE 0x00000005
#define EVENT_TYPE_MENU_CLICK 0x00000006
#define EVENT_TYPE_MENU_ACK 0x00000007
#define EVENT_TYPE_BUTTON_CLICK 0x80000000
#define EVENT_TYPE_EMPTY 0xFFFFFFFF
// widget types
#define WIDGET_TYPE_BUTTON 0x00000000

492
gcc/bindings.kts Executable file
View File

@ -0,0 +1,492 @@
#!/usr/bin/env kotlin
class Type(val name: String) {
val ref get() = Type("$name*")
override fun toString() = name
}
val None = Type("void")
val Byte = Type("unsigned char")
val IByte = Type("signed char")
val Half = Type("unsigned short")
val IHalf = Type("signed short")
val Word = Type("unsigned int")
val IWord = Type("signed int")
class Variable(val type: Type, val name: String)
class Function(val address: UInt, val name: String) {
class Register(val index: Int, val variable: Variable)
val parameters = MutableList<Variable?>(32) { null }
val returns = MutableList<Variable?>(32) { null }
fun parameter(type: Type, name: String) {
parameter(parameters.indexOfFirst { it == null }, type, name)
}
fun parameter(index: Int, type: Type, name: String) {
parameters[index] = Variable(type, name)
}
fun returns(type: Type) {
returns(returns.indexOfFirst { it == null }, type)
}
fun returns(index: Int, type: Type) {
returns[index] = Variable(type, "result_${index}")
}
override fun toString(): String {
val text = StringBuilder()
val inputs = parameters
.mapIndexedNotNull { index, variable -> variable?.let { Register(index, it) } }
val outputs = returns
.mapIndexedNotNull { index, variable -> variable?.let { Register(index, it) } }
text.append("static inline ")
val returns = outputs.firstOrNull()
if (returns != null) {
text.append(returns.variable.type)
} else {
text.append(None)
}
text.append(" ")
text.append(name)
text.append("(")
if (inputs.isNotEmpty()) {
text.append("\n")
text.append(inputs.joinToString(",\n") { " ${it.variable.type} ${it.variable.name}" })
text.append("\n) {\n")
} else {
text.append(None)
text.append(") {\n")
}
outputs.forEach {
text.append(" ")
text.append(it.variable.type)
text.append(" ")
text.append(it.variable.name)
text.append(";\n")
}
inputs.forEach {
text.append(" ")
text.append("parameter(")
text.append(it.index)
text.append(", ")
text.append(it.variable.name)
text.append(");\n")
}
text.append(" ")
text.append("call(")
text.append("0x%08X".format(address.toInt()))
text.append(");\n")
outputs.forEach {
text.append(" ")
text.append("ret(")
text.append(it.index)
text.append(", ")
text.append(it.variable.name)
text.append(");\n")
}
if (returns != null) {
text.append(" ")
text.append("return ")
text.append(returns.variable.name)
text.append(";\n")
}
text.append("}\n")
return text.toString()
}
}
val source = StringBuilder()
source.append("#pragma once\n")
source.append("\n")
source.append("#include \"call.h\"\n")
source.append("\n")
fun comment(text: String) {
source.append("// ")
source.append(text)
source.append("\n\n")
}
fun constant(name: String, value: UInt) {
source.append("#define ")
source.append(name)
source.append(" ")
source.append("0x%08X".format(value.toInt()))
source.append("\n\n")
}
fun define(address: UInt, name: String, block: Function.() -> Unit) {
Function(address, name)
.also(block)
.also {
source.append(it)
source.append("\n")
}
}
// BEGIN FUNCTION DEFINITIONS
comment("fox32rom definitions")
comment("system jump table")
define(0xF0040000U, "get_rom_version") {
}
define(0xF0040004U, "system_vsync_handler") {
}
define(0xF0040008U, "get_mouse_position") {
}
define(0xF004000CU, "new_event") {
}
define(0xF0040010U, "wait_for_event") {
}
define(0xF0040014U, "get_next_event") {
}
define(0xF0040018U, "panic") {
}
define(0xF004001CU, "get_mouse_button") {
}
define(0xF0040020U, "scancode_to_ascii") {
}
define(0xF0040024U, "shift_pressed") {
}
define(0xF0040028U, "shift_released") {
}
define(0xF004002CU, "caps_pressed") {
}
define(0xF0040030U, "poweroff") {
}
comment("generic drawing jump table")
define(0xF0041000U, "draw_str_generic") {
}
define(0xF0041004U, "draw_format_str_generic") {
}
define(0xF0041008U, "draw_decimal_generic") {
}
define(0xF004100CU, "draw_hex_generic") {
}
define(0xF0041010U, "draw_font_tile_generic") {
}
define(0xF0041014U, "draw_tile_generic") {
}
define(0xF0041018U, "set_tilemap") {
}
define(0xF004101CU, "draw_pixel_generic") {
}
define(0xF0041020U, "draw_filled_rectangle_generic") {
}
define(0xF0041024U, "get_tilemap") {
}
comment("background jump table")
define(0xF0042000U, "fill_background") {
parameter(Word, "color")
}
define(0xF0042004U, "draw_str_to_background") {
parameter(Byte.ref, "str")
parameter(Word, "x")
parameter(Word, "y")
parameter(Word, "foreground_color")
parameter(Word, "background_color")
returns(1, Word)
}
define(0xF0042008U, "draw_format_str_to_background") {
parameter(Byte.ref, "str")
parameter(Word, "x")
parameter(Word, "y")
parameter(Word, "foreground_color")
parameter(Word, "background_color")
parameter(10, Word, "format_value_0")
parameter(11, Word, "format_value_1")
parameter(12, Word, "format_value_2")
parameter(13, Word, "format_value_3")
parameter(14, Word, "format_value_4")
parameter(15, Word, "format_value_5")
returns(1, Word)
}
define(0xF004200CU, "draw_decimal_to_background") {
parameter(Word, "value")
parameter(Word, "x")
parameter(Word, "y")
parameter(Word, "foreground_color")
parameter(Word, "background_color")
returns(1, Word)
}
define(0xF0042010U, "draw_hex_to_background") {
parameter(Word, "value")
parameter(Word, "x")
parameter(Word, "y")
parameter(Word, "foreground_color")
parameter(Word, "background_color")
returns(1, Word)
}
define(0xF0042014U, "draw_font_tile_to_background") {
parameter(Word, "tile")
parameter(Word, "x")
parameter(Word, "y")
parameter(Word, "foreground_color")
parameter(Word, "background_color")
}
define(0xF0042018U, "draw_tile_to_background") {
parameter(Word, "tile")
parameter(Word, "x")
parameter(Word, "y")
}
define(0xF004201CU, "draw_pixel_to_background") {
parameter(Word, "x")
parameter(Word, "y")
parameter(Word, "color")
}
define(0xF0042020U, "draw_filled_rectangle_to_background") {
parameter(Word, "x")
parameter(Word, "y")
parameter(Word, "width")
parameter(Word, "height")
parameter(Word, "color")
}
comment("overlay jump table")
define(0xF0043000U, "fill_overlay") {
}
define(0xF0043004U, "draw_str_to_overlay") {
}
define(0xF0043008U, "draw_format_str_to_overlay") {
}
define(0xF004300CU, "draw_decimal_to_overlay") {
}
define(0xF0043010U, "draw_hex_to_overlay") {
}
define(0xF0043014U, "draw_font_tile_to_overlay") {
}
define(0xF0043018U, "draw_tile_to_overlay") {
}
define(0xF004301CU, "draw_pixel_to_overlay") {
}
define(0xF0043020U, "draw_filled_rectangle_to_overlay") {
}
define(0xF0043024U, "check_if_overlay_covers_position") {
}
define(0xF0043028U, "check_if_enabled_overlay_covers_position") {
}
define(0xF004302CU, "enable_overlay") {
}
define(0xF0043030U, "disable_overlay") {
}
define(0xF0043034U, "move_overlay") {
}
define(0xF0043038U, "resize_overlay") {
}
define(0xF004303CU, "set_overlay_framebuffer_pointer") {
}
define(0xF0043040U, "get_unused_overlay") {
}
define(0xF0043044U, "make_coordinates_relative_to_overlay") {
}
comment("menu bar jump table")
define(0xF0044000U, "enable_menu_bar") {
}
define(0xF0044004U, "disable_menu_bar") {
}
define(0xF0044008U, "menu_bar_click_event") {
}
define(0xF004400CU, "clear_menu_bar") {
}
define(0xF0044010U, "draw_menu_bar_root_items") {
}
define(0xF0044014U, "draw_menu_items") {
}
define(0xF0044018U, "close_menu") {
}
define(0xF004401CU, "menu_update_event") {
}
comment("disk jump table")
define(0xF0045000U, "read_sector") {
}
define(0xF0045004U, "write_sector") {
}
define(0xF0045008U, "ryfs_open") {
}
define(0xF004500CU, "ryfs_seek") {
}
define(0xF0045010U, "ryfs_read") {
}
define(0xF0045014U, "ryfs_read_whole_file") {
}
define(0xF0045018U, "ryfs_get_size") {
}
define(0xF004501CU, "ryfs_get_file_list") {
}
define(0xF0045020U, "ryfs_tell") {
}
define(0xF0045024U, "ryfs_write") {
}
comment("memory copy/compare jump table")
define(0xF0046000U, "copy_memory_bytes") {
}
define(0xF0046004U, "copy_memory_words") {
}
define(0xF0046008U, "copy_string") {
}
define(0xF004600CU, "compare_memory_bytes") {
}
define(0xF0046010U, "compare_memory_words") {
}
define(0xF0046014U, "compare_string") {
}
define(0xF0046018U, "string_length") {
}
comment("integer jump table")
define(0xF0047000U, "string_to_int") {
}
comment("audio jump table")
define(0xF0048000U, "play_audio") {
}
define(0xF0048004U, "stop_audio") {
}
comment("random number jump table")
define(0xF0049000U, "random") {
returns(Word)
}
define(0xF0049004U, "random_range") {
parameter(1, Word, "minimum")
parameter(2, Word, "maximum")
returns(Word)
}
comment("keys")
constant("KEY_CTRL", 0x1DU)
constant("KEY_LSHIFT", 0x2AU)
constant("KEY_RSHIFT", 0x36U)
constant("KEY_CAPS", 0x3AU)
comment("fox32os definitions")
comment("system jump table")
define(0x00000810U, "get_os_version") {
}
comment("FXF jump table")
define(0x00000910U, "parse_fxf_binary") {
}
comment("task jump table")
define(0x00000A10U, "new_task") {
}
define(0x00000A14U, "yield_task") {
}
define(0x00000A18U, "end_current_task") {
}
define(0x00000A1CU, "get_current_task_id") {
}
define(0x00000A20U, "get_unused_task_id") {
}
define(0x00000A24U, "is_task_id_used") {
}
comment("memory jump table")
define(0x00000B10U, "allocate_memory") {
}
define(0x00000B14U, "free_memory") {
}
comment("window jump table")
define(0x00000C10U, "new_window") {
}
define(0x00000C14U, "destroy_window") {
}
define(0x00000C18U, "new_window_event") {
}
define(0x00000C1CU, "get_next_window_event") {
}
define(0x00000C20U, "draw_title_bar_to_window") {
}
define(0x00000C24U, "move_window") {
}
define(0x00000C28U, "fill_window") {
}
define(0x00000C2CU, "get_window_overlay_number") {
}
define(0x00000C30U, "start_dragging_window") {
}
define(0x00000C34U, "new_messagebox") {
}
define(0x00000C38U, "get_active_window_struct") {
}
comment("VFS jump table")
define(0x00000D10U, "open") {
}
define(0x00000D14U, "seek") {
}
define(0x00000D18U, "tell") {
}
define(0x00000D1CU, "read") {
}
define(0x00000D20U, "write") {
}
comment("widget jump table")
define(0x00000E10U, "draw_widgets_to_window") {
}
define(0x00000E14U, "handle_widget_click") {
}
comment("event types")
constant("EVENT_TYPE_MOUSE_CLICK", 0x00000000U)
constant("EVENT_TYPE_MOUSE_RELEASE", 0x00000001U)
constant("EVENT_TYPE_KEY_DOWN", 0x00000002U)
constant("EVENT_TYPE_KEY_UP", 0x00000003U)
constant("EVENT_TYPE_MENU_BAR_CLICK", 0x00000004U)
constant("EVENT_TYPE_MENU_UPDATE", 0x00000005U)
constant("EVENT_TYPE_MENU_CLICK", 0x00000006U)
constant("EVENT_TYPE_MENU_ACK", 0x00000007U)
constant("EVENT_TYPE_BUTTON_CLICK", 0x80000000U)
constant("EVENT_TYPE_EMPTY", 0xFFFFFFFFU)
comment("widget types")
constant("WIDGET_TYPE_BUTTON", 0x00000000U)
// END FUNCTION DEFINITIONS
println(source)

20
gcc/call.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#define STR2(x) #x
#define STR(x) STR2(x)
#define _call2(c, jt_addr) \
asm("li a0,ret_" #c "\n" \
"addi sp,sp,-4\n" \
"sw a0,0(sp)\n" \
"li a0,[" STR(jt_addr) "]\n" \
"jr a0\n" \
"ret_" #c ":" \
::: "a0" \
);
#define _call(c, jt_addr) _call2(c, jt_addr)
#define call(jt_addr) _call(__COUNTER__, jt_addr)
#define parameter(i, p) asm("mv x" #i ",%0" :: "r" (p) : "x" #i)
#define ret(i, var) asm("mv %0,x" #i : "=r" (var) :: "x" #i)