Skip to content
Snippets Groups Projects
Verified Commit 128e627d authored by rahix's avatar rahix
Browse files

feat: Use API for pycardium serial IO


Signed-off-by: default avatarRahix <rahix@rahix.de>
parent 1b4037ff
No related branches found
No related tags found
No related merge requests found
#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;
}
#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);
#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;
#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;
}
#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);
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()
#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 */
#include <stdio.h> #include <stdio.h>
#include "card10.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) int main(void)
{ {
card10_init(); card10_init();
card10_diag(); card10_diag();
printf("Initializing dispatcher ...\n");
api_dispatcher_init();
printf("Staring core1 payload ...\n"); printf("Staring core1 payload ...\n");
core1_start(); core1_start();
while(1) {
__WFE();
api_dispatcher_poll();
}
} }
name = 'epicardium' 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( elf = executable(
name + '.elf', name + '.elf',
'main.c', 'main.c',
dependencies: [libcard10, max32665_startup_core0], dependencies: [libcard10, max32665_startup_core0],
link_with: api_dispatcher_lib,
link_whole: [max32665_startup_core0_lib, board_card10_lib], link_whole: [max32665_startup_core0_lib, board_card10_lib],
link_args: [ link_args: [
'-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map', '-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map',
......
...@@ -53,7 +53,7 @@ executable( ...@@ -53,7 +53,7 @@ executable(
modsrc, modsrc,
mp_headers, mp_headers,
include_directories: micropython_includes, 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_whole: [max32665_startup_core1_lib, board_card10_lib],
link_with: upy, link_with: upy,
link_args: [ link_args: [
......
...@@ -6,24 +6,22 @@ ...@@ -6,24 +6,22 @@
#include "py/obj.h" #include "py/obj.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "epicardium.h"
/****************************************************************************** /******************************************************************************
* Serial Communication * Serial Communication
*/ */
/* TODO: Use API boundary instead of direct communication */
#include "uart.h"
extern mxc_uart_regs_t * ConsoleUart;
/* Receive single character */ /* Receive single character */
int mp_hal_stdin_rx_chr(void) int mp_hal_stdin_rx_chr(void)
{ {
return UART_ReadByte(ConsoleUart); return (int)epic_uart_read_chr();
} }
/* Send string of given length */ /* Send string of given length */
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) 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); ...@@ -60,12 +58,12 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
int _getpid(void) int _getpid(void)
{ {
; return -1;
} }
int _kill(int pid, int f) int _kill(int pid, int f)
{ {
; return -1;
} }
void _exit(int r) void _exit(int r)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment