Commit 9811441e authored by Federico Vaga's avatar Federico Vaga

sw:rt: re-design API

Because of some inter-dependencies here I'm doing a big patch that changes
many different things. Forgive me
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent c6c69f99
......@@ -13,31 +13,6 @@ static unsigned int period = 1000000;
static unsigned int alarm_enable;
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 {
AC_TIME = 0,
AC_PERIOD_UPDATE,
......@@ -75,13 +50,10 @@ static struct rt_variable variables[] = {
static struct rt_application app = {
.name = "alarm-clk",
.version = {
.fpga_id = CONFIG_FPGA_APPLICATION_ID,
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.mq = mq,
.n_mq = ARRAY_SIZE(mq),
.variables = variables,
.n_variables = ARRAY_SIZE(variables),
......@@ -96,14 +68,14 @@ static void ac_update(void)
if ((--period_c) == 0) {
period_c = period;
trtl_rt_mq_send_uint32(AC_DATA, 0x12, 1,
trtl_rt_mq_send_uint32(TRTL_HMQ, 0, 0x12, 1,
iteration);
pr_debug("Iteration %d\n\r", iteration);
}
if (alarm_enable) {
if (alarm_iter < iteration) {
trtl_rt_mq_send_uint32(AC_DATA, 0x34, 2,
trtl_rt_mq_send_uint32(TRTL_HMQ, 0, 0x34, 2,
iteration, alarm_iter);
alarm_enable = 0;
alarm_iter = 0;
......@@ -132,12 +104,8 @@ int main()
ac_init();
while (1) {
/*
* Handle all messages incoming from slot
* AC_CMD_IN
* as actions
*/
rt_mq_action_dispatch(AC_CMD_IN);
/* Handle all messages incoming from HMQ 0 as actions */
rt_mq_action_dispatch(TRTL_HMQ, 0);
ac_update();
}
......
......@@ -22,31 +22,6 @@ static struct dg_conf dg_conf;
static uint32_t dg_last_sample_idx;
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 {
DG_PERIOD_UPDATE = 0,
};
......@@ -79,13 +54,10 @@ struct rt_buffer buffers[] = {
static struct rt_application app = {
.name = "data-gen",
.version = {
.fpga_id = CONFIG_FPGA_APPLICATION_ID,
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
},
.mq = mq,
.n_mq = ARRAY_SIZE(mq),
.variables = variables,
.n_variables = ARRAY_SIZE(variables),
......@@ -109,7 +81,9 @@ static void generate_sample(void)
dg_last_sample_idx + 1, DG_BUF_SIZE, 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)
......@@ -143,12 +117,8 @@ int main()
dg_init();
while (1) {
/*
* Handle all messages incoming from slot
* DG_MQ_CMD_IN
* as actions
*/
rt_mq_action_dispatch(DG_MQ_CMD_IN);
/* Handle all messages incoming from HMQ 0 as actions */
rt_mq_action_dispatch(TRTL_HMQ, 0);
dg_update();
}
......
......@@ -15,23 +15,6 @@
#define GPIO_DDR 0x8 /* Direction Data 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;
struct rt_buffer svec_buffers[] = {
......@@ -88,13 +71,10 @@ struct rt_variable svec_variables[] = {
struct rt_application app = {
.name = "svec-svec",
.version = {
.fpga_id = FPGA_APPLICATION_ID,
.rt_id = RT_APPLICATION_ID,
.rt_version = RT_VERSION(1, 0),
.git_version = GIT_VERSION
},
.mq = mq,
.n_mq = 2,
.buffers = svec_buffers,
.n_buffers = ARRAY_SIZE(svec_buffers),
......@@ -123,9 +103,8 @@ int main()
svec_debug_interface();
while (1) {
/* Handle all messages incoming from slot SVEC_HMQ_IN
as actions */
rt_mq_action_dispatch(SVEC_CMD_IN);
/* Handle all messages incoming from HMQ 0 as actions */
rt_mq_action_dispatch(TRTL_HMQ, 0);
}
return 0;
......
......@@ -8,7 +8,7 @@
#ifndef __SVEC_COMMON_H
#define __SVEC_COMMON_H
#include <mockturtle-common.h>
#include <mockturtle.h>
/* HMQ slots used for input */
......
......@@ -43,7 +43,6 @@ static void svec_print_status(struct svec_status *status)
static void svec_print_version(struct trtl_rt_version *version)
{
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 Version: 0x%x\n", version->rt_version);
fprintf(stdout, "\tGit Version: 0x%x\n", version->git_version);
......
......@@ -6,32 +6,13 @@
#include <mockturtle-framework.h>
enum rt_slot_name {
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",
.version = {
.fpga_id = CONFIG_FPGA_APPLICATION_ID,
.rt_id = CONFIG_RT_APPLICATION_ID,
.rt_version = RT_VERSION(0, 1),
.git_version = GIT_VERSION
.git_version = GIT_VERSION,
},
.mq = mq,
.n_mq = ARRAY_SIZE(mq),
};
/**
......@@ -43,11 +24,10 @@ int main()
while (1) {
/*
* Handle all messages incoming from slot
* HELLOFRM_CMD_IN
* Handle all messages incoming from slot 0
* as actions
*/
rt_mq_action_dispatch(HELLOFRM_CMD_IN);
rt_mq_action_dispatch(TRTL_HMQ, 0);
}
return 0;
......
/*
* 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,12 +21,109 @@
#define __TRTL_USER_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_rt_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 */
};
#define TRTL_MAX_CARRIER 20 /**< Maximum number of WRNC components on a
single computer*/
/**
* 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
*/
......@@ -56,15 +153,6 @@ enum trtl_smem_modifier {
};
/**
* Messages descriptor
*/
struct trtl_msg {
struct trtl_hmq_header hdr;
uint32_t data[TRTL_MAX_PAYLOAD_SIZE]; /**< payload very maximum size */
};
/**
* @enum trtl_msg_filter_operation_type
* List of available filter's operations
......@@ -123,4 +211,21 @@ enum trtl_ioctl_commands {
#define TRTL_IOCTL_MSG_FILTER_CLEAN _IOW(TRTL_IOCTL_MAGIC, \
TRTL_MSG_FILTER_CLEAN, \
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
};
#endif
......@@ -111,6 +111,14 @@ class TrtlMessage(Structure):
return True
class TrtlFirmwareVersion(Structure):
_fields_ = [
("id", c_uint32),
("fw-version", c_uint32),
("git-version", c_uint32),
]
class TrtlDevice(object):
"""It is a Python class that represent a Mock Turtle Device
"""
......@@ -229,7 +237,16 @@ class TrtlDevice(object):
]
self.libtrtl.trtl_hmq_flush.restype = c_int
self.libtrtl.trtl_hmq_flush.errcheck = self.errcheck
# FW PING
self.libtrtl.trtl_rt_ping.argtypes = [c_void_p, c_uint, c_uint]
self.libtrtl.trtl_rt_ping.restype = c_int
self.libtrtl.trtl_rt_ping.errcheck = self.__errcheck_int
# FW VERSION
self.libtrtl.trtl_rt_version.argtypes = [c_void_p, c_uint, c_uint,
POINTER(TrtlFirmwareVersion),
]
self.libtrtl.trtl_rt_version.restype = c_int
self.libtrtl.trtl_rt_version.errcheck = self.__errcheck_int
# self.libtrtl.trtl_hmq_filter_add.argtypes = [c_void_p]
# self.libtrtl.trtl_hmq_filter_clean.argtypes = [c_void_p]
# # Return
......@@ -326,6 +343,22 @@ class TrtlCpu(object):
self.idx_cpu,
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_rt_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_rt_version(self.trtl_dev.tkn,
self.idx_cpu, idx_hmq,
pointer(version))
return version
class TrtlHmq(object):
"""
......
......@@ -14,6 +14,8 @@
*/
struct trtl_desc {
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 path[TRTL_PATH_LEN]; /**< path to device */
int fd_dev; /**< File Descriptor of the device */
......
This diff is collapsed.
......@@ -243,6 +243,8 @@ static struct trtl_dev *__trtl_open(const char *device)
}
}
trtl->seq = 0;
return (struct trtl_dev *)trtl;
out_hmq_fd:
......
......@@ -20,7 +20,6 @@ extern "C" {
#include <stdio.h>
#include <poll.h>
#include "hw/mockturtle_config.h"
#include "mockturtle-common.h"
#include "mockturtle.h"
extern const unsigned int trtl_default_timeout_ms;
......@@ -98,15 +97,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
*/
......@@ -134,8 +124,8 @@ const struct trtl_config_rom *trtl_config_get(struct trtl_dev *trtl);
* Utilities collection
* @{
*/
extern void trtl_print_header(struct trtl_proto_header *h);
extern void trtl_print_payload(struct trtl_proto_header *h, void *buf);
extern void trtl_print_header(struct trtl_msg *msg);
extern void trtl_print_payload(struct trtl_msg *msg);
extern void trtl_print_message(struct trtl_msg *msg);
extern char *trtl_strerror(int err);
/**@}*/
......@@ -224,38 +214,15 @@ 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
* Message builders for RT service messages
* @{
*/
extern int trtl_rt_version_get(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_rt_version *version);
extern int trtl_rt_version(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_rt_version *version);
extern int trtl_rt_ping(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq);
......@@ -270,12 +237,12 @@ extern int trtl_rt_variable_get(struct trtl_dev *trtl,
extern int trtl_rt_buffer_set(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_structure_tlv *tlv,
struct trtl_tlv *tlv,
unsigned int n_tlv);
extern int trtl_rt_buffer_get(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_structure_tlv *tlv,
struct trtl_tlv *tlv,
unsigned int n_tlv);
/**@}*/
#ifdef __cplusplus
......
......@@ -16,6 +16,7 @@ AUTOCONF = $(CURDIR)/$(BUILDDIR)/include/generated/autoconf.h
CROSS_COMPILE_TARGET ?= riscv32-elf-
# FIXME the mult/div is broken, for the time being remove it completely
# -march=rv32im should be the future option
CFLAGS += -D__TRTL_FIRMWARE__
CFLAGS += -mabi=ilp32 -march=rv32i -ffunction-sections -fdata-sections
LDFLAGS += -lgcc -lc -Wl,--gc-sections
......@@ -66,10 +67,7 @@ OBJS += lib/printf.o
OBJS += lib/mockturtle-rt-common.o
OBJDIR-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework
OBJS-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework/mockturtle-frm-core.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
OBJS-$(CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE) += framework/mockturtle-framework.o
OBJDIR += $(OBJDIR-y)
OBJS += $(OBJS-y)
......
This diff is collapsed.
......@@ -10,13 +10,99 @@
#ifndef __TRTL_FW_FRM_H__
#define __TRTL_FW_FRM_H__
#include <inttypes.h>
#include <generated/autoconf.h>
#include <hw/mockturtle_config.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"
#include "mockturtle-frm-variable.h"
/**
* Action prototype type
* @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 (action_t)(struct trtl_msg *msg_i, struct trtl_msg *msg_o);
/**
* 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 */
};
/**
* 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 */
};
/**
* 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_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 */
unsigned int seq; /** sequence number reference */
const struct trtl_config_rom *cfgrom;
};
extern struct rt_application *_app;
extern int rt_init(struct rt_application *app);
extern void rt_get_time(uint32_t *seconds, uint32_t *cycles);
extern void rt_print_header(struct trtl_hmq_header *h);
extern void rt_print_data(uint32_t *d, unsigned int count);
extern void rt_print_message(struct trtl_msg *msg);
extern int trtl_rt_mq_send_uint32(enum trtl_mq_type type,
unsigned int idx_mq,
uint8_t msg_id,
unsigned int n,
...);
extern int trtl_rt_mq_send_buf(enum trtl_mq_type type,
unsigned int idx_mq,
uint8_t msg_id,
unsigned int n,
void *data);
extern int rt_mq_action_dispatch(enum trtl_mq_type type,
unsigned int idx_mq);
extern void rt_message_error(struct trtl_msg *msg, int err);
#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
......@@ -18,14 +18,11 @@
#include <hw/mockturtle_addresses.h>
#include "hw/mockturtle_cpu_lr.h"
#include <mockturtle-common.h>
#include <mockturtle.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
......@@ -144,5 +141,15 @@ static inline void trtl_notify_send(enum trtl_cpu_notification id)
lr_writel(1, MT_CPU_LR_REG_NTF_INT);
}
/**
* It returns the core ID on which the firmware is running
* @return the core ID
*/
static inline uint32_t trtl_get_core_id(void)
{
return lr_readl(0);
}
#endif
/**@}*/
......@@ -17,6 +17,8 @@
#include <hw/mockturtle_queue.h>
#include <hw/mockturtle_cpu_lr.h>
#include "mockturtle-rt-common.h"
#define TRTL_MQ_SLOT_IN(slot) (TRTL_MQ_BASE_IN + ((slot) << 16))
// Outgoung slot base address, relative to BASE_HMQ
......@@ -27,6 +29,7 @@
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,
};
......@@ -145,43 +148,56 @@ static inline void *mq_map_in_header(enum trtl_mq_type type, int slot)
}
/**
* It gets the current status of the input Host Message Queues
* 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 uint32_t hmq_poll_in(void)
static inline void mq_map_out_message(enum trtl_mq_type type,
unsigned idx_mq,
struct trtl_msg *msg)
{
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);
msg->header = mq_map_out_header(type, idx_mq);
msg->payload = mq_map_out_buffer(type, idx_mq);
}
/**
* It gets the current status of the output Host Message Queues
* 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 uint32_t hmq_poll_out(void)
static inline void mq_map_in_message(enum trtl_mq_type type,
unsigned idx_mq,
struct trtl_msg *msg)
{
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);
msg->header = mq_map_in_header(type, idx_mq);
msg->payload = mq_map_in_buffer(type, idx_mq);
}
/**
* It gets the current status of the input Remote Message Queues
* It gets the current MQ input status
* @return message queues input status bitmask
*/
static inline uint32_t rmq_poll_in(void)
static inline uint32_t mq_poll_in(enum trtl_mq_type type)
{
volatile uint32_t *poll = (void *)TRTL_ADDR_LR_BASE + MT_CPU_LR_REG_RMQ_STAT;
uint32_t poll = lr_readl(MT_CPU_LR_REG_HMQ_STAT + (type * 4));
return ((*poll & MT_CPU_LR_RMQ_STAT_IN_MASK) >> MT_CPU_LR_RMQ_STAT_IN_SHIFT);
/* 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 status of the output Remote Message Queues
* It gets the current MQ output status
* @return message queues output status bitmask
*/
static inline uint32_t rmq_poll_out(void)
static inline uint32_t mq_poll_out(enum trtl_mq_type type)
{
volatile uint32_t *poll = (void *)TRTL_ADDR_LR_BASE + MT_CPU_LR_REG_RMQ_STAT;
uint32_t poll = lr_readl(MT_CPU_LR_REG_HMQ_STAT + (type * 4));
return ((*poll & MT_CPU_LR_RMQ_STAT_OUT_MASK) >> MT_CPU_LR_RMQ_STAT_OUT_SHIFT);
/* 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);
}
#endif
......
......@@ -14,7 +14,6 @@
#include <stdint.h>
#include "mockturtle-rt-mqueue.h"
#include "mockturtle-rt-message.h"
#include "mockturtle-rt-common.h"
#include "mockturtle-rt-smem.h"
#include "mockturtle-rt-serial.h"
......
......@@ -50,7 +50,7 @@ int main(int argc, char *argv[])
char c;
int err, n, dev_id = -1, v, i, k;
enum operations mode;
struct trtl_structure_tlv *tlv;
struct trtl_tlv *tlv;
unsigned int n_tlv, idx_cpu = 0, idx_hmq = 0;;
uint32_t *data;
......@@ -108,23 +108,23 @@ int main(int argc, char *argv[])
else
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) {
fprintf(stderr, "Cannot allocate TLV descriptors\n");
exit(1);
}
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) {
fprintf(stderr,
"Invalid index: it must be a decimal number (%s)\n",
"Invalid type: it must be a decimal number (%s)\n",
argv[i]);
exit(1);
}
n = sscanf(argv[i + 1], "%zu", &tlv[v].size);
if (n != 1) {
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]);
exit(1);
}
......
......@@ -47,8 +47,6 @@ static void help(char *name)
static void trtl_ping_version_print(struct trtl_rt_version *v)
{
fprintf(stdout, "\tFirmware Version:\n");
fprintf(stdout, "\t bitstream_id: 0x%08X\n",
v->fpga_id);
fprintf(stdout, "\t application_id: 0x%08X\n",
v->rt_id);
fprintf(stdout, "\tfirmware_version: 0x%08X\n",
......@@ -132,7 +130,7 @@ int main(int argc, char *argv[])
/* Get the version */
if (f_version) {
trtl_rt_version_get(trtl, idx_cpu, idx_hmq, &version);
trtl_rt_version(trtl, idx_cpu, idx_hmq, &version);
trtl_ping_version_print(&version);
}
......
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