Commit d5868bff authored by Tristan Gingold's avatar Tristan Gingold

Initial version of adc firmware.

parent 71424729
mainmenu "WRTD ADC firmware configuration"
comment "Project specific configuration"
# include Mock Turtle's Kconfig
source "Kconfig.mt"
-include Makefile.specific
OBJS := wrtd-rt-adcout.o
OUTPUT = wrtd-rt-adcout
TRTL ?= ../../../dependencies/mock-turtle/
TRTL_SW = $(TRTL)/software
EXTRA2_CFLAGS= # To be set by user on make line
EXTRA_CFLAGS += -I../../include -I../common \
-I../../../dependencies/fmc-adc-100m14b4cha-gw/hdl/rtl/wb_gen/ \
-Werror $(EXTRA2_CFLAGS)
vpath %.c ../
MEM_INIT_GEN=../../../dependencies/general-cores/tools/mem_init_gen.py
$(OUTPUT).bram: $(OUTPUT).bin
python $(MEM_INIT_GEN) -i $< > $@
include $(TRTL_SW)/firmware/Makefile
#
# Automatically generated file; DO NOT EDIT.
# fmc-svec-carrier fw-01 demo configuration
#
#
# Project specific configuration
#
#
# Mock Turtle configuration
#
CONFIG_FPGA_APPLICATION_ID=0
CONFIG_RT_APPLICATION_ID=0
CONFIG_CFLAGS_OPT="-Os"
CONFIG_CFLAGS_EXTRA="-ggdb"
#
# Mock Turtle framework configuration
#
CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE=y
CONFIG_MOCKTURTLE_FRAMEWORK_ACTION_ENABLE=y
CONFIG_MOCKTURTLE_FRAMEWORK_VARIABLE_ENABLE=y
CONFIG_MOCKTURTLE_FRAMEWORK_BUFFER_ENABLE=y
CONFIG_MOCKTURTLE_FRAMEWORK_PING_ENABLE=y
CONFIG_MOCKTURTLE_FRAMEWORK_VERSION_ENABLE=y
#
# Mock Turtle library configuration
#
CONFIG_MOCKTURTLE_LIBRARY_PRINT_ENABLE=y
# CONFIG_MOCKTURTLE_LIBRARY_PRINT_DEBUG_ENABLE is not set
# CONFIG_MOCKTURTLE_LIBRARY_PRINT_ERROR_ENABLE is not set
# CONFIG_MOCKTURTLE_LIBRARY_PRINT_MESSAGE_ENABLE is not set
/* Generic output queue.
User needs to define:
OUT_QUEUE_PREFIX: the prefix (ends with an '_')
OUT_QUEUE_SIZE: max length of the queue
OUT_QUEUE_MAXTIME: maximum time in advance.
*/
#define OUT_QUEUE_NAME(x) OUT_QUEUE_PREFIX##x
#define OUT_QUEUE_STRUCT OUT_QUEUE_NAME(out_queue)
struct OUT_QUEUE_STRUCT {
struct wrtd_event events[OUT_QUEUE_SIZE];
int head, tail, count;
/* Last timestamp value written to output config. */
uint32_t last_programmed_sec;
uint32_t last_programmed_ns;
};
/**
* Initializes an empty pulse queue
*/
static void OUT_QUEUE_NAME(out_queue_init)(struct OUT_QUEUE_STRUCT *p)
{
p->head = 0;
p->tail = 0;
p->count = 0;
p->last_programmed_sec = 0;
p->last_programmed_ns = 0;
}
/**
* Requests a new entry in a pulse queue. Returns pointer to the ne
* entry or NULL if the queue is full.
*/
static struct wrtd_event *OUT_QUEUE_NAME(out_queue_push)(struct OUT_QUEUE_STRUCT *p)
{
struct wrtd_event *ev;
if (p->count == OUT_QUEUE_SIZE)
return NULL;
ev = &p->events[p->head];
p->count++;
p->head++;
if (p->head == OUT_QUEUE_SIZE)
p->head = 0;
return ev;
}
/**
* Returns non-0 if pulse queue p contains any pulses.
*/
static inline int OUT_QUEUE_NAME(out_queue_empty)(struct OUT_QUEUE_STRUCT *p)
{
return (p->count == 0);
}
/**
* Returns the oldest entry in the pulse queue (or NULL if empty).
*/
static struct wrtd_event *OUT_QUEUE_NAME(out_queue_front)(struct OUT_QUEUE_STRUCT *p)
{
if (!p->count)
return NULL;
return &p->events[p->tail];
}
/**
* Releases the oldest entry from the pulse queue.
*/
static void OUT_QUEUE_NAME(out_queue_pop)(struct OUT_QUEUE_STRUCT *p)
{
p->tail++;
if(p->tail == OUT_QUEUE_SIZE)
p->tail = 0;
p->count--;
}
/**
* Checks if the timestamp of the last programmed pulse is lost because
* of timeout
*/
static int OUT_QUEUE_NAME(out_queue_check_timeout) (struct OUT_QUEUE_STRUCT *q)
{
uint32_t now_sec;
uint32_t now_ns;
int delta;
/*
* Read the current WR time, order is important: first seconds,
* then cycles (cycles get latched on reading secs register.
*/
now_sec = lr_readl(MT_CPU_LR_REG_TAI_SEC);
now_ns = lr_readl(MT_CPU_LR_REG_TAI_CYCLES) * 8;
if(q->last_programmed_sec > now_sec + OUT_QUEUE_MAXTIME) {
pr_error("Enqueued event very far in the future. Dropping.");
return 0;
}
/* Current time exceeds FD setpoint? */
delta = now_sec - q->last_programmed_sec;
if (delta != 0)
return delta > 0;
delta = now_ns - q->last_programmed_ns;
return (delta > 0);
}
#undef OUT_QUEUE_STRUCT
#undef OUT_QUEUE_NAME
/*
* Copyright (C) 2013-2018 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <errno.h>
#include <string.h>
#include "mockturtle-rt.h"
#include <mockturtle-framework.h>
#include "wrtd-common.h"
#define OUT_QUEUE_MAXTIME 10
#define OUT_QUEUE_PREFIX adcin_
#define OUT_QUEUE_SIZE 4
#include "out_queue.h"
struct wrtd_adcin_dev {
uint32_t io_addr;
adcin_out_queue queue;
};
static inline int adcin_wr_present(struct wrtd_adcin_dev *fd)
{
return 1;
}
static inline int adcin_wr_link_up(struct wrtd_adcin_dev *fd)
{
return 1;
}
static inline int adcin_wr_time_locked(struct wrtd_adcin_dev *fd)
{
return 1;
}
static inline int adcin_wr_time_ready(struct wrtd_adcin_dev *fd)
{
return 1;
}
static inline int adcin_wr_sync_timeout(void)
{
return 0;
}
static void adcin_wr_enable_lock(struct wrtd_adcin_dev *fd, int enable)
{
return;
}
static inline void adcin_writel(struct wrtd_adcin_dev *dev, uint32_t value,
uint32_t reg)
{
dp_writel(value, dev->io_addr + reg);
}
static inline uint32_t adcin_readl (struct wrtd_adcin *dev, uint32_t reg)
{
return dp_readl(dev->io_addr + reg);
}
/**
* Drop the given enqueued trigger
*/
static void drop_trigger(struct wrtd_fd_channel *out,
struct wrtd_event *ev,
struct lrt_pulse_queue *q, unsigned reason)
{
out->idle = 1;
if (pulse_queue_empty(q))
return;
/* Drop the pulse */
pulse_queue_pop(q);
/* Disarm the FD output */
fd_ch_writel(out, FD_DCR_MODE, FD_REG_DCR);
wrtd_log(WRTD_LOG_MSG_EV_DISCARDED, reason, ev, NULL);
}
/**
* Output driving function. Reads pulses from the output queue,
* programs the output and updates the output statistics.
*/
static void adcin_output (struct wrtd_adcin_dev *dev)
{
struct adcin_out_queue *q = &dev->queue;
struct wrtd_event *ev = adcin_out_queue_front(q);
uint32_t ctrl = adcin_readl(dev, ALT_TRIGIN_CTRL);
struct wrtd_tstamp *ts;
/* Check if the output has triggered */
if (!dev->idle) {
#if 0
if (!wr_is_timing_ok()) {
/* Timing has been lost. */
drop_trigger(out, ev, q, WRTD_LOG_DISCARD_NO_SYNC);
return;
}
#endif
if (ctrl & ALT_TRIGIN_CTRL_ENABLE) {
/* Armed but still waiting for trigger */
if (check_output_timeout (dev)) {
/* Will never trigger. Missed. */
drop_trigger(dev, ev, q, WRTD_LOG_DISCARD_TIMEOUT);
}
} else {
/* Has been triggered. */
wrtd_log(WRTD_LOG_MSG_EV_CONSUMED, WRTD_LOG_CONSUMED_DONE, ev, NULL);
adcin_out_queue_pop(q);
dev->idle = 1;
}
return;
}
/* Output is idle: check if there's something in the queue to execute */
if (adcin_out_queue_empty(q))
return;
ev = pulse_queue_front(q);
ts = &ev->ts;
if (!wr_is_timing_ok()) {
drop_trigger(out, ev, q, WRTD_LOG_DISCARD_NO_SYNC);
return;
}
/* Program the output start time */
adcin_writel(dev, ts->seconds, ALT_TRIGIN_SECONDS + 0);
adcin_writel(dev, ts->ns / 8, ALT_TRIGIN_CYCLES);
adcin_writel(dev, ALT_TRIGIN_CTRL_ENABLE, ALT_TRIGIN_CTRL);
wrtd_log(WRTD_LOG_MSG_EV_CONSUMED, WRTD_LOG_CONSUMED_START, ev, NULL);
ts_add2_ns (ts, 8000);
/*
* Store the last programmed timestamp (+ some margin) and mark
* the output as busy
*/
q->last_programmed_sec = ts->seconds;
q->last_programmed_ns = ts->ns;
dev->idle = 0;
}
static void fd_local_output(struct wrtd_fd_dev *fd,
struct wrtd_event *ev, unsigned ch)
{
struct wrtd_fd_channel *out = &fd->channels[ch];
struct wrtd_event *pq_ev;
pq_ev = pulse_queue_push(&out->queue);
if (!pq_ev) {
/* overflow.
FIXME: stats ? */
wrtd_log(WRTD_LOG_MSG_EV_DISCARDED, WRTD_LOG_DISCARD_OVERFLOW,
ev, NULL);
return;
}
*pq_ev = *ev;
}
#if 0
/**
* It disable the given channel and clear its internal queue
*/
static int wrtd_out_disable(struct trtl_fw_msg *msg_i,
struct trtl_fw_msg *msg_o)
{
uint32_t ch = ((uint32_t *)msg_i->payload)[0];
pulse_queue_init(&wrtd_out_channels[ch].queue);
fd_ch_writel(&wrtd_out_channels[ch], FD_DCR_MODE, FD_REG_DCR);
msg_o->header->msg_id = msg_i->header->msg_id;
return 0;
}
#endif
static void wrtd_adcin_data_init(struct wrtd_adcin_dev *dev)
{
adcin_out_queue_init(&fd->channels[i].queue);
adcin->idle = 1;
}
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "mockturtle-rt.h"
#define ADCOUT_NUM_CHANNELS 5
struct wrtd_adcout_dev {
uint32_t io_addr;
/* FIXME: base channel (to create the event id). */
};
static inline void adcout_writel(const struct wrtd_adcout_dev *dev,
uint32_t value, uint32_t reg)
{
dp_writel(value, dev->io_addr + reg);
}
static inline uint32_t adcout_readl(const struct wrtd_adcout_dev *dev, uint32_t reg)
{
return dp_readl(dev->io_addr + reg);
}
static int adcout_init(struct wrtd_adcout_dev *adcout)
{
pr_debug("%s: ADCout initialization complete\n\r", __func__);
/* Disable all channels. */
adcout_writel(adcout, 0, ALT_TRIGOUT_CTRL);
return 0;
}
static inline int adcout_wr_link_up(struct wrtd_adcout_dev *adcout)
{
return adcout_readl(adcout, ALT_TRIGOUT_STATUS) & ALT_TRIGOUT_WR_LINK;
}
static inline int adcout_wr_time_locked(struct wrtd_adcout_dev *adcout)
{
return 1;
}
static inline int adcout_wr_time_ready(struct wrtd_adcout_dev *adcout)
{
return adcout_readl(adcout, ALT_TRIGOUT_STATUS) & ALT_TRIGOUT_WR_VALID;
}
static inline int adcout_wr_sync_timeout(void)
{
return 0;
}
/**
* Handles input timestamps from all TDC channels.
*
* TODO: tdc config: base address
* first channel number (for sid)
* time offset
*/
static void adcout_input(struct wrtd_adcout_dev *adcout)
{
uint32_t status = adcout_readl(adcout, ALT_TRIGOUT_STATUS);
uint32_t mask;
struct wrtd_event ev;
int i;
/* Poll the FIFO and read the timestamp */
if(!(status & ALT_TRIGOUT_TS_PRESENT))
return;
/* FIXME: MSB word ? */
ev.ts.seconds = adcout_readl(adcout, ALT_TRIGOUT_TS_MASK_SEC + 0);
mask = adcout_readl(adcout, ALT_TRIGOUT_TS_MASK_SEC + 4);
ev.ts.ns = adcout_readl(adcout, ALT_TRIGOUT_TS_CYCLES) * 8;
ev.ts.frac = 0;
for (i = 0; i < ADCOUT_NUM_CHANNELS; i++) {
if (!(mask & ((ALT_TRIGOUT_CH1_MASK >> 32) << i)))
continue;
memset(ev.id, 0, WRTD_ID_LEN);
ev.id[0] = 'A';
ev.id[1] = 'D';
ev.id[2] = 'C';
ev.id[3] = 'O';
ev.id[4] = '1' + i;
ev.flags = 0;
wrtd_log(WRTD_LOG_MSG_EV_GENERATED,
WRTD_LOG_GENERATED_DEVICE + i, &ev, NULL);
/* Pass to wrtd. */
wrtd_route_in(&ev);
}
}
/*
* Copyright (C) 2013-2018 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "mockturtle-rt.h"
#include <mockturtle-framework.h>
#include "wrtd-common.h"
#include "fmc_adc_alt_trigout.h"
#define NBR_CPUS 1
#define CPU_IDX 0
#define NBR_LOCAL_INPUTS 5
#define NBR_LOCAL_OUTPUTS 0
#define NBR_RULES 16
#define NBR_DEVICES 1
#define NBR_ALARMS 0
#define DEVICES_IO_ADDR { TRTL_ADDR_DP_BASE + 0x0000, 0, 0, 0}
#define APP_ID WRTD_APP_ADCIN_5CH
#define APP_VER RT_VERSION(2, 0)
#define APP_NAME "wrtd-adcin"
#define WRTD_NET_TX
#include "wrtd-rt-common.h"
#include "wrtd-adcout.c"
static struct wrtd_adcout_dev adcout0 =
{
.io_addr = 0x0,
};
static inline int wr_link_up(void)
{
return adcout_wr_link_up(&adcout0);
}
static inline int wr_time_locked(void)
{
return adcout_wr_time_locked(&adcout0);
}
static inline int wr_time_ready(void)
{
return adcout_wr_time_ready(&adcout0);
}
static inline void wr_enable_lock(int enable)
{
}
static inline int wr_sync_timeout(void)
{
return 0;
}
static void wrtd_local_output(struct wrtd_event *ev, unsigned ch)
{
/* No output. */
return;
}
#ifdef SIMULATION
static int wrtd_i_sim_init(struct wrtd_tdc_dev *tdc)
{
/* TODO: preconfigure the rules. */
int i;
for(i = 0; i < TDC_NUM_CHANNELS; i++) {
wrtd_in_channels[i].config.log_level = WRTD_LOG_ALL;
wrtd_in_channels[i].config.id.system = 0;
wrtd_in_channels[i].config.id.source_port = i;
wrtd_in_channels[i].config.id.trigger = i;
wrtd_in_channels[i].config.flags =
WRTD_ENABLED | WRTD_ARMED | WRTD_TRIGGER_ASSIGNED;
}
tdc_writel(tdc, 0x40, BASE_DP_TDC_DIRECT + DR_REG_DEAD_TIME);
tdc_writel(tdc, 0x1f, BASE_DP_TDC_DIRECT + DR_REG_CHAN_ENABLE);
return 0;
}
#endif
static int wrtd_user_init(void)
{
#ifdef SIMULATION
/* Skip WR sync and automatically generate some events when
simulating */
wrtd_i_sim_init(&tdc0);
#else
adcout_init(&adcout0);
#endif
wr_enable_lock(0);
pr_debug("rt-input firmware initialized.\n\r");
return 0;
}
static void wrtd_io(void)
{
adcout_input(&adcout0);
}
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