diff --git a/epicardium/api/caller.c b/epicardium/api/caller.c new file mode 100644 index 0000000000000000000000000000000000000000..3b6d27b9a2ca277b9fa8607c9cdb92202e105d54 --- /dev/null +++ b/epicardium/api/caller.c @@ -0,0 +1,39 @@ +#include <stdlib.h> +#include "sema.h" +#include "api/caller.h" + +void*_api_call_start(api_id_t id, uintptr_t size) +{ + while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {} + + /* TODO: Check flag */ + + API_CALL_MEM->id = id; + return API_CALL_MEM->buffer; +} + +void*_api_call_transact(void*buffer) +{ + API_CALL_MEM->call_flag = _API_FLAG_CALLING; + SEMA_FreeSema(_API_SEMAPHORE); + + /* Notify the dispather of the new call */ + __SEV(); + __WFE(); + + while (1) { + /* Wait for the dispather to return */ + __WFE(); + + while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {} + if (API_CALL_MEM->call_flag == _API_FLAG_RETURNED) { + break; + } + SEMA_FreeSema(_API_SEMAPHORE); + } + + API_CALL_MEM->call_flag = _API_FLAG_IDLE; + SEMA_FreeSema(_API_SEMAPHORE); + + return API_CALL_MEM->buffer; +} diff --git a/epicardium/api/caller.h b/epicardium/api/caller.h new file mode 100644 index 0000000000000000000000000000000000000000..092f2fa7b21ae06ef9f3346eda16b749a569cd8d --- /dev/null +++ b/epicardium/api/caller.h @@ -0,0 +1,29 @@ +#include <stdint.h> +#include "api/common.h" + +/* + * Initiate an API call. This function is used internally by code + * generated from the API header. + * + * Args: + * - id: ID of the call to be initiated + * - size: Size of the arguments buffer + * + * Returns: + * - A pointer to the argument buffer which the caller is supposed + * to fill. NULL if an error occured or no buffer of the requested + * size is available. + */ +void*_api_call_start(api_id_t id, uintptr_t size); + +/* + * Actually do the API call that was previously initiated using + * _api_call_start(). + * + * Args: + * - buffer: Pointer to the buffer that was returned by _api_call_start(). + * + * Returns: + * - Pointer to a buffer containing the return value + */ +void*_api_call_transact(void*buffer); diff --git a/epicardium/api/common.h b/epicardium/api/common.h new file mode 100644 index 0000000000000000000000000000000000000000..70b24a35a067b417939f3008c17f0b2a19cf26f0 --- /dev/null +++ b/epicardium/api/common.h @@ -0,0 +1,39 @@ +#include <stdint.h> + +/* + * Semaphore used for API synchronization. + * TODO: Replace this with a LDREX/STREX based implementation + */ +#define _API_SEMAPHORE 0 + +/* Type of API IDs */ +typedef uint32_t api_id_t ; + +#define _API_FLAG_IDLE 0 +#define _API_FLAG_CALLING 1 +#define _API_FLAG_RETURNED 2 + +/* Layout of the shared memory for API calls */ +struct api_call_mem { + /* + * Flag for synchronization of API calls. When this flag + * is set, the caller has issued a call and is waiting for + * the dispatcher to reset the flag. + */ + uint8_t call_flag; + + /* ID if the ongoing API call */ + api_id_t id; + + /* + * Buffer for arguments/return value. This buffer will be + * *overflown*, because there is guaranteed space behind it. + * + * TODO: Add a maximum bounds check + */ + uint8_t buffer[1]; +}; + +/* TODO: Make this address part of the linker script */ +static __attribute__((unused)) struct api_call_mem* API_CALL_MEM = + (struct api_call_mem*)0x20080000; diff --git a/epicardium/api/dispatcher.c b/epicardium/api/dispatcher.c new file mode 100644 index 0000000000000000000000000000000000000000..d499bd16f261689a667a1ebf95c6bd1da3b8e281 --- /dev/null +++ b/epicardium/api/dispatcher.c @@ -0,0 +1,42 @@ +#include <stdlib.h> +#include "sema.h" +#include "api/dispatcher.h" + +int api_dispatcher_init() +{ + int ret; + + ret = SEMA_Init(NULL); + API_CALL_MEM->call_flag = _API_FLAG_IDLE; + + /* + * Enable TX events for both cores. + * TODO: Is this the right place? + */ + MXC_GCR->evten |= 0x24; + + return ret; +} + +api_id_t api_dispatcher_poll() +{ + api_id_t id = 0; + while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {} + + if (API_CALL_MEM->call_flag != _API_FLAG_CALLING) { + SEMA_FreeSema(_API_SEMAPHORE); + return 0; + } + + id = API_CALL_MEM->id; + __api_dispatch_call(id, API_CALL_MEM->buffer); + API_CALL_MEM->call_flag = _API_FLAG_RETURNED; + + SEMA_FreeSema(_API_SEMAPHORE); + + /* Notify the caller that we returned */ + __SEV(); + __WFE(); + + return id; +} diff --git a/epicardium/api/dispatcher.h b/epicardium/api/dispatcher.h new file mode 100644 index 0000000000000000000000000000000000000000..1385b719487b578f93c7294ba0b7863822aab265 --- /dev/null +++ b/epicardium/api/dispatcher.h @@ -0,0 +1,17 @@ +#include "api/common.h" + +/* + * Initialize the API system. This function *must* be called + * before any API action can take place. + */ +int api_dispatcher_init(); + +/* + * Attempt to dispatch a call, if the caller has requested one. + * Will return 0 if no call was dispatched and the ID of the dispatched + * call otherwise. + */ +api_id_t api_dispatcher_poll(); + +/* This function is defined by the generated dispatcher code */ +void __api_dispatch_call(api_id_t id, void*buffer); diff --git a/epicardium/api/genapi.py b/epicardium/api/genapi.py new file mode 100644 index 0000000000000000000000000000000000000000..5adddf8fcf725744b14ae91e4779ffbbb72f8399 --- /dev/null +++ b/epicardium/api/genapi.py @@ -0,0 +1,189 @@ +import argparse +import contextlib +import os +import re +import subprocess + + +def main(): + parser = argparse.ArgumentParser( + description="Generate the API stubs from a header file." + ) + parser.add_argument( + "-H", "--header", required=True, help="The header to base the definitions on." + ) + parser.add_argument( + "-c", "--client", required=True, help="The output client-side c source file." + ) + parser.add_argument( + "-s", "--server", required=True, help="The output server-side c source file." + ) + args = parser.parse_args() + + with contextlib.ExitStack() as cx: + # Run the preprocessor on the header file to get the API definitions. + # + # For this, we first need a source to include the header which contains + # an alternative definition of the `API` macro that marks definitions in + # a way we can find later on. + api_src = """\ +#define API(id, def) __GENERATE_API $ __GEN_ID_##id $ def $ +#include "{header}" +""".format( + header=os.path.relpath(args.header) + ) + + # Evaluate the preprocessor + source = subprocess.check_output( + ["gcc", "-E", "-"], input=api_src.encode() + ).decode() + + # Parse the header for API definitions + matcher = re.compile( + r"__GENERATE_API \$ __GEN_ID_(?P<id>\w+) \$ (?P<type>\w+(?:\*+|\s+))(?P<decl>.+?)\((?P<args>.*?)\) \$", + re.DOTALL | re.MULTILINE, + ) + + args_matcher = re.compile(r"(?P<type>\w+(?:\*+|\s+))(?P<name>\w+),") + + # Open output files + f_client = cx.enter_context(open(args.client, "w")) + f_server = cx.enter_context(open(args.server, "w")) + + print("""\ +#include <stdio.h> + +#include "{}" +#include "api/caller.h" +""".format( + os.path.basename(args.header) + ), file=f_client) + + print("""\ +#include <stdio.h> +#include "{}" + +void __api_dispatch_call(uint32_t id, void*buffer) +{{ + switch (id) {{""".format( + os.path.basename(args.header) + ), file=f_server) + + for match in matcher.finditer(source): + api_id = match.group("id") + api_return = match.group("type").strip() + api_decl = match.group("decl") + api_args = match.group("args") + + api_args_names = [] + api_args_types = [] + api_args_sizes = [] + + # Destructure args + for match in args_matcher.finditer(api_args + ","): + arg_type = match.group("type").strip() + arg_name = match.group("name") + + api_args_names.append(arg_name) + api_args_types.append(arg_type) + api_args_sizes.append("sizeof({})".format(arg_type)) + + print( + """\ +/* Autogenerated stub for {id} */ +{ret} {cdecl}({cargs}) +{{ + const int size = {total_size}; + void*buffer; + + buffer = _api_call_start({id}, size); + /* TODO: Check if buffer is no NULL */ +""".format( + id=api_id, + ret=api_return, + cdecl=api_decl, + cargs=api_args, + total_size=" + ".join(api_args_sizes) if api_args_sizes != [] else "0", + ), + file=f_client, + ) + + if api_return != "void": + print("""\ + case {id}: + *(({ret}*)buffer) = {cdecl}(""".format(id=api_id, ret=api_return, cdecl=api_decl), + file=f_server, + ) + else: + print("""\ + case {id}: + {cdecl}(""".format(id=api_id, ret=api_return, cdecl=api_decl), + file=f_server, + ) + + for i, (arg, ty) in enumerate(zip(api_args_names, api_args_types)): + print( + """ *({type}*)(buffer + {offset}) = {arg};""".format( + type=ty, + offset=" + ".join(api_args_sizes[:i]) if i > 0 else "0", + arg=arg, + ), + file=f_client, + ) + + if i != 0: + print(",", file=f_server) + + print( + """\ + *({type}*)(buffer + {offset})""".format( + type=ty, + offset=" + ".join(api_args_sizes[:i]) if i > 0 else "0", + ), + file=f_server, + end="", + ) + + print(""" + ); + break;""".format( + cdecl=api_decl, + args=", ".join(api_args_names), + ), + file=f_server, + ) + + if api_return != "void": + print( + """ + return *({ret}*)_api_call_transact(buffer); +}} +""".format( + id=api_id, + ret=api_return, + ), + file=f_client, + ) + else: + print( + """ + _api_call_transact(buffer); +}} +""".format( + id=api_id, + ), + file=f_client, + ) + + print("""\ + default: + printf("Error: API function %x is unknown!!\\n", {id}); + break; + }} +}}""".format( + id=api_id, + ), file=f_server) + + +if __name__ == "__main__": + main() diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h new file mode 100644 index 0000000000000000000000000000000000000000..ee5900f2142569845b2b3303115a33197902c814 --- /dev/null +++ b/epicardium/epicardium.h @@ -0,0 +1,15 @@ +#ifndef _EPICARDIUM_H +#define _EPICARDIUM_H +#include <stdint.h> + +#ifndef API +# define API(id, def) def +#endif + +#define API_UART_WRITE 0x1 +API(API_UART_WRITE, void epic_uart_write_str(char*str, intptr_t length)); + +#define API_UART_READ 0x2 +API(API_UART_READ, char epic_uart_read_chr(void)); + +#endif /* _EPICARDIUM_H */ diff --git a/epicardium/main.c b/epicardium/main.c index cb2051e3dc996aa63dd66e9d242bd45dddab8427..627d876345f860f78a87b15e810fe1cff6496f2c 100644 --- a/epicardium/main.c +++ b/epicardium/main.c @@ -1,11 +1,33 @@ #include <stdio.h> #include "card10.h" +#include "uart.h" +#include "api/dispatcher.h" + +extern mxc_uart_regs_t * ConsoleUart; + +void epic_uart_write_str(char*str, intptr_t length) +{ + UART_Write(ConsoleUart, (uint8_t*)str, length); +} + +char epic_uart_read_chr(void) +{ + return UART_ReadByte(ConsoleUart); +} int main(void) { card10_init(); card10_diag(); + printf("Initializing dispatcher ...\n"); + api_dispatcher_init(); + printf("Staring core1 payload ...\n"); core1_start(); + + while(1) { + __WFE(); + api_dispatcher_poll(); + } } diff --git a/epicardium/meson.build b/epicardium/meson.build index 51cc66740759e53e22892ffe8bda02db19e857af..767c9c4f9273203af677cc1dcc10775721510f60 100644 --- a/epicardium/meson.build +++ b/epicardium/meson.build @@ -1,9 +1,55 @@ name = 'epicardium' +########################################################################## +# +# API +# +########################################################################## + +api = custom_target( + 'api_*.c', + input: 'epicardium.h', + output: ['api_caller.c', 'api_dispatcher.c'], + command: [ + python3, + meson.current_source_dir() + '/api/genapi.py', + '-H', '@INPUT0@', + '-c', '@OUTPUT0@', '-s', '@OUTPUT1@', + ], + depend_files: 'api/genapi.py', +) + +api_caller_lib = static_library( + 'api-caller', + 'api/caller.c', + api[0], # Caller + dependencies: periphdriver, +) + +api_caller = declare_dependency( + include_directories: include_directories('.'), + link_with: api_caller_lib, + dependencies: periphdriver, +) + +api_dispatcher_lib = static_library( + 'api-dispatcher', + 'api/dispatcher.c', + api[1], # Dispatcher + dependencies: periphdriver, +) + +########################################################################## +# +# Epicardium executable +# +########################################################################## + elf = executable( name + '.elf', 'main.c', dependencies: [libcard10, max32665_startup_core0], + link_with: api_dispatcher_lib, link_whole: [max32665_startup_core0_lib, board_card10_lib], link_args: [ '-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map', diff --git a/hw-tests/meson.build b/hw-tests/meson.build index 0523f5006d3e9a55b000f276564ad5a052db24de..ed36cc1c1834553585dc5a8ca578477914520a12 100644 --- a/hw-tests/meson.build +++ b/hw-tests/meson.build @@ -1,4 +1,5 @@ -subdir('api-demo/') +# Disabled due to meson bug in older version +# subdir('api-demo/') subdir('bmatest/') subdir('bmetest/') subdir('dual-core/') @@ -7,4 +8,5 @@ subdir('hello-freertos/') subdir('hello-world/') subdir('imutest/') subdir('ips/') -subdir('upy-minimal/') +# Disabled due to meson bug in older version +# subdir('upy-minimal/') diff --git a/pycardium/meson.build b/pycardium/meson.build index 7bb11316fe865e7bbf1dae740eddb15dd950ffcd..de4d35be675fff87f3276424068a6fb609d91e0c 100644 --- a/pycardium/meson.build +++ b/pycardium/meson.build @@ -53,7 +53,7 @@ executable( modsrc, mp_headers, include_directories: micropython_includes, - dependencies: [max32665_startup_core1, board_card10, periphdriver], + dependencies: [max32665_startup_core1, board_card10, periphdriver, api_caller], link_whole: [max32665_startup_core1_lib, board_card10_lib], link_with: upy, link_args: [ diff --git a/pycardium/mphalport.c b/pycardium/mphalport.c index 5f69a7d2f656d01b5147a2a78745e99560fd6ef7..26521235cd2e98cd7c0309b02cef57b8b48a0524 100644 --- a/pycardium/mphalport.c +++ b/pycardium/mphalport.c @@ -6,24 +6,22 @@ #include "py/obj.h" #include "py/runtime.h" +#include "epicardium.h" + /****************************************************************************** * Serial Communication */ -/* TODO: Use API boundary instead of direct communication */ -#include "uart.h" -extern mxc_uart_regs_t * ConsoleUart; - /* Receive single character */ int mp_hal_stdin_rx_chr(void) { - return UART_ReadByte(ConsoleUart); + return (int)epic_uart_read_chr(); } /* Send string of given length */ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { - UART_Write(ConsoleUart, (uint8_t*)str, len); + epic_uart_write_str(str, len); } /****************************************************************************** @@ -60,12 +58,12 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); int _getpid(void) { - ; + return -1; } int _kill(int pid, int f) { - ; + return -1; } void _exit(int r)