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 */
......
......@@ -5,184 +5,61 @@
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <libmockturtle.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
* synchronous message.
* @param[in] trtl device token
* @param[out] version FPGA, RT and GIT version
* @param[in] hmq_in hmq slot index where send the message
* @param[in] hmq_out hmq slot index where you expect the answer
* @param[in] idx_cpu which CPU
* @param[in] idx_hmq which HMQ
* @param[out] version RT id, RT and GIT version
* @return 0 on success, -1 on error and errno is set appropriately
*/
int trtl_rt_version_get(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_rt_version *version)
int trtl_rt_version(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq,
struct trtl_rt_version *version)
{
struct trtl_msg msg;
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,
trtl_default_timeout_ms);
if (err <= 0)
return -1;
/* FIXME put the payload in the version field */
memcpy(version, msg.data, msg.hdr.len * 4);
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] hmq_in hmq slot index where send the message
* @param[in] hmq_out hmq slot index where you expect the answer
* @param[in] idx_cpu which CPU
* @param[in] idx_hmq which HMQ
* @return 0 on success, -1 on error and errno is set appropriately
*/
int trtl_rt_ping(struct trtl_dev *trtl,
unsigned int idx_cpu,
unsigned int idx_hmq)
{
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
struct trtl_msg msg;
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,
trtl_default_timeout_ms);
if (err <= 0)
......@@ -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.
*
......@@ -228,11 +91,13 @@ static inline int trtl_rt_variable(struct trtl_dev *trtl,
* This function will change the header content, in particular it will change
* the following fields: msg_id, len
* @param[in] trtl device token
* @param[in|out] hdr header to send on input, header received on output
* @param[in|out] var variables to get on input, variables values on output
* @param[in] n_var number of variables to set. In other words,
* the number of indexes you have in the 'variables' fields.
* @param[in] sync set if you want a synchronous message
* @param[in] idx_cpu
* @param[in] idx_hmq
* @param[in|out] variables on input variable indexes and values.
* 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
* @return 0 on success, -1 on error and errno is appropriately set.
*/
int trtl_rt_variable_set(struct trtl_dev *trtl,
unsigned int idx_cpu,
......@@ -240,9 +105,26 @@ int trtl_rt_variable_set(struct trtl_dev *trtl,
uint32_t *variables,
unsigned int n_variables)
{
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
struct trtl_msg msg;
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,10 +147,13 @@ int trtl_rt_variable_set(struct trtl_dev *trtl,
* This function will change the header content, in particular it will change
* the following fields: msg_id, flags, len
* @param[in] trtl device token
* @param[in|out] hdr header to send on input, header received on output
* @param[in|out] var variables to get on input, variables values on output
* @param[in] n_var number of variables to set. In other words,
* @param[in] idx_cpu
* @param[in] idx_hmq
* @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
* @return 0 on success, -1 on error and errno is appropriately set.
*/
int trtl_rt_variable_get(struct trtl_dev *trtl,
unsigned int idx_cpu,
......@@ -276,9 +161,26 @@ int trtl_rt_variable_get(struct trtl_dev *trtl,
uint32_t *variables,
unsigned int n_variables)
{
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
struct trtl_msg msg;
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;
}
......@@ -294,14 +196,45 @@ int trtl_rt_variable_get(struct trtl_dev *trtl,
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)
{
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
struct trtl_msg msg;
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
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.
* This function will change the header content, in particular it will change
......@@ -314,12 +247,49 @@ int trtl_rt_buffer_set(struct trtl_dev *trtl,
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)
{
/* FIXME Re-implement with new protocol */
errno = ETRTL_NO_IMPLEMENTATION;
return -1;
struct trtl_msg msg;
struct trtl_desc *wdesc = (struct trtl_desc *)trtl;
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,
* It prints the message header in a human readable format
* @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,
" app_id 0x%x | msg_id %d | slot_io 0x%x | seq %d\n",
h->rt_app_id, h->msg_id, h->slot_io, h->seq);
"\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);
fprintf(stdout,
" len %d | flags 0x%x | trans 0x%x | time %d\n",
h->len, h->flags, h->trans, h->time);
"\tlen 0x%04"PRIx16" | sync_id 0x%04"PRIx16"\r\n",
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)
* @param[in] h message header
* @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;
switch (h->msg_id) {
case TRTL_MSG_ID_VAR_SET:
switch (msg->hdr.msg_id) {
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_rt_version *v = (struct trtl_rt_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_ANS:
for (i = 0; i < h->len; i += 2) {
fprintf(stdout, "[%d] 0x%08x\n",
payload[i], payload[i + 1]);
case TRTL_MSG_ID_VAR_SET:
for (i = 0; i < msg->hdr.len; i += 2) {
fprintf(stdout, "Variable %"PRId32": 0x%08"PRIx32"\n",
msg->data[i], msg->data[i + 1]);
}
break;
case TRTL_MSG_ID_BUF_SET:
case TRTL_MSG_ID_BUF_GET:
fprintf(stdout, "Buffer message\n");
/* TODO */
break;
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)
fprintf(stdout, "\n %04d :", i);
fprintf(stdout, " 0x%08x", payload[i]);
fprintf(stdout, " 0x%08"PRIx32, msg->data[i]);
}
break;
}
}
......@@ -377,15 +381,6 @@ void trtl_print_payload(struct trtl_proto_header *h, void *buf)
*/
void trtl_print_message(struct trtl_msg *msg)
{
struct trtl_proto_header h;
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);
}
trtl_print_header(msg);
trtl_print_payload(msg);
}
......@@ -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)
......
/**
* 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 rt_application *_app;
/**
* It makes the given message an error message
*/
void rt_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 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 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_rt_version) / 4;
memcpy(msg_o->payload, (void *)&_app->version,
sizeof(struct trtl_rt_version));
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.
*/
static int rt_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 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 rt_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 rt_buffer_getter(msg_i, msg_o);
return 0;
}
/**
* This is an @ref action_t function type. Accorind the message request,
* it copies a number of declared variables.
*/
static int rt_variable_getter(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
struct rt_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 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 rt_variable_setter(struct trtl_msg *msg_i, struct trtl_msg *msg_o)
{
struct rt_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_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, 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 rt_variable_getter(msg_i, msg_o);
return 0;
}
/**
* List of standard actions
*/
static 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] = rt_variable_setter,
[TRTL_MSG_ID_VAR_GET - __TRTL_MSG_ID_MAX_USER] = rt_variable_getter,
[TRTL_MSG_ID_BUF_SET - __TRTL_MSG_ID_MAX_USER] = rt_buffer_setter,
[TRTL_MSG_ID_BUF_GET - __TRTL_MSG_ID_MAX_USER] = rt_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 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;
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)
rt_message_error(&msg_out, err);
rt_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 rt_mq_action_dispatch(enum trtl_mq_type type, unsigned int idx_mq)
{
struct trtl_msg msg;
int err = 0;
/* Check if we have a pending message */
if (type == TRTL_HMQ) {
if (!(hmq_poll_in() & (1 << idx_mq)))
return -EAGAIN;
} else {
if (!(rmq_poll_in() & (1 << idx_mq)))
return -EAGAIN;
}
/* Map the message */
mq_map_in_message(type, idx_mq, &msg);
rt_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_rt_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_rt_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_rt_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 rt_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 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);
}
}
/**
* It prints on the serial console the given message
* @param[in] msg a mock turtle message
*/
void rt_print_message(struct trtl_msg *msg)
{
pr_debug("Message\n\r");
rt_print_header(msg->header);
rt_print_data(msg->payload, msg->header->len);
}
/**
* 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 validates the user application actions
* @param[in] app the user application
* @return 0 on success. -EINVAL on error
*/
static inline int rt_init_action(struct rt_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 rt_init_fpga(struct rt_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 rt_init_mq(struct rt_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 rt_init_variables(struct rt_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 rt_init_buffers(struct rt_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 rt_init(struct rt_application *app)
{
int err;
_app = app;
_app->seq = 0;
_app->cfgrom = trtl_config_rom_get();
err = rt_init_action(_app);
if (err)
return err;
err = rt_init_fpga(_app);
if (err)
return err;
err = rt_init_mq(_app);
if (err)
return err;
err = rt_init_buffers(_app);
if (err)
return err;
err = rt_init_variables(_app);
if (err)
return err;
return 0;
}
......@@ -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