Commit 475bc35d authored by Federico Vaga's avatar Federico Vaga

sw:rt redesign and re-organization

It compiles ... still to be tested, the HDL is not ready yet
parents c6c69f99 05f17114
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* License: GPLv3 * License: GPLv3
*/ */
#include <mockturtle-rt-smem.h>
#include <mockturtle-framework.h> #include <mockturtle-framework.h>
static unsigned int iteration; static unsigned int iteration;
...@@ -13,31 +12,6 @@ static unsigned int period = 1000000; ...@@ -13,31 +12,6 @@ static unsigned int period = 1000000;
static unsigned int alarm_enable; static unsigned int alarm_enable;
static uint32_t alarm_iter; static uint32_t alarm_iter;
enum rt_slot_name {
AC_CMD_IN = 0,
AC_CMD_OUT,
AC_DATA,
};
static struct rt_mq mq[] = {
[AC_CMD_IN] = {
.type = TRTL_HMQ,
.index = 0,
.flags = TRTL_RT_MQ_FLAGS_INPUT,
},
[AC_CMD_OUT] = {
.type = TRTL_HMQ,
.index = 0,
.flags = TRTL_RT_MQ_FLAGS_OUTPUT,
},
[AC_DATA] = {
.type = TRTL_HMQ,
.index = 1,
.flags = TRTL_RT_MQ_FLAGS_OUTPUT | TRTL_RT_MQ_FLAGS_CLAIM,
},
};
enum ac_variable { enum ac_variable {
AC_TIME = 0, AC_TIME = 0,
AC_PERIOD_UPDATE, AC_PERIOD_UPDATE,
...@@ -45,7 +19,7 @@ enum ac_variable { ...@@ -45,7 +19,7 @@ enum ac_variable {
AC_ALARM_ITER, AC_ALARM_ITER,
}; };
static struct rt_variable variables[] = { static struct trtl_fw_variable variables[] = {
[AC_TIME] = { [AC_TIME] = {
.addr = (void *)&iteration, .addr = (void *)&iteration,
.mask = 0xFFFFFFFF, .mask = 0xFFFFFFFF,
...@@ -72,16 +46,13 @@ static struct rt_variable variables[] = { ...@@ -72,16 +46,13 @@ static struct rt_variable variables[] = {
}, },
}; };
static struct rt_application app = { static struct trtl_fw_application app = {
.name = "alarm-clk", .name = "alarm-clk",
.version = { .version = {
.fpga_id = CONFIG_FPGA_APPLICATION_ID,
.rt_id = CONFIG_RT_APPLICATION_ID, .rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1), .rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION .git_version = GIT_VERSION
}, },
.mq = mq,
.n_mq = ARRAY_SIZE(mq),
.variables = variables, .variables = variables,
.n_variables = ARRAY_SIZE(variables), .n_variables = ARRAY_SIZE(variables),
...@@ -92,18 +63,18 @@ static void ac_update(void) ...@@ -92,18 +63,18 @@ static void ac_update(void)
{ {
uint32_t sec, cyc; uint32_t sec, cyc;
rt_get_time(&sec, &cyc); trtl_fw_time(&sec, &cyc);
if ((--period_c) == 0) { if ((--period_c) == 0) {
period_c = period; period_c = period;
trtl_rt_mq_send_uint32(AC_DATA, 0x12, 1, trtl_fw_mq_send_uint32(TRTL_HMQ, 0, 0x12, 1,
iteration); iteration);
pr_debug("Iteration %d\n\r", iteration); pr_debug("Iteration %d\n\r", iteration);
} }
if (alarm_enable) { if (alarm_enable) {
if (alarm_iter < iteration) { if (alarm_iter < iteration) {
trtl_rt_mq_send_uint32(AC_DATA, 0x34, 2, trtl_fw_mq_send_uint32(TRTL_HMQ, 0, 0x34, 2,
iteration, alarm_iter); iteration, alarm_iter);
alarm_enable = 0; alarm_enable = 0;
alarm_iter = 0; alarm_iter = 0;
...@@ -128,16 +99,12 @@ static void ac_init(void) ...@@ -128,16 +99,12 @@ static void ac_init(void)
*/ */
int main() int main()
{ {
rt_init(&app); trtl_fw_init(&app);
ac_init(); ac_init();
while (1) { while (1) {
/* /* Handle all messages incoming from HMQ 0 as actions */
* Handle all messages incoming from slot trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
* AC_CMD_IN
* as actions
*/
rt_mq_action_dispatch(AC_CMD_IN);
ac_update(); ac_update();
} }
......
...@@ -22,36 +22,11 @@ static struct dg_conf dg_conf; ...@@ -22,36 +22,11 @@ static struct dg_conf dg_conf;
static uint32_t dg_last_sample_idx; static uint32_t dg_last_sample_idx;
static uint32_t dg_last_sample = 1; static uint32_t dg_last_sample = 1;
enum rt_slot_name {
DG_MQ_CMD_IN = 0,
DG_MQ_CMD_OUT,
DG_MQ_DATA,
};
static struct rt_mq mq[] = {
[DG_MQ_CMD_IN] = {
.type = TRTL_HMQ,
.index = 0,
.flags = TRTL_RT_MQ_FLAGS_INPUT,
},
[DG_MQ_CMD_OUT] = {
.type = TRTL_HMQ,
.index = 0,
.flags = TRTL_RT_MQ_FLAGS_OUTPUT,
},
[DG_MQ_DATA] = {
.type = TRTL_HMQ,
.index = 1,
.flags = TRTL_RT_MQ_FLAGS_OUTPUT | TRTL_RT_MQ_FLAGS_CLAIM,
},
};
enum dg_variable { enum dg_variable {
DG_PERIOD_UPDATE = 0, DG_PERIOD_UPDATE = 0,
}; };
static struct rt_variable variables[] = { static struct trtl_fw_variable variables[] = {
[DG_PERIOD_UPDATE] = { [DG_PERIOD_UPDATE] = {
.addr = (void *)&period, .addr = (void *)&period,
.mask = 0xFFFFFFFF, .mask = 0xFFFFFFFF,
...@@ -65,7 +40,7 @@ enum dg_structures { ...@@ -65,7 +40,7 @@ enum dg_structures {
DG_CONF, DG_CONF,
}; };
struct rt_buffer buffers[] = { struct trtl_fw_buffer buffers[] = {
[DG_DATA] = { [DG_DATA] = {
.buf = dg_data, .buf = dg_data,
.len = sizeof(dg_data), .len = sizeof(dg_data),
...@@ -76,16 +51,13 @@ struct rt_buffer buffers[] = { ...@@ -76,16 +51,13 @@ struct rt_buffer buffers[] = {
}, },
}; };
static struct rt_application app = { static struct trtl_fw_application app = {
.name = "data-gen", .name = "data-gen",
.version = { .version = {
.fpga_id = CONFIG_FPGA_APPLICATION_ID,
.rt_id = CONFIG_RT_APPLICATION_ID, .rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1), .rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION .git_version = GIT_VERSION
}, },
.mq = mq,
.n_mq = ARRAY_SIZE(mq),
.variables = variables, .variables = variables,
.n_variables = ARRAY_SIZE(variables), .n_variables = ARRAY_SIZE(variables),
...@@ -109,7 +81,9 @@ static void generate_sample(void) ...@@ -109,7 +81,9 @@ static void generate_sample(void)
dg_last_sample_idx + 1, DG_BUF_SIZE, dg_last_sample); dg_last_sample_idx + 1, DG_BUF_SIZE, dg_last_sample);
dg_data[dg_last_sample_idx] = dg_last_sample; dg_data[dg_last_sample_idx] = dg_last_sample;
dg_last_sample_idx = ++dg_last_sample_idx & (DG_BUF_SIZE - 1);
dg_last_sample_idx++;
dg_last_sample_idx &= (DG_BUF_SIZE - 1);
} }
static void dg_update(void) static void dg_update(void)
...@@ -139,16 +113,12 @@ static void dg_init(void) ...@@ -139,16 +113,12 @@ static void dg_init(void)
*/ */
int main() int main()
{ {
rt_init(&app); trtl_fw_init(&app);
dg_init(); dg_init();
while (1) { while (1) {
/* /* Handle all messages incoming from HMQ 0 as actions */
* Handle all messages incoming from slot trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
* DG_MQ_CMD_IN
* as actions
*/
rt_mq_action_dispatch(DG_MQ_CMD_IN);
dg_update(); dg_update();
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#ifndef __FW_SVEC_COMMON_H__ #ifndef __FW_SVEC_COMMON_H__
#define __FW_SVEC_COMMON_H__ #define __FW_SVEC_COMMON_H__
#include <mockturtle-rt-smem.h> #include <mockturtle-rt.h>
#include <svec-common.h> #include <svec-common.h>
extern volatile int autosvec_run; extern volatile int autosvec_run;
......
...@@ -15,33 +15,16 @@ ...@@ -15,33 +15,16 @@
#define GPIO_DDR 0x8 /* Direction Data Register */ #define GPIO_DDR 0x8 /* Direction Data Register */
#define GPIO_PSR 0xC /* Status Register */ #define GPIO_PSR 0xC /* Status Register */
enum rt_slot_name {
SVEC_CMD_IN = 0,
SVEC_CMD_OUT,
};
struct rt_mq mq[] = {
[SVEC_CMD_IN] = {
.index = 0,
.flags = TRTL_RT_MQ_FLAGS_HMQ | TRTL_RT_MQ_FLAGS_INPUT,
},
[SVEC_CMD_OUT] = {
.index = 0,
.flags = TRTL_RT_MQ_FLAGS_HMQ | TRTL_RT_MQ_FLAGS_OUTPUT,
},
};
static struct svec_structure svec_struct; static struct svec_structure svec_struct;
struct rt_buffer svec_buffers[] = { struct trtl_fw_buffer svec_buffers[] = {
[SVEC_BUF_TEST] = { [SVEC_BUF_TEST] = {
.buf = &svec_struct, .buf = &svec_struct,
.len = sizeof(struct svec_structure), .len = sizeof(struct svec_structure),
} }
}; };
struct rt_variable svec_variables[] = { struct trtl_fw_variable svec_variables[] = {
[SVEC_VAR_LEMO_STA] = { [SVEC_VAR_LEMO_STA] = {
.addr = TRTL_ADDR_DP(GPIO_PSR), .addr = TRTL_ADDR_DP(GPIO_PSR),
.mask = PIN_LEMO_MASK, .mask = PIN_LEMO_MASK,
...@@ -85,16 +68,13 @@ struct rt_variable svec_variables[] = { ...@@ -85,16 +68,13 @@ struct rt_variable svec_variables[] = {
}; };
struct rt_application app = { struct trtl_fw_application app = {
.name = "svec-svec", .name = "svec-svec",
.version = { .version = {
.fpga_id = FPGA_APPLICATION_ID,
.rt_id = RT_APPLICATION_ID, .rt_id = RT_APPLICATION_ID,
.rt_version = RT_VERSION(1, 0), .rt_version = RT_VERSION(1, 0),
.git_version = GIT_VERSION .git_version = GIT_VERSION
}, },
.mq = mq,
.n_mq = 2,
.buffers = svec_buffers, .buffers = svec_buffers,
.n_buffers = ARRAY_SIZE(svec_buffers), .n_buffers = ARRAY_SIZE(svec_buffers),
...@@ -119,13 +99,12 @@ static void svec_debug_interface(void) ...@@ -119,13 +99,12 @@ static void svec_debug_interface(void)
*/ */
int main() int main()
{ {
rt_init(&app); trtl_fw_init(&app);
svec_debug_interface(); svec_debug_interface();
while (1) { while (1) {
/* Handle all messages incoming from slot SVEC_HMQ_IN /* Handle all messages incoming from HMQ 0 as actions */
as actions */ trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
rt_mq_action_dispatch(SVEC_CMD_IN);
} }
return 0; return 0;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#ifndef __SVEC_COMMON_H #ifndef __SVEC_COMMON_H
#define __SVEC_COMMON_H #define __SVEC_COMMON_H
#include <mockturtle-common.h> #include <mockturtle.h>
/* HMQ slots used for input */ /* HMQ slots used for input */
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#define SVEC_HMQ_OUT 0 #define SVEC_HMQ_OUT 0
/* Variable index - used only by svec-librt */ /* Variable index - used only by svec-librt */
enum rt_variable_index { enum trtl_fw_variable_index {
SVEC_VAR_LEMO_STA = 0, SVEC_VAR_LEMO_STA = 0,
SVEC_VAR_LEMO_DIR, SVEC_VAR_LEMO_DIR,
SVEC_VAR_LEMO_SET, SVEC_VAR_LEMO_SET,
...@@ -30,14 +30,14 @@ enum rt_variable_index { ...@@ -30,14 +30,14 @@ enum rt_variable_index {
__SVEC_VAR_MAX, __SVEC_VAR_MAX,
}; };
enum rt_buffer_index { enum trtl_fw_buffer_index {
SVEC_BUF_TEST = 0, SVEC_BUF_TEST = 0,
__SVEC_BUF_MAX, __SVEC_BUF_MAX,
}; };
/* Command and log message IDs */ /* Command and log message IDs */
enum rt_action_recv_svec { enum rt_action_recv_svec {
SVEC_ID_LED_SET = __RT_ACTION_RECV_STANDARD_NUMBER, SVEC_ID_LED_SET = 0,
SVEC_ID_LEMO_SET, SVEC_ID_LEMO_SET,
SVEC_ID_LEMO_DIR_SET, SVEC_ID_LEMO_DIR_SET,
SVEC_ID_STATE_GET, SVEC_ID_STATE_GET,
......
...@@ -14,13 +14,6 @@ ...@@ -14,13 +14,6 @@
#include <libmockturtle.h> #include <libmockturtle.h>
#include <libsvec-internal.h> #include <libsvec-internal.h>
static const struct trtl_proto_header hdr_tmpl = {
.rt_app_id = 0,
.slot_io = (SVEC_HMQ_IN << 4) |
(SVEC_HMQ_OUT & 0xF),
};
const char *svec_errors[] = { const char *svec_errors[] = {
"Received an invalid answer from white-rabbit-node-code CPU", "Received an invalid answer from white-rabbit-node-code CPU",
"Real-Time application does not acknowledge", "Real-Time application does not acknowledge",
...@@ -132,7 +125,7 @@ int svec_lemo_dir_set(struct svec_node *dev, uint32_t value) ...@@ -132,7 +125,7 @@ int svec_lemo_dir_set(struct svec_node *dev, uint32_t value)
struct svec_desc *svec = (struct svec_desc *)dev; struct svec_desc *svec = (struct svec_desc *)dev;
uint32_t fields[] = {SVEC_VAR_LEMO_DIR, value}; uint32_t fields[] = {SVEC_VAR_LEMO_DIR, value};
return trtl_rt_variable_set(svec->trtl, return trtl_fw_variable_set(svec->trtl,
SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ, SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ,
fields, 1); fields, 1);
} }
...@@ -143,7 +136,7 @@ int svec_lemo_set(struct svec_node *dev, uint32_t value) ...@@ -143,7 +136,7 @@ int svec_lemo_set(struct svec_node *dev, uint32_t value)
uint32_t fields[] = {SVEC_VAR_LEMO_SET, value, uint32_t fields[] = {SVEC_VAR_LEMO_SET, value,
SVEC_VAR_LEMO_CLR, ~value}; SVEC_VAR_LEMO_CLR, ~value};
return trtl_rt_variable_set(svec->trtl, return trtl_fw_variable_set(svec->trtl,
SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ, SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ,
fields, 2); fields, 2);
} }
...@@ -185,7 +178,7 @@ int svec_led_set(struct svec_node *dev, uint32_t value, enum svec_color color) ...@@ -185,7 +178,7 @@ int svec_led_set(struct svec_node *dev, uint32_t value, enum svec_color color)
uint32_t fields[] = {SVEC_VAR_LED_SET, real_value, uint32_t fields[] = {SVEC_VAR_LED_SET, real_value,
SVEC_VAR_LED_CLR, ~real_value}; SVEC_VAR_LED_CLR, ~real_value};
return trtl_rt_variable_set(svec->trtl, return trtl_fw_variable_set(svec->trtl,
SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ, SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ,
fields, 2); fields, 2);
} }
...@@ -202,7 +195,7 @@ int svec_status_get(struct svec_node *dev, struct svec_status *status) ...@@ -202,7 +195,7 @@ int svec_status_get(struct svec_node *dev, struct svec_status *status)
SVEC_VAR_LEMO_DIR, 0}; SVEC_VAR_LEMO_DIR, 0};
int err; int err;
err = trtl_rt_variable_get(svec->trtl, err = trtl_fw_variable_get(svec->trtl,
SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ, SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ,
fields, 3); fields, 3);
if (err) if (err)
...@@ -220,30 +213,30 @@ int svec_run_autosvec(struct svec_node *dev, uint32_t run) ...@@ -220,30 +213,30 @@ int svec_run_autosvec(struct svec_node *dev, uint32_t run)
struct svec_desc *svec = (struct svec_desc *)dev; struct svec_desc *svec = (struct svec_desc *)dev;
uint32_t fields[] = {SVEC_VAR_AUTO, run}; uint32_t fields[] = {SVEC_VAR_AUTO, run};
return trtl_rt_variable_set(svec->trtl, return trtl_fw_variable_set(svec->trtl,
SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ, SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ,
fields, 1); fields, 1);
} }
int svec_version(struct svec_node *dev, struct trtl_rt_version *version) int svec_version(struct svec_node *dev, struct trtl_fw_version *version)
{ {
struct svec_desc *svec = (struct svec_desc *)dev; struct svec_desc *svec = (struct svec_desc *)dev;
return trtl_rt_version_get(svec->trtl, return trtl_fw_version(svec->trtl,
SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ, SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ,
version); version);
} }
int svec_test_struct_get(struct svec_node *dev, struct svec_structure *test) int svec_test_struct_get(struct svec_node *dev, struct svec_structure *test)
{ {
struct svec_desc *svec = (struct svec_desc *)dev; struct svec_desc *svec = (struct svec_desc *)dev;
struct trtl_structure_tlv tlv = { struct trtl_tlv tlv = {
.index = SVEC_BUF_TEST, .type = SVEC_BUF_TEST,
.size = sizeof(struct svec_structure), .size = sizeof(struct svec_structure),
.buf = test, .buf = test,
}; };
return trtl_rt_buffer_get(svec->trtl, return trtl_fw_buffer_get(svec->trtl,
SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ, SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ,
&tlv, 1); &tlv, 1);
} }
...@@ -251,13 +244,13 @@ int svec_test_struct_get(struct svec_node *dev, struct svec_structure *test) ...@@ -251,13 +244,13 @@ int svec_test_struct_get(struct svec_node *dev, struct svec_structure *test)
int svec_test_struct_set(struct svec_node *dev, struct svec_structure *test) int svec_test_struct_set(struct svec_node *dev, struct svec_structure *test)
{ {
struct svec_desc *svec = (struct svec_desc *)dev; struct svec_desc *svec = (struct svec_desc *)dev;
struct trtl_structure_tlv tlv = { struct trtl_tlv tlv = {
.index = SVEC_BUF_TEST, .type = SVEC_BUF_TEST,
.size = sizeof(struct svec_structure), .size = sizeof(struct svec_structure),
.buf = test, .buf = test,
}; };
return trtl_rt_buffer_set(svec->trtl, return trtl_fw_buffer_set(svec->trtl,
SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ, SVEC_CPU_MANUAL, SVEC_CPU_MANUAL_HMQ,
&tlv, 1); &tlv, 1);
} }
...@@ -56,7 +56,7 @@ extern int svec_lemo_set(struct svec_node *dev, uint32_t value); ...@@ -56,7 +56,7 @@ extern int svec_lemo_set(struct svec_node *dev, uint32_t value);
extern int svec_lemo_dir_set(struct svec_node *dev, uint32_t value); extern int svec_lemo_dir_set(struct svec_node *dev, uint32_t value);
extern int svec_status_get(struct svec_node *dev, struct svec_status *status); extern int svec_status_get(struct svec_node *dev, struct svec_status *status);
extern int svec_run_autosvec(struct svec_node *dev, uint32_t run); extern int svec_run_autosvec(struct svec_node *dev, uint32_t run);
extern int svec_version(struct svec_node *dev, struct trtl_rt_version *version); extern int svec_version(struct svec_node *dev, struct trtl_fw_version *version);
extern int svec_test_struct_set(struct svec_node *dev, extern int svec_test_struct_set(struct svec_node *dev,
struct svec_structure *test); struct svec_structure *test);
extern int svec_test_struct_get(struct svec_node *dev, extern int svec_test_struct_get(struct svec_node *dev,
......
...@@ -40,10 +40,9 @@ static void svec_print_status(struct svec_status *status) ...@@ -40,10 +40,9 @@ static void svec_print_status(struct svec_status *status)
fprintf(stdout, "\tautosvec\t%s\n", status->autosvec ? "run" : "stop"); fprintf(stdout, "\tautosvec\t%s\n", status->autosvec ? "run" : "stop");
} }
static void svec_print_version(struct trtl_rt_version *version) static void svec_print_version(struct trtl_fw_version *version)
{ {
fprintf(stdout, "Version:\n"); fprintf(stdout, "Version:\n");
fprintf(stdout, "\tFPGA: 0x%x\n", version->fpga_id);
fprintf(stdout, "\tRT: 0x%x\n", version->rt_id); fprintf(stdout, "\tRT: 0x%x\n", version->rt_id);
fprintf(stdout, "\tRT Version: 0x%x\n", version->rt_version); fprintf(stdout, "\tRT Version: 0x%x\n", version->rt_version);
fprintf(stdout, "\tGit Version: 0x%x\n", version->git_version); fprintf(stdout, "\tGit Version: 0x%x\n", version->git_version);
...@@ -68,7 +67,7 @@ int main(int argc, char *argv[]) ...@@ -68,7 +67,7 @@ int main(int argc, char *argv[])
char c, c_color = 0, autosvec = 0; char c, c_color = 0, autosvec = 0;
int err = 0, show_status = 0, show_version = 0, structure = 0; int err = 0, show_status = 0, show_version = 0, structure = 0;
enum svec_color color = SVEC_RED; enum svec_color color = SVEC_RED;
struct trtl_rt_version version; struct trtl_fw_version version;
struct svec_structure test, test_rb; struct svec_structure test, test_rb;
while ((c = getopt (argc, argv, "hD:l:L:d:c:sa:vt")) != -1) { while ((c = getopt (argc, argv, "hD:l:L:d:c:sa:vt")) != -1) {
......
#include <mockturtle-rt-serial.h> #include <mockturtle-rt.h>
int main() int main()
{ {
......
...@@ -6,32 +6,13 @@ ...@@ -6,32 +6,13 @@
#include <mockturtle-framework.h> #include <mockturtle-framework.h>
enum rt_slot_name { static struct trtl_fw_application app = {
HELLOFRM_CMD_IN = 0,
HELLOFRM_CMD_OUT,
};
static struct rt_mq mq[] = {
[HELLOFRM_CMD_IN] = {
.index = 0,
.flags = TRTL_RT_MQ_FLAGS_HMQ | TRTL_RT_MQ_FLAGS_INPUT,
},
[HELLOFRM_CMD_OUT] = {
.index = 0,
.flags = TRTL_RT_MQ_FLAGS_HMQ | TRTL_RT_MQ_FLAGS_OUTPUT,
},
};
static struct rt_application app = {
.name = "hellofrm", .name = "hellofrm",
.version = { .version = {
.fpga_id = CONFIG_FPGA_APPLICATION_ID,
.rt_id = CONFIG_RT_APPLICATION_ID, .rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1), .rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION .git_version = GIT_VERSION,
}, },
.mq = mq,
.n_mq = ARRAY_SIZE(mq),
}; };
/** /**
...@@ -39,15 +20,14 @@ static struct rt_application app = { ...@@ -39,15 +20,14 @@ static struct rt_application app = {
*/ */
int main() int main()
{ {
rt_init(&app); trtl_fw_init(&app);
while (1) { while (1) {
/* /*
* Handle all messages incoming from slot * Handle all messages incoming from slot 0
* HELLOFRM_CMD_IN
* as actions * as actions
*/ */
rt_mq_action_dispatch(HELLOFRM_CMD_IN); trtl_fw_mq_action_dispatch(TRTL_HMQ, 0);
} }
return 0; return 0;
......
#ifndef __TRTL_CONFIG_ROM_H__
#define __TRTL_CONFIG_ROM_H__
#define TRTL_CONFIG_ROM_SIGNATURE 0x5452544c
#define TRTL_MAX_CPU 8 /**< Maximum number of CPU core in a bitstream */
#define TRTL_MAX_MQ_CHAN 8 /**< Maximum number of (H|R)MQ slots in a
bitstream */
#define TRTL_CONFIG_ROM_MQ_ENTRIES_SHIFT 16
#define TRTL_CONFIG_ROM_MQ_ENTRIES_MASK 0x00FF0000
#define TRTL_CONFIG_ROM_MQ_PAYLOAD_SHIFT 8
#define TRTL_CONFIG_ROM_MQ_PAYLOAD_MASK 0x0000FF00
#define TRTL_CONFIG_ROM_MQ_HEADER_SHIFT 0
#define TRTL_CONFIG_ROM_MQ_HEADER_MASK 0x000000FF
#define TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_ENTRIES_MASK) >> TRTL_CONFIG_ROM_MQ_ENTRIES_SHIFT))
#define TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_PAYLOAD_MASK) >> TRTL_CONFIG_ROM_MQ_PAYLOAD_SHIFT))
#define TRTL_CONFIG_ROM_MQ_SIZE_HEADER(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_HEADER_MASK) >> TRTL_CONFIG_ROM_MQ_HEADER_SHIFT))
/**
* The synthesis configuration for a single MQ.
* Note that there is always an input and output channel for each declaration.
*/
struct trtl_config_rom_mq {
uint32_t sizes;
uint32_t endpoint_id;
};
/**
* The synthesis configuration ROM descriptor shows useful configuration
* options during synthesis.
*/
struct trtl_config_rom {
uint32_t signature; /**< we expect to see a known value */
uint32_t version; /**< Mock Turtle version */
uint32_t pad1[1];
uint32_t clock_freq;
uint32_t flags;
uint32_t app_id; /**< Application ID */
uint32_t n_cpu; /**< number of CPU */
uint32_t smem_size; /**< shared memory size */
uint32_t mem_size[TRTL_MAX_CPU]; /**< memory size for each CPU */
uint32_t n_hmq[TRTL_MAX_CPU]; /**< number of HMQ for each CPU */
uint32_t n_rmq[TRTL_MAX_CPU]; /**< number of RMQ for each CPU */
uint32_t pad2[96];
struct trtl_config_rom_mq hmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN];
struct trtl_config_rom_mq rmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN];
};
#endif
/*
* Copyright (C) 2015-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TRTL_COMMON_H__
#define __TRTL_COMMON_H__
#ifndef __KERNEL__
#include <string.h>
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(_a) (sizeof(_a) / sizeof(_a[0]))
#endif
#define __TRTL_MSG_ID_MAX_USER 96
#define __TRTL_MSG_ID_MAX 128
/**
* It lists all notification's code.
*/
enum trtl_cpu_notification {
TRTL_CPU_NOTIFY_APPLICATION = 0,
__TRTL_CPU_NOTIFY_MAX,
};
/**
* List of Mock Turtle message identifiers for firmware input
*/
enum trtl_msg_id_i {
TRTL_MSG_ID_PING = __TRTL_MSG_ID_MAX_USER,
TRTL_MSG_ID_VERS_REQ,
TRTL_MSG_ID_VAR_SET,
TRTL_MSG_ID_VAR_GET,
TRTL_MSG_ID_BUF_SET,
TRTL_MSG_ID_BUF_GET,
};
/**
* List of Mock Turtle message identifiers for firmware output
*/
enum trtl_msg_id_o {
TRTL_MSG_ID_ACK = __TRTL_MSG_ID_MAX_USER,
TRTL_MSG_ID_NACK,
TRTL_MSG_ID_VERS_ANS,
TRTL_MSG_ID_DBG,
TRTL_MSG_ID_VAR_GET_ANS,
TRTL_MSG_ID_BUF_GET_ANS,
};
/**
* Synchronous. When set, the sync_id is valid and the receiver
* must answer with a message with the same sync_id
*/
#define TRTL_HMQ_HEADER_FLAG_SYNC (1 << 0)
/**
* HMQ header descriptor
*/
struct trtl_hmq_header {
/* word 0 */
uint16_t rt_app_id; /**< Real-Time application unique identifier */
uint8_t flags;
uint8_t msg_id; /**< Message identifier */
/* word 1 */
uint16_t len; /**< message-length */
uint16_t sync_id;/**< synchronous identifier */
/* word 2 */
uint32_t seq; /**< sequence number */
};
/**
* It describes the version running on the embedded CPU
*/
struct trtl_rt_version {
uint32_t fpga_id; /**< FPGA identifier expected to run the RT app */
uint32_t rt_id; /**< RT application identifier */
uint32_t rt_version; /**< RT application version*/
uint32_t git_version; /**< git commit SHA1 of the compilation time */
};
enum rt_action_standard {
RT_ACTION_RECV_PING = 0,
RT_ACTION_RECV_STRUCT_SET,
RT_ACTION_RECV_STRUCT_GET,
RT_ACTION_RECV_VERSION,
RT_ACTION_SEND_ACK,
RT_ACTION_SEND_NACK,
RT_ACTION_SEND_STRUCT_GET,
RT_ACTION_SEND_VERSION,
RT_ACTION_SEND_DEBUG,
__RT_ACTION_RECV_STANDARD_NUMBER,
};
/**< __MAX_ACTION_RECV coming from GCC on compilation */
#define MAX_ACTION_RECV (__MAX_ACTION_RECV + __RT_ACTION_RECV_STANDARD_NUMBER)
/**< __MAX_ACTION_SEND coming from GCC on compilation */
#define MAX_ACTION_SEND (__MAX_ACTION_SEND + __RT_ACTION_SEND_STANDARD_NUMBER)
/* Protocol Definition */
#define TRTL_HEAD_FLAG_REMOTE (1 << 0)
#define TRTL_HEAD_FLAG_SYNC (1 << 1)
#define TRTL_HEAD_FLAG_RPC (1 << 2)
#define TRTL_HEAD_FLAG_PERIODICAL (1 << 3)
/**
* Protocol header definition
*/
struct trtl_proto_header {
uint16_t rt_app_id; /**< Real-Time application unique identifier */
uint8_t msg_id; /**< Message identifier */
uint8_t slot_io; /**< Message Queue IO to use
(4bit Input, 4 bit output) */
uint32_t seq; /**< sequence number */
uint8_t len; /**< message data lenght */
uint8_t flags; /**< protocol flags */
uint8_t unused; /**< not used, future use */
uint8_t trans; /**< transaction descriptor - flag and seq number */
uint32_t time;
};
/**
* Data structure representing a MockTurtle packet
*/
struct mturtle_packet {
/* offset 0x00 */
volatile struct trtl_proto_header header; /**< packet header */
/* offset 0x10 */
volatile uint32_t payload[]; /**< packet payload */
};
/**
* It returns the pointer to the MockTurtle packet
* @param[in] buf buffer containing the packet
* @return pointer to the packet
*/
static inline struct mturtle_packet *rt_proto_packet_get(void *buf)
{
return (struct mturtle_packet *)buf;
}
/**
* It extracts the header from a raw message
* @param[in] raw_msg raw message
* @param[out] header the header from the message
*/
static inline struct trtl_proto_header *rt_proto_header_get(void *raw_msg)
{
return (struct trtl_proto_header *) raw_msg;
}
/**
* It embeds the header from a raw message
* @param[in] raw_msg raw message
* @param[out] header the header from the message
*/
static inline void rt_proto_header_set(void *raw_msg,
struct trtl_proto_header *header)
{
memcpy(raw_msg, header, sizeof(struct trtl_proto_header));
}
/**
* It returns the pointer where it starts the message payload
* @param[in] raw_msg raw message
* @param[out] header the header from the message
*/
static inline void *rt_proto_payload_get(void *raw_msg)
{
return ((char *)raw_msg + sizeof(struct trtl_proto_header));
}
#endif
...@@ -21,11 +21,123 @@ ...@@ -21,11 +21,123 @@
#define __TRTL_USER_H__ #define __TRTL_USER_H__
/** @file mock-turtle.h */ /** @file mock-turtle.h */
#include "mockturtle-common.h" #ifndef __KERNEL__
#include <string.h>
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(_a) (sizeof(_a) / sizeof(_a[0]))
#endif
#define __TRTL_MSG_ID_MAX 128
#define __TRTL_MSG_ID_MAX_TRTL 32
#define __TRTL_MSG_ID_MAX_USER (__TRTL_MSG_ID_MAX - __TRTL_MSG_ID_MAX_TRTL)
/**
* It lists all notification's code.
*/
enum trtl_cpu_notification {
TRTL_CPU_NOTIFY_APPLICATION = 0,
__TRTL_CPU_NOTIFY_MAX,
};
/**
* It enumerates the Mock Turtle message ID.
* These IDs starts after the user defined ones
*/
enum trtl_msg_id {
TRTL_MSG_ID_UNDEFINED = __TRTL_MSG_ID_MAX_USER,
TRTL_MSG_ID_ERROR,
TRTL_MSG_ID_PING,
TRTL_MSG_ID_VER,
TRTL_MSG_ID_DBG,
TRTL_MSG_ID_VAR_GET,
TRTL_MSG_ID_BUF_GET,
TRTL_MSG_ID_VAR_SET,
TRTL_MSG_ID_BUF_SET,
};
/**
* Synchronous. When set, the sync_id is valid and the receiver
* must answer with a message with the same sync_id
*/
#define TRTL_HMQ_HEADER_FLAG_SYNC (1 << 0)
/**
* Acknowledgment. When set, the sync_id is valid and it is the
* same as the sync message previously sent
*/
#define TRTL_HMQ_HEADER_FLAG_ACK (1 << 1)
/**
* Remote Procedure Call. when set the message ID will be used
* to execute a special function by the receiver
*/
#define TRTL_HMQ_HEADER_FLAG_RPC (1 << 2)
/**
* HMQ header descriptor
*/
struct trtl_hmq_header {
/* word 0 */
uint16_t rt_app_id; /**< Real-Time application unique identifier */
uint8_t flags;
uint8_t msg_id; /**< Message identifier */
/* word 1 */
uint16_t len; /**< message-length */
uint16_t sync_id;/**< synchronous identifier */
/* word 2 */
uint32_t seq; /**< sequence number (automatically set by the library) */
};
#define RT_VERSION_MAJ(_v) ((_v >> 16) & 0xFFFF)
#define RT_VERSION_MIN(_v) (_v & 0xFFFF)
#define RT_VERSION(_a, _b) (((_a & 0xFFFF) << 16) | (_b & 0xFFFF))
/**
* It describes the version running on the embedded CPU
*/
struct trtl_fw_version {
uint32_t rt_id; /**< RT application identifier */
uint32_t rt_version; /**< RT application version*/
uint32_t git_version; /**< git commit SHA1 of the compilation time */
};
/**
* Maximum number of CPU core in a bitstream
*/
#define TRTL_MAX_CPU 8
/**
* Maximum number of (H|R)MQ slots in a bitstream
*/
#define TRTL_MAX_MQ_CHAN 8
#define TRTL_MAX_CARRIER 20 /**< Maximum number of WRNC components on a /**
single computer*/ * Maximum number of Mock Turtle components on a single computer
*/
#define TRTL_MAX_CARRIER 20
/**
* TLV used to embed buffers within a message
*/
struct trtl_tlv {
uint32_t type; /**< buffer type */
size_t size; /**< buffer size in byte */
void *buf; /**< pointer to the buffer */
};
/** /**
* Maximum number of notifications ID in the driver buffer * Maximum number of notifications ID in the driver buffer
...@@ -46,22 +158,13 @@ ...@@ -46,22 +158,13 @@
* that you can use to access the shared memory. * that you can use to access the shared memory.
*/ */
enum trtl_smem_modifier { enum trtl_smem_modifier {
TRTL_SMEM_DIRECT = 0, /**< direct read/write of the memory */ TRTL_SMEM_TYPE_BASE = 0, /**< no operation */
TRTL_SMEM_ADD, /**< on write, atomic ADD to memory content */ TRTL_SMEM_TYPE_ADD, /**< atomic addition */
TRTL_SMEM_SUB, /**< on write, atomic SUB to memory content */ TRTL_SMEM_TYPE_SUB, /**< atomic subtraction */
TRTL_SMEM_OR, /**< on write, atomic OR with memory content */ TRTL_SMEM_TYPE_SET, /**< atomic bit set */
TRTL_SMEM_CLR_AND, /**< on write, atomic AND with complemented memory TRTL_SMEM_TYPE_CLR, /**< atomic bit clear */
content */ TRTL_SMEM_TYPE_FLP, /**< atomic bit flip */
TRTL_SMEM_XOR, /**< on write, atomic XOR with memory content */ TRTL_SMEM_TYPE_TST_SET, /**< atomic test and set */
};
/**
* Messages descriptor
*/
struct trtl_msg {
struct trtl_hmq_header hdr;
uint32_t data[TRTL_MAX_PAYLOAD_SIZE]; /**< payload very maximum size */
}; };
...@@ -123,4 +226,71 @@ enum trtl_ioctl_commands { ...@@ -123,4 +226,71 @@ enum trtl_ioctl_commands {
#define TRTL_IOCTL_MSG_FILTER_CLEAN _IOW(TRTL_IOCTL_MAGIC, \ #define TRTL_IOCTL_MSG_FILTER_CLEAN _IOW(TRTL_IOCTL_MAGIC, \
TRTL_MSG_FILTER_CLEAN, \ TRTL_MSG_FILTER_CLEAN, \
struct trtl_msg_filter) struct trtl_msg_filter)
/**
* Messages descriptor
*/
struct trtl_msg {
#ifdef __TRTL_FIRMWARE__
/* Only firmware */
struct trtl_hmq_header *header;
void *payload;
#else
/* library and kernel */
struct trtl_hmq_header hdr;
uint32_t data[TRTL_MAX_PAYLOAD_SIZE]; /**< payload very maximum size */
#endif
};
#define TRTL_CONFIG_ROM_MQ_ENTRIES_SHIFT 16
#define TRTL_CONFIG_ROM_MQ_ENTRIES_MASK 0x00FF0000
#define TRTL_CONFIG_ROM_MQ_PAYLOAD_SHIFT 8
#define TRTL_CONFIG_ROM_MQ_PAYLOAD_MASK 0x0000FF00
#define TRTL_CONFIG_ROM_MQ_HEADER_SHIFT 0
#define TRTL_CONFIG_ROM_MQ_HEADER_MASK 0x000000FF
#define TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_ENTRIES_MASK) >> TRTL_CONFIG_ROM_MQ_ENTRIES_SHIFT))
#define TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_PAYLOAD_MASK) >> TRTL_CONFIG_ROM_MQ_PAYLOAD_SHIFT))
#define TRTL_CONFIG_ROM_MQ_SIZE_HEADER(_size) (1 << ((_size & TRTL_CONFIG_ROM_MQ_HEADER_MASK) >> TRTL_CONFIG_ROM_MQ_HEADER_SHIFT))
/**
* The synthesis configuration for a single MQ.
* Note that there is always an input and output channel for each declaration.
*/
struct trtl_config_rom_mq {
uint32_t sizes;
uint32_t endpoint_id;
};
/**
* This signature must be present on all the configuration rom
*/
#define TRTL_CONFIG_ROM_SIGNATURE 0x5452544c
/**
* The synthesis configuration ROM descriptor shows useful configuration
* options during synthesis.
*/
struct trtl_config_rom {
uint32_t signature; /**< we expect to see a known value */
uint32_t version; /**< Mock Turtle version */
uint32_t pad1[1];
uint32_t clock_freq;
uint32_t flags;
uint32_t app_id; /**< Application ID */
uint32_t n_cpu; /**< number of CPU */
uint32_t smem_size; /**< shared memory size */
uint32_t mem_size[TRTL_MAX_CPU]; /**< memory size for each CPU */
uint32_t n_hmq[TRTL_MAX_CPU]; /**< number of HMQ for each CPU */
uint32_t n_rmq[TRTL_MAX_CPU]; /**< number of RMQ for each CPU */
uint32_t pad2[96];
struct trtl_config_rom_mq hmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN];
struct trtl_config_rom_mq rmq[TRTL_MAX_CPU][TRTL_MAX_MQ_CHAN];
};
#endif #endif
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <hw/mockturtle_cpu_csr.h> #include <hw/mockturtle_cpu_csr.h>
#include <hw/mockturtle_queue.h> #include <hw/mockturtle_queue.h>
#include <hw/mockturtle_config.h>
#include "mockturtle-drv.h" #include "mockturtle-drv.h"
...@@ -198,7 +197,7 @@ static ssize_t trtl_store_smem_op(struct device *dev, ...@@ -198,7 +197,7 @@ static ssize_t trtl_store_smem_op(struct device *dev,
if (kstrtol(buf, 0, &val)) if (kstrtol(buf, 0, &val))
return -EINVAL; return -EINVAL;
if (val < TRTL_SMEM_DIRECT || val > TRTL_SMEM_ADD) { if (val < TRTL_SMEM_TYPE_BASE || val > TRTL_SMEM_TYPE_ADD) {
dev_err(&trtl->dev, "Unsupported operation %ld\n", val); dev_err(&trtl->dev, "Unsupported operation %ld\n", val);
return -EINVAL; return -EINVAL;
} }
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "hw/mockturtle_addresses.h" #include "hw/mockturtle_addresses.h"
#include "hw/mockturtle_queue.h" #include "hw/mockturtle_queue.h"
#include "hw/mockturtle_config.h"
#include "mockturtle.h" #include "mockturtle.h"
#define MAX_MQUEUE_SLOTS (TRTL_MAX_HMQ_SLOT / 2) #define MAX_MQUEUE_SLOTS (TRTL_MAX_HMQ_SLOT / 2)
......
...@@ -111,6 +111,14 @@ class TrtlMessage(Structure): ...@@ -111,6 +111,14 @@ class TrtlMessage(Structure):
return True return True
class TrtlFirmwareVersion(Structure):
_fields_ = [
("id", c_uint32),
("fw-version", c_uint32),
("git-version", c_uint32),
]
class TrtlDevice(object): class TrtlDevice(object):
"""It is a Python class that represent a Mock Turtle Device """It is a Python class that represent a Mock Turtle Device
""" """
...@@ -229,7 +237,16 @@ class TrtlDevice(object): ...@@ -229,7 +237,16 @@ class TrtlDevice(object):
] ]
self.libtrtl.trtl_hmq_flush.restype = c_int self.libtrtl.trtl_hmq_flush.restype = c_int
self.libtrtl.trtl_hmq_flush.errcheck = self.errcheck self.libtrtl.trtl_hmq_flush.errcheck = self.errcheck
# FW PING
self.libtrtl.trtl_fw_ping.argtypes = [c_void_p, c_uint, c_uint]
self.libtrtl.trtl_fw_ping.restype = c_int
self.libtrtl.trtl_fw_ping.errcheck = self.__errcheck_int
# FW VERSION
self.libtrtl.trtl_fw_version.argtypes = [c_void_p, c_uint, c_uint,
POINTER(TrtlFirmwareVersion),
]
self.libtrtl.trtl_fw_version.restype = c_int
self.libtrtl.trtl_fw_version.errcheck = self.__errcheck_int
# self.libtrtl.trtl_hmq_filter_add.argtypes = [c_void_p] # self.libtrtl.trtl_hmq_filter_add.argtypes = [c_void_p]
# self.libtrtl.trtl_hmq_filter_clean.argtypes = [c_void_p] # self.libtrtl.trtl_hmq_filter_clean.argtypes = [c_void_p]
# # Return # # Return
...@@ -326,6 +343,22 @@ class TrtlCpu(object): ...@@ -326,6 +343,22 @@ class TrtlCpu(object):
self.idx_cpu, self.idx_cpu,
file_path.encode()) file_path.encode())
def ping(self, idx_hmq):
"""
It pings the firmware running on the CPU
@return True if the firmware is alive, False otherwise
"""
val = self.libtrtl.trtl_fw_ping(self.trtl_dev.tkn,
self.idx_cpu, idx_hmq)
return True if val == 0 else False
def version(self):
version = TrtlFirmwareVersion()
self.libtrtl.trtl_fw_version(self.trtl_dev.tkn,
self.idx_cpu, idx_hmq,
pointer(version))
return version
class TrtlHmq(object): class TrtlHmq(object):
""" """
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
*/ */
struct trtl_desc { struct trtl_desc {
uint32_t devid; uint32_t devid;
uint32_t seq; /**< global sequence number for messages sent from
this instance*/
char name[TRTL_NAME_LEN]; /**< Name of the device */ char name[TRTL_NAME_LEN]; /**< Name of the device */
char path[TRTL_PATH_LEN]; /**< path to device */ char path[TRTL_PATH_LEN]; /**< path to device */
int fd_dev; /**< File Descriptor of the device */ int fd_dev; /**< File Descriptor of the device */
......
...@@ -5,184 +5,61 @@ ...@@ -5,184 +5,61 @@
* SPDX-License-Identifier: LGPL-3.0-or-later * SPDX-License-Identifier: LGPL-3.0-or-later
*/ */
#include <libmockturtle.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h>
#include "libmockturtle-internal.h"
/**
* It embeds the header into the message
* @param[in] msg the trtl message
* @param[in] hdr the header you want to embed into the message
*/
void trtl_message_header_set(struct trtl_msg *msg,
struct trtl_proto_header *hdr)
{
memcpy(msg->data, hdr, sizeof(struct trtl_proto_header));
msg->hdr.len = sizeof(struct trtl_proto_header) / 4;
}
/**
* It retrieves the header from the message
* @param[in] msg the trtl message
* @param[out] hdr the header from the message
*/
void trtl_message_header_get(struct trtl_msg *msg,
struct trtl_proto_header *hdr)
{
memcpy(hdr, msg->data, sizeof(struct trtl_proto_header));
}
/**
* It packs a message to send to the HMQ. The function uses the header to get
* the payload size. Rembember that the payload length unit is the 32bit word.
* Remind also that the TRTL VHDL code, will convert a given 32bit word between
* little endian and big endian
* @param[out] msg raw message
* @param[in] hdr message header
* @param[in] payload data
*/
void trtl_message_pack(struct trtl_msg *msg,
struct trtl_proto_header *hdr,
void *payload)
{
void *data = msg->data;
trtl_message_header_set(msg, hdr);
if (!payload)
return;
memcpy(data + sizeof(struct trtl_proto_header), payload,
hdr->len * 4);
msg->hdr.len += hdr->len;
}
/**
* it unpacks a message coming from the HMQ by separating the header from
* the payload. You will find the payload size in the header.
* Rembember that the payload length unit is the 32bit word.
* Remind also that the TRTL VHDL code, will convert a given 32bit word between
* little endian and big endian
* @param[in] msg raw message
* @param[out] hdr message header
* @param[out] payload data
*/
void trtl_message_unpack(struct trtl_msg *msg,
struct trtl_proto_header *hdr,
void *payload)
{
void *data = msg->data;
trtl_message_header_get(msg, hdr);
if (!payload)
return;
memcpy(payload, data + sizeof(struct trtl_proto_header),
hdr->len * 4);
}
/**
* It appends a TLV structure to the given message
* @param[in] msg
* @param[in] hdr message header to use
* @param[in] tlv element to append
*/
void trtl_message_buffer_push(struct trtl_msg *msg,
struct trtl_proto_header *hdr,
struct trtl_structure_tlv *tlv)
{
unsigned int offset = sizeof(struct trtl_proto_header) / 4 + hdr->len;
void *data;
msg->data[offset++] = tlv->index;
msg->data[offset++] = tlv->size;
data = &msg->data[offset];
memcpy(data, tlv->buf, tlv->size);
hdr->len += 2 + (tlv->size / 4);
trtl_message_header_set(msg, hdr);
msg->hdr.len = hdr->len + sizeof(struct trtl_proto_header) / 4;
}
/**
* A TLV record containing a structure will be take from the message head.
* The function will update the message lenght in the header by removing
* the size occupied by the last record.
*
* @TODO perhaps re think it because it consumes the hdr. It is better to
* keep it safe
* @param[in] msg raw message
* @param[in] offset where start to pop buffers in 32bit words
* @param[in] hdr message header
* @param[out] tlv TLV record containing a structure
*/
off_t trtl_message_buffer_pop(struct trtl_msg *msg, off_t offset,
struct trtl_proto_header *hdr,
struct trtl_structure_tlv *tlv)
{
if (offset > hdr->len) {
errno = EINVAL;
return -1;
}
tlv->index = msg->data[offset++];
tlv->size = msg->data[offset++];
if (tlv->size / 4 > hdr->len - 2) {/* -2 for intex and size */
errno = EINVAL;
return -1; /* TLV greater than what is declared in header */
}
memcpy(tlv->buf, &msg->data[offset], tlv->size);
offset += (tlv->size / 4);
return offset;
}
/** /**
* Retrieve the current Real-Time Application version running. This is a * Retrieve the current Real-Time Application version running. This is a
* synchronous message. * synchronous message.
* @param[in] trtl device token * @param[in] trtl device token
* @param[out] version FPGA, RT and GIT version * @param[in] idx_cpu which CPU
* @param[in] hmq_in hmq slot index where send the message * @param[in] idx_hmq which HMQ
* @param[in] hmq_out hmq slot index where you expect the answer * @param[out] version RT id, RT and GIT version
* @return 0 on success, -1 on error and errno is set appropriately * @return 0 on success, -1 on error and errno is set appropriately
*/ */
int trtl_rt_version_get(struct trtl_dev *trtl, int trtl_fw_version(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
struct trtl_rt_version *version) struct trtl_fw_version *version)
{ {
struct trtl_msg msg; struct trtl_msg msg;
int err; int err;
/* FIXME with new protocol redefine messages to ACK/NACK */ /* FIXME with new hmqcol redefine messages to ACK/NACK */
err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg, err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg,
trtl_default_timeout_ms); trtl_default_timeout_ms);
if (err <= 0) if (err <= 0)
return -1; return -1;
/* FIXME put the payload in the version field */ memcpy(version, msg.data, msg.hdr.len * 4);
return 0; return 0;
} }
/** /**
* It checks if a Real-Time application is running and answering to messages * It checks if firmware core is running and answering to messages
* @param[in] trtl device token * @param[in] trtl device token
* @param[in] hmq_in hmq slot index where send the message * @param[in] idx_cpu which CPU
* @param[in] hmq_out hmq slot index where you expect the answer * @param[in] idx_hmq which HMQ
* @return 0 on success, -1 on error and errno is set appropriately * @return 0 on success, -1 on error and errno is set appropriately
*/ */
int trtl_rt_ping(struct trtl_dev *trtl, int trtl_fw_ping(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq) unsigned int idx_hmq)
{ {
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
struct trtl_msg msg; struct trtl_msg msg;
int err; int err;
/* FIXME with new protocol redefine messages to ACK/NACK */ memset(&msg, 0, sizeof(struct trtl_msg));
msg.hdr.msg_id = TRTL_MSG_ID_PING;
msg.hdr.seq = wdesc->seq;
msg.hdr.sync_id = msg.hdr.seq;
err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg, err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg,
trtl_default_timeout_ms); trtl_default_timeout_ms);
if (err <= 0) if (err <= 0)
...@@ -192,20 +69,6 @@ int trtl_rt_ping(struct trtl_dev *trtl, ...@@ -192,20 +69,6 @@ int trtl_rt_ping(struct trtl_dev *trtl,
} }
/**
* Real implementation to read/write variables
*/
static inline int trtl_rt_variable(struct trtl_dev *trtl,
struct trtl_proto_header *hdr,
uint32_t *variables,
unsigned int n_variables)
{
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
}
/** /**
* It sends/receive a set of variables to/from the Real-Time application. * It sends/receive a set of variables to/from the Real-Time application.
* *
...@@ -228,21 +91,40 @@ static inline int trtl_rt_variable(struct trtl_dev *trtl, ...@@ -228,21 +91,40 @@ static inline int trtl_rt_variable(struct trtl_dev *trtl,
* This function will change the header content, in particular it will change * This function will change the header content, in particular it will change
* the following fields: msg_id, len * the following fields: msg_id, len
* @param[in] trtl device token * @param[in] trtl device token
* @param[in|out] hdr header to send on input, header received on output * @param[in] idx_cpu
* @param[in|out] var variables to get on input, variables values on output * @param[in] idx_hmq
* @param[in] n_var number of variables to set. In other words, * @param[in|out] variables on input variable indexes and values.
* the number of indexes you have in the 'variables' fields. * On output variable indexes and values.
* @param[in] sync set if you want a synchronous message * @param[in] n_variables number of variables to set. In other words,
* the number of indexes you have in the 'variables' fields
* @return 0 on success, -1 on error and errno is appropriately set.
*/ */
int trtl_rt_variable_set(struct trtl_dev *trtl, int trtl_fw_variable_set(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
uint32_t *variables, uint32_t *variables,
unsigned int n_variables) unsigned int n_variables)
{ {
/* FIXME Re-implement with new protocol */ struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
errno = ETRTL_NO_IMPLEMENTATION; struct trtl_msg msg;
return -1; int err;
memset(&msg, 0, sizeof(struct trtl_msg));
msg.hdr.msg_id = TRTL_MSG_ID_VAR_GET;
msg.hdr.seq = wdesc->seq;
msg.hdr.sync_id = msg.hdr.seq;
memcpy(msg.data, variables, sizeof(uint32_t) * n_variables);
err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg,
trtl_default_timeout_ms);
if (err <= 0)
return -1;
memcpy(variables, msg.data, sizeof(uint32_t) * n_variables);
return 0;
} }
...@@ -265,20 +147,40 @@ int trtl_rt_variable_set(struct trtl_dev *trtl, ...@@ -265,20 +147,40 @@ int trtl_rt_variable_set(struct trtl_dev *trtl,
* This function will change the header content, in particular it will change * This function will change the header content, in particular it will change
* the following fields: msg_id, flags, len * the following fields: msg_id, flags, len
* @param[in] trtl device token * @param[in] trtl device token
* @param[in|out] hdr header to send on input, header received on output * @param[in] idx_cpu
* @param[in|out] var variables to get on input, variables values on output * @param[in] idx_hmq
* @param[in] n_var number of variables to set. In other words, * @param[in|out] variables on input variable indexes. On output variable
* indexes and values.
* @param[in] n_variables number of variables to set. In other words,
* the number of indexes you have in the 'variables' fields * the number of indexes you have in the 'variables' fields
* @return 0 on success, -1 on error and errno is appropriately set.
*/ */
int trtl_rt_variable_get(struct trtl_dev *trtl, int trtl_fw_variable_get(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
uint32_t *variables, uint32_t *variables,
unsigned int n_variables) unsigned int n_variables)
{ {
/* FIXME Re-implement with new protocol */ struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
errno = ETRTL_NO_IMPLEMENTATION; struct trtl_msg msg;
return -1; int err;
memset(&msg, 0, sizeof(struct trtl_msg));
msg.hdr.msg_id = TRTL_MSG_ID_VAR_GET;
msg.hdr.seq = wdesc->seq;
msg.hdr.sync_id = msg.hdr.seq;
memcpy(msg.data, variables, sizeof(uint32_t) * n_variables);
err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg,
trtl_default_timeout_ms);
if (err <= 0)
return -1;
memcpy(variables, msg.data, sizeof(uint32_t) * n_variables);
return 0;
} }
...@@ -291,17 +193,48 @@ int trtl_rt_variable_get(struct trtl_dev *trtl, ...@@ -291,17 +193,48 @@ int trtl_rt_variable_get(struct trtl_dev *trtl,
* @param[in|out] tlv structures to get on input, structures values on output * @param[in|out] tlv structures to get on input, structures values on output
* @param[in] n_tlv number of tlv structures * @param[in] n_tlv number of tlv structures
*/ */
int trtl_rt_buffer_set(struct trtl_dev *trtl, int trtl_fw_buffer_set(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
struct trtl_structure_tlv *tlv, struct trtl_tlv *tlv,
unsigned int n_tlv) unsigned int n_tlv)
{ {
/* FIXME Re-implement with new protocol */ struct trtl_msg msg;
errno = ETRTL_NO_IMPLEMENTATION; struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
return -1; unsigned int offset;
unsigned int total_size = 0;
uint32_t sizes;
int err, i;
/* Validate */
for (i = 0; i < n_tlv; ++i) {
total_size += 8; /* 32bit for type and size */
total_size += tlv->size;
sizes = wdesc->cfgrom.hmq[idx_cpu][idx_hmq].sizes;
if (total_size > TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(sizes) * 4) {
errno = EINVAL;
return -1;
}
}
/* Copy buffers */
for (offset = 0, i = 0; i < n_tlv; ++i) {
msg.data[offset + 0] = tlv[i].type;
msg.data[offset + 1] = tlv[i].size;
memcpy(&msg.data[offset + 2], tlv[i].buf, tlv[i].size);
offset += (2 + (tlv->size / 4));
}
err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg,
trtl_default_timeout_ms);
if (err <= 0)
return -1;
return 0;
} }
/** /**
* It receives a set of structures within TLV records. * It receives a set of structures within TLV records.
* This function will change the header content, in particular it will change * This function will change the header content, in particular it will change
...@@ -311,15 +244,52 @@ int trtl_rt_buffer_set(struct trtl_dev *trtl, ...@@ -311,15 +244,52 @@ int trtl_rt_buffer_set(struct trtl_dev *trtl,
* @param[in|out] tlv structures to get on input, structures values on output * @param[in|out] tlv structures to get on input, structures values on output
* @param[in] n_tlv number of tlv structures * @param[in] n_tlv number of tlv structures
*/ */
int trtl_rt_buffer_get(struct trtl_dev *trtl, int trtl_fw_buffer_get(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
struct trtl_structure_tlv *tlv, struct trtl_tlv *tlv,
unsigned int n_tlv) unsigned int n_tlv)
{ {
/* FIXME Re-implement with new protocol */ struct trtl_msg msg;
errno = ETRTL_NO_IMPLEMENTATION; struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
return -1; unsigned int offset;
unsigned int total_size = 0;
uint32_t sizes;
int err, i;
/* Validate */
for (i = 0; i < n_tlv; ++i) {
total_size += 8; /* 32bit for type and size */
total_size += tlv->size;
sizes = wdesc->cfgrom.hmq[idx_cpu][idx_hmq].sizes;
if (total_size > TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD(sizes) * 4) {
errno = EINVAL;
return -1;
}
}
/* Copy buffers - only Type and Length */
for (offset = 0, i = 0; i < n_tlv; ++i) {
msg.data[offset + 0] = tlv[i].type;
msg.data[offset + 1] = tlv[i].size;
offset += (2 + (tlv->size / 4));
}
err = trtl_msg_sync(trtl, idx_cpu, idx_hmq, &msg, &msg,
trtl_default_timeout_ms);
if (err <= 0)
return -1;
/* Copy back buffers - only Type and Length */
for (offset = 0, i = 0; i < n_tlv; ++i) {
tlv[i].type = msg.data[offset + 0];
tlv[i].size = msg.data[offset + 1];
memcpy(&tlv[i].buf, &msg.data[offset + 2], tlv[i].size);
offset += (2 + (tlv->size / 4));
}
return 0;
} }
...@@ -327,14 +297,19 @@ int trtl_rt_buffer_get(struct trtl_dev *trtl, ...@@ -327,14 +297,19 @@ int trtl_rt_buffer_get(struct trtl_dev *trtl,
* It prints the message header in a human readable format * It prints the message header in a human readable format
* @param[in] h message header * @param[in] h message header
*/ */
void trtl_print_header(struct trtl_proto_header *h) void trtl_print_header(struct trtl_msg *msg)
{ {
struct trtl_hmq_header *h = &msg->hdr;
fprintf(stdout, fprintf(stdout,
" app_id 0x%x | msg_id %d | slot_io 0x%x | seq %d\n", "\tapp_id 0x%04"PRIx16" | flags 0x%02"PRIx8" | msg_id 0x%02"PRIx8"\r\n",
h->rt_app_id, h->msg_id, h->slot_io, h->seq); h->rt_app_id, h->flags, h->msg_id);
fprintf(stdout, fprintf(stdout,
" len %d | flags 0x%x | trans 0x%x | time %d\n", "\tlen 0x%04"PRIx16" | sync_id 0x%04"PRIx16"\r\n",
h->len, h->flags, h->trans, h->time); h->len, h->sync_id);
fprintf(stdout,
"\tlen 0x%08"PRIx32"\r\n",
h->seq);
} }
...@@ -344,26 +319,55 @@ void trtl_print_header(struct trtl_proto_header *h) ...@@ -344,26 +319,55 @@ void trtl_print_header(struct trtl_proto_header *h)
* @param[in] h message header * @param[in] h message header
* @param[in] buf message payload * @param[in] buf message payload
*/ */
void trtl_print_payload(struct trtl_proto_header *h, void *buf) void trtl_print_payload(struct trtl_msg *msg)
{ {
uint32_t *payload = buf;
int i; int i;
switch (h->msg_id) { switch (msg->hdr.msg_id) {
case TRTL_MSG_ID_VAR_SET: case TRTL_MSG_ID_ERROR:
fprintf(stdout, "Error message\n");
fprintf(stdout, "Error number: %d\n", msg->data[0]);
break;
case TRTL_MSG_ID_PING:
fprintf(stdout, "Ping message\n");
break;
case TRTL_MSG_ID_VER: {
struct trtl_fw_version *v = (struct trtl_fw_version *)msg->data;
fprintf(stdout, "Version message\n");
fprintf(stdout, "Firmware ID: 0x%08"PRIx32"\n", v->rt_id);
fprintf(stdout, "Firmware version: %d.%d\n",
RT_VERSION_MAJ(v->rt_version),
RT_VERSION_MIN(v->rt_version));
fprintf(stdout, "git SHA: 0x%08"PRIx32"\n", v->git_version);
break;
}
case TRTL_MSG_ID_DBG:
fprintf(stdout, "Debug message\n");
for (i = 0; i < msg->hdr.len; ++i) {
fprintf(stdout, "Value %d: 0x%08"PRIx32"\n",
i, msg->data[i]);
}
break;
case TRTL_MSG_ID_VAR_GET: case TRTL_MSG_ID_VAR_GET:
case TRTL_MSG_ID_VAR_GET_ANS: case TRTL_MSG_ID_VAR_SET:
for (i = 0; i < h->len; i += 2) { for (i = 0; i < msg->hdr.len; i += 2) {
fprintf(stdout, "[%d] 0x%08x\n", fprintf(stdout, "Variable %"PRId32": 0x%08"PRIx32"\n",
payload[i], payload[i + 1]); msg->data[i], msg->data[i + 1]);
} }
break; break;
case TRTL_MSG_ID_BUF_SET:
case TRTL_MSG_ID_BUF_GET:
fprintf(stdout, "Buffer message\n");
/* TODO */
break;
default: default:
for (i = 0; i < h->len; ++i) { fprintf(stdout, "Unknown message\n");
for (i = 0; i < msg->hdr.len; ++i) {
if (i % 4 == 0) if (i % 4 == 0)
fprintf(stdout, "\n %04d :", i); fprintf(stdout, "\n %04d :", i);
fprintf(stdout, " 0x%08x", payload[i]); fprintf(stdout, " 0x%08"PRIx32, msg->data[i]);
} }
break; break;
} }
} }
...@@ -377,15 +381,6 @@ void trtl_print_payload(struct trtl_proto_header *h, void *buf) ...@@ -377,15 +381,6 @@ void trtl_print_payload(struct trtl_proto_header *h, void *buf)
*/ */
void trtl_print_message(struct trtl_msg *msg) void trtl_print_message(struct trtl_msg *msg)
{ {
struct trtl_proto_header h; trtl_print_header(msg);
trtl_print_payload(msg);
trtl_message_unpack(msg, &h, NULL);
trtl_print_header(&h);
if (h.len) {
uint32_t payload[h.len];
trtl_message_unpack(msg, &h, payload);
trtl_print_payload(&h, payload);
}
} }
...@@ -243,6 +243,8 @@ static struct trtl_dev *__trtl_open(const char *device) ...@@ -243,6 +243,8 @@ static struct trtl_dev *__trtl_open(const char *device)
} }
} }
trtl->seq = 0;
return (struct trtl_dev *)trtl; return (struct trtl_dev *)trtl;
out_hmq_fd: out_hmq_fd:
......
...@@ -19,8 +19,6 @@ extern "C" { ...@@ -19,8 +19,6 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <poll.h> #include <poll.h>
#include "hw/mockturtle_config.h"
#include "mockturtle-common.h"
#include "mockturtle.h" #include "mockturtle.h"
extern const unsigned int trtl_default_timeout_ms; extern const unsigned int trtl_default_timeout_ms;
...@@ -98,15 +96,6 @@ enum trtl_error_number { ...@@ -98,15 +96,6 @@ enum trtl_error_number {
}; };
/**
* TLV structure used to embed structures within a message
*/
struct trtl_structure_tlv {
uint32_t index; /**< structure index (type) */
void *buf; /**< pointer to the structure */
size_t size; /**< structure size in byte */
};
/** /**
* @file libmockturtle.c * @file libmockturtle.c
*/ */
...@@ -134,8 +123,8 @@ const struct trtl_config_rom *trtl_config_get(struct trtl_dev *trtl); ...@@ -134,8 +123,8 @@ const struct trtl_config_rom *trtl_config_get(struct trtl_dev *trtl);
* Utilities collection * Utilities collection
* @{ * @{
*/ */
extern void trtl_print_header(struct trtl_proto_header *h); extern void trtl_print_header(struct trtl_msg *msg);
extern void trtl_print_payload(struct trtl_proto_header *h, void *buf); extern void trtl_print_payload(struct trtl_msg *msg);
extern void trtl_print_message(struct trtl_msg *msg); extern void trtl_print_message(struct trtl_msg *msg);
extern char *trtl_strerror(int err); extern char *trtl_strerror(int err);
/**@}*/ /**@}*/
...@@ -224,58 +213,35 @@ extern int trtl_smem_write(struct trtl_dev *trtl, uint32_t addr, uint32_t *data, ...@@ -224,58 +213,35 @@ extern int trtl_smem_write(struct trtl_dev *trtl, uint32_t addr, uint32_t *data,
/**@}*/ /**@}*/
/**
* @defgroup proto Protocol management
* Set of utilities to properly handle the protocol
* @{
*/
extern void trtl_message_header_set(struct trtl_msg *msg,
struct trtl_proto_header *hdr);
extern void trtl_message_header_get(struct trtl_msg *msg,
struct trtl_proto_header *hdr);
extern void trtl_message_pack(struct trtl_msg *msg,
struct trtl_proto_header *hdr,
void *payload);
extern void trtl_message_unpack(struct trtl_msg *msg,
struct trtl_proto_header *hdr,
void *payload);
extern void trtl_message_buffer_push(struct trtl_msg *msg,
struct trtl_proto_header *hdr,
struct trtl_structure_tlv *tlv);
extern off_t trtl_message_buffer_pop(struct trtl_msg *msg, off_t offset,
struct trtl_proto_header *hdr,
struct trtl_structure_tlv *tlv);
/**@}*/
/** /**
* @defgroup rtmsg Real Time service messages * @defgroup rtmsg Real Time service messages
* Message builders for RT service messages * Message builders for RT service messages
* @{ * @{
*/ */
extern int trtl_rt_version_get(struct trtl_dev *trtl, extern int trtl_fw_version(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
struct trtl_rt_version *version); struct trtl_fw_version *version);
extern int trtl_rt_ping(struct trtl_dev *trtl, extern int trtl_fw_ping(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq); unsigned int idx_hmq);
extern int trtl_rt_variable_set(struct trtl_dev *trtl, extern int trtl_fw_variable_set(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
uint32_t *var, unsigned int n_var); uint32_t *var, unsigned int n_var);
extern int trtl_rt_variable_get(struct trtl_dev *trtl, extern int trtl_fw_variable_get(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
uint32_t *var, unsigned int n_var); uint32_t *var, unsigned int n_var);
extern int trtl_rt_buffer_set(struct trtl_dev *trtl, extern int trtl_fw_buffer_set(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
struct trtl_structure_tlv *tlv, struct trtl_tlv *tlv,
unsigned int n_tlv); unsigned int n_tlv);
extern int trtl_rt_buffer_get(struct trtl_dev *trtl, extern int trtl_fw_buffer_get(struct trtl_dev *trtl,
unsigned int idx_cpu, unsigned int idx_cpu,
unsigned int idx_hmq, unsigned int idx_hmq,
struct trtl_structure_tlv *tlv, struct trtl_tlv *tlv,
unsigned int n_tlv); unsigned int n_tlv);
/**@}*/ /**@}*/
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -16,6 +16,7 @@ AUTOCONF = $(CURDIR)/$(BUILDDIR)/include/generated/autoconf.h ...@@ -16,6 +16,7 @@ AUTOCONF = $(CURDIR)/$(BUILDDIR)/include/generated/autoconf.h
CROSS_COMPILE_TARGET ?= riscv32-elf- CROSS_COMPILE_TARGET ?= riscv32-elf-
# FIXME the mult/div is broken, for the time being remove it completely # FIXME the mult/div is broken, for the time being remove it completely
# -march=rv32im should be the future option # -march=rv32im should be the future option
CFLAGS += -D__TRTL_FIRMWARE__
CFLAGS += -mabi=ilp32 -march=rv32i -ffunction-sections -fdata-sections CFLAGS += -mabi=ilp32 -march=rv32i -ffunction-sections -fdata-sections
LDFLAGS += -lgcc -lc -Wl,--gc-sections LDFLAGS += -lgcc -lc -Wl,--gc-sections
...@@ -66,10 +67,7 @@ OBJS += lib/printf.o ...@@ -66,10 +67,7 @@ OBJS += lib/printf.o
OBJS += lib/mockturtle-rt-common.o OBJS += lib/mockturtle-rt-common.o
OBJDIR-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework OBJDIR-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework
OBJS-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework/mockturtle-frm-core.o OBJS-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework/mockturtle-framework.o
OBJS-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework/mockturtle-frm-debug.o
OBJS-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework/mockturtle-frm-action.o
OBJS-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework/mockturtle-frm-mqueue.o
OBJDIR += $(OBJDIR-y) OBJDIR += $(OBJDIR-y)
OBJS += $(OBJS-y) OBJS += $(OBJS-y)
......
/**
* Copyright (C) 2015-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <mockturtle-framework.h>
uint32_t msg_seq = 0;
struct trtl_fw_application *_app;
/**
* It makes the given message an error message
*/
void trtl_fw_message_error(struct trtl_msg *msg, int err)
{
msg->header->msg_id = TRTL_MSG_ID_ERROR;
msg->header->len = 1;
((uint32_t *)msg->payload)[0] = err;
}
/**
* This is an @ref trtl_fw_action_t function type. It fills the payload
* witht an answer for the ping message.
*/
static int rt_recv_ping(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
msg_o->header->msg_id = TRTL_MSG_ID_PING;
return 0;
}
/**
* This is an @ref trtl_fw_action_t function type. It fills the payload with
* version information.
*/
static int rt_version_getter(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
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,
sizeof(struct trtl_fw_version));
return 0;
}
/**
* This is an @ref trtl_fw_action_t function type. Accorind the message request,
* it copies one of the declared data structure to the output payload.
*/
static int trtl_fw_buffer_getter(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
unsigned int offset = 0, index, size;
uint32_t *din;
uint32_t *dout;
if (!HAS_MOCKTURTLE_FRAMEWORK_BUFFER_ENABLE) {
return -EPERM;
}
/* Only synchronous */
if (!(msg_i->header->flags & TRTL_HMQ_HEADER_FLAG_SYNC))
return -EINVAL;
msg_o->header->msg_id = TRTL_MSG_ID_BUF_GET;
din = msg_i->payload;
dout = msg_o->payload;
while (offset < msg_i->header->len) {
pr_debug("%s: offset %d/%d\n\r", __func__,
offset, msg_i->header->len);
index = din[offset];
dout[offset++] = index;
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);
if (_app->buffers[index].len == size) {
memcpy(&dout[offset],
(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);
}
offset += (size / 4); /* Next TLV record */
}
return 0;
}
/**
* This is an @ref trtl_fw_action_t function type. Accorind the message request,
* it overwrite a data structure with the one contained in the input
* payload. If the message is syncrnous it will copy back the data structure.
*/
static int trtl_fw_buffer_setter(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
unsigned int offset = 0, index, size;
uint32_t *din;
if (!HAS_MOCKTURTLE_FRAMEWORK_BUFFER_ENABLE) {
return -EPERM;
}
din = msg_i->payload;
while (offset < msg_i->header->len) {
pr_debug("%s: offset %d/%d\n\r", __func__,
offset, msg_i->header->len);
index = din[offset++];
size = din[offset++];
pr_debug("%s Type %d Len %d Addr 0x%p\n\r", __func__,
index, size, _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);
}
offset += (size / 4); /* Next TLV record */
}
/* Return back new values. Host can compare with what it sent
to spot errors */
if (msg_i->header->flags & TRTL_HMQ_HEADER_FLAG_SYNC)
return trtl_fw_buffer_getter(msg_i, msg_o);
return 0;
}
/**
* This is an @ref trtl_fw_action_t function type. Accorind the message request,
* it copies a number of declared variables.
*/
static int trtl_fw_variable_getter(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
struct trtl_fw_variable *var;
uint32_t *dout, *din , *mem, val;
int i;
if (!HAS_MOCKTURTLE_FRAMEWORK_VARIABLE_ENABLE) {
return -EPERM;
}
/* Only synchronous */
if (!(msg_i->header->flags & TRTL_HMQ_HEADER_FLAG_SYNC))
return -EINVAL;
/* we always have a pair of values */
if (msg_i->header->len & 0x1)
return -EINVAL;
din = msg_i->payload;
dout = msg_o->payload;
msg_o->header->msg_id = TRTL_MSG_ID_VAR_GET;
msg_o->header->len = msg_i->header->len;
/* Write all values in the proper place */
for (i = 0; i < msg_o->header->len; i += 2) {
if (din[i] >= _app->n_variables) {
dout[i] = ~0; /* Report invalid index */
continue;
}
dout[i] = din[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,
mem, *mem, dout[i + 1],
i + 1, msg_i->header->len - 1);
}
return 0;
}
/**
* This is an @ref trtl_fw_action_t function type. Accorind the message request,
* it writes a number of declared variables. If the message is synchronous
* it copies back the values in the output payload.
*/
static int trtl_fw_variable_setter(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
struct trtl_fw_variable *var;
uint32_t *din, *mem, val;
int i;
if (!HAS_MOCKTURTLE_FRAMEWORK_VARIABLE_ENABLE) {
return -EPERM;
}
/* we always have a pair of values */
if (msg_i->header->len & 0x1)
return -EINVAL;
din = msg_i->payload;
/* Write all values in the proper place */
for (i = 0; i < msg_i->header->len; i += 2) {
if (din[i] >= _app->n_variables)
continue;
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)
*mem = (*mem & ~var->mask) | val;
else
*mem = val;
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,
mem, *mem, val, din[i + 1],
i + 1, msg_i->header->len - 1);
}
/* Return back new values. Host can compare with what it sent
to spot errors */
if (msg_i->header->flags & TRTL_HMQ_HEADER_FLAG_SYNC)
return trtl_fw_variable_getter(msg_i, msg_o);
return 0;
}
/**
* List of standard actions
*/
static trtl_fw_action_t *trtl_actions_in[] = {
[TRTL_MSG_ID_PING - __TRTL_MSG_ID_MAX_USER] = rt_recv_ping,
[TRTL_MSG_ID_VER - __TRTL_MSG_ID_MAX_USER] = rt_version_getter,
[TRTL_MSG_ID_VAR_SET - __TRTL_MSG_ID_MAX_USER] = trtl_fw_variable_setter,
[TRTL_MSG_ID_VAR_GET - __TRTL_MSG_ID_MAX_USER] = trtl_fw_variable_getter,
[TRTL_MSG_ID_BUF_SET - __TRTL_MSG_ID_MAX_USER] = trtl_fw_buffer_setter,
[TRTL_MSG_ID_BUF_GET - __TRTL_MSG_ID_MAX_USER] = trtl_fw_buffer_getter,
};
/**
* According to the given message ID it returns the correspondent action
* @param[in] msg_id message id
* @return pointer to action function
*/
static inline trtl_fw_action_t *rt_action_get(unsigned int msg_id)
{
unsigned int idx_act = msg_id;
if (idx_act < __TRTL_MSG_ID_MAX_USER) {
/* User Actions */
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];
} else {
/* Mock Turtle Standard Actions */
idx_act -= __TRTL_MSG_ID_MAX_USER;
if (ARRAY_SIZE(trtl_actions_in) < idx_act) {
pr_error("Unknown action msg_id 0x%x\n\r",
msg_id);
return NULL;
}
return trtl_actions_in[idx_act];
}
}
/**
* It runs the action associated with the given identifier
* @param[in] id action identifier
* @param[in] msg_i input message for the action
* @param[out] msg_o output message from the action
* @return 0 on success. Otherwise an error code
*
* If the action generates an error, the framework will send
* an error message with the error code.
*/
static inline int rt_action_run(enum trtl_mq_type type,
unsigned int idx_mq,
struct trtl_msg *msg)
{
struct trtl_msg msg_out;
trtl_fw_action_t *action = rt_action_get(msg->header->msg_id);
int err = 0;
if (!action)
return EINVAL;
if (!(msg->header->flags & TRTL_HMQ_HEADER_FLAG_SYNC)) {
/* Asynchronous message, then no output */
return action(msg, NULL);
}
/* Synchronous message */
mq_claim(type, idx_mq);
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->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++;
err = action(msg, &msg_out);
if (err)
trtl_fw_message_error(&msg_out, err);
trtl_fw_print_message(&msg_out);
mq_send(type, idx_mq);
return err;
}
/**
* It dispatch messages coming from a given message queue.
* @param[in] mq_in MQ index within mq declaration in rt_application
* @todo provide support for remote queue
* @return 0 on success. -1 on error
*/
int trtl_fw_mq_action_dispatch(enum trtl_mq_type type, unsigned int idx_mq)
{
struct trtl_msg msg;
int err = 0;
if (type == TRTL_RMQ)
return -EPERM; /* not supported yet */
/* Check if we have a pending message */
if (!(mq_poll_in(type) & (1 << idx_mq)))
return -EAGAIN;
/* Map the message */
mq_map_in_message(type, idx_mq, &msg);
trtl_fw_print_message(&msg);
if (!(msg.header->flags & TRTL_HMQ_HEADER_FLAG_RPC)) {
return -EINVAL;
}
if (msg.header->rt_app_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;
goto out;
}
/* Run the correspondent action */
err = rt_action_run(type, idx_mq, &msg);
if (err)
pr_error("Action failure err: %d\n\r", err);
out:
mq_discard(type, idx_mq);
return err;
}
/**
* It builds and it sends a message over MQ.
* The vargs will be copied into the payload message.
* @param[in] type MQ type
* @param[in] idx_mq MQ index within the declaration
* @param[in] msg_id message identifier
* @param[in] n number of vargs
*/
int trtl_fw_mq_send_uint32(enum trtl_mq_type type,
unsigned int idx_mq,
uint8_t msg_id,
unsigned int n, ...)
{
struct trtl_msg msg;
uint32_t sizes;
va_list ap;
int i;
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->flags = 0;
msg.header->msg_id = msg_id;
msg.header->len = n;
msg.header->seq = _app->seq++;
va_start(ap, n);
for (i = 0; i < msg.header->len;++i)
((uint32_t *)msg.payload)[i] = va_arg(ap, uint32_t);
va_end(ap);
mq_send(type, idx_mq);
return 0;
}
/**
* It builds and it sends a message over MQ.
* The buffer will be copied into the payload message.
* Beware that, internally, it uses trtl_fw_mq_send().
* @param[in] type MQ type
* @param[in] idx_mq MQ index within the declaration
* @param[in] msg_id message identifier
* @param[in] n buffer size in bytes
* @param[in] data buffer to send
*/
int trtl_fw_mq_send_buf(enum trtl_mq_type type,
unsigned int idx_mq,
uint8_t msg_id,
unsigned int n,
void *data)
{
struct trtl_msg msg;
uint32_t 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->flags = 0;
msg.header->msg_id = msg_id;
msg.header->len = n / 4;
msg.header->seq = _app->seq++;
memcpy(msg.payload, data, n);
mq_send(type, idx_mq);
return 0;
}
/**
* It prints on the serial interface the given message header
* @param[in] h message header to print
*/
void trtl_fw_print_header(struct trtl_hmq_header *h)
{
if (!HAS_MOCKTURTLE_FRAMEWORK_DEBUG_ENABLE) {
return;
}
pr_debug("\tapp_id 0x%04"PRIx16" | flags 0x%02"PRIx8" | msg_id 0x%02"PRIx8"\r\n",
h->rt_app_id, h->flags, h->msg_id);
delay(1000);
pr_debug("\tlen 0x%04"PRIx16" | sync_id 0x%04"PRIx16"\r\n",
h->len, h->sync_id);
delay(1000);
pr_debug("\tseq 0x%08"PRIx32"\r\n",
h->seq);
delay(1000);
}
/**
* It prints on the serial interface a buffer
* @param[in] d buffer data
* @param[in] count number of 32bit words to show
*/
void trtl_fw_print_data(uint32_t *d, unsigned int count)
{
int i;
if (!HAS_MOCKTURTLE_FRAMEWORK_DEBUG_ENABLE) {
return;
}
for (i = 0; i < count; i++) {
pr_debug("%s: data[%d] = 0x%"PRIx32"\n\r", __func__, i , d[i]);
delay(1000);
}
}
/**
* It prints on the serial console the given message
* @param[in] msg a mock turtle message
*/
void trtl_fw_print_message(struct trtl_msg *msg)
{
pr_debug("Message\n\r");
trtl_fw_print_header(msg->header);
trtl_fw_print_data(msg->payload, msg->header->len);
}
/**
* It get the current time from the internal WRNC timer
* @param[out] seconds
* @param[out] cycles
*/
void trtl_fw_time(uint32_t *seconds, uint32_t *cycles)
{
*seconds = lr_readl(MT_CPU_LR_REG_TAI_SEC);
*cycles = lr_readl(MT_CPU_LR_REG_TAI_CYCLES);
}
/**
* It validates the user application actions
* @param[in] app the user application
* @return 0 on success. -EINVAL on error
*/
static inline int trtl_fw_init_action(struct trtl_fw_application *app)
{
int i;
/* Validate actions */
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) {
pr_error("Undefined action %d\n\r", i);
return -EINVAL;
}
}
return 0;
}
/**
* It validates the FPGA
* @param[in] app the user application
* @return 0 on success. -EINVAL on error
*/
static inline int trtl_fw_init_fpga(struct trtl_fw_application *app)
{
int i, found = 0;
for (i = 0; i < app->fpga_id_compat_n; i++) {
if (app->fpga_id_compat[i] == app->cfgrom->app_id) {
found = 1;
break;
}
}
if (!found) {
pr_error("\tFPGA '0x%"PRIx32"' not compatible with RT app: 0x%"PRIx32" 0x%"PRIx32" (git %"PRIx32")\n\r",
app->cfgrom->app_id,
app->version.rt_id,
app->version.rt_version,
app->version.git_version);
return -EINVAL;
}
pr_debug("Running application '%s'\n\r", app->name);
pr_debug("\tapp id \t'0x%"PRIx32"'\n\r",
app->version.rt_id);
pr_debug("\tapp version\t'%"PRId32".%"PRId32"'\n\r",
RT_VERSION_MAJ(app->version.rt_version),
RT_VERSION_MIN(app->version.rt_version));
pr_debug("\tsource id \t'0x%"PRIx32"'\n\r",
app->version.git_version);
return 0;
}
/**
* It validates the RMQ and the HMQ
* @param[in] app the user application
* @return 0 on success. -EINVAL on error
*/
static inline int trtl_fw_init_mq(struct trtl_fw_application *app)
{
return 0;
}
/**
* It validates the RMQ and the HMQ
* @param[in] app the user application
* @return 0 on success. -EINVAL on error
*/
static inline int trtl_fw_init_variables(struct trtl_fw_application *app)
{
int i;
pr_debug("Exported Variables\n\r");
for (i = 0; i < app->n_variables; ++i)
pr_debug("[%d] addr %p | mask 0x%"PRIx32" | off %d\n\r",
i,
app->variables[i].addr,
app->variables[i].mask,
app->variables[i].offset);
return 0;
}
/**
* It validates the RMQ and the HMQ
* @param[in] app the user application
* @return 0 on success. -EINVAL on error
*/
static inline int trtl_fw_init_buffers(struct trtl_fw_application *app)
{
int i;
pr_debug("Exported Buffers\n\r");
for (i = 0; i < app->n_buffers; ++i)
pr_debug("[%d] addr %p | len %"PRId32"\n\r", i,
app->buffers[i].buf,
app->buffers[i].len);
return 0;
}
/**
* The function initializes the library and it does some compatibility check.
*
* Initialization
* - purge all the output host-message-queue
*
* compatibility checks:
* - check bitstream FPGA ID if compatibile with the application. The value in
* app->version.fpga_id will be updated with the FPGA ID from the bitstream
*
* @param[in] app application declaration
* @return 0 on success. -1 on error
*/
int trtl_fw_init(struct trtl_fw_application *app)
{
int err;
_app = app;
_app->seq = 0;
_app->cfgrom = trtl_config_rom_get();
err = trtl_fw_init_action(_app);
if (err)
return err;
err = trtl_fw_init_fpga(_app);
if (err)
return err;
err = trtl_fw_init_mq(_app);
if (err)
return err;
err = trtl_fw_init_buffers(_app);
if (err)
return err;
err = trtl_fw_init_variables(_app);
if (err)
return err;
return 0;
}
...@@ -10,13 +10,98 @@ ...@@ -10,13 +10,98 @@
#ifndef __TRTL_FW_FRM_H__ #ifndef __TRTL_FW_FRM_H__
#define __TRTL_FW_FRM_H__ #define __TRTL_FW_FRM_H__
#include <inttypes.h>
#include <generated/autoconf.h> #include <generated/autoconf.h>
#include "mockturtle-rt.h" #include "mockturtle-rt.h"
#include "mockturtle-frm-action.h"
#include "mockturtle-frm-mqueue.h"
#include "mockturtle-frm-common.h" /**
#include "mockturtle-frm-debug.h" * Action prototype type
#include "mockturtle-frm-variable.h" * @param[in] msg_i input message
* @param[out] msg_o output message
* @return 0 on success. -1 on error
*
* The header for the output message is prepared by the framework.
* The header's fields that the user should touch are
*
* On error the message will be sent anyway to the host. This
* is just in case of future development.
*/
typedef int (trtl_fw_action_t)(struct trtl_msg *msg_i, struct trtl_msg *msg_o);
/**
* Variable flag. Register
*/
#define TRTL_FW_VARIABLE_FLAG_FLD (1 << 0)
/**
* Description of a variable that we want to export to the external
* world (host or network).
*/
struct trtl_fw_variable {
void *addr; /**< variable address */
uint32_t mask; /**< variable mask without offset applied */
uint8_t offset; /**< variable offset within the word */
uint32_t flags; /**< variable options */
};
/**
* Description of a buffer that we want to export to the external world
* (host or network)
*/
struct trtl_fw_buffer {
void *buf; /**< structure location */
uint32_t len; /**< data structure lenght */
/* Maybe other option later in time */
};
/**
* Real-Time Application Descriptor
*/
struct trtl_fw_application {
const char name[16]; /**< Firmware name*/
const uint32_t *fpga_id_compat; /**< list of compatible FPGA
application ID */
const unsigned int fpga_id_compat_n; /**< number of entry in
the fpga_id_compat list */
const struct trtl_fw_version version; /**< version running */
struct trtl_fw_buffer *buffers; /**< exported buffers */
unsigned int n_buffers; /**< number or exported buffers */
struct trtl_fw_variable *variables; /**< exported variables */
unsigned int n_variables; /**< number or exported variables */
trtl_fw_action_t **actions; /**< list of custum actions */
unsigned int n_actions; /**< number of custum actions */
unsigned int seq; /** sequence number reference */
const struct trtl_config_rom *cfgrom;
};
extern struct trtl_fw_application *_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);
extern void trtl_fw_print_message(struct trtl_msg *msg);
extern int trtl_fw_mq_send_uint32(enum trtl_mq_type type,
unsigned int idx_mq,
uint8_t msg_id,
unsigned int n,
...);
extern int trtl_fw_mq_send_buf(enum trtl_mq_type type,
unsigned int idx_mq,
uint8_t msg_id,
unsigned int n,
void *data);
extern int trtl_fw_mq_action_dispatch(enum trtl_mq_type type,
unsigned int idx_mq);
extern void trtl_fw_message_error(struct trtl_msg *msg, int err);
#endif #endif
/**@}*/ /**@}*/
/**
* Copyright (C) 2015-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <errno.h>
#include <inttypes.h>
#include <mockturtle-framework.h>
/**
* This is an @ref action_t function type. It fills the payload
* witht an answer for the ping message.
*/
int rt_recv_ping(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout)
{
rt_send_ack(hin, pin, hout, pout);
return 0;
}
/**
* This is an @ref action_t function type. It fills the payload with
* version information.
*/
int rt_version_getter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout)
{
uint32_t *dout = pout;
hout->msg_id = TRTL_MSG_ID_VERS_ANS;
hout->len = sizeof(struct trtl_rt_version) / 4;
memcpy(dout, (uint32_t *)&_app->version,
sizeof(struct trtl_rt_version));
return 0;
}
/**
* This is an @ref action_t function type. Accorind the message request,
* it overwrite a data structure with the one contained in the input
* payload. If the message is syncrnous it will copy back the data structure.
*/
int rt_buffer_setter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout)
{
unsigned int offset = 0, index, size;
uint32_t *din = pin;
if (!HAS_MOCKTURTLE_FRAMEWORK_BUFFER_ENABLE) {
rt_send_nack(hin, pin, hout, NULL);
return 0;
}
while (offset < hin->len) {
pr_debug("%s: offset %d/%d\n\r", __func__, offset, hin->len);
index = din[offset++];
size = din[offset++];
pr_debug("%s Type %d Len %d Addr 0x%p\n\r", __func__,
index, size, _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);
}
offset += (size / 4); /* Next TLV record */
}
/* Return back new values. Host can compare with what it sent
to spot errors */
if (hin->flags & TRTL_HEAD_FLAG_SYNC)
return rt_buffer_getter(hin, pin, hout, pout);
return 0;
}
/**
* This is an @ref action_t function type. Accorind the message request,
* it copies one of the declared data structure to the output payload.
*/
int rt_buffer_getter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout)
{
unsigned int offset = 0, index, size;
uint32_t *din = pin;
uint32_t *dout = pout;
if (!HAS_MOCKTURTLE_FRAMEWORK_BUFFER_ENABLE) {
rt_send_nack(hin, pin, hout, NULL);
return 0;
}
hout->msg_id = TRTL_MSG_ID_BUF_GET_ANS;
while (offset < hin->len) {
pr_debug("%s: offset %d/%d\n\r", __func__, offset, hin->len);
index = din[offset];
dout[offset++] = index;
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);
if (_app->buffers[index].len == size) {
memcpy(&dout[offset],
(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);
}
offset += (size / 4); /* Next TLV record */
}
return 0;
}
/**
* This is an @ref action_t function type. Accorind the message request,
* it writes a number of declared variables. If the message is synchronous
* it copies back the values in the output payload.
*/
int rt_variable_setter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout)
{
struct rt_variable *var;
uint32_t *din = pin, *mem, val;
int i;
if (!HAS_MOCKTURTLE_FRAMEWORK_VARIABLE_ENABLE) {
pr_debug("Variable set action not supported\n\r");
rt_send_nack(hin, pin, hout, NULL);
return 0;
}
/* we always have a pair of values */
if (hin->len % 2)
rt_send_nack(hin, pin, hout, pout);
/* Write all values in the proper place */
for (i = 0; i < hin->len; i += 2) {
if (din[i] >= _app->n_variables)
continue;
var = &_app->variables[din[i]];
mem = (uint32_t *) var->addr;
val = ((din[i + 1] & var->mask) << var->offset);
if (var->flags & TRTL_RT_VARIABLE_FLAG_FLD)
*mem = (*mem & ~var->mask) | val;
else
*mem = val;
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,
mem, *mem, val, din[i + 1],
i + 1, hin->len - 1);
}
/* Return back new values. Host can compare with what it sent
to spot errors */
if (hin->flags & TRTL_HEAD_FLAG_SYNC)
return rt_variable_getter(hin, pin, hout, pout);
return 0;
}
/**
* This is an @ref action_t function type. Accorind the message request,
* it copies a number of declared variables.
*/
int rt_variable_getter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout)
{
struct rt_variable *var;
uint32_t *dout = pout, *din = pin, *mem, val;
int i;
if (!HAS_MOCKTURTLE_FRAMEWORK_VARIABLE_ENABLE) {
pr_debug("Variable get action not supported\n\r");
rt_send_nack(hin, pin, hout, NULL);
return 0;
}
if (!hout || !pout)
return -1;
/* we always have a pair of values */
if (hin->len % 2)
return -1;
hout->msg_id = TRTL_MSG_ID_VAR_GET_ANS;
/* Write all values in the proper place */
for (i = 0; i < hout->len; i += 2) {
if (din[i] >= _app->n_variables) {
dout[i] = ~0; /* Report invalid index */
continue;
}
dout[i] = din[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,
mem, *mem, dout[i + 1],
i + 1, hin->len - 1);
}
return 0;
}
/**
* List of standard actions
*/
static action_t *trtl_actions_in[] = {
rt_recv_ping,
rt_version_getter,
rt_variable_setter,
rt_variable_getter,
rt_buffer_setter,
rt_buffer_getter,
};
/**
* It runs the action associated with the given identifier
* @param[in] id action identifier
* @param[in] msg input message for the action
* @return 0 on success. A negative value on error
*/
static inline int rt_action_run(struct trtl_proto_header *hin, void *pin)
{
action_t *action;
struct trtl_msg out_buf;
struct trtl_proto_header hout;
void *pout;
int err = 0;
if (hin->msg_id >= __TRTL_MSG_ID_MAX) {
pr_error("Invalid Message ID %d\n\r", hin->msg_id);
return -EINVAL;
}
if (hin->msg_id < __TRTL_MSG_ID_MAX_USER) {
/* User Actions */
if (hin->msg_id >= _app->n_actions ||
!_app->actions[hin->msg_id]) {
pr_error("Cannot dispatch (usr) msg_id 0x%x\n\r",
hin->msg_id);
return -EINVAL;
}
action = _app->actions[hin->msg_id];
} else {
/* Mock Turtle Standard Actions */
if (ARRAY_SIZE(trtl_actions_in) < hin->msg_id - __TRTL_MSG_ID_MAX_USER) {
pr_error("Cannot dispatch msg_id 0x%x\n\r",
hin->msg_id);
return -EINVAL;
}
action = trtl_actions_in[hin->msg_id - __TRTL_MSG_ID_MAX_USER];
}
pr_debug("Message Input\n\r");
rt_print_header(hin);
rt_print_data(pin, 8);
if (!(hin->flags & TRTL_HEAD_FLAG_SYNC)) {
/* Asynchronous message, then no output */
return action(hin, pin, NULL, NULL);
}
/* Synchronous message */
out_buf = rt_mq_claim_out(hin);
/* Do not write directly the header on the buffer because it does not
work for fields size different than 32bit */
pout = rt_proto_payload_get((void *) out_buf.data);
memcpy((uint32_t *)&hout, (uint32_t *)hin,
sizeof(struct trtl_proto_header));
err = action(hin, pin, &hout, pout);
if (err)
rt_send_nack(hin, pin, &hout, NULL);
rt_proto_header_set((void *) out_buf.data, &hout);
rt_mq_msg_send(&out_buf);
pr_debug("Message Output\n\r");
rt_print_header(&hout);
rt_print_data(pout, 8);
return err;
}
/**
* It dispatch messages coming from a given message queue.
* @param[in] mq_in MQ index within mq declaration in rt_application
* @todo provide support for remote queue
* @return 0 on success. -1 on error
*/
int rt_mq_action_dispatch(unsigned int mq_in)
{
struct trtl_proto_header *header;
unsigned int mq_in_slot = _app->mq[mq_in].index;
uint32_t *msg;
void *pin;
int err = 0;
/* HMQ control slot empty? */
if (_app->mq[mq_in].type == TRTL_HMQ) {
if (!(hmq_poll_in() & ( 1 << mq_in_slot)))
return -EAGAIN;
} else {
return -EAGAIN; /* Not used now */
}
/* Get the message from the HMQ */
msg = mq_map_in_buffer(0, mq_in_slot);
pr_debug("Incoming message\n\r");
rt_print_data(msg, 8);
header = rt_proto_header_get((void *) msg);
rt_print_header(header);
if (header->rt_app_id && header->rt_app_id != _app->version.rt_id) {
pr_error("Not for this application 0x%x\n\r", header->rt_app_id);
err = -EINVAL;
goto out;
}
if (!(header->flags & TRTL_HEAD_FLAG_RPC)) {
pr_error("%s: The message is not an RPC\n", __func__);
err = -EINVAL;
goto out;
}
pin = rt_proto_payload_get((void *) msg);
/* Run the correspondent action */
err = rt_action_run(header, pin);
if (err)
pr_error("%s: action failure err: %d\n\r", __func__, err);
out:
mq_discard(0, mq_in_slot);
return err;
}
/**
* @defgroup framework-action Framework Action
* @{
* @ingroup framework
* @brief Action (RPC)
* @copyright (C) 2015-2016 CERN (www.cern.ch)
* @author Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_FW_FRM_ACTION_H__
#define __TRTL_FW_FRM_ACTION_H__
/**
* Action prototype type
* @param[in] hin input message header
* @param[in] pin input message payload
* @param[out] hout output message header
* @param[out] pout output message payload
* @return 0 on success. -1 on error
*/
typedef int (action_t)(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout);
/**
* This is an @ref action_t function type. It fills the output payload
* with an acknowledged message
*/
static inline void rt_send_ack(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout)
{
hout->msg_id = TRTL_MSG_ID_ACK;
hout->len = 0;
}
/**
* This is an @ref action_t function type. It fills the output payload
* with a not-acknowledged message
*/
static inline void rt_send_nack(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout)
{
hout->msg_id = TRTL_MSG_ID_NACK;
hout->len = 0;
}
extern int rt_recv_ping(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout);
extern int rt_version_getter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout);
extern int rt_variable_setter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout);
extern int rt_variable_getter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout);
extern int rt_buffer_setter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout);
extern int rt_buffer_getter(struct trtl_proto_header *hin, void *pin,
struct trtl_proto_header *hout, void *pout);
extern int rt_mq_action_dispatch(unsigned int mq_in);
#endif
/**@}*/
/**
* @defgroup framework-buffer Framework Buffer
* @{
* @ingroup framework
* @brief Buffer exchange mechanism
* @copyright (C) 2015-2016 CERN (www.cern.ch)
* @author Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_FW_FRM_BUFFER_H__
#define __TRTL_FW_FRM_BUFFER_H__
/**
* Description of a buffer that we want to export to the external world
* (host or network)
*/
struct rt_buffer {
void *buf; /**< structure location */
uint32_t len; /**< data structure lenght */
/* Maybe other option later in time */
};
#endif
/**@}*/
/**
* @defgroup framework-common Framework Common Utilities
* @{
* @ingroup framework
* @brief Common Utilities
* @copyright (C) 2015-2016 CERN (www.cern.ch)
* @author Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_FW_FRM_COMMON_H__
#define __TRTL_FW_FRM_COMMON_H__
#include "mockturtle-frm-action.h"
#include "mockturtle-frm-mqueue.h"
#include "mockturtle-frm-variable.h"
#include "mockturtle-frm-buffer.h"
#define RT_VERSION_MAJ(_v) ((_v >> 16) & 0xFFFF)
#define RT_VERSION_MIN(_v) (_v & 0xFFFF)
#define RT_VERSION(_a, _b) (((_a & 0xFFFF) << 16) | (_b & 0xFFFF))
/**
* Real-Time Application Descriptor
*/
struct rt_application {
const char name[16]; /**< Firmware name*/
const uint32_t *fpga_id_compat; /**< list of compatible FPGA
application ID */
const unsigned int fpga_id_compat_n; /**< number of entry in
the fpga_id_compat list */
const struct trtl_rt_version version; /**< version running */
struct rt_mq *mq; /**< list of used MQ */
uint8_t n_mq; /**< number of available MQ */
struct rt_buffer *buffers; /**< exported buffers */
unsigned int n_buffers; /**< number or exported buffers */
struct rt_variable *variables; /**< exported variables */
unsigned int n_variables; /**< number or exported variables */
action_t **actions; /**< list of custum actions */
unsigned int n_actions; /**< number of custum actions */
};
extern struct rt_application *_app;
extern int rt_init(struct rt_application *app);
extern void rt_get_time(uint32_t *seconds, uint32_t *cycles);
#endif
/**@}*/
/**
* Copyright (C) 2015-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <stdint.h>
#include <errno.h>
#include <mockturtle-framework.h>
uint32_t msg_seq = 0;
struct rt_application *_app;
/**
* It get the current time from the internal WRNC timer
* @param[out] seconds
* @param[out] cycles
*/
void rt_get_time(uint32_t *seconds, uint32_t *cycles)
{
*seconds = lr_readl(MT_CPU_LR_REG_TAI_SEC);
*cycles = lr_readl(MT_CPU_LR_REG_TAI_CYCLES);
}
/**
* It initilizes the declared MQs
* @param[in] app application declaration
* @return 0 on success. -1 on error
*/
static inline int trtl_rt_init_mq(void)
{
int i;
for (i = 0; i < _app->n_mq; ++i) {
if (_app->mq[i].flags & TRTL_RT_MQ_FLAGS_OUTPUT) {
_app->mq[i].buf = mq_map_out_buffer(_app->mq[i].type,
_app->mq[i].index);
mq_purge(_app->mq[i].type, _app->mq[i].index);
if (_app->mq[i].flags & TRTL_RT_MQ_FLAGS_CLAIM) {
mq_claim(_app->mq[i].type, _app->mq[i].index);
}
} else {
_app->mq[i].buf = mq_map_in_buffer(_app->mq[i].type,
_app->mq[i].index);
}
}
return 0;
}
/**
* The function initializes the library and it does some compatibility check.
*
* Initialization
* - purge all the output host-message-queue
*
* compatibility checks:
* - check bitstream FPGA ID if compatibile with the application. The value in
* app->version.fpga_id will be updated with the FPGA ID from the bitstream
*
* @param[in] app application declaration
* @return 0 on success. -1 on error
*/
int rt_init(struct rt_application *app)
{
int i, err;
uint32_t *fpga_id = &app->version.fpga_id; /* in order to overwrite the const */
_app = app;
/* Validate actions */
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 -1;
}
if (_app->actions[i] == NULL) {
pr_error("Undefined action %d\n\r", i);
return -1;
}
}
pr_debug("Running application '%s'\n\r", _app->name);
/* *fpga_id = 0x1234; /\* TODO read it from the FPGA ID register *\/ */
for (i = 0; i < app->fpga_id_compat_n; i++) {
if (app->fpga_id_compat[i] == *fpga_id)
break;
}
if (app->fpga_id_compat_n && app->fpga_id_compat_n == i) {
pr_error("\tFPGA '0x%"PRIx32"' not compatible with RT app: 0x%"PRIx32" 0x%"PRIx32" (git %"PRIx32")\n\r",
_app->version.fpga_id,
_app->version.rt_id,
_app->version.rt_version,
_app->version.git_version);
return -1;
}
pr_debug("\tapp id \t'0x%"PRIx32"'\n\r",
_app->version.rt_id);
pr_debug("\tapp version\t'%"PRId32".%"PRId32"'\n\r",
RT_VERSION_MAJ(_app->version.rt_version),
RT_VERSION_MIN(_app->version.rt_version));
pr_debug("\tsource id \t'0x%"PRIx32"'\n\r",
_app->version.git_version);
err = trtl_rt_init_mq();
if (err)
return err;
#ifdef LIBRT_DEBUG
pr_debug("Exported Variables\n\r");
for (i = 0; i < _app->n_variables; ++i)
pr_debug("[%d] addr %p | mask 0x%"PRIx32" | off %d\n\r",
i,
_app->variables[i].addr,
_app->variables[i].mask,
_app->variables[i].offset);
pr_debug("Exported Buffers\n\r");
for (i = 0; i < _app->n_buffers; ++i)
pr_debug("[%d] addr %p | len %"PRId32"\n\r", i,
_app->buffers[i].buf,
_app->buffers[i].len);
#endif
return 0;
}
/**
* Copyright (C) 2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <mockturtle-framework.h>
/**
* The function can be used to send debug information to the host
* trought the HMQ
* @param[in] mq_in MQ index within mq declaration in rt_application
* @param[in] n_values number of variadic arguments
* @return 0 on success. -1 on error
*/
int rt_send_debug(int mq_in, int n_values, ...)
{
va_list ap;
struct trtl_msg out_buf;
uint32_t *buf;
struct trtl_proto_header hdr = {
.rt_app_id = _app->version.rt_id,
.msg_id = TRTL_MSG_ID_DBG,
.slot_io = _app->mq[mq_in].index & 0xF,
.seq = 0,
.len = n_values,
.flags = 0x0,
.trans = 0x0,
.time = 0x0,
};
int i;
if (!HAS_MOCKTURTLE_FRAMEWORK_DEBUG_ENABLE) {
return 0;
}
out_buf = rt_mq_claim_out(&hdr);
buf = (uint32_t *)rt_proto_payload_get(out_buf.data);
va_start(ap, n_values);
for (i = 0; i < hdr.len;++i)
buf[i] = va_arg(ap, uint32_t);
va_end(ap);
rt_proto_header_set((void *) out_buf.data, &hdr);
rt_mq_msg_send(&out_buf);
return 0;
}
/**
* It prints on the serial interface the given message header
* @param[in] h message header to print
*/
void rt_print_header(struct trtl_proto_header *h)
{
if (!HAS_MOCKTURTLE_FRAMEWORK_DEBUG_ENABLE) {
return;
}
pr_debug(" app_id 0x%x | msg_id %d | slot_io 0x%x | seq %"PRIu32"d\n\r",
h->rt_app_id, h->msg_id, h->slot_io, h->seq);
delay(1000);
pr_debug(" len %d | flags 0x%x | trans 0x%x | time %"PRIu32"d\n\r",
h->len, h->flags, h->trans, h->time);
delay(1000);
}
/**
* It prints on the serial interface a buffer
* @param[in] d buffer data
* @param[in] count number of 32bit words to show
*/
void rt_print_data(uint32_t *d, unsigned int count)
{
int i;
if (!HAS_MOCKTURTLE_FRAMEWORK_DEBUG_ENABLE) {
return;
}
for (i = 0; i < count; i++) {
pr_debug("%s: data[%d] = 0x%"PRIx32"\n\r", __func__, i , d[i]);
delay(1000);
}
}
/**
* @defgroup framework-debug Framework Debug
* @{
* @ingroup framework
* @brief Debug functions
* @copyright (C) 2015-2016 CERN (www.cern.ch)
* @author Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_FW_FRM_DEBUG_H__
#define __TRTL_FW_FRM_DEBUG_H__
#include <stdarg.h>
#include "mockturtle-common.h"
extern int rt_send_debug(int slot, int n_values, ...);
extern void rt_print_header(struct trtl_proto_header *h);
extern void rt_print_data(uint32_t *d, unsigned int count);
#endif
/**@}*/
/*
* Copyright (C) 2015-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <mockturtle-framework.h>
/**
* It sends the MQ content.
* In order to save space the function *does not* perform any
* argument validation. This means that you may crash the system
* if you provide the wrong mq_idx.
* @param[in] mq_idx MQ index within the declaration
* @param[in] count number of bytes to send
*/
void trtl_rt_mq_send(unsigned int mq_idx, unsigned int count)
{
mq_send(_app->mq[mq_idx].type, _app->mq[mq_idx].index);
if (_app->mq[mq_idx].flags & TRTL_RT_MQ_FLAGS_CLAIM) {
mq_claim(_app->mq[mq_idx].type, _app->mq[mq_idx].index);
}
}
/**
* It builds and it sends a message over MQ.
* The vargs will be copied into the payload message.
* Beware that, internally, it uses trtl_rt_mq_send().
* @param[in] mq_idx MQ index within the declaration
* @param[in] msg_id message identifier
* @param[in] n number of vargs
*/
void trtl_rt_mq_send_uint32(unsigned int mq_idx, uint8_t msg_id,
unsigned int n, ...)
{
struct trtl_proto_header hdr = {
.rt_app_id = _app->version.rt_id,
.msg_id = msg_id,
.slot_io = _app->mq[mq_idx].index & 0xF,
.seq = msg_seq++,
.len = n,
.flags = 0x0,
.trans = 0x0,
.time = 0x0,
};
void *buf = _app->mq[mq_idx].buf;
uint32_t *payload = rt_proto_payload_get(buf);
va_list ap;
int i;
va_start(ap, n);
for (i = 0; i < hdr.len;++i)
payload[i] = va_arg(ap, uint32_t);
va_end(ap);
rt_proto_header_set(buf, &hdr);
trtl_rt_mq_send(mq_idx, (sizeof(struct trtl_proto_header) / 4) +
hdr.len);
}
/**
* It builds and it sends a message over MQ.
* The buffer will be copied into the payload message.
* Beware that, internally, it uses trtl_rt_mq_send().
* @param[in] mq_idx MQ index within the declaration
* @param[in] msg_id message identifier
* @param[in] n buffer size in bytes
* @param[in] data buffer to send
*/
void trtl_rt_mq_send_buf(unsigned int mq_idx, uint8_t msg_id,
unsigned int n, void *data)
{
struct trtl_proto_header hdr = {
.rt_app_id = _app->version.rt_id,
.msg_id = msg_id,
.slot_io = _app->mq[mq_idx].index & 0xF,
.seq = msg_seq++,
.len = n / 4,
.flags = 0x0,
.trans = 0x0,
.time = 0x0,
};
void *buf = _app->mq[mq_idx].buf;
memcpy(rt_proto_payload_get(buf), data, n);
rt_proto_header_set(buf, &hdr);
trtl_rt_mq_send(mq_idx, (sizeof(struct trtl_proto_header) / 4) +
hdr.len);
}
/**
* @defgroup framework-mqueue Framework Message Queue
* @{
* @ingroup framework
* @brief Message Queues definitions and functions
* @copyright (C) 2015-2016 CERN (www.cern.ch)
* @author Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_FW_FRM_MQUEUE_H__
#define __TRTL_FW_FRM_MQUEUE_H__
extern uint32_t msg_seq;
/**
* Description of the message queue
*/
struct rt_mq {
enum trtl_mq_type type; /**< MQ type */
uint8_t index; /**< MQ gateware index */
unsigned long flags; /**< MQ flag info */
void *buf; /**< MQ buffer */
};
/**
* MQ Flag. It is RMQ
*/
#define TRTL_RT_MQ_FLAGS_RMQ (1 << 0)
/**
* MQ Flag. It is HMQ
*/
#define TRTL_RT_MQ_FLAGS_HMQ (0)
/**
* MQ Flag. It is output
*/
#define TRTL_RT_MQ_FLAGS_OUTPUT (1 << 1)
/**
* MQ Flags. On output keep claimed.
* This means that as soon as you send a message on a slot,
* the framework will claim the slot immediately.
*/
#define TRTL_RT_MQ_FLAGS_CLAIM (1 << 2)
/**
* MQ Flag. It is input
*/
#define TRTL_RT_MQ_FLAGS_INPUT (0)
/**
* It send the message associate to the given header
* @param[in] msg message to send
*/
static inline void rt_mq_msg_send(struct trtl_msg *msg)
{
struct trtl_proto_header *hdr;
hdr = rt_proto_header_get((void *)msg->data);
/* When we are not using sync messages, we use the global
sequence number */
if (!(hdr->flags & TRTL_HEAD_FLAG_SYNC))
hdr->seq = msg_seq++;
mq_send(!!(hdr->flags & TRTL_HEAD_FLAG_REMOTE),
(hdr->slot_io & 0xF));
}
extern void trtl_rt_mq_send(unsigned int mq_idx, unsigned int count);
extern void trtl_rt_mq_send_uint32(unsigned int mq_idx, uint8_t msg_id,
unsigned int n, ...);
extern void trtl_rt_mq_send_buf(unsigned int mq_idx, uint8_t msg_id,
unsigned int n, void *data);
#endif
/**@}*/
/**
* @defgroup framework-variable Framework Variable
* @{
* @ingroup framework
* @brief Variable exchange mechanism
* @copyright (C) 2015-2016 CERN (www.cern.ch)
* @author Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_FW_FRM_VARIABLE_H__
#define __TRTL_FW_FRM_VARIABLE_H__
/**
* Variable flag. Register
*/
#define TRTL_RT_VARIABLE_FLAG_FLD (1 << 0)
/**
* Description of a variable that we want to export to the external
* world (host or network).
*/
struct rt_variable {
void *addr; /**< variable address */
uint32_t mask; /**< variable mask without offset applied */
uint8_t offset; /**< variable offset within the word */
uint32_t flags; /**< variable options */
};
#endif
/**@}*/
/*
* Message assembling helper functions
*
* Copyright (C) 2013-2016 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __RT_MESSAGE_H
#define __RT_MESSAGE_H
#include <mockturtle-rt-common.h>
#ifdef MOCKTURTLE_RT
/**
* It claims an output slot. This means that you get exclusive access to
* the slot.
*/
static inline struct trtl_msg rt_mq_claim_out(struct trtl_proto_header *h)
{
struct trtl_msg b;
int remote = !!(h->flags & TRTL_HEAD_FLAG_REMOTE);
int slot = h->slot_io & 0xF;
mq_claim(remote, slot);
b.data = mq_map_out_buffer(remote, slot);
b.hdr.len = 0;
return b;
}
/**
* Obsolete. Use rt_mq_claim_out
*/
static inline struct trtl_msg hmq_msg_claim_out(int slot, int max_size)
{
struct trtl_proto_header h = {
.slot_io = (slot & 0xF),
.len = max_size,
};
return rt_mq_claim_out(&h);
}
/**
* It claims an input slot. This mean that you get exclusive access to
* the slot
*/
static inline struct trtl_msg rt_mq_claim_in(struct trtl_proto_header *h)
{
struct trtl_msg b;
int slot = (h->slot_io >> 4) & 0xF;
b.data = mq_map_in_buffer(0, slot);
b.hdr.len = h->len;
return b;
}
/**
* Obsolete. Use rt_mq_claim_in
*/
static inline struct trtl_msg hmq_msg_claim_in(int slot, int max_size)
{
struct trtl_proto_header h = {
.slot_io = (slot & 0xF) << 4,
.len = max_size,
};
return rt_mq_claim_in(&h);
}
#endif
#endif
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "mockturtle-rt-common.h" #include "mockturtle-rt.h"
int putchar(int c) int putchar(int c)
{ {
......
/**
* @defgroup library-utilities Common Utilities
* @{
* @ingroup library
* @brief Common utilities
* @copyright (C) 2013-2016 CERN (www.cern.ch)
* @author Federico Vaga <federico.vaga@cern.ch>
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_RT_COMMON_H
#define __TRTL_RT_COMMON_H
#include <stdint.h>
#include <stdio.h>
#include <hw/mockturtle_addresses.h>
#include "hw/mockturtle_cpu_lr.h"
#include <mockturtle-common.h>
#include "mockturtle-rt-serial.h"
struct trtl_msg {
struct trtl_hmq_header hdr;
uint32_t *data;
};
/**
* Read a 32bit word value from the given address
* @param[in] addr source address
* @return the value fromt the register
*/
static inline uint32_t readl(void *addr)
{
return *(volatile uint32_t *) (addr);
}
/**
* Write a 32bit word value to the given address
* @param[in] value value to write
* @param[in] addr destination address
*/
static inline void writel(uint32_t value, void *addr)
{
*(volatile uint32_t *) (addr) = value;
}
/**
* Read a 32bit word value from the Dedicated Peripheral address space
* @param[in] reg register offset within the Dedicated Peripheral
* @return the value fromt the register
*/
static inline uint32_t dp_readl(uint32_t reg)
{
return readl(TRTL_ADDR_DP(reg));
}
/**
* Write a 32bit word value to the Dedicated Peripheral address space
* @param[in] value value to write
* @param[in] reg register offset within the Dedicated Peripheral
*/
static inline void dp_writel(uint32_t value, uint32_t reg)
{
writel(value, TRTL_ADDR_DP(reg));
}
/**
* Read 32bit word value from the CPU Local Registers address space
* @param[in] reg register offset within the Local Registers
* @return the value fromt the register
*/
static inline uint32_t lr_readl(uint32_t reg)
{
return readl(TRTL_ADDR_LR(reg));
}
/**
* Write 32bit word value to the CPU Local Registers address space
* @param[in] value value to write
* @param[in] reg register offset within the Local Registers
*/
static inline void lr_writel(uint32_t value, uint32_t reg)
{
writel(value, TRTL_ADDR_LR(reg));
}
/**
* Set a bit in the CPU GPIO Register
* @param[in] pin GPIO pin to set
*/
static inline void gpio_set(int pin)
{
lr_writel ((1 << pin), MT_CPU_LR_REG_GPIO_SET);
}
/**
* Clear a bit in the CPU GPIO Register
* @param[in] pin GPIO pin to clear
*/
static inline void gpio_clear(int pin)
{
lr_writel ((1 << pin), MT_CPU_LR_REG_GPIO_CLEAR);
}
/**
* Wait n cycles
* @todo: use Timing Unit, compute it accoring to CPU frequency
* @param[in] n number of cycles to wait
*/
static inline void delay(int n)
{
int i;
for(i = 0; i < n; i++)
asm volatile("nop");
}
/**
* It returns a pointer to the config ROM
*/
static inline const struct trtl_config_rom *trtl_config_rom_get(void)
{
return (const struct trtl_config_rom *)(TRTL_ADDR_CONFIG_ROM_BASE);
}
/**
* It generates a notification signal (IRQ) to ask the HOST CPU
* to take some action.
*/
static inline void trtl_notify_send(enum trtl_cpu_notification id)
{
lr_writel(1, MT_CPU_LR_REG_NTF_INT);
}
#endif
/**@}*/
/**
* @defgroup library-message-queue Message Queue
* @{
* @ingroup library
* @brief Message Queues definitions and functions
* @copyright (C) 2013-2016 CERN (www.cern.ch)
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_RT_MQUEUE_H
#define __TRTL_RT_MQUEUE_H
#include <hw/mockturtle_addresses.h>
#include <hw/mockturtle_queue.h>
#include <hw/mockturtle_cpu_lr.h>
#define TRTL_MQ_SLOT_IN(slot) (TRTL_MQ_BASE_IN + ((slot) << 16))
// Outgoung slot base address, relative to BASE_HMQ
#define TRTL_MQ_SLOT_OUT(slot) (TRTL_MQ_BASE_OUT + ((slot) << 16))
/**
* List of Message Queue types
*/
enum trtl_mq_type {
TRTL_HMQ = 0, /**< Host Message Queue - Host-Firmware communication */
TRTL_RMQ, /**< Remote Message Queue - Network-Firmware communication */
};
/**
* It gets the Message Queue base address
* @param[in] type MQ type
*/
static inline void *trtl_mq_base_address(enum trtl_mq_type type)
{
return (void *)(type == TRTL_HMQ ? TRTL_ADDR_HMQ_BASE : TRTL_ADDR_RMQ_BASE);
}
/**
* It writes on a Message Queue register
* @param[in] type MQ type to use
* @param[val] value to write
* @param[reg] reg register offset
*/
static inline void mq_writel(enum trtl_mq_type type, uint32_t val, uint32_t reg)
{
*(volatile uint32_t *)(trtl_mq_base_address(type) + reg) = val;
}
/**
* @copydoc TRTL_MQ_CMD_CLAIM
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void mq_claim(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_CLAIM, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
}
/**
* @copydoc TRTL_MQ_CMD_PURGE
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void mq_purge(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_PURGE, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
mq_writel(type, TRTL_MQ_CMD_PURGE, TRTL_MQ_SLOT_IN(slot) + TRTL_MQ_SLOT_COMMAND);
}
/**
* @copydoc TRTL_MQ_CMD_READY
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void mq_send(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_READY, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
}
/**
* @copydoc TRTL_MQ_CMD_DISCARD
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void mq_discard(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_DISCARD, TRTL_MQ_SLOT_IN(slot));
}
/**
* It gets the output slot data field pointer
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void *mq_map_out_buffer(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_SLOT_OUT (slot) + TRTL_MQ_SLOT_DATA_START);
}
/**
* It gets the input slot data field pointer
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void *mq_map_in_buffer(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_SLOT_IN (slot) + TRTL_MQ_SLOT_DATA_START);
}
/**
* It gets the output slot header field pointer
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void *mq_map_out_header(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_SLOT_OUT (slot) + TRTL_MQ_SLOT_HEADER_START);
}
/**
* It gets the input slot header field pointer
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void *mq_map_in_header(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_SLOT_IN (slot) + TRTL_MQ_SLOT_HEADER_START);
}
/**
* It gets the current status of the input Host Message Queues
*/
static inline uint32_t hmq_poll_in(void)
{
volatile uint32_t *poll = (void *)TRTL_ADDR_LR_BASE + MT_CPU_LR_REG_HMQ_STAT;
return ((*poll & MT_CPU_LR_HMQ_STAT_IN_MASK) >> MT_CPU_LR_HMQ_STAT_IN_SHIFT);
}
/**
* It gets the current status of the output Host Message Queues
*/
static inline uint32_t hmq_poll_out(void)
{
volatile uint32_t *poll = (void *)TRTL_ADDR_LR_BASE + MT_CPU_LR_REG_HMQ_STAT;
return ((*poll & MT_CPU_LR_HMQ_STAT_OUT_MASK) >> MT_CPU_LR_HMQ_STAT_OUT_SHIFT);
}
/**
* It gets the current status of the input Remote Message Queues
*/
static inline uint32_t rmq_poll_in(void)
{
volatile uint32_t *poll = (void *)TRTL_ADDR_LR_BASE + MT_CPU_LR_REG_RMQ_STAT;
return ((*poll & MT_CPU_LR_RMQ_STAT_IN_MASK) >> MT_CPU_LR_RMQ_STAT_IN_SHIFT);
}
/**
* It gets the current status of the output Remote Message Queues
*/
static inline uint32_t rmq_poll_out(void)
{
volatile uint32_t *poll = (void *)TRTL_ADDR_LR_BASE + MT_CPU_LR_REG_RMQ_STAT;
return ((*poll & MT_CPU_LR_RMQ_STAT_OUT_MASK) >> MT_CPU_LR_RMQ_STAT_OUT_SHIFT);
}
#endif
/**@}*/
/**
* @defgroup library-serial Serial Console
* @{
* @ingroup library
* @brief Serial Console functions
* @copyright (C) 2013-2016 CERN (www.cern.ch)
* @author Alessandro Rubini <rubini@gnudd.com>
* @author Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_RT_PP_PRINTF_H
#define __TRTL_RT_PP_PRINTF_H
#include <stdarg.h>
#include <generated/autoconf.h>
/**
* Print buffer size. This means that your printf string
* should not exceed this value. If the string exceed this value
* then it will be trouncated.
*/
#define CONFIG_PRINT_BUFSIZE 128
/**
* It prints a string on the serial interface.
* Internally, it uses the puts() function.
* @param[in] fmt string format
* @param[in] ... argument according to the string format
* @return number of printed characters
*/
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1
extern int pp_printf(const char *fmt, ...)
__attribute__((format(printf,1,2)));
#else
static inline int pp_printf(const char *fmt, ...)
{
return 0;
}
#endif
/**
* It creates a new string according to the given format
* @param[out] s output string
* @param[in] fmt string format
* @param[in] ... argument according to the string format
* @return number of printed characters
*/
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1
extern int pp_sprintf(char *s, const char *fmt, ...)
__attribute__((format(printf,2,3)));
#else
static inline int pp_sprintf(char *s, const char *fmt, ...)
{
return 0;
}
#endif
/**
* It prints a string on the serial interface.
* Internally, it uses the puts() function.
* @param[in] fmt string format
* @param[in] args list of arguments according to the string format
* @return number of printed characters
*/
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE
extern int pp_vprintf(const char *fmt, va_list args);
#else
static inline int pp_vprintf(const char *fmt, va_list args)
{
return 0;
}
#endif
/**
* It creates a new string according to the given format
* @param[out] buf output string
* @param[in] fmt string format
* @param[in] args list of arguments according to the string format
* @return number of printed characters
*/
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1
extern int pp_vsprintf(char *buf, const char *, va_list args)
__attribute__ ((format (printf, 2, 0)));
#else
static inline int pp_vsprintf(char *buf, const char *fmt, va_list args)
{
return 0;
}
#endif
/**
* It prints a string on the serial interface only when the support
* for error messages is enable.
*
* Kconfig ->CONFIG_MOCKTURTLE_LIBRARY_PRINT_DEBUG_ENABLE
*
* Internally, it uses the puts() function.
* @param[in] fmt string format
* @param[in] ... argument according to the string format
* @return number of printed characters
*/
#if (HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1) && (HAS_MOCKTURTLE_LIBRARY_PRINT_DEBUG_ENABLE == 1)
extern int pr_debug(const char *fmt, ...)
__attribute__((format(printf,1,2)));
#else
static inline int pr_debug(const char *fmt, ...)
{
return 0;
}
#endif
/**
* It prints a string on the serial interface only when the support
* for error messages is enable.
*
* Kconfig -> CONFIG_MOCKTURTLE_LIBRARY_PRINT_ERROR_ENABLE
*
* Internally, it uses the puts() function.
* @param[in] fmt string format
* @param[in] ... argument according to the string format
* @return number of printed characters
*/
#if (HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1) && (HAS_MOCKTURTLE_LIBRARY_PRINT_ERROR_ENABLE == 1)
extern int pr_error(const char *fmt, ...)
__attribute__((format(printf,1,2)));
#else
static inline int pr_error(const char *fmt, ...)
{
return 0;
}
#endif
extern int putchar (int c);
extern int puts(const char *p);
/**@}*/
#endif
/**
* @defgroup library-shared-memory Shared Memory Utilities
* @{
* @ingroup library
* @brief Shared Memory definitions & API
* @copyright (C) 2013-2016 CERN (www.cern.ch)
* @author Federico Vaga <federico.vaga@cern.ch>
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TRTL_RT_SMEM_H
#define __TRTL_RT_SMEM_H
/**
* List of supported Shared Memory access type
*/
enum trtl_smem_type {
TRTL_SMEM_TYPE_BASE = 0, /**< no operation */
TRTL_SMEM_TYPE_ADD, /**< atomic addition */
TRTL_SMEM_TYPE_SUB, /**< atomic subtraction */
TRTL_SMEM_TYPE_SET, /**< atomic bit set */
TRTL_SMEM_TYPE_CLR, /**< atomic bit clear */
TRTL_SMEM_TYPE_FLP, /**< atomic bit flip */
TRTL_SMEM_TYPE_TST_SET, /**< atomic test and set */
};
/**
* Shared Memory Size
*/
#define TRTL_SMEM_SIZE 0x10000
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_BASE
* memory access
*/
#define TRTL_SMEM_RANGE_BASE 0x00000
/**
* It generates the SHM address range for a given SHM type
*/
#define TRTL_SMEM_TYPE_TO_RANGE(_type) \
(TRTL_SMEM_RANGE_BASE + (_type) * TRTL_SMEM_SIZE)
/**
* Shared Memory base address for the
* @copydoc TRTL_SMEM_TYPE_ADD
* memory access
*/
#define TRTL_SMEM_RANGE_ADD \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_ADD)
/**
* Shared Memory base address for the
* @copydoc TRTL_SMEM_TYPE_SUB
* memory access
*/
#define TRTL_SMEM_RANGE_SUB \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_SUB)
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_SET
* memory access
*/
#define TRTL_SMEM_RANGE_SET \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_SET)
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_CLR
* memory access
*/
#define TRTL_SMEM_RANGE_CLEAR \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_CLR)
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_FLP
* memory access
*/
#define TRTL_SMEM_RANGE_FLIP \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_FLP)
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_TST_SET
* memory access
*/
#define TRTL_SMEM_RANGE_TEST_AND_SET \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_TST_SET)
/**
* Compiler attribute to allocate variable on the Share Memory.
* Add this to the variable declaration to put it on the Shared Memory.
*
* SMEM int x;
*/
#define SMEM volatile __attribute__((section(".smem")))
/**
* It performs an operations on the shared memory. What the function
* performs can be summerized as:
*
* (*p) = (*p) <operation-type> x
*
* Use this function only when the operation type that you want to use
* is not supported yet by the library directly. Otherwise,
* use the other functions.
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
* @param[in] type operation type
*/
static inline void __smem_atomic_op(volatile int *p, int x,
enum trtl_smem_type type)
{
*(volatile int *)(p + (TRTL_SMEM_TYPE_TO_RANGE(type) >> 2)) = x;
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_ADD
*
* (*p) = (*p) + x
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_add(volatile int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_ADD);
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_SUB
*
* (*p) = (*p) - x
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_sub(volatile int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_SUB);
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_SET
*
* (*p) = (*p) | x
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_or(volatile int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_SET);
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_CLR
*
* (*p) = (*p) & (~x)
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_and_not(volatile int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_CLR);
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_FLP
*
* (*p) = (*p) ^ x
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_xor(int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_FLP);
}
/**
* It performs an:
* @copydoc TRTL_SMEM_TYPE_TST_SET
*
* val = (*p);
* if (val == 0) {
* (*p) = 1;
* }
* return val;
*
* This is useful to implement mutex
*
* @param[in] p address on the shared memory
* @return the value before the set
*/
static inline int smem_atomic_test_and_set(int *p)
{
/* shift right translates range in bytes into range in words */
return *(volatile int *)(p + (TRTL_SMEM_TYPE_TST_SET >> 2));
}
#endif
/**@}*/
...@@ -12,12 +12,674 @@ ...@@ -12,12 +12,674 @@
#define __MOCKTURTLE_RT_H #define __MOCKTURTLE_RT_H
#include <stdint.h> #include <stdint.h>
#include <stdarg.h>
#include <generated/autoconf.h>
#include "mockturtle-rt-mqueue.h" #include <hw/mockturtle_addresses.h>
#include "mockturtle-rt-message.h" #include <hw/mockturtle_queue.h>
#include "mockturtle-rt-common.h" #include <hw/mockturtle_cpu_lr.h>
#include "mockturtle-rt-smem.h"
#include "mockturtle-rt-serial.h" #include <mockturtle.h>
/**
* Print buffer size. This means that your printf string
* should not exceed this value. If the string exceed this value
* then it will be trouncated.
*/
#define CONFIG_PRINT_BUFSIZE 128
/**
* It prints a string on the serial interface.
* Internally, it uses the puts() function.
* @param[in] fmt string format
* @param[in] ... argument according to the string format
* @return number of printed characters
*/
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1
extern int pp_printf(const char *fmt, ...)
__attribute__((format(printf,1,2)));
#else
static inline int pp_printf(const char *fmt, ...)
{
return 0;
}
#endif
/**
* It creates a new string according to the given format
* @param[out] s output string
* @param[in] fmt string format
* @param[in] ... argument according to the string format
* @return number of printed characters
*/
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1
extern int pp_sprintf(char *s, const char *fmt, ...)
__attribute__((format(printf,2,3)));
#else
static inline int pp_sprintf(char *s, const char *fmt, ...)
{
return 0;
}
#endif
/**
* It prints a string on the serial interface.
* Internally, it uses the puts() function.
* @param[in] fmt string format
* @param[in] args list of arguments according to the string format
* @return number of printed characters
*/
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE
extern int pp_vprintf(const char *fmt, va_list args);
#else
static inline int pp_vprintf(const char *fmt, va_list args)
{
return 0;
}
#endif
/**
* It creates a new string according to the given format
* @param[out] buf output string
* @param[in] fmt string format
* @param[in] args list of arguments according to the string format
* @return number of printed characters
*/
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1
extern int pp_vsprintf(char *buf, const char *, va_list args)
__attribute__ ((format (printf, 2, 0)));
#else
static inline int pp_vsprintf(char *buf, const char *fmt, va_list args)
{
return 0;
}
#endif
/**
* It prints a string on the serial interface only when the support
* for error messages is enable.
*
* Kconfig ->CONFIG_MOCKTURTLE_LIBRARY_PRINT_DEBUG_ENABLE
*
* Internally, it uses the puts() function.
* @param[in] fmt string format
* @param[in] ... argument according to the string format
* @return number of printed characters
*/
#if (HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1) && (HAS_MOCKTURTLE_LIBRARY_PRINT_DEBUG_ENABLE == 1)
extern int pr_debug(const char *fmt, ...)
__attribute__((format(printf,1,2)));
#else
static inline int pr_debug(const char *fmt, ...)
{
return 0;
}
#endif
/**
* It prints a string on the serial interface only when the support
* for error messages is enable.
*
* Kconfig -> CONFIG_MOCKTURTLE_LIBRARY_PRINT_ERROR_ENABLE
*
* Internally, it uses the puts() function.
* @param[in] fmt string format
* @param[in] ... argument according to the string format
* @return number of printed characters
*/
#if (HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1) && (HAS_MOCKTURTLE_LIBRARY_PRINT_ERROR_ENABLE == 1)
extern int pr_error(const char *fmt, ...)
__attribute__((format(printf,1,2)));
#else
static inline int pr_error(const char *fmt, ...)
{
return 0;
}
#endif
extern int putchar (int c);
extern int puts(const char *p);
/**
* Read a 32bit word value from the given address
* @param[in] addr source address
* @return the value fromt the register
*/
static inline uint32_t readl(void *addr)
{
return *(volatile uint32_t *) (addr);
}
/**
* Write a 32bit word value to the given address
* @param[in] value value to write
* @param[in] addr destination address
*/
static inline void writel(uint32_t value, void *addr)
{
*(volatile uint32_t *) (addr) = value;
}
/**
* Read a 32bit word value from the Dedicated Peripheral address space
* @param[in] reg register offset within the Dedicated Peripheral
* @return the value fromt the register
*/
static inline uint32_t dp_readl(uint32_t reg)
{
return readl(TRTL_ADDR_DP(reg));
}
/**
* Write a 32bit word value to the Dedicated Peripheral address space
* @param[in] value value to write
* @param[in] reg register offset within the Dedicated Peripheral
*/
static inline void dp_writel(uint32_t value, uint32_t reg)
{
writel(value, TRTL_ADDR_DP(reg));
}
/**
* Read 32bit word value from the CPU Local Registers address space
* @param[in] reg register offset within the Local Registers
* @return the value fromt the register
*/
static inline uint32_t lr_readl(uint32_t reg)
{
return readl(TRTL_ADDR_LR(reg));
}
/**
* Write 32bit word value to the CPU Local Registers address space
* @param[in] value value to write
* @param[in] reg register offset within the Local Registers
*/
static inline void lr_writel(uint32_t value, uint32_t reg)
{
writel(value, TRTL_ADDR_LR(reg));
}
/**
* Set a bit in the CPU GPIO Register
* @param[in] pin GPIO pin to set
*/
static inline void gpio_set(int pin)
{
lr_writel ((1 << pin), MT_CPU_LR_REG_GPIO_SET);
}
/**
* Clear a bit in the CPU GPIO Register
* @param[in] pin GPIO pin to clear
*/
static inline void gpio_clear(int pin)
{
lr_writel ((1 << pin), MT_CPU_LR_REG_GPIO_CLEAR);
}
/**
* It gets the GPIO status
* @param[in] pin GPIO pin to query
* @return the GPIO status
*/
static inline unsigned int gpio_status(int pin)
{
return !!(lr_readl(MT_CPU_LR_REG_GPIO_IN) & (1 << pin));
}
/**
* Wait n cycles
* @todo: use Timing Unit, compute it accoring to CPU frequency
* @param[in] n number of cycles to wait
*/
static inline void delay(int n)
{
int i;
for(i = 0; i < n; i++)
asm volatile("nop");
}
/**
* It returns a pointer to the config ROM
* @return pointer to the configuration ROM
*/
static inline const struct trtl_config_rom *trtl_config_rom_get(void)
{
return (const struct trtl_config_rom *)(TRTL_ADDR_CONFIG_ROM_BASE);
}
/**
* It generates a notification signal (IRQ) to ask the HOST CPU
* to take some action.
* @param[in] id CPU notification identifier
*/
static inline void trtl_notify(unsigned int id)
{
lr_writel(1, MT_CPU_LR_REG_NTF_INT);
}
/**
* It generates a notification signal (IRQ) to ask the HOST CPU
* to take some action.
* @param[in] id CPU notification identifier
*/
static inline void trtl_notify_user(unsigned int id)
{
if (id < __TRTL_CPU_NOTIFY_MAX) {
pr_error("%s invalid user id %d. Replaced with %d\r\n",
__func__, id, TRTL_CPU_NOTIFY_APPLICATION);
id = TRTL_CPU_NOTIFY_APPLICATION;
}
trtl_notify(id);
}
/**
* It returns the core ID on which the firmware is running
* @return the core ID
* @todo implement me
*/
static inline uint32_t trtl_get_core_id(void)
{
return lr_readl(0);
}
#define TRTL_MQ_SLOT_IN(slot) (TRTL_MQ_BASE_IN + ((slot) << 16))
// Outgoung slot base address, relative to BASE_HMQ
#define TRTL_MQ_SLOT_OUT(slot) (TRTL_MQ_BASE_OUT + ((slot) << 16))
/**
* List of Message Queue types
*/
enum trtl_mq_type {
TRTL_HMQ = 0, /**< Host Message Queue - Host-Firmware communication */
TRTL_RMQ, /**< Remote Message Queue - Network-Firmware communication */
__TRTL_MAX_MQ_TYPE,
};
/**
* It gets the Message Queue base address
* @param[in] type MQ type
*/
static inline void *trtl_mq_base_address(enum trtl_mq_type type)
{
return (void *)(type == TRTL_HMQ ? TRTL_ADDR_HMQ_BASE : TRTL_ADDR_RMQ_BASE);
}
/**
* It writes on a Message Queue register
* @param[in] type MQ type to use
* @param[val] value to write
* @param[reg] reg register offset
*/
static inline void mq_writel(enum trtl_mq_type type, uint32_t val, uint32_t reg)
{
*(volatile uint32_t *)(trtl_mq_base_address(type) + reg) = val;
}
/**
* It gets the output slot data field pointer
* @param[in] type MQ type to use
* @param[in] slot slot number
* @return pointer to the input buffer
*/
static inline void *mq_map_out_buffer(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_SLOT_OUT (slot) + TRTL_MQ_SLOT_DATA_START);
}
/**
* It gets the input slot data field pointer
* @param[in] type MQ type to use
* @param[in] slot slot number
* @return pointer to the input buffer
*/
static inline void *mq_map_in_buffer(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_SLOT_IN (slot) + TRTL_MQ_SLOT_DATA_START);
}
/**
* It gets the output slot header field pointer
* @param[in] type MQ type to use
* @param[in] slot slot number
* @return pointer to the output header
*/
static inline void *mq_map_out_header(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_SLOT_OUT (slot) + TRTL_MQ_SLOT_HEADER_START);
}
/**
* It gets the input slot header field pointer
* @param[in] type MQ type to use
* @param[in] slot slot number
* @return pointer to the input header
*/
static inline void *mq_map_in_header(enum trtl_mq_type type, int slot)
{
return (void *) (trtl_mq_base_address(type) +
TRTL_MQ_SLOT_IN (slot) + TRTL_MQ_SLOT_HEADER_START);
}
/**
* @copydoc TRTL_MQ_CMD_CLAIM
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void mq_claim(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_CLAIM, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
}
/**
* @copydoc TRTL_MQ_CMD_PURGE
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void mq_purge(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_PURGE, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
mq_writel(type, TRTL_MQ_CMD_PURGE, TRTL_MQ_SLOT_IN(slot) + TRTL_MQ_SLOT_COMMAND);
}
/**
* @copydoc TRTL_MQ_CMD_READY
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void mq_send(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_READY, TRTL_MQ_SLOT_OUT(slot) + TRTL_MQ_SLOT_COMMAND);
}
/**
* @copydoc TRTL_MQ_CMD_DISCARD
* @param[in] type MQ type to use
* @param[in] slot slot number
*/
static inline void mq_discard(enum trtl_mq_type type, int slot)
{
mq_writel(type, TRTL_MQ_CMD_DISCARD, TRTL_MQ_SLOT_IN(slot));
}
/**
* It maps a given MQ for outcoming messages
* @param[in] type MQ type to use
* @param[in] idx_mq MQ index
* @param[out] msg where to map the message
*/
static inline void mq_map_out_message(enum trtl_mq_type type,
unsigned idx_mq,
struct trtl_msg *msg)
{
msg->header = mq_map_out_header(type, idx_mq);
msg->payload = mq_map_out_buffer(type, idx_mq);
}
/**
* It maps a given MQ for incoming messages
* @param[in] type MQ type to use
* @param[in] idx_mq MQ index
* @param[out] msg where to map the message
*/
static inline void mq_map_in_message(enum trtl_mq_type type,
unsigned idx_mq,
struct trtl_msg *msg)
{
msg->header = mq_map_in_header(type, idx_mq);
msg->payload = mq_map_in_buffer(type, idx_mq);
}
/**
* It gets the current MQ input status
* @return message queues input status bitmask
*/
static inline uint32_t mq_poll_in(enum trtl_mq_type type)
{
uint32_t poll = lr_readl(MT_CPU_LR_REG_HMQ_STAT + (type * 4));
/* HMQ and RMQ have the same format -> use the same mask */
return ((poll & MT_CPU_LR_HMQ_STAT_IN_MASK) >> MT_CPU_LR_HMQ_STAT_IN_SHIFT);
}
/**
* It gets the current MQ output status
* @return message queues output status bitmask
*/
static inline uint32_t mq_poll_out(enum trtl_mq_type type)
{
uint32_t poll = lr_readl(MT_CPU_LR_REG_HMQ_STAT + (type * 4));
/* HMQ and RMQ have the same format -> use the same mask */
return ((poll & MT_CPU_LR_HMQ_STAT_OUT_MASK) >> MT_CPU_LR_HMQ_STAT_OUT_SHIFT);
}
/**
* Shared Memory Size
*/
#define TRTL_SMEM_SIZE 0x10000
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_BASE
* memory access
*/
#define TRTL_SMEM_RANGE_BASE 0x00000
/**
* It generates the SHM address range for a given SHM type
*/
#define TRTL_SMEM_TYPE_TO_RANGE(_type) \
(TRTL_SMEM_RANGE_BASE + (_type) * TRTL_SMEM_SIZE)
/**
* Shared Memory base address for the
* @copydoc TRTL_SMEM_TYPE_ADD
* memory access
*/
#define TRTL_SMEM_RANGE_ADD \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_ADD)
/**
* Shared Memory base address for the
* @copydoc TRTL_SMEM_TYPE_SUB
* memory access
*/
#define TRTL_SMEM_RANGE_SUB \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_SUB)
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_SET
* memory access
*/
#define TRTL_SMEM_RANGE_SET \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_SET)
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_CLR
* memory access
*/
#define TRTL_SMEM_RANGE_CLEAR \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_CLR)
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_FLP
* memory access
*/
#define TRTL_SMEM_RANGE_FLIP \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_FLP)
/**
* Shared Memory address for the
* @copydoc TRTL_SMEM_TYPE_TST_SET
* memory access
*/
#define TRTL_SMEM_RANGE_TEST_AND_SET \
TRTL_SMEM_TYPE_TO_RANGE(TRTL_SMEM_TYPE_TST_SET)
/**
* Compiler attribute to allocate variable on the Share Memory.
* Add this to the variable declaration to put it on the Shared Memory.
*
* SMEM int x;
*/
#define SMEM volatile __attribute__((section(".smem")))
/**
* It performs an operations on the shared memory. What the function
* performs can be summerized as:
*
* (*p) = (*p) <operation-type> x
*
* Use this function only when the operation type that you want to use
* is not supported yet by the library directly. Otherwise,
* use the other functions.
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
* @param[in] type operation type
*/
static inline void __smem_atomic_op(volatile int *p, int x,
enum trtl_smem_modifier type)
{
*(volatile int *)(p + (TRTL_SMEM_TYPE_TO_RANGE(type) >> 2)) = x;
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_ADD
*
* (*p) = (*p) + x
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_add(volatile int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_ADD);
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_SUB
*
* (*p) = (*p) - x
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_sub(volatile int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_SUB);
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_SET
*
* (*p) = (*p) | x
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_or(volatile int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_SET);
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_CLR
*
* (*p) = (*p) & (~x)
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_and_not(volatile int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_CLR);
}
/**
* It performs an
* @copydoc TRTL_SMEM_TYPE_FLP
*
* (*p) = (*p) ^ x
*
* @param[in] p address on the shared memory of the first operator and store location
* @param[in] x second operation argument
*/
static inline void smem_atomic_xor(int *p, int x)
{
__smem_atomic_op(p, x, TRTL_SMEM_TYPE_FLP);
}
/**
* It performs an:
* @copydoc TRTL_SMEM_TYPE_TST_SET
*
* val = (*p);
* if (val == 0) {
* (*p) = 1;
* }
* return val;
*
* This is useful to implement mutex
*
* @param[in] p address on the shared memory
* @return the value before the set
*/
static inline int smem_atomic_test_and_set(int *p)
{
/* shift right translates range in bytes into range in words */
return *(volatile int *)(p + (TRTL_SMEM_TYPE_TST_SET >> 2));
}
#endif #endif
/**@}*/ /**@}*/
...@@ -11,8 +11,7 @@ ...@@ -11,8 +11,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <mockturtle-rt-common.h> #include <mockturtle-rt.h>
#include <mockturtle-rt-serial.h>
#if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1 #if HAS_MOCKTURTLE_LIBRARY_PRINT_ENABLE == 1
......
...@@ -50,7 +50,7 @@ int main(int argc, char *argv[]) ...@@ -50,7 +50,7 @@ int main(int argc, char *argv[])
char c; char c;
int err, n, dev_id = -1, v, i, k; int err, n, dev_id = -1, v, i, k;
enum operations mode; enum operations mode;
struct trtl_structure_tlv *tlv; struct trtl_tlv *tlv;
unsigned int n_tlv, idx_cpu = 0, idx_hmq = 0;; unsigned int n_tlv, idx_cpu = 0, idx_hmq = 0;;
uint32_t *data; uint32_t *data;
...@@ -108,23 +108,23 @@ int main(int argc, char *argv[]) ...@@ -108,23 +108,23 @@ int main(int argc, char *argv[])
else else
n_tlv = 1; /* Only 1 buffer on write */ n_tlv = 1; /* Only 1 buffer on write */
tlv = calloc(n_tlv, sizeof(struct trtl_structure_tlv)); tlv = calloc(n_tlv, sizeof(struct trtl_tlv));
if (!tlv) { if (!tlv) {
fprintf(stderr, "Cannot allocate TLV descriptors\n"); fprintf(stderr, "Cannot allocate TLV descriptors\n");
exit(1); exit(1);
} }
for (i = optind, v = 0; v < n_tlv; i += 2, ++v) { for (i = optind, v = 0; v < n_tlv; i += 2, ++v) {
n = sscanf(argv[i], "%d", &tlv[v].index); n = sscanf(argv[i], "%d", &tlv[v].type);
if (n != 1) { if (n != 1) {
fprintf(stderr, fprintf(stderr,
"Invalid index: it must be a decimal number (%s)\n", "Invalid type: it must be a decimal number (%s)\n",
argv[i]); argv[i]);
exit(1); exit(1);
} }
n = sscanf(argv[i + 1], "%zu", &tlv[v].size); n = sscanf(argv[i + 1], "%zu", &tlv[v].size);
if (n != 1) { if (n != 1) {
fprintf(stderr, fprintf(stderr,
"Invalid index: it must be a decimal number (%s)\n", "Invalid size: it must be a decimal number (%s)\n",
argv[i + 1]); argv[i + 1]);
exit(1); exit(1);
} }
...@@ -174,7 +174,7 @@ int main(int argc, char *argv[]) ...@@ -174,7 +174,7 @@ int main(int argc, char *argv[])
switch (mode) { switch (mode) {
case OP_READ: case OP_READ:
err = trtl_rt_buffer_get(trtl, idx_cpu, idx_hmq, tlv, n_tlv); err = trtl_fw_buffer_get(trtl, idx_cpu, idx_hmq, tlv, n_tlv);
if (err) { if (err) {
fprintf(stderr, "Cannot read buffer: %s\n", fprintf(stderr, "Cannot read buffer: %s\n",
trtl_strerror(errno)); trtl_strerror(errno));
...@@ -183,7 +183,7 @@ int main(int argc, char *argv[]) ...@@ -183,7 +183,7 @@ int main(int argc, char *argv[])
/* trtl_print_payload(&hdr, tlv); */ /* trtl_print_payload(&hdr, tlv); */
break; break;
case OP_WRITE: case OP_WRITE:
err = trtl_rt_buffer_set(trtl, idx_cpu, idx_hmq, tlv, n_tlv); err = trtl_fw_buffer_set(trtl, idx_cpu, idx_hmq, tlv, n_tlv);
break; break;
} }
......
...@@ -44,11 +44,9 @@ static void help(char *name) ...@@ -44,11 +44,9 @@ static void help(char *name)
* It prints the given Mock Turtle firmware version * It prints the given Mock Turtle firmware version
* @param[in] v version to print * @param[in] v version to print
*/ */
static void trtl_ping_version_print(struct trtl_rt_version *v) static void trtl_ping_version_print(struct trtl_fw_version *v)
{ {
fprintf(stdout, "\tFirmware Version:\n"); fprintf(stdout, "\tFirmware Version:\n");
fprintf(stdout, "\t bitstream_id: 0x%08X\n",
v->fpga_id);
fprintf(stdout, "\t application_id: 0x%08X\n", fprintf(stdout, "\t application_id: 0x%08X\n",
v->rt_id); v->rt_id);
fprintf(stdout, "\tfirmware_version: 0x%08X\n", fprintf(stdout, "\tfirmware_version: 0x%08X\n",
...@@ -62,7 +60,7 @@ int main(int argc, char *argv[]) ...@@ -62,7 +60,7 @@ int main(int argc, char *argv[])
{ {
struct trtl_dev *trtl; struct trtl_dev *trtl;
uint32_t dev_id = 0, n = 1; uint32_t dev_id = 0, n = 1;
struct trtl_rt_version version; struct trtl_fw_version version;
uint64_t period = 0; uint64_t period = 0;
int err, f_version = 0, idx_cpu = 0, idx_hmq = 0; int err, f_version = 0, idx_cpu = 0, idx_hmq = 0;
char c; char c;
...@@ -118,7 +116,7 @@ int main(int argc, char *argv[]) ...@@ -118,7 +116,7 @@ int main(int argc, char *argv[])
usleep(period); usleep(period);
/* Try to ping */ /* Try to ping */
err = trtl_rt_ping(trtl, idx_cpu, idx_hmq); err = trtl_fw_ping(trtl, idx_cpu, idx_hmq);
if (err) { if (err) {
fprintf(stderr, fprintf(stderr,
"Ping failed on Device 0x%x CPU %d HMQ %d: %s\n", "Ping failed on Device 0x%x CPU %d HMQ %d: %s\n",
...@@ -132,7 +130,7 @@ int main(int argc, char *argv[]) ...@@ -132,7 +130,7 @@ int main(int argc, char *argv[])
/* Get the version */ /* Get the version */
if (f_version) { if (f_version) {
trtl_rt_version_get(trtl, idx_cpu, idx_hmq, &version); trtl_fw_version(trtl, idx_cpu, idx_hmq, &version);
trtl_ping_version_print(&version); trtl_ping_version_print(&version);
} }
......
...@@ -79,7 +79,7 @@ int main(int argc, char *argv[]) ...@@ -79,7 +79,7 @@ int main(int argc, char *argv[])
break; break;
case 'm': case 'm':
sscanf(optarg, "%d", &mod); sscanf(optarg, "%d", &mod);
if (mod > TRTL_SMEM_ADD) { if (mod > TRTL_SMEM_TYPE_ADD) {
fprintf(stderr, "Invalid operation mode\n"); fprintf(stderr, "Invalid operation mode\n");
help(); help();
exit(1); exit(1);
......
...@@ -146,7 +146,7 @@ int main(int argc, char *argv[]) ...@@ -146,7 +146,7 @@ int main(int argc, char *argv[])
switch (mode) { switch (mode) {
case OP_READ: case OP_READ:
err = trtl_rt_variable_get(trtl, idx_cpu, idx_hmq, var, n_var); err = trtl_fw_variable_get(trtl, idx_cpu, idx_hmq, var, n_var);
if (err) { if (err) {
fprintf(stderr, "Cannot read variables: %s\n", fprintf(stderr, "Cannot read variables: %s\n",
trtl_strerror(errno)); trtl_strerror(errno));
...@@ -158,7 +158,7 @@ int main(int argc, char *argv[]) ...@@ -158,7 +158,7 @@ int main(int argc, char *argv[])
} }
break; break;
case OP_WRITE: case OP_WRITE:
err = trtl_rt_variable_set(trtl, idx_cpu, idx_hmq, var, n_var); err = trtl_fw_variable_set(trtl, idx_cpu, idx_hmq, var, n_var);
if (err) { if (err) {
fprintf(stderr, "Cannot write variables: %s\n", fprintf(stderr, "Cannot write variables: %s\n",
trtl_strerror(errno)); trtl_strerror(errno));
......
...@@ -25,7 +25,7 @@ static struct rt_mq mq[] = { ...@@ -25,7 +25,7 @@ static struct rt_mq mq[] = {
}; };
static struct rt_variable variables[] = { static struct trtl_fw_variable variables[] = {
/* put here variables that you want to share */ /* put here variables that you want to share */
}; };
...@@ -33,17 +33,17 @@ static struct rt_structure structures[] = { ...@@ -33,17 +33,17 @@ static struct rt_structure structures[] = {
/* put here data structures that you want to share */ /* put here data structures that you want to share */
}; };
static action_t *actions[] = { static trtl_fw_action_t *actions[] = {
[RT_ACTION_RECV_PING] = rt_recv_ping, [RT_ACTION_RECV_PING] = rt_recv_ping,
[RT_ACTION_RECV_VERSION] = rt_version_getter, [RT_ACTION_RECV_VERSION] = rt_version_getter,
[RT_ACTION_RECV_FIELD_SET] = rt_variable_setter, [RT_ACTION_RECV_FIELD_SET] = trtl_fw_variable_setter,
[RT_ACTION_RECV_FIELD_GET] = rt_variable_getter, [RT_ACTION_RECV_FIELD_GET] = trtl_fw_variable_getter,
[RT_ACTION_RECV_STRUCT_SET] = rt_structure_setter, [RT_ACTION_RECV_STRUCT_SET] = rt_structure_setter,
[RT_ACTION_RECV_STRUCT_GET] = rt_structure_getter, [RT_ACTION_RECV_STRUCT_GET] = rt_structure_getter,
/* Add your actions here */ /* Add your actions here */
}; };
struct rt_application app = { struct trtl_fw_application app = {
.name = "{{short_name}}", .name = "{{short_name}}",
.version = { .version = {
.fpga_id = FPGA_APPLICATION_ID, .fpga_id = FPGA_APPLICATION_ID,
...@@ -69,7 +69,7 @@ struct rt_application app = { ...@@ -69,7 +69,7 @@ struct rt_application app = {
*/ */
int main() int main()
{ {
rt_init(&app); trtl_fw_init(&app);
while (1) { while (1) {
/* /*
...@@ -77,7 +77,7 @@ int main() ...@@ -77,7 +77,7 @@ int main()
* {{short_name_capital}}_CMD_IN * {{short_name_capital}}_CMD_IN
* as actions * as actions
*/ */
rt_mq_action_dispatch({{short_name_capital}}_CMD_IN); trtl_fw_mq_action_dispatch({{short_name_capital}}_CMD_IN);
} }
return 0; return 0;
......
#include <mockturtle-rt.h> #include <mockturtle-rt.h>
#include <hw/mockturtle_config.h>
int main() int main()
{ {
......
#include <mockturtle-rt-serial.h>
int main() int main()
{ {
int sum = 0; int sum = 0;
......
#include <mockturtle-rt.h> #include <mockturtle-rt.h>
#include <hw/mockturtle_config.h>
int main() int main()
{ {
......
#include <mockturtle-rt.h> #include <mockturtle-rt.h>
#include <hw/mockturtle_config.h>
int main() int main()
...@@ -21,7 +20,7 @@ int main() ...@@ -21,7 +20,7 @@ int main()
max_wait_cycle = 0xFFFF; max_wait_cycle = 0xFFFF;
while (1) { while (1) {
/* Wait incoming message */ /* Wait incoming message */
while ((hmq_poll_in() & wait) != wait) { while ((mq_poll_in(TRTL_HMQ) & wait) != wait) {
if (--max_wait_cycle == 0) { if (--max_wait_cycle == 0) {
pr_error("\tNO MESSAGE PENDING h:%d, cnt:0x%x\r\n", pr_error("\tNO MESSAGE PENDING h:%d, cnt:0x%x\r\n",
hmq, count); hmq, count);
...@@ -31,13 +30,13 @@ int main() ...@@ -31,13 +30,13 @@ int main()
/* validate message */ /* validate message */
if (hdr->len != 1 || msg[0] != count) { if (hdr->len != 1 || msg[0] != count) {
pr_error("\th: %d, l:%ld, d[0]:0x%lx, cnt:0x%x\r\n", pr_error("\th: %d, l:%d, d[0]:0x%lx, cnt:0x%x\r\n",
hmq, hdr->len, msg[0], count); hmq, hdr->len, msg[0], count);
mq_discard(TRTL_HMQ, hmq); mq_discard(TRTL_HMQ, hmq);
return -1; return -1;
} }
if (msg[1] < count) { if (msg[1] < count) {
pr_error("\th:%d, l:%ld d[1]:0x%lx, cnt:0x%x\r\n", pr_error("\th:%d, l:%d d[1]:0x%lx, cnt:0x%x\r\n",
hmq, hdr->len, msg[1], count); hmq, hdr->len, msg[1], count);
mq_discard(TRTL_HMQ, hmq); mq_discard(TRTL_HMQ, hmq);
return -1; return -1;
......
#include <mockturtle-rt.h> #include <mockturtle-rt.h>
#include <hw/mockturtle_config.h>
int main() int main()
{ {
...@@ -11,23 +10,23 @@ int main() ...@@ -11,23 +10,23 @@ int main()
cpu = 0; cpu = 0;
for (hmq = 0; hmq < cfgrom->n_hmq[cpu]; ++hmq) { for (hmq = 0; hmq < cfgrom->n_hmq[cpu]; ++hmq) {
if ((hmq_poll_in() & (1 << hmq)) != (1 << hmq)) { if ((mq_poll_in(TRTL_HMQ) & (1 << hmq)) != (1 << hmq)) {
pr_error("HMQ-%d after poll: 0x%lx\r\n", pr_error("HMQ-%d after poll: 0x%"PRIx32"\r\n",
hmq, hmq_poll_in()); hmq, mq_poll_in(TRTL_HMQ));
return -1; return -1;
} }
mq_purge(TRTL_HMQ, hmq); mq_purge(TRTL_HMQ, hmq);
if ((hmq_poll_in() & (1 << hmq)) == (1 << hmq)) { if ((mq_poll_in(TRTL_HMQ) & (1 << hmq)) == (1 << hmq)) {
pr_error("HMQ-%d after poll: 0x%lx\r\n", pr_error("HMQ-%d after poll: 0x%"PRIx32"\r\n",
hmq, hmq_poll_in()); hmq, mq_poll_in(TRTL_HMQ));
return -1; return -1;
} }
} }
if (hmq_poll_in() != 0) { if (mq_poll_in(TRTL_HMQ) != 0) {
pr_error("END poll: 0x%lx\r\n", hmq_poll_in()); pr_error("END poll: 0x%"PRIx32"\r\n", mq_poll_in(TRTL_HMQ));
return -1; return -1;
} }
......
#include <mockturtle-rt.h> #include <mockturtle-rt.h>
#include <hw/mockturtle_config.h>
int main() int main()
{ {
...@@ -24,7 +23,7 @@ int main() ...@@ -24,7 +23,7 @@ int main()
max_wait_cycle = 0xFFFFFFFF; max_wait_cycle = 0xFFFFFFFF;
while (1) { while (1) {
/* Wait incoming message */ /* Wait incoming message */
while ((hmq_poll_in() & wait) != wait) { while ((mq_poll_in(TRTL_HMQ) & wait) != wait) {
if (--max_wait_cycle == 0) { if (--max_wait_cycle == 0) {
pr_error("\tNO MESSAGE PENDING h:%d, cnt:0x%x\r\n", pr_error("\tNO MESSAGE PENDING h:%d, cnt:0x%x\r\n",
hmq, count); hmq, count);
...@@ -34,13 +33,13 @@ int main() ...@@ -34,13 +33,13 @@ int main()
/* validate message */ /* validate message */
if (hdr_r->len != 1 || msg_r[0] != count) { if (hdr_r->len != 1 || msg_r[0] != count) {
pr_error("\th: %d, l:%ld, d[0]:0x%lx, cnt:0x%x\r\n", pr_error("\th: %d, l:%d, d[0]:0x%lx, cnt:0x%x\r\n",
hmq, hdr_r->len, msg_r[0], count); hmq, hdr_r->len, msg_r[0], count);
mq_discard(TRTL_HMQ, hmq); mq_discard(TRTL_HMQ, hmq);
return -1; return -1;
} }
if (msg_r[1] < count) { if (msg_r[1] < count) {
pr_error("\th:%d, l:%ld d[1]:0x%lx, cnt:0x%x\r\n", pr_error("\th:%d, l:%d d[1]:0x%lx, cnt:0x%x\r\n",
hmq, hdr_r->len, msg_r[1], count); hmq, hdr_r->len, msg_r[1], count);
mq_discard(TRTL_HMQ, hmq); mq_discard(TRTL_HMQ, hmq);
return -1; return -1;
......
#include <mockturtle-rt-serial.h> #include <mockturtle-rt.h>
int main() int main()
{ {
......
...@@ -65,7 +65,7 @@ test_hmq(void) ...@@ -65,7 +65,7 @@ test_hmq(void)
mq_send(TRTL_HMQ, 0); mq_send(TRTL_HMQ, 0);
// Wait for answer // Wait for answer
while((hmq_poll_in() & 1) == 0) while((mq_poll_in(TRTL_HMQ) & 1) == 0)
; ;
if (counts[cpu] != v + 1) if (counts[cpu] != v + 1)
failed('H'); failed('H');
...@@ -80,7 +80,7 @@ test_hmq(void) ...@@ -80,7 +80,7 @@ test_hmq(void)
failed('K'); failed('K');
mq_discard(TRTL_HMQ, 0); mq_discard(TRTL_HMQ, 0);
if ((hmq_poll_in() & 1) != 0) if ((mq_poll_in(TRTL_HMQ) & 1) != 0)
failed('k'); failed('k');
} }
...@@ -103,7 +103,7 @@ test_rmq(void) ...@@ -103,7 +103,7 @@ test_rmq(void)
mq_send(TRTL_RMQ, 0); mq_send(TRTL_RMQ, 0);
// Wait for answer // Wait for answer
while((rmq_poll_in() & 1) == 0) while((mq_poll_in(TRTL_RMQ) & 1) == 0)
; ;
// Read answer // Read answer
...@@ -116,7 +116,7 @@ test_rmq(void) ...@@ -116,7 +116,7 @@ test_rmq(void)
failed('r'); failed('r');
mq_discard(TRTL_RMQ, 0); mq_discard(TRTL_RMQ, 0);
if ((rmq_poll_in() & 1) != 0) if ((mq_poll_in(TRTL_RMQ) & 1) != 0)
failed('s'); failed('s');
} }
......
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