Commit f76a575b authored by Federico Vaga's avatar Federico Vaga

sw:fw:frm: add app operations to execute firmware code

something like Arduino. This allows us to execute special code
before or after each operation
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 352a1d7a
......@@ -46,17 +46,6 @@ static struct trtl_fw_variable variables[] = {
},
};
static struct trtl_fw_application app = {
.name = "alarm-clk",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.variables = variables,
.n_variables = ARRAY_SIZE(variables),
};
static void ac_update(void)
......@@ -88,20 +77,19 @@ static void ac_update(void)
/**
* Firmware initialization
*/
static void ac_init(void)
static int ac_init(void)
{
period_c = period;
return 0;
}
/**
* Well, the main :)
*/
int main()
static int ac_main(void)
{
trtl_fw_init(&app);
ac_init();
while (1) {
/* Handle all messages incoming from HMQ 0 as actions */
trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
......@@ -111,3 +99,19 @@ int main()
return 0;
}
struct trtl_fw_application app = {
.name = "alarm-clk",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.variables = variables,
.n_variables = ARRAY_SIZE(variables),
.init = ac_init,
.main = ac_main,
};
......@@ -51,20 +51,6 @@ struct trtl_fw_buffer buffers[] = {
},
};
static struct trtl_fw_application app = {
.name = "data-gen",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.variables = variables,
.n_variables = ARRAY_SIZE(variables),
.buffers = buffers,
.n_buffers = ARRAY_SIZE(buffers),
};
static void generate_sample(void)
{
......@@ -98,24 +84,23 @@ static void dg_update(void)
/**
* Firmware initialization
*/
static void dg_init(void)
static int dg_init(void)
{
period_c = period;
dg_last_sample_idx = 0;
dg_last_sample = 1;
dg_conf.offset = 0;
dg_conf.gain = 1;
return 0;
}
/**
* Well, the main :)
*/
int main()
static int dg_main()
{
trtl_fw_init(&app);
dg_init();
while (1) {
/* Handle all messages incoming from HMQ 0 as actions */
trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
......@@ -125,3 +110,22 @@ int main()
return 0;
}
struct trtl_fw_application app = {
.name = "data-gen",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.variables = variables,
.n_variables = ARRAY_SIZE(variables),
.buffers = buffers,
.n_buffers = ARRAY_SIZE(buffers),
.init = dg_init,
.main = dg_main,
};
......@@ -68,40 +68,24 @@ struct trtl_fw_variable svec_variables[] = {
};
struct trtl_fw_application app = {
.name = "manualsvec",
.version = {
.rt_id = RT_APPLICATION_ID,
.rt_version = RT_VERSION(1, 0),
.git_version = GIT_VERSION
},
.buffers = svec_buffers,
.n_buffers = ARRAY_SIZE(svec_buffers),
.variables = svec_variables,
.n_variables = ARRAY_SIZE(svec_variables),
};
/**
* It sends messages over the debug interface
*/
static void svec_debug_interface(void)
static int svec_debug_interface(void)
{
pp_printf("Hello world.\n\r");
pp_printf("We are messages over the serial interface.\n\r");
pp_printf("Print here your messages.\n\r");
return 0;
}
/**
* Well, the main :)
*/
int main()
static int svec_main()
{
trtl_fw_init(&app);
svec_debug_interface();
while (1) {
/* Handle all messages incoming from HMQ 0 as actions */
trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
......@@ -109,3 +93,22 @@ int main()
return 0;
}
struct trtl_fw_application app = {
.name = "manualsvec",
.version = {
.rt_id = RT_APPLICATION_ID,
.rt_version = RT_VERSION(1, 0),
.git_version = GIT_VERSION
},
.buffers = svec_buffers,
.n_buffers = ARRAY_SIZE(svec_buffers),
.variables = svec_variables,
.n_variables = ARRAY_SIZE(svec_variables),
.init = svec_debug_interface,
.main = svec_main,
};
......@@ -6,22 +6,18 @@
#include <mockturtle-framework.h>
static struct trtl_fw_application app = {
.name = "hellofrm",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION,
},
};
static int frm_init()
{
pp_printf("Hello world!\r\n");
return 0;
}
/**
* Well, the main :)
*/
int main()
static int frm_main()
{
trtl_fw_init(&app);
while (1) {
/*
* Handle all messages incoming from slot 0
......@@ -32,3 +28,16 @@ int main()
return 0;
}
struct trtl_fw_application app = {
.name = "hellofrm",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION,
},
.init = frm_init,
.main = frm_main,
};
......@@ -25,11 +25,46 @@ Application
===========
Firmwares developed with this framework need to be described by
:c:type:`trtl_fw_application`. You should declare a new :c:type:`trtl_fw_application`
and initialize it using :c:func:`trtl_fw_init` .::
:c:type:`trtl_fw_application`. Firmware applications develop with this
framework does not have a ``main()``. The ``main()`` is implemented within the
framework itself. What you should do is to declare a new
:c:type:`trtl_fw_application` named **app** and implement the operations
*init*, *main* and *exit*. These operations are all optional, it means that if
you do not implement them nothing will be executed.
.. graphviz::
:align: center
:caption: Mock Turtle Firmware Framework Phases.
digraph phases {
init -> main;
main -> exit;
}
Here an example.::
#include <mockturtle-framework.h>
static init myinit()
{
return 0;
}
static int mymain()
{
while (1) {
/* main code here */
}
return 0;
}
static init myexit()
{
return 0;
}
struct trtl_application app = {
.name = "myfirmware",
.fpga_id_compat = NULL,
......@@ -39,14 +74,12 @@ and initialize it using :c:func:`trtl_fw_init` .::
.version = RT_VERSION(1, 0),
.git = GIT_VERSION,
},
};
int main()
{
trtl_dw_init(&app);
.init = myinit,
.main = mymain,
.exit = myexit,
};
return 0;
}
The Mock Turtle is FPGA based, this means that the firmwares are
typically loaded by the host. The procedure is error prone, so it may
......@@ -63,8 +96,6 @@ not provide a compatibility list (like in the example above).
.. doxygenstruct:: trtl_fw_version
:members:
.. doxygenfunction:: trtl_fw_init
Actions
========
......@@ -122,19 +153,9 @@ RPC messages on a given mq. Here an example.::
/* ... */
};
/* POINT [4]*/
struct trtl_application app = {
/* ... */
/* Export Actions */
.actions = actions,
.n_actions = ARRAY_SIZE(actions),
};
int main()
static int mymain()
{
int err;
trtl_fw_init(&app);
while (1) {
/* ... */
......@@ -145,6 +166,19 @@ RPC messages on a given mq. Here an example.::
return 0;
}
/* POINT [4]*/
struct trtl_application app = {
/* ... */
/* Export Actions */
.actions = actions,
.n_actions = ARRAY_SIZE(actions),
.main = mymain,
};
.. doxygentypedef:: trtl_fw_action_t
.. doxygenfunction:: trtl_fw_mq_action_dispatch
......@@ -195,14 +229,7 @@ be used to dispatch incoming actions::
},
};
struct trtl_fw_application app = {
/* ... */
.variables = variables,
.n_variable = ARRAY_SIZE(variables),
};
int main()
static int mymain()
{
/* ... */
......@@ -214,6 +241,15 @@ be used to dispatch incoming actions::
return 0;
}
struct trtl_fw_application app = {
/* ... */
.variables = variables,
.n_variable = ARRAY_SIZE(variables),
.main = mymain,
};
The user can define any number of variables, the firmware framework does
not impose any constraint.
......@@ -269,18 +305,8 @@ be used to dispatch incoming actions::
},
};
/* ... */
struct trtl_fw_application app = {
/* ... */
.buffers = buffers,
.n_buffer = ARRAY_SIZE(buffers),
};
int main()
static int mymain()
{
/* ... */
......@@ -292,6 +318,15 @@ be used to dispatch incoming actions::
return 0;
}
struct trtl_fw_application app = {
/* ... */
.buffers = buffers,
.n_buffer = ARRAY_SIZE(buffers),
.main = mymain,
};
The user can define any number of buffers, the firmware framework does
not impose any constraint.
......
......@@ -11,7 +11,6 @@
#include <mockturtle-framework.h>
uint32_t msg_seq = 0;
struct trtl_fw_application *_app;
/**
* It makes the given message an error message
......@@ -42,7 +41,7 @@ static int rt_version_getter(struct trtl_fw_msg *msg_i, struct trtl_fw_msg *msg_
{
msg_o->header->msg_id = TRTL_MSG_ID_VER;
msg_o->header->len = sizeof(struct trtl_fw_version) / 4;
memcpy(msg_o->payload, (void *)&_app->version,
memcpy(msg_o->payload, (void *)&app.version,
sizeof(struct trtl_fw_version));
return 0;
}
......@@ -79,15 +78,15 @@ static int trtl_fw_buffer_getter(struct trtl_fw_msg *msg_i, struct trtl_fw_msg *
size = din[offset];
dout[offset++] = size;
pr_debug("%s Type %d Len %d Addr 0x%p\n\r", __func__,
index, size, _app->buffers[index].buf);
index, size, app.buffers[index].buf);
if (_app->buffers[index].len == size) {
if (app.buffers[index].len == size) {
memcpy(&dout[offset],
(uint32_t *)_app->buffers[index].buf,
(uint32_t *)app.buffers[index].buf,
size);
} else {
pr_error("%s: structure %d len not correct %"PRId32" != %d\n\r",
__func__, index, _app->buffers[index].len, size);
__func__, index, app.buffers[index].len, size);
}
offset += (size / 4); /* Next TLV record */
......@@ -121,15 +120,15 @@ static int trtl_fw_buffer_setter(struct trtl_fw_msg *msg_i, struct trtl_fw_msg *
size = din[offset++];
pr_debug("%s Type %d Len %d Addr 0x%p\n\r", __func__,
index, size, _app->buffers[index].buf);
index, size, app.buffers[index].buf);
if (_app->buffers[index].len == size) {
memcpy((uint32_t *)_app->buffers[index].buf,
if (app.buffers[index].len == size) {
memcpy((uint32_t *)app.buffers[index].buf,
&din[offset], size);
} else {
pr_error("%s:%d structure %d len not correct %"PRId32" != %d\n\r",
__func__, __LINE__, index,
_app->buffers[index].len, size);
app.buffers[index].len, size);
}
offset += (size / 4); /* Next TLV record */
......@@ -173,19 +172,19 @@ static int trtl_fw_variable_getter(struct trtl_fw_msg *msg_i, struct trtl_fw_msg
/* Write all values in the proper place */
for (i = 0; i < msg_o->header->len; i += 2) {
if (din[i] >= _app->n_variables) {
if (din[i] >= app.n_variables) {
dout[i] = ~0; /* Report invalid index */
continue;
}
dout[i] = din[i];
var = &_app->variables[dout[i]];
var = &app.variables[dout[i]];
mem = (uint32_t *) var->addr;
val = (*mem >> var->offset) & var->mask;
dout[i + 1] = val;
pr_debug("%s index %"PRIu32"d/%d | [0x%p] = 0x%08"PRIx32" -> 0x%08"PRIx32" | index in msg (%d/%d)\n\r",
__func__,
dout[i], _app->n_variables - 1,
dout[i], app.n_variables - 1,
mem, *mem, dout[i + 1],
i + 1, msg_i->header->len - 1);
}
......@@ -217,9 +216,9 @@ static int trtl_fw_variable_setter(struct trtl_fw_msg *msg_i, struct trtl_fw_msg
/* Write all values in the proper place */
for (i = 0; i < msg_i->header->len; i += 2) {
if (din[i] >= _app->n_variables)
if (din[i] >= app.n_variables)
continue;
var = &_app->variables[din[i]];
var = &app.variables[din[i]];
mem = (uint32_t *) var->addr;
val = ((din[i + 1] & var->mask) << var->offset);
if (var->flags & TRTL_FW_VARIABLE_FLAG_FLD)
......@@ -229,7 +228,7 @@ static int trtl_fw_variable_setter(struct trtl_fw_msg *msg_i, struct trtl_fw_msg
pr_debug("%s index %"PRIu32"/%d | [0x%p] = 0x%08"PRIx32" <- 0x%08"PRIx32" (0x%08"PRIx32") | index in msg (%d/%d)\n\r",
__func__,
din[i], _app->n_variables - 1,
din[i], app.n_variables - 1,
mem, *mem, val, din[i + 1],
i + 1, msg_i->header->len - 1);
}
......@@ -267,12 +266,12 @@ static inline trtl_fw_action_t *rt_action_get(unsigned int msg_id)
if (idx_act < __TRTL_MSG_ID_MAX_USER) {
/* User Actions */
if (idx_act >= _app->n_actions || !_app->actions[idx_act]) {
if (idx_act >= app.n_actions || !app.actions[idx_act]) {
pr_error("Unknown action (usr) msg_id 0x%x\n\r",
msg_id);
return NULL;
}
return _app->actions[idx_act];
return app.actions[idx_act];
} else {
/* Mock Turtle Standard Actions */
idx_act -= __TRTL_MSG_ID_MAX_USER;
......@@ -316,12 +315,12 @@ static inline int rt_action_run(enum trtl_mq_type type,
mq_map_out_message(type, idx_mq, &msg_out);
/* prepare the header */
msg_out.header->rt_app_id = _app->version.rt_id;
msg_out.header->rt_app_id = app.version.rt_id;
msg_out.header->flags = TRTL_HMQ_HEADER_FLAG_ACK;
msg_out.header->msg_id = 0;
msg_out.header->len = 0;
msg_out.header->sync_id = msg->header->sync_id;
msg_out.header->seq = _app->seq++;
msg_out.header->seq = app.seq++;
err = action(msg, &msg_out);
if (err)
......@@ -363,7 +362,7 @@ int trtl_fw_mq_action_dispatch(enum trtl_mq_type type, unsigned int idx_mq)
}
if (msg.header->rt_app_id &&
msg.header->rt_app_id != _app->version.rt_id) {
msg.header->rt_app_id != app.version.rt_id) {
pr_error("Invalid app id 0x%x\n\r",
msg.header->rt_app_id);
err = -EINVAL;
......@@ -398,18 +397,18 @@ int trtl_fw_mq_send_uint32(enum trtl_mq_type type,
va_list ap;
int i;
sizes = _app->cfgrom->hmq[trtl_get_core_id()][idx_mq].sizes;
sizes = app.cfgrom->hmq[trtl_get_core_id()][idx_mq].sizes;
if (n > TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(sizes))
return -EINVAL;
mq_claim(type, idx_mq);
mq_map_out_message(type, idx_mq, &msg);
msg.header->rt_app_id = _app->version.rt_id;
msg.header->rt_app_id = app.version.rt_id;
msg.header->flags = 0;
msg.header->msg_id = msg_id;
msg.header->len = n;
msg.header->seq = _app->seq++;
msg.header->seq = app.seq++;
va_start(ap, n);
for (i = 0; i < msg.header->len;++i)
......@@ -441,18 +440,18 @@ int trtl_fw_mq_send_buf(enum trtl_mq_type type,
struct trtl_fw_msg msg;
uint32_t sizes;
sizes = _app->cfgrom->hmq[trtl_get_core_id()][idx_mq].sizes;
sizes = app.cfgrom->hmq[trtl_get_core_id()][idx_mq].sizes;
if ((n / 4) > TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(sizes))
return -EINVAL;
mq_claim(type, idx_mq);
mq_map_out_message(type, idx_mq, &msg);
msg.header->rt_app_id = _app->version.rt_id;
msg.header->rt_app_id = app.version.rt_id;
msg.header->flags = 0;
msg.header->msg_id = msg_id;
msg.header->len = n / 4;
msg.header->seq = _app->seq++;
msg.header->seq = app.seq++;
memcpy(msg.payload, data, n);
mq_send(type, idx_mq);
......@@ -536,13 +535,13 @@ static inline int trtl_fw_init_action(struct trtl_fw_application *app)
int i;
/* Validate actions */
for (i = 0; i < _app->n_actions; ++i) {
for (i = 0; i < app->n_actions; ++i) {
if (i > __TRTL_MSG_ID_MAX_USER) {
pr_error("Too many actions defined. Maximum '%d'\n\r",
__TRTL_MSG_ID_MAX_USER);
return -EINVAL;
}
if (_app->actions[i] == NULL) {
if (app->actions[i] == NULL) {
pr_error("Undefined action %d\n\r", i);
return -EINVAL;
}
......@@ -650,33 +649,67 @@ static inline int trtl_fw_init_buffers(struct trtl_fw_application *app)
* @param[in] app application to initialize
* @return 0 on success. -1 on error
*/
int trtl_fw_init(struct trtl_fw_application *app)
int trtl_fw_init(void)
{
int err;
_app = app;
_app->seq = 0;
_app->cfgrom = trtl_config_rom_get();
app.seq = 0;
app.cfgrom = trtl_config_rom_get();
err = trtl_fw_init_action(_app);
err = trtl_fw_init_action(&app);
if (err)
return err;
err = trtl_fw_init_fpga(_app);
err = trtl_fw_init_fpga(&app);
if (err)
return err;
err = trtl_fw_init_mq(_app);
err = trtl_fw_init_mq(&app);
if (err)
return err;
err = trtl_fw_init_buffers(_app);
err = trtl_fw_init_buffers(&app);
if (err)
return err;
err = trtl_fw_init_variables(_app);
err = trtl_fw_init_variables(&app);
if (err)
return err;
return 0;
}
/**
* The main function
*/
int main(void)
{
int err = 0;
trtl_notify(TRTL_CPU_NOTIFY_INIT);
trtl_fw_init();
if (app.init){
err = app.init();
if (err)
return -1;
}
trtl_notify(TRTL_CPU_NOTIFY_MAIN);
if (app.main) {
err = app.main();
if (err)
return -1;
}
trtl_notify(TRTL_CPU_NOTIFY_EXIT);
if (app.exit) {
err = app.exit();
if (err)
return -1;
}
return 0;
}
......@@ -29,6 +29,13 @@
*/
typedef int (trtl_fw_action_t)(struct trtl_fw_msg *msg_i, struct trtl_fw_msg *msg_o);
/**
* Application phase
* @return 0 on success. -1 on error
*/
typedef int (trtl_fw_phase_t)(void);
/**
* Variable flag. Register
*/
......@@ -81,12 +88,29 @@ struct trtl_fw_application {
unsigned int seq; /** sequence number reference */
const struct trtl_config_rom *cfgrom; /**< configuration ROM */
/* Operations */
trtl_fw_phase_t *init; /**< function where you prepare
the application */
trtl_fw_phase_t *main; /**< function where you execute your
application */
trtl_fw_phase_t *exit; /**< function where you clean-up firmware
status */
};
extern struct trtl_fw_application *_app;
extern struct trtl_fw_application app;
/**
* It returns the application descriptor
* @return application descriptor
*/
static inline struct trtl_fw_application *trtl_fw_application_get(void)
{
return &app;
}
extern int trtl_fw_init(struct trtl_fw_application *app);
extern void trtl_fw_time(uint32_t *seconds, uint32_t *cycles);
extern void trtl_fw_print_header(struct trtl_hmq_header *h);
extern void trtl_fw_print_data(uint32_t *d, unsigned int count);
......
......@@ -41,6 +41,11 @@
enum trtl_cpu_notification {
TRTL_CPU_NOTIFY_APPLICATION = 0, /**< anonymous application
notification (user) */
TRTL_CPU_NOTIFY_INIT, /**< the firmware is executing init phase */
TRTL_CPU_NOTIFY_MAIN, /**< the firmware is executing main phase */
TRTL_CPU_NOTIFY_EXIT, /**< the firmware is executing exit finishing */
TRTL_CPU_NOTIFY_ERR, /**< general error, firmware is not running
anymore */
__TRTL_CPU_NOTIFY_MAX,
};
......
......@@ -28,31 +28,20 @@ static trtl_fw_action_t *actions[] = {
};
static struct trtl_fw_application app = {
.name = "{{short_name}}",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.buffers = buffers,
.n_buffers = ARRAY_SIZE(buffers),
.variables = variables,
.n_variables = ARRAY_SIZE(variables),
.actions = actions,
.n_actions = ARRAY_SIZE(actions),
};
/**
* Initialization code
*/
static int {{short_name}}_init()
{
return 0;
}
/**
* Well, the main :)
*/
int main()
static int {{short_name}}_main()
{
trtl_fw_init(&app);
while (1) {
/*
* Handle all messages incoming from slot
......@@ -63,3 +52,34 @@ int main()
return 0;
}
/**
* Exit code
*/
static int {{short_name}}_exit()
{
return 0;
}
struct trtl_fw_application app = {
.name = "{{short_name}}",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.buffers = buffers,
.n_buffers = ARRAY_SIZE(buffers),
.variables = variables,
.n_variables = ARRAY_SIZE(variables),
.actions = actions,
.n_actions = ARRAY_SIZE(actions),
.init = {{short_name}}_init,
.main = {{short_name}}_main,
.exit = {{short_name}}_exit,
};
......@@ -6,22 +6,12 @@
#include <mockturtle-framework.h>
static struct trtl_fw_application app = {
.name = "hellofrm",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
};
/**
* Well, the main :)
*/
int main()
static int ping_main()
{
trtl_fw_init(&app);
while (1) {
/* Handle all messages incoming from HMQ 0 as actions */
trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
......@@ -29,3 +19,15 @@ int main()
return 0;
}
struct trtl_fw_application app = {
.name = "hellofrm",
.version = {
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.main = ping_main,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment