Commit 6cb4c9ee authored by Maciej Lipinski's avatar Maciej Lipinski

Merge branch 'dio_extension' into 'master'

Dio extension

See merge request !4
parents 31e53528 1c190a5f
......@@ -53,3 +53,5 @@ modules.order
# Project Specifi #
###################
wr-dio.mod*
sw/irq-demo/irq-demo
sw/irq-demo/*.log
\ No newline at end of file
*~
*.aux
*.cp
*.cps
*.fn
*.html
*.info
*.ky
*.log
*.pdf
*.pg
*.texi
*.toc
*.tp
/*.txt
*.vr
#
# Makefile for the documentation directory
#
# Copyright 1994,2000,2010,2011 Alessandro Rubini <rubini@linux.it>
#
#################
# There is not basenames here, all *.in are considered input
INPUT = $(wildcard *.in)
TEXI = $(INPUT:.in=.texi)
INFO = $(INPUT:.in=.info)
HTML = $(INPUT:.in=.html)
TXT = $(INPUT:.in=.txt)
PDF = $(INPUT:.in=.pdf)
ALL = $(INFO) $(HTML) $(TXT) $(PDF)
MAKEINFO ?= makeinfo
RELEASE=$(shell git describe --always --dirty)
%.texi: %.in
@rm -f $@
sed s/__RELEASE_GIT_ID__/$(RELEASE)/ $< | sed -f ./infofilter > $@
emacs -batch --no-site-file -l fixinfo $@
chmod -w $@
%.pdf: %.texi
texi2pdf --batch $<
%.info: %.texi
$(MAKEINFO) $< -o $@
%.html: %.texi
$(MAKEINFO) --html --no-split -o $@ $<
%.txt: %.texi
$(MAKEINFO) --no-headers $< > $@
##############################################
.PHONY: all images check terse clean install
.INTERMEDIATE: $(TEXI)
all: images $(ALL)
$(MAKE) terse
images::
if [ -d images ]; then $(MAKE) -C images || exit 1; fi
check: _err.ps
gs -sDEVICE=linux -r320x200x16 $<
terse:
for n in cp fn ky pg toc tp vr aux log; do rm -f *.$$n; done
rm -f *~
clean: terse
rm -f $(ALL) $(TEXI)
install:
# add the other unused targets, so the rule in ../Makefile works
modules modules_install:
;; use:
;; emacs -batch -l ./fixinfo.el <file>
;; or, better:
;; emacs -batch --no-site-file -l ./fixinfo.el <file>
(defun fixinfo (file)
(find-file-other-window file)
(message (concat "Maxing texinfo tree in " file))
(texinfo-all-menus-update)
(texinfo-every-node-update)
(save-buffer)
(kill-buffer (current-buffer))
)
;; loop over command line arguments
(mapcar 'fixinfo command-line-args-left)
(kill-emacs)
\input texinfo @c -*-texinfo-*-
% fmc-dio.in - main file for the documentation
%
%
%%%%
%------------------------------------------------------------------------------
%
% NOTE FOR THE UNAWARE USER
% =========================
%
% This file is a texinfo source. It isn't the binary file of some strange
% editor of mine. If you want ASCII, you should "make spec-sw.txt".
%
%------------------------------------------------------------------------------
%
% This is not a conventional info file...
% I use three extra features:
% - The '%' as a comment marker, if at beginning of line ("\%" -> "%")
% - leading blanks are allowed (this is something I can't live without)
% - braces are automatically escaped when they appear in example blocks
%
@comment %**start of header
@documentlanguage en
@setfilename fmc-dio.info
@settitle fmc-dio
@iftex
@afourpaper
@end iftex
@comment %**end of header
@setchapternewpage off
@set update-month July 2020
@c the release name below is substituted at build time
@set release __RELEASE_GIT_ID__
@finalout
@titlepage
@title FMC DIO Software Support
@subtitle @value{update-month} (@value{release})
@subtitle A driver for the FMC DIO module
@author Alessandro Rubini for CERN (BE-CO-HT)
@author Jorge Machado Cano for Seven Solutions
@end titlepage
@headings single
@c ##########################################################################
@iftex
@contents
@end iftex
@paragraphindent 1
@c ##########################################################################
@node Top
@top Introduction
This is the manual for the fmc-dio device driver.
@c ##########################################################################
@node History and Overview
@chapter History and Overview
This version of the driver adds support for generating a train pulses in HW and
a new virtual channel that generates interrupts and is fully configurable by the user.
The HW train pulse generator improves the precision of the pulses which are
not any more generated in software as it was the case in the previous versions.
In this implementation, the software only takes care of the number of pulses to
disable them when all the pulses have been generated.
This and previous versions of the driver provide support for immediate pulse
generation, programmed pulse generation synchronized with White Rabbit clock,
and input pulse timestamping. The driver provides an ioctl interface to configure
the hdl core.
@c ##########################################################################
@node Compiling the Drivers
@chapter Compiling the Drivers
The kernel modules that are part of this package live in the @i{sw/kernel}
subdirectory. To compile them, you need to
set the following variables in your environment:
@table @code
@item LINUX
The top directory of the kernel sources for the version you
are going to run the driver under. I'm testing mostly with 4.15,
but this version compiles against Linux-4.15-4.18 and later ones.
@item CROSS_COMPILE
If you are cross-compiling, you need to set this variable.
It is not usually needed for the PC, but if you are using
the @i{Powec} board, you'll most likely need this. It is not
needed if you compile for a different-sized PC (see below).
@item ARCH
If you are cross-compiling, set this variable. Use @code{powerpc}
for the @i{Powec}, @code{x86-64} if you compile on a 32-bit PC
to run on a 64-bit PC and @code{i386} if you compile on a 64-bit
PC to run on a 32-bit PC.
@end table
To compile run ``@code{make}'' with the previous variables set. To
install run ``@code{make install} to install under
@code{/lib/modules/4.15} (or other version-based directory). You can
set @code{INSTALL_MOD_PATH} to force and installation directory
(as a prefix followed by @code{/lib/modules/...}).
For example, if your target computer's filesystem is mounted under
@code{/mnt/target} you can run
@example
make install INSTALL_MOD_PATH=/mnt/target
@end example
The modules are installed under the subdirectory @code{extra}. In
the case shown above your driver will end up being installed
(together with the other modules) as
@example
/mnt/target/lib/modules/4.15.0/extra/fmc-dio.ko
@end example
Please note that by default the package compiles and installs the
@i{fmc-bus} modules, too (the project is a @i{git} submodule).
@c ##########################################################################
@node Role of fmc-dio.ko
@chapter Role of fmc-dio.ko
The FMC-DIO driver consists of a set of functions accesible through an IOCTL
call to write on the registers of each channel of the FMC-DIO board to generate
totally configurable pulses. It also recovers timestamps of external and generated
pulses.
@c ==========================================================================
@node Initialization of fmc-dio
@section Initialization of fmc-dio
There is no need to explicitly initialize the FMC-DIO driver.
@c ==========================================================================
@node Interrupts in fmc-dio.ko
@section Interrupts in fmc-dio.ko
There are two types of interrupts:
@table @file
@item I/O channel interrupt
This interrupt is generated when one channel generates an
output pulse or detects an input pulse. The timestamp of the
pulse is stored into the timestamp FIFO queue of the channel.
@item Dedicated interrupt channel
This interrupt is generated only when the interrupt channel
is triggered. The timestamp of the interrupt is stored into
the interrupt timestamp FIFO.
@end table
Both interrupt types comes from an unique HW interrupt. The software interrupt
handler manages both types.
@c ==========================================================================
@node Code Layout
@section Code Layout
This section is mainly for the developers who look in the code, and for
me to make order in my own mind. FMC-DIO users are expected to skip to
the next section.
The @code{fmc-dio.ko} is built using a number of headers and source files,
spread over several directories:
@table @file
@item sw/fmc-bus/
FMC-BUS kernel driver support (see specific doc inside)
@item sw/kernel/
This directory contains the low level functions to configure each
physical channel and the interrupt management.
@item sw/tools/
This directory hosts the userspace tools that uses the low level
functions.
@end table
The @i{fmc-dio} driver refers to several headers, in addition to the
register definitions. This is the role of each of them:
@table @file
@item sw/kernel/fmc-dio.c
@item sw/kernel/fmc-dio.h
Code and headers of the driver initialization. It also detects
the version of the FPGA binary to able coherent memory accesses
through all the code.
@item sw/kernel/fmc-dio-gpio.c
DIO GPIO support skeleton to be developed using gpiolib Linux feature.
@item sw/kernel/fmc-dio-internal.c
Code that implements the low-level functions to handle FMC DIO devices
through the IOCTL and interrupt handler.
@item sw/kernel/fmc-dio-mdev.c
This code created the device and connects the IOCTL.
@item sw/kernel/hw/ppsg-regs.h
@item sw/kernel/hw/wr-dio-regs.c
@item sw/kernel/hw/wr-dio-regs.h
@item sw/kernel/hw/wr-dio-regs_v1.c
@item sw/kernel/hw/wr-dio-regs_v1.h
@item sw/kernel/hw/wr-dio-regs_v2.c
@item sw/kernel/hw/wr-dio-regs_v2.h
Code and headers with the registers map of the fmc-dio. It also
implements some functions to get the offset of each register.
@end table
The @i{sw/tools} directory contains all the userspace tools the manage the
@i{fmc-dio} driver. This is the role of each of them:
@table @file
@item sw/tools/net_tstamp.h
@item sw/tools/stamp-frame.c
Code and headers of timestampig related functions.
@item sw/tools/wr-dio-agent.c
Code that implements a very basic server to receive contol packets from
ruler. Once received them, it executes some operation to the FMC DIO device
(mode change, pulse generation, etc).
@item sw/tools/wr-dio-cmd.c
Code that implements the userpace commands to manage the fmc-dio
channels.
@item sw/tools/wr-dio-pps.c
Example of a PPS generation.
@item sw/tools/wr-dio-ruler.c
Code that implements a basic client to send DIO command to the agent.
It also is able to run local FMC DIO commands.
@end table
@c ==========================================================================
@node Overview of the Driver
@section Overview of the Driver
This fmc-dio driver provides support for both versions of the fmc-dio hdl core,
i.e. the current version with extended functionality and a previous version.
The fmc-dio hdl core provides immediate pulse generation, immediate pulse
train generator, programmed pulse/pulse train generation synchronized with
White Rabbit clock, programmed/immediate interrupt generation and input
pulse timestamping.
@c ==========================================================================
@node Accessing the DIO Channels
@section Accessing the DIO Channels
In order to access the DIO channels, user-space programs are expected
to issue device-specific @i{ioctl} commands. The driver supports two
commands, allocated at the end of the range of command numbers reserved
for device-specific use:
@table @code
@item PRIV_MEZZANINE_ID
The command is used to identify the features of the
specific NIC device. It tells user space which mezzanine is
currently plugged and also which type of carrier you are talking to.
The command exchanges a data structure with user space in order
to be able to extend its functionality over time, and such data
structure includes a sub-command
field. (For example, we may return EEPROM contents to user space
on request).
@b{Warning}: The command is not implemented because we still have
no mezzanine identification in place. The error being returned
is @code{EAGAIN}; user code can rely on that error to know it
is actually talking with a SPEC device, even if no identification
is currently possible.
@item PRIV_MEZZANINE_CMD
The command is based on the exchange of a data structure: by
means of sub-commands included in such structure user space
programs can request different services to the mezzanine driver.
In the case of the DIO mezzanine this includes generating pulses
and timestamping input events; other mezzanine drivers will
be able to use the command in a different way. The application
is expected to first run @code{PRIV_MEZZANINE_ID} to ensure the
NIC device is connected to the right mezzanine.
@end table
The data structure is defined and explained in @code{wr-dio.h} and
is not repeated here.
The structure includes a few integer fields and an array of
@code{struct timespec}. Such structures define time stamps with
nanosecond precision, but the @i{simple-DIO} mezzanine and its gateware
are able to time-stamp input events and generate output events with a
resolution of 8ns.
When the device is asked to timestamp input events, the array of
@code{struct timespec} is used
to return such events to user space. When the device is asked to
generate output pulses at specific points in time, the array is used
to pass three values: the beginning of the pulse, the duration of the
pulse and (optionally) the period of the pulse train.
Specifics about the use of individual fields are shown in the header
(in a big comment block), in the driver itself and in the user-space
programs that call @i{ioctl}.
In lab environments you may be concerned about the duration of the
@i{ioctl} implementation, because it sometimes seems to do more work
than needed. To verify whether we have an over-engineering problem in
kernel space, I provided a simple measurement of how much time is
spent in the @i{Ioctl} itself. The @i{make} variable
@code{WR_DIO_FLAGS} can be used to pass extra flags to the compiler,
and the macro @code{DIO_STAT} enables the time measurement.
Compiling with the following command thus enable such measurement
and associated @i{printk}
@example
make WR_DIO_FLAGS=-DDIO_STAT
@end example
Previous versions of this manual described how to command pulses on
several channels with a single @i{ioctl} command, but that feature has
never been implemented (one of the reasons is that @i{ioctl} revealed
fast, so calling it several times is acceptable).
@c ==========================================================================
@node FMC-DIO Command Tool
@section FMC-DIO Command Tool
In the @file{sw/tools/} subdirectory of this project, you find the
@file{wr-dio-cmd} program, which is a command-line interface to the
@i{ioctl} command that acts on the @i{simple-DIO} mezzanine card. Other
@code{wr-dio-} tools are provided (and described below) but this is
the most generic one.
@b{Please note that neither timestamping nor pulse generation work
if the WR core is not running or has an invalid time: it must either be
a master or a synchronized slave.}
Moreover, please note that this tool is just a demonstration to quickly
test the I/O features of the device (and for me to verify the kernel
part is actually working): for serious use you should call
@i{ioctl} by yourself with proper arguments, and avoid all the parsing
of ASCII and repeated invocation of this program.
This is the general syntax of the command:
@example
wr-dio-cmd <devname> <cmd> [<arg> ...]
@end example
The arguments have the following meaning
@table @code
@item devname
The name of the device, most likely @code{/dev/fmc-dio-1:0}
(if you have more than one SPEC card, the other interfaces are
called @code{/dev/fmc-dio-1:1}, @code{/dev/fmc-dio-1:2} and so on).
@item cmd
The specific command. Supported commands are listed below.
Each command takes zero or more of arguments. If you pass
a wrong number of arguments you'll get help, and
if one argument is wrong (e.g., not a number) the
error message is meant to be directly helpful.
@end table
@b{Note}: This command, like everything else in this package, numbers
channels from 0 through 5, whereas the back panel of the mezzanine
numbers them 1 through 5. The last channel does not represent a physical channel,
it is a virtual channel to generate interrupts.
The current version of the tool supports the following commands:
@table @code
@item stamp [<channel>] [wait]
@itemx stampm [<channel-mask>]
The commands are used to retrieve timestamps from the card.
If no arguments are passed, the tool reports to @i{stdout} all
timestamps for all channels (they are ordered by channel, not
by time). If one integer argument is passed, it can be a channel
number in the range 0 to 5 (@code{stamp} command) or a mask
in the range 0 to 0x3f (@code{stampm} command). If getting stamps
for an individual channel, you can add the @code{wait} option
to have the tool wait for (and report) new timestamps until killed.
@b{Warning}: use of @code{wait} is dangerous because it has
been implemented against the rules. You must
terminate any waiting process before you unload the driver, or
your PC will explode and will destroy your academic career.
@item pulse <channel> <duration> <when> [<period> <count>]
Channel is an integer in the range 0 to 4. The duration must
be specified as a fraction of a second (decimal number, less than
one second), the @code{when} argument can be the string @code{now},
an absolute time (@code{<seconds>.<fraction>}) or a relative
time (@code{+<seconds>.<fraction>}). In the last case, the
current second is added to @code{<seconds>} while the fraction
is used unchanged. The @code{+} form is useful for simple checks with
visual inspection. The @code{period} parameter, if specified, requests for
a pulse train, with the specified time period between raising edges;
the @code{count} parameter is the number of times to run pulse generation (-1 means forever,
0 means ``stop ongoing pulse generation'').
@item irq <when> [<period> <count>]
This command only generates interrupts and does not generate any
physical pulse. The @code{when} argument can be the string @code{now},
an absolute time (@code{<seconds>.<fraction>}) or a relative time
(@code{+<seconds>.<fraction>}). In the last case, the current second
is added to @code{<seconds>} while the fraction is used unchanged.
The @code{+} form is useful for simple checks with visual inspection.
The @code{period} parameter, if specified, requests for a interrupt train,
with the specified time period between interrupts. It must be specified in
a range between 1ms and 2s; the @code{count} parameter is the number
of times to run interrupt generation (-1 means forever, 0 means ``stop ongoing interrupt generation'').
@item mode <channel> <mode> [<channel> <mode> ...]
@itemx mode <m0><m1><m2><m3><m4>
Configure one or more channels for the specified mode. Each mode
is represented by one character; the latter form above thus
configures all 5 channels by means of a 5-bytes-long string,
each characters specifies a mode according to the next table.
The irq channel can not be configured with this command, it is
should be configured with the @code{irq} command.
This is the list of supported modes for channels:
@table @code
@item I i
Input mode, with termination or without termination. Uppercase
forces the termination on (the rationale is you need a stronger
signal to drive the input). Termination is 50 Ohm. Pulses on
an input channel are timestamped.
@item 0 1
Digital output mode, from the GPIO logic core, resp. low and high.
Both modes disable the termination resistor.
@item D d
DIO core output (not the GPIO core). With this mode the channel
is driven by the WR-aware digital I/O, and can thus generate pulses
and so on. Uppercase enables the termination.
A channel managed by the DIO core is normally low and can
pulse high on request (see @code{pulse})
command. The termination resistor doesn't make much sense for
output, but the code is provided for consistency with input modes.
@item P p (Channel 0)
Pulse per second output from the White Rabbit core that can be used
only for the first channel (ch0). This @i{PPS} is sharper in its absolute
time than the one that can be
generated by software using DIO pulses. Again, upper case
selects the termination, for symmetry with input modes.
@item C c (Channel 4)
``Clock'' input. This mode (with or without termination) is
used to feed a clock to the White Rabbit core (currently the
WR core supports a 10MHz input on channel 4 (the last one)).
For other channel, the mode is just like @t{I} or @t{i} but
without timestamping (and thus without a software interrupt).
@end table
@item update_width <channel> <new_width>
This command updates the width of the last pulse train programmed.
The duration must be specified as a fraction of a second (decimal number,
less than one second). The command reads the previous period and checks if
the new width is compatible.
@item mask_irq <channel> <Y/y>
This command disables interrupt coming from the selected channel if the second
argument is 'y' and enables it if the argument is 'Y'. In normal operation
(if not disabled), an interrupt is generated on a channel (0-4) when a pulse
is received or transmitted on this channel. For example, if channel 0 is
configured to generate 1 Pulse Per Second, an interrupt is generated every
time 1 PPS is generated on this channel. This command allows to disable
such generation of interrupts.
@end table
@b{Note}: The first channel (channel 0) has been modified and now support only the
@t{P}/@t{p} as output mode. You will not be able to use @t{D},@t{d},@t{1},@t{0} modes.
@b{Note}: At startup, the DIO channels are configured by default as:
@code{wr-dio-cmd mode p00ic}.
The new hardware pulse generation feature allows to configure a pulse train with a higher
frequency than the previous version. However, there is still a software limitation due to the
interrupts handling. If the interrupt of the channel is disabled, the pulse train generation can
be as fast as the reference clock period allows, but there will be no timestamps in the FIFO and
the pulse train will be indefinite because the pulse counting mechanism remains excecuted in the
sofware interrupt handler. This frequency should be controlled in a proper way just to avoid PC
freezing. Because of this, the maximum frequency depends on your current machine configuration
and can be easily characterized with the existing tools for fmc-dio project.
There is no command to flush the timestamp FIFOs, but you can
always ``@code{wr-dio-cmd stamp > /dev/null}'' if needed.
Example uses of the tool follow:
@example
# Pulse channel 4 for 0.1 seconds now
sudo wr-dio-cmd /dev/fmc-dio-1:0 pulse 4 .1 now
# Pulse for 10 microseconds in the middle of the next second
sudo wr-dio-cmd /dev/fmc-dio-1:0 pulse 4 .00001 +1.5
# Pulse for 1ms at 17:00 today
sudo wr-dio-cmd /dev/fmc-dio-1:0 pulse 4 .001 $(date +%s --date 17:00)
# Get timestamps for the output events above
sudo wr-dio-cmd /dev/fmc-dio-1:0 stamp 4
# Make a train of 5 pulses, 0.5ms wide, every ms at next second
sudo wr-dio-cmd /dev/fmc-dio-1:0 pulse 4 0.0005 +1 .001 5
# Configure channel 0 as input with termination, 1 as input, 4 as low
sudo wr-dio-cmd /dev/fmc-dio-1:0 mode Ii--0
# Generate interrupt now
sudo wr-dio-cmd /dev/fmc-dio-1:0 irq now
# Generate a train of 100 interrupts every 10 ms starting at the next second
sudo wr-dio-cmd /dev/fmc-dio-1:0 irq +1 .01 100
# Make a train of indefinite pulses, 1ms wide every 5ms
sudo wr-dio-cmd /dev/fmc-dio-1:0 pulse 1 0.001 now 0.005 -1
# Stop the previous pulse train
sudo wr-dio-cmd /dev/fmc-dio-1:0 pulse 1 0.001 now 0.005 0
# Update pulse width in channel 1 to 10ms
sudo wr-dio-cmd /dev/fmc-dio-1:0 update_width 1 0.01
# Disable interrupts in channel 0
sudo wr-dio-cmd /dev/fmc-dio-1:0 mask_irq 0 y
# Enable interrupts in channel 2
sudo wr-dio-cmd /dev/fmc-dio-1:0 mask_irq 2 Y
@end example
@c ==========================================================================
@node Timestamping Fast Input Signals
@section Timestamping Fast Input Signals
When timestamping pulses in the @i{simple-DIO} mezzanine board, an
interrupt is generated to notify the driver that a new timestamp is
pending. On recent computers this works reliably up to more than
100kHz, but clearly there is a point where the system locks up,
because it spends all of its time in interrupt handling.
This problem is transient: as soon as you remove the offending cable
the system recovers. However, you need a 10MHz input signal if you
want to run your SPEC device to be a White Rabbit @i{grandmaster}. In
order to support that, the driver automatically disables DIO interrupts when the
time spent in interrupt management exceeds 80% of the total time,
averaged over one thousand interrupt events. Ethernet interrupts
are not affected. The fact is reported by a kernel message, using
the PCI address of the card that triggered the problem.
@example
spec 0000:04:00.0: DIO irq takes > 80% CPU time: disabling
@end example
This choice allows stamping your pulse trains up to a few dozen
kilohertz and still be able to feed higher frequencies without manual
intervention. However, after DIO interrupts are disabled, the only
way to re-enable them is removing and reloading the device driver.
On the other hand, you can manually disable interrupts on a channel where
you expect high frequency input signals by using the mask_irq command, see
previous section.
@b{Note}: If you run two SPEC cards, and one is fed with high frequency
pulses without disabling the interrupts manually, it may happen that interrupts
are automatically disabled on both boards. The safeguard is currently not
very refined, as it was implemented in a hurry.
@c ==========================================================================
@node WR-DIO Pulse per Second
@section WR-DIO Pulse per Second
To better show how to write your own application with the SPEC driver
and the @i{simple-DIO} mezzanine card, this package includes
@file{wr-dio-pps}, which features a very small and readable source
file.
The program is meant as a source code example, more than a real PPS
signal. If you need a real WR-driven pulse-per-second, you should
use the channel0 which is "hard-wired" to the PTP core and can be configured by
executing: ``@t{wr-dio-cmd mode 0 p}''.
The program just fires a 1ms-long @i{PPS} pulse on one of the output
channels. The device name defaults to @i{wri0} but can specify a different one;
the channel number is a mandatory argument.
@b{Note}: This command, like everything else in this package, numbers
channels from 0 through 4, whereas the back panel of the mezzanine
numbers them 1 through 5. My devices have no panel, so I just made
the wrong guess.
@example
# run pps on channel 2 of the default SPEC card
./wr-dio-pps 2
# run pps on channel 0 of the "second" card
./wr-dio-pps wri1 0
@end example
The following two figures show two such @i{pulse-per-second} signals
retrieved from two different @i{simple-DIO} cards, connected by a 10km
roll of fiber, after syncing with @i{White Rabbit}. In some cases, it
may happen that the leading edges differ by almost exactly 8ns; this
happens because in the @i{simple-DIO} all times are quantized by
8ns-long clock ticks. The differences in internal delays (which depend
on the carrier, the mezzanine and the FPGA binary), are not
self-measured and calibrated in this simple design and may appear in
the output after quantization. A more complete experimental setup
would include calibration of the internal delays of the boards, like
the mechanism in place for the @i{fine-delay} mezzanine card (see
@url{http://www.ohwr.org/projects/fmc-delay-1ns-8cha} and
@url{http://www.ohwr.org/projects/fine-delay-sw}).
@sp 1
@center @image{two-pps-whole, 10cm}
@sp 1
@center @image{two-pps-detail, 10cm}
@sp 1
@c ==========================================================================
@node Distributing Output Pulses
@section Distributing Output Pulses
A typical application for @i{White Rabbit} (or any time
synchronization system) is being able to generate output signals at the
same time in different output boards; another typical application is
time stamping input events.
By using the Ethernet interface included in the SPEC,
an application can exchange data with other @i{White
Rabbit} devices; thus, it can easily request output event to
other output peripherals, or collect remote input events.
The tool-set offered by the driver
is made up of the the @code{PRIV_MEZZANINE_CMD} @i{ioctl} command,
amd the usual Posix API for network communication.
The @i{DIO-specific} @i{ioctl} command is the one used by the
@code{wr-dio-cmd} tool described above, while network communication
should be known to most users of this package. In order to ease new
@i{White Rabbit} users, though, this package includes sample code to
implement a simple dual-headed system with concurrent output. The
examples are also meant to show the basic code that uses the provided
@i{ioctl} command, without all the boring parameter parsing that is
required in more generic tools like @code{wr-dio-cmd}. Because of this
simplification of parameter passing, the pulse width is hardwired to 1ms.
The example is made up of two programs: @code{wr-dio-agent} and
@code{wr-dio-ruler} (the former is a dumb actor, while the latter
states the rules). To keep things simple the two programs
assume that the SPEC is connected point-to-point to another SPEC
and both carry the @i{simple-DIO} mezzanine. @b{The wr-nic driver should
be installed to run this example @url{https://ohwr.org/project/wr-nic}}
Under this simplified assumptions, the @i{ruler} transmits raw Ethernet
frames to the broadcast address, while the @i{agent} receives almost
everything that appears on the cable. This choice allows plugging two SPEC
cards in the same computer and run the example; if the example
used an IP-based protocol (like UDP) it couldn't be used
with two cards on a single PC -- and a fiber through them.
The simplification above, however, most likely
prevents the programs from working within a more complex
network topology. I expect real @i{White Rabbit} users to add proper
network addressing in their applications.
If you have a single SPEC card, you can still use the @i{ruler} by
itself to mirror an input channel to an output channel of the same
card, with a specified delay.
@sp 1
The @i{agent} program silently listens to the network interface and
receives a data structure ready to be passed to @i{ioctl}. Its only
command line argument is the name of the @i{White Rabbit} interface to
use (for most users it is @code{wr0}):
@example
wr-dio-agent [-V] <wr-if> <dio-dev>
@end example
The @i{ruler} command, on the other hand, waits for timestamps
to appear on the specified input channel;
when notified about a positive-going edge, ot
replicates the edge on one or more outputs. Each output can be
local or remote, and can use a different delay from the input pulse.
If you lack an input signal, you can make an output pulse with
@code{wr-dio-pps} or other means and use it as a trigger. Please note
that the @i{ruler} does not configure the channel mode, so you might
want to use the @code{mode} command of @code{wr-dio-cmd} in advance.
The following command waits for events on channel 0 of the card connected
to @i{wr1}, and replicates the event with a delay of 1ms on channel 3 of
both the local and the remote card; it also replicates with a 2ms
delay to local channel 4. Please note that the delays should be no
more than the interval between input pulses, because the tools
reprograms all output triggers at each input event.
@b{Note}: As usual, channels are numbered 0 through 4.
@example
wr-dio-ruler wr1 /dev/fmc-dio-1:0 IN0 L3+0.001 R3+0.001 L4+0.002
@end example
There is no sample code that generates trains of pulses as a response
to events, nor support for other than 1ms-long output pulses; anyways,
the code is
thoroughly commented in order to serve as a starting point for
more complex lab environments.
As a final remark, please note that all pulse generation is driven by
host hardware, after an hardware interrupt reports the input event,
but the software controls the number of number of pulses that has been
generated.
For this reason, you'll not be able to reliably replicate pulses with
delays smaller than a few hundred microseconds, depending on the
processing power of your computer and the load introduced by other
processes. For remote connections, you must also count the overhead
of network communication as well as transmission delays over
the fiber (a 10km fiber introduces a
delay of 50 microseconds).
The following example shows use of the @i{ruler} and @i{agent} on
two hosts, called @code{spusa} and @code{tornado}. The input events
on @code{spusa} are replicated to one local channel and two remote channels,
with a delay of 1ms. The input events in this case are from a @i{pulse-per-second} signal:
@smallexample
tornado.root# /tmp/wr-dio-agent wr0 /dev/fmc-dio-1:0 &
spusa.root# sudo wr-dio-ruler wr1 /dev/fmc-dio-1:0 IN4 L3+.001 R4+.001 R2+.001
wr-dio-ruler: configured for local channel 3, delay 0.001000000
wr-dio-ruler: configured for remote channel 4, delay 0.001000000
wr-dio-ruler: configured for remote channel 2, delay 0.001000000
[... wait a few seconds ...]
spusa.root# sudo wr-dio-cmd /dev/fmc-dio-1:0 stamp 3
ch 3, 385.001000000
ch 3, 386.001000000
ch 3, 387.001000000
ch 3, 388.001000000
tornado.root# sudo wr-dio-cmd /dev/fmc-dio-1:0 stamp 2
ch 2, 385.001000000
ch 2, 386.001000000
ch 2, 387.001000000
ch 2, 388.001000000
tornado.root# sudo wr-dio-cmd /dev/fmc-dio-1:0 stamp 4
ch 4, 385.001000000
ch 4, 386.001000000
ch 4, 387.001000000
ch 4, 388.001000000
@end smallexample
@c ##########################################################################
@node Interrupt Demo
@chapter Interrupt Demo
The interrupt demo software can be found in the @code{sw/irq-demo} directory.
This demo sofware disables the interrupts of all channel except the new one, only
dedicated to interrupts.
By default, it setups the interrupt with 100 milliseconds between them.
The tool provides the total number of interrupts, the interrupts per second and
some statistic information calculated with the difference between OS time and
WR time.
This is the general syntax of the command:
@table @code
@item irq-demo -f <dio-device> [-p <period in ns> -c <MONOTONIC/REALTIME>]
@end table
Example uses of the tool follow:
@example
# Generate one interrupt each 100 ms
sudo irq-demo -f /dev/fmc-dio-1:0
# Generate one interrupt each 10 ms
sudo irq-demo -f /dev/fmc-dio-1:0 -p 10000000
@end example
@c ##########################################################################
@node Bugs and Missing Features
@chapter Bugs and Missing Features
@itemize @bullet
@item Identification of the mezzanine is completely missing; every @i{fmc}
driver at this point takes hold of every device. We are working on this,
and the next version of fmc-dio will support identification, with a flag
to run without identification for users whose EEPROM has not been programmed.
@item The NIC driver should directly support setting the White Rabbit
mode for each card (grandmaster, free-running master or slave). This
will be supported at module load time, not at runtime (for that please
use the UART).
@item DIO support is missing some of the features listed
in @file{wr-dio.h} (i.e. DAC control)>
@item Locking in kernel code should be verified with a serious audit
effort. There are no known issues at this point, but some code may
be made safer.
@end itemize
@c ##########################################################################
@node Portability
@chapter Portability
This package should be portable. However I didn't test it on a wide
variety of systems. Currently most of my use is
on a 64-bit x86 host, running version between 4.15-4.18 of the kernel.
@c ##########################################################################
@bye
@c LocalWords: gnudd titlepage iftex texinfo CERN documentlanguage settitle
@c LocalWords: documentencoding setfilename afourpaper paragraphindent EEPROM
@c LocalWords: setchapternewpage finalout eeprom gateware devmem devfn busid
@c LocalWords: speclib Gennum timestamps stampm ifname timespec timestamp
@c LocalWords: timestamping linux FPGA ohwr http
#! /usr/bin/sed -f
# allow "%" as a comment char, but only at the beginning of the line
s/^%/@c /
#s/[^\\]%.*$//
s/^\\%/%/
#preserve blanks and braces in @example blocks
/^@example/,/^@end example/ s/{/@{/g
/^@example/,/^@end example/ s/}/@}/g
/^@example/,/^@end example/ p
/^@example/,/^@end example/ d
/^@smallexample/,/^@end smallexample/ s/{/@{/g
/^@smallexample/,/^@end smallexample/ s/}/@}/g
/^@smallexample/,/^@end smallexample/ p
/^@smallexample/,/^@end smallexample/ d
# remove leading blanks
s/^[ ]*//
......@@ -3,6 +3,7 @@ files = ["wr_dio_wb.vhd",
"wr_dio.vhd",
"wr_dio_pkg.vhd",
"pulse_gen_pl.vhd",
"immed_pulse_counter.vhd",
"dummy_time.vhd" ]
"immed_pulse_counter.vhd",
"dummy_time.vhd",
"imm_pulse_train_gen.vhd" ]
-------------------------------------------------------------------------------
-- Title : Immediate pulse train generator
-- Project : White Rabbit Network Interface
-------------------------------------------------------------------------------
-- File : imm_pulse_train_gen.vhd
-- Author : Jorge Machado
-- Company : Seven Solutions
-- Created : 2020-03-19
-- Last update:
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity imm_pulse_train_gen is
generic(
pulse_period_width : integer := 28
);
port(
clk_ref_i : in std_logic;
rst_n_i : in std_logic;
dio_pulse_immed_stb_i : in std_logic;
pulse_period_i : in std_logic_vector(pulse_period_width-1 downto 0);
pulse_output_o : out std_logic
);
end imm_pulse_train_gen;
architecture Behavioral of imm_pulse_train_gen is
signal nozeroperiod, nozeroperiod_aux : boolean;
signal pulse_period : std_logic_vector(pulse_period_width-1 downto 0);
signal dio_pulse_immed_stb_d0, dio_pulse_immed_stb_d1,
dio_pulse_immed_stb_d2, dio_pulse_immed_stb_d3 : std_logic;
-- Internal registers to hold pulse duration
signal counter : unsigned (pulse_period_width-1 downto 0);
-- Signals for states
type counter_state is (WAIT_ST, COUNTING, CAPTURE_PERIOD, TRIGGER);
signal state : counter_state;
signal repeat_pulse : std_logic;
-- Aux
constant zeros : std_logic_vector(pulse_period_width-1 downto 0) := (others => '0');
constant initial_pulse_delay_compensation : integer := 7;
constant repeat_pulse_delay_compensation : integer := 4;
begin
synchronization : process(clk_ref_i, rst_n_i)
begin
if (rst_n_i = '0') then
dio_pulse_immed_stb_d0 <= '0';
dio_pulse_immed_stb_d1 <= '0';
dio_pulse_immed_stb_d2 <= '0';
dio_pulse_immed_stb_d3 <= '0';
elsif rising_edge(clk_ref_i) then
dio_pulse_immed_stb_d0 <= dio_pulse_immed_stb_i;
dio_pulse_immed_stb_d1 <= dio_pulse_immed_stb_d0;
dio_pulse_immed_stb_d2 <= dio_pulse_immed_stb_d1;
dio_pulse_immed_stb_d3 <= dio_pulse_immed_stb_d2;
--pulse_period <= pulse_period_i;
nozeroperiod_aux <= pulse_period_i /= zeros;
if ((dio_pulse_immed_stb_d2 = '1' and dio_pulse_immed_stb_d1 = '0') or (state = CAPTURE_PERIOD)) then
nozeroperiod <= nozeroperiod_aux;
pulse_period <= pulse_period_i;
end if;
end if;
end process;
state_process : process(clk_ref_i, rst_n_i)
begin
if (rst_n_i = '0') then
counter <= (others => '0');
state <= WAIT_ST;
repeat_pulse <= '0';
elsif rising_edge(clk_ref_i) then
case state is
when WAIT_ST =>
if dio_pulse_immed_stb_d3 = '1' and nozeroperiod then
state <= COUNTING;
--Store the period two cycle before than the immed_pulse_counter_process to not lost one cycle.
counter <= unsigned(pulse_period)-initial_pulse_delay_compensation;
elsif repeat_pulse = '1' and nozeroperiod then
state <= COUNTING;
--Store the period four cycles before
counter <= unsigned(pulse_period)-repeat_pulse_delay_compensation;
else
state <= WAIT_ST;
end if;
when COUNTING =>
if counter = 0 then
state <= CAPTURE_PERIOD;
elsif dio_pulse_immed_stb_d2 = '1' then
state <= WAIT_ST;
else
state <= COUNTING;
counter <= counter-1;
end if;
when CAPTURE_PERIOD =>
state <= TRIGGER;
when TRIGGER =>
state <= WAIT_ST;
if(nozeroperiod) then
repeat_pulse <= '1';
else
repeat_pulse <= '0';
end if;
when others =>
state <= WAIT_ST;
end case;
end if;
end process;
output_process : process(rst_n_i, state)
begin
if (rst_n_i = '0') then
pulse_output_o <= '0';
else
case state is
when WAIT_ST =>
pulse_output_o <= '0';
when COUNTING =>
pulse_output_o <= '0';
when TRIGGER =>
pulse_output_o <= '1';
when others =>
pulse_output_o <= '0';
end case;
end if;
end process;
end Behavioral;
......@@ -66,6 +66,8 @@ architecture rtl of immed_pulse_counter is
-- Aux
constant zeros : std_logic_vector(pulse_length_width-1 downto 0) := (others => '0');
signal pulse_length : std_logic_vector(pulse_length_width-1 downto 0);
begin -- architecture rtl
synchronization : process(clk_i, rst_n_i)
......@@ -81,8 +83,10 @@ begin -- architecture rtl
pulse_start_d2 <= pulse_start_d1;
pulse_start_d3 <= pulse_start_d2;
nozerolength_aux <= pulse_length_i /= zeros;
--pulse_length <= pulse_length_i;
if (pulse_start_d2 = '1' and pulse_start_d1 = '0') then
nozerolength <= nozerolength_aux;
nozerolength <= nozerolength_aux;
pulse_length <= pulse_length_i;
end if;
end if;
end process;
......@@ -97,7 +101,7 @@ begin -- architecture rtl
when WAIT_ST =>
if pulse_start_d3 = '1' and nozerolength then
state <= COUNTING;
counter <= unsigned(pulse_length_i)-1;
counter <= unsigned(pulse_length)-1;
else
state <= WAIT_ST;
end if;
......@@ -114,7 +118,7 @@ begin -- architecture rtl
end if;
end process;
output_process : process(counter, state)
output_process : process(rst_n_i, state)
begin
if (rst_n_i = '0') then
pulse_output_o <= '0';
......
......@@ -76,8 +76,9 @@ entity pulse_gen_pl is
trig_utc_i : in std_logic_vector(39 downto 0);
trig_cycles_i : in std_logic_vector(27 downto 0);
trig_valid_p1_i : in std_logic;
pulse_length_i : in std_logic_vector(27 downto 0)
);
pulse_length_i : in std_logic_vector(27 downto 0);
pulse_period_i : in std_logic_vector(27 downto 0)
);
end pulse_gen_pl;
......@@ -87,7 +88,7 @@ architecture rtl of pulse_gen_pl is
signal trig_utc, trig_utc_ref : std_logic_vector(39 downto 0);
signal trig_cycles, trig_cycles_ref : std_logic_vector(27 downto 0);
signal pulse_length, pulse_length_ref : std_logic_vector(27 downto 0);
signal pulse_period, pulse_period_ref : std_logic_vector(27 downto 0);
-- Signals for the synchronizer
signal trig_valid_sys_d1, trig_valid_sys_d2 : std_logic;
signal rst_from_sync, rst_from_sync_d1 : std_logic;
......@@ -97,8 +98,11 @@ architecture rtl of pulse_gen_pl is
-- Aux
constant zeros : std_logic_vector(27 downto 0) := (others => '0');
signal counter : unsigned (27 downto 0);
signal nozerolength : boolean;
signal counter, train_counter : unsigned (27 downto 0);
signal nozerolength, nozeroperiod : boolean;
signal pulse_o_internal : std_logic;
signal pulse_train_trigger : std_logic;
signal load_values : std_logic;
begin -- architecture rtl
......@@ -110,10 +114,12 @@ begin -- architecture rtl
trig_utc <= (others => '0');
trig_cycles <= (others => '0');
pulse_length <= (others => '0');
pulse_period <= (others => '0');
elsif trig_valid_p1_i = '1' then
trig_utc <= trig_utc_i;
trig_cycles <= trig_cycles_i;
pulse_length <= pulse_length_i;
pulse_period <= pulse_period_i;
end if;
end if;
end process trig_regs;
......@@ -166,11 +172,13 @@ begin -- architecture rtl
trig_regs_ref : process (clk_ref_i)
begin
if clk_ref_i'event and clk_ref_i = '1' then
if trig_valid_ref_p1 = '1' then
if trig_valid_ref_p1 = '1' or load_values = '1' then
trig_utc_ref <= trig_utc;
trig_cycles_ref <= trig_cycles;
pulse_length_ref <= pulse_length;
pulse_period_ref <= pulse_period;
pulse_length_ref <= pulse_length;
nozerolength <= pulse_length /= zeros;
nozeroperiod <= pulse_period /= zeros;
end if;
end if;
end process trig_regs_ref;
......@@ -192,6 +200,7 @@ begin -- architecture rtl
end if;
end process ready_for_trig;
-- Produce output
-- Note rst_n_i is used as an async reset because it comes from the
-- clk_sys_i domain. Not the most elegant but it ensures no glitches
......@@ -201,19 +210,37 @@ begin -- architecture rtl
gen_out : process (rst_n_i, clk_ref_i)
begin
if rst_n_i = '0' then
pulse_o <= '0';
pulse_o_internal <= '0';
elsif clk_ref_i'event and clk_ref_i = '1' then
if tm_time_valid_i = '0' then
pulse_o <= '0';
elsif tm_utc_i = trig_utc_ref and tm_cycles_i = trig_cycles_ref and nozerolength then
pulse_o <= '1';
pulse_o_internal <= '0';
elsif tm_utc_i = trig_utc_ref and tm_cycles_i = trig_cycles_ref and nozerolength then --Original trigger
pulse_o_internal <= '1';
counter <= unsigned(pulse_length_ref)-1;
elsif counter /= 0 then
train_counter <= unsigned(pulse_period_ref); --Store the value of the period
elsif counter /= 0 then --The period counter is reduced at the same time than the pulse counter
counter <= counter-1;
if(train_counter /= 0) then
train_counter <= train_counter-1;
end if;
-- elsif(train_counter = 10) then --Load new values for then next cycle
-- load_values <= '1';
elsif(train_counter = 1) then --Period trigger. Rearm both counters
pulse_o_internal <= '1';
counter <= unsigned(pulse_length_ref)-1;
train_counter <= unsigned(pulse_period_ref);
--load_values <= '1';
elsif train_counter > 1 then
train_counter <= train_counter-1;
pulse_o_internal <= '0';
load_values <= '0';
else
pulse_o <= '0';
pulse_o_internal <= '0';
load_values <= '0';
end if;
end if;
end process gen_out;
end architecture rtl;
pulse_o <= pulse_o_internal;
end architecture rtl;
\ No newline at end of file
......@@ -32,12 +32,15 @@ peripheral {
prefix="dio";
hdl_entity="wr_dio_wb";
hdl_entity="wr_dio_wb";
-- Version info for wbgen2
version=2;
----------------------------------------------------
-- FIFOS & INTERRUPTS FOR INPUT EVENT TIME STAMPING
----------------------------------------------------
-- CHANNEL 0 INPUT FIFO
fifo_reg {
......@@ -45,45 +48,77 @@ peripheral {
direction = CORE_TO_BUS;
prefix = "tsf0";
name = "Timestamp FIFO 0";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting of 2 numbers:\
- tag_seconds - seconds time\
- tag_cycles - counter value for sub-second accuracy";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting from the following values:\
- tag_seconds - seconds time\
- tag_cycles - counter value for sub-second accuracy\
- leap_second_value - LeapSecond value\
- leap_second_valid - LeapSecond valid flag";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
name = "seconds time";
descritpion = "seconds time (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
};
field {
name = "seconds time";
descritpion = "seconds time (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
};
field {
name = "LeapSecond value";
description = "LeapSecond value synchronized with PPS";
prefix = "leap_second_value";
type = SLV;
size = 16;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
name = "LeapSecond flag 59";
description = "LeapSecond flag 59";
prefix = "leap_second_flag_59";
type = BIT;
};
field {
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
name = "LeapSecond flag 61";
description = "LeapSecond flag 61";
prefix = "leap_second_flag_61";
type = BIT;
};
field {
name = "LeapSecond valid";
description = "LeapSecond valid";
prefix = "leap_second_valid";
type = BIT;
};
};
-- CHANNEL 0 INTERRUPTS
irq {
name = "dio fifo not-empty 0";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_0";
trigger = LEVEL_1;
name = "dio fifo not-empty 0";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_0";
trigger = LEVEL_1;
};
-- CHANNEL 1 INPUT FIFO
......@@ -93,47 +128,78 @@ peripheral {
direction = CORE_TO_BUS;
prefix = "tsf1";
name = "Timestamp FIFO 1";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting of 2 numbers:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting from the following values:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy\
- leap_second_value - LeapSecond value\
- leap_second_valid - LeapSecond valid flag";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
name = "LeapSecond value";
description = "LeapSecond value synchronized with PPS";
prefix = "leap_second_value";
type = SLV;
size = 16;
};
field {
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
name = "LeapSecond flag 59";
description = "LeapSecond flag 59";
prefix = "leap_second_flag_59";
type = BIT;
};
field {
name = "LeapSecond flag 61";
description = "LeapSecond flag 61";
prefix = "leap_second_flag_61";
type = BIT;
};
field {
name = "LeapSecond valid";
description = "LeapSecond valid";
prefix = "leap_second_valid";
type = BIT;
};
};
-- CHANNEL 1 INTERRUPTS
irq {
name = "dio fifo not-empty 1";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_1";
trigger = LEVEL_1;
name = "dio fifo not-empty 1";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_1";
trigger = LEVEL_1;
};
-- CHANNEL 2 INPUT FIFO
fifo_reg {
......@@ -141,47 +207,78 @@ peripheral {
direction = CORE_TO_BUS;
prefix = "tsf2";
name = "Timestamp FIFO 2";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting of 2 numbers:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting from the following values:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy\
- leap_second_value - LeapSecond value\
- leap_second_valid - LeapSecond valid flag";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
name = "LeapSecond value";
description = "LeapSecond value synchronized with PPS";
prefix = "leap_second_value";
type = SLV;
size = 16;
};
field {
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
name = "LeapSecond flag 59";
description = "LeapSecond flag 59";
prefix = "leap_second_flag_59";
type = BIT;
};
field {
name = "LeapSecond flag 61";
description = "LeapSecond flag 61";
prefix = "leap_second_flag_61";
type = BIT;
};
field {
name = "LeapSecond valid";
description = "LeapSecond valid";
prefix = "leap_second_valid";
type = BIT;
};
};
-- CHANNEL 2 INTERRUPTS
irq {
name = "dio fifo not-empty 2";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_2";
trigger = LEVEL_1;
name = "dio fifo not-empty 2";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_2";
trigger = LEVEL_1;
};
-- CHANNEL 3 INPUT FIFO
fifo_reg {
......@@ -189,47 +286,78 @@ peripheral {
direction = CORE_TO_BUS;
prefix = "tsf3";
name = "Timestamp FIFO 3";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting of 2 numbers:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting from the following values:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy\
- leap_second_value - LeapSecond value\
- leap_second_valid - LeapSecond valid flag";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
name = "LeapSecond value";
description = "LeapSecond value synchronized with PPS";
prefix = "leap_second_value";
type = SLV;
size = 16;
};
field {
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
name = "LeapSecond flag 59";
description = "LeapSecond flag 59";
prefix = "leap_second_flag_59";
type = BIT;
};
field {
name = "LeapSecond flag 61";
description = "LeapSecond flag 61";
prefix = "leap_second_flag_61";
type = BIT;
};
field {
name = "LeapSecond valid";
description = "LeapSecond valid";
prefix = "leap_second_valid";
type = BIT;
};
};
-- CHANNEL 3 INTERRUPTS
irq {
name = "dio fifo not-empty 3";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_3";
trigger = LEVEL_1;
name = "dio fifo not-empty 3";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_3";
trigger = LEVEL_1;
};
-- CHANNEL 4 INPUT FIFO
fifo_reg {
......@@ -237,37 +365,67 @@ peripheral {
direction = CORE_TO_BUS;
prefix = "tsf4";
name = "Timestamp FIFO 4";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting of 2 numbers:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting from the following values:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy\
- leap_second_value - LeapSecond value\
- leap_second_valid - LeapSecond valid flag";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
};
field {
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
name = "LeapSecond value";
description = "LeapSecond value synchronized with PPS";
prefix = "leap_second_value";
type = SLV;
size = 16;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
name = "LeapSecond flag 59";
description = "LeapSecond flag 59";
prefix = "leap_second_flag_59";
type = BIT;
};
field {
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
name = "LeapSecond flag 61";
description = "LeapSecond flag 61";
prefix = "leap_second_flag_61";
type = BIT;
};
field {
name = "LeapSecond valid";
description = "LeapSecond valid";
prefix = "leap_second_valid";
type = BIT;
};
};
-- CHANNEL 4 INTERRUPTS
......@@ -278,6 +436,85 @@ peripheral {
trigger = LEVEL_1;
};
-- CHANNEL 5 INPUT FIFO (IRQ)
fifo_reg {
size = 256; -- or more. We'll see :)
direction = CORE_TO_BUS;
prefix = "tsf5";
name = "Timestamp FIFO 5";
description = "This FIFO holds the DIO input timestamps for each input channel. Each entry contains a single timestamp value consisting from the following values:\
- tag_seconds - time in seconds\
- tag_cycles - counter value for sub-second accuracy\
- leap_second_value - LeapSecond value\
- leap_second_valid - LeapSecond valid flag";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
name = "seconds time";
descritpion = "time in seconds (LSB)";
prefix = "tag_seconds";
type = SLV;
size = 32;
};
field {
name = "seconds time H";
descritpion = "time in seconds (MSB)";
prefix = "tag_secondsH";
type = SLV;
size = 8;
};
field {
name = "Sub-second accuracy";
descritpion = "Sub-second accuracy based on systme clock counters";
prefix = "tag_cycles";
type = SLV;
size = 28;
};
field {
name = "LeapSecond value";
description = "LeapSecond value synchronized with PPS";
prefix = "leap_second_value";
type = SLV;
size = 16;
};
field {
name = "LeapSecond flag 59";
description = "LeapSecond flag 59";
prefix = "leap_second_flag_59";
type = BIT;
};
field {
name = "LeapSecond flag 61";
description = "LeapSecond flag 61";
prefix = "leap_second_flag_61";
type = BIT;
};
field {
name = "LeapSecond valid";
description = "LeapSecond valid";
prefix = "leap_second_valid";
type = BIT;
};
};
-- CHANNEL 5 INTERRUPTS
irq {
name = "dio fifo not-empty 5";
description = "Interrupt active when dio input FIFO contains any timestamps.";
prefix = "nempty_5";
trigger = LEVEL_1;
};
-------------------------------------------------
-- REGISTERS FOR OUTPUT EVENT TIME-BASED TRIGGER
-------------------------------------------------
......@@ -309,7 +546,7 @@ peripheral {
description = "Number of seconds";
prefix = "seconds";
type = SLV;
size = 8;
size = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
......@@ -358,7 +595,7 @@ peripheral {
description = "Number of seconds";
prefix = "seconds";
type = SLV;
size = 8;
size = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
......@@ -407,7 +644,7 @@ peripheral {
description = "Number of seconds";
prefix = "seconds";
type = SLV;
size = 8;
size = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
......@@ -456,7 +693,7 @@ peripheral {
description = "Number of seconds";
prefix = "seconds";
type = SLV;
size = 8;
size = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
......@@ -505,7 +742,7 @@ peripheral {
description = "Number of seconds";
prefix = "seconds";
type = SLV;
size = 8;
size = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
......@@ -527,6 +764,55 @@ peripheral {
};
};
-- DIO CHANNEL 5 (IRQ): seconds value . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio 5 seconds-based trigger for pulse generation";
description = "trigger seconds value for dio output (LSB).";
prefix = "trig5";
field {
name = "seconds field";
description = "TBD";
prefix = "seconds";
type = SLV;
size = 32;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "fmc-dio 5 seconds-based trigger for pulse generation";
description = "trigger seconds value for dio output (MSB).";
prefix = "trigH5";
field {
name = "seconds field";
description = "Number of seconds";
prefix = "seconds";
type = SLV;
size = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 5 (IRQ): Cycles value. Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio 5 cycles to trigger a pulse generation";
description = "sub-second accuracy values (clock cycles) to trigger dio output channels.";
prefix = "cyc5";
field {
name = "cycles field";
description = "Number of cycles in one second (depends on current clock frequency)";
prefix = "cyc";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-----------------------------------------
-- OUTPUT CONFIGURATION/CONTROL REGISTERS
-----------------------------------------
......@@ -534,10 +820,13 @@ peripheral {
-- Programmable IO mode selection
reg {
name = "FMC-DIO input/output configuration register. ";
description = "It allows to choose the I/0 mode for each channel. \
description = "It allows to choose the I/0 mode for each channel (CH0-CH4). \
- [0-1]: The two first bit correspond to which signal its connected: 0 (00) GPIO, 1 (01) DIO core, 2 (10) WRPC core, 3 Undefined\
- [2]: Output Enable Negative (Input enable)\
- [3]: 50 Ohm termination enable";
- [3]: 50 Ohm termination enable\
CH5 is a special one whose configuration is:\
- [0]: Enable/Disable channel for IRQ\
- [3-1]: Undefined";
prefix = "iomode";
field {
name = "channel0";
......@@ -589,6 +878,16 @@ peripheral {
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
name = "channel5";
description = "Channel 5: Special channel for programmable IRQ";
prefix = "ch5";
type = SLV;
size = 4;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
};
-- Single-cycle strobe signal to latch the second/cycles values of the programamble output
......@@ -627,6 +926,12 @@ peripheral {
prefix = "time_ch4";
type = MONOSTABLE;
};
field {
name = "Sincle-cycle strobe";
description = "It generates a one-clock cycle pulse for programmable time latching";
prefix = "time_ch5";
type = MONOSTABLE;
};
};
-- seconds trigger ready value. Readable-writable the bus, writable from the device.
......@@ -640,7 +945,7 @@ peripheral {
description = "TBD";
prefix = "rdy";
type = SLV;
size = 5;
size = 6;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
......@@ -648,38 +953,45 @@ peripheral {
-- DIO CHANNEL 0 trigger ready interrupt
irq {
name = "Channel 0 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_0";
trigger = LEVEL_1;
name = "Channel 0 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_0";
trigger = LEVEL_1;
};
-- DIO CHANNEL 1 trigger ready interrupt
irq {
name = "Channel 1 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_1";
trigger = LEVEL_1;
name = "Channel 1 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_1";
trigger = LEVEL_1;
};
-- DIO CHANNEL 2 trigger ready interrupt
irq {
name = "Channel 2 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_2";
trigger = LEVEL_1;
name = "Channel 2 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_2";
trigger = LEVEL_1;
};
-- DIO CHANNEL 3 trigger ready interrupt
irq {
name = "Channel 3 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_3";
trigger = LEVEL_1;
name = "Channel 3 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_3";
trigger = LEVEL_1;
};
-- DIO CHANNEL 4 trigger ready interrupt
irq {
name = "Channel 4 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_4";
trigger = LEVEL_1;
name = "Channel 4 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_4";
trigger = LEVEL_1;
};
-- DIO CHANNEL 5 trigger ready interrupt
irq {
name = "Channel 5 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_5";
trigger = LEVEL_1;
};
-- DIO CHANNEL 0: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
......@@ -699,6 +1011,22 @@ peripheral {
};
};
-- DIO CHANNEL 0: Programmable/immediate output pulse period. Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 0 Programmable/immediate output pulse period";
description = "Number of clk_ref clock ticks for pulse period";
prefix = "prog0_pulse_per";
field {
name = "number of ticks (period) field for channel 0";
description = "ticks number (period)";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 1: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 1 Programmable/immediate output pulse length";
......@@ -715,6 +1043,23 @@ peripheral {
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 1: Programmable/immediate output pulse period. Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 1 Programmable/immediate output pulse period";
description = "Number of clk_ref clock ticks for pulse period";
prefix = "prog1_pulse_per";
field {
name = "number of ticks (period) field for channel 1";
description = "ticks number (period)";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 2: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 2 Programmable/immediate output pulse length";
......@@ -731,6 +1076,23 @@ peripheral {
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 2: Programmable/immediate output pulse period. Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 2 Programmable/immediate output pulse period";
description = "Number of clk_ref clock ticks for pulse period";
prefix = "prog2_pulse_per";
field {
name = "number of ticks (period) field for channel 2";
description = "ticks number (period)";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 3: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 3 Programmable/immediate output pulse length";
......@@ -747,6 +1109,23 @@ peripheral {
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 3: Programmable/immediate output pulse period. Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 3 Programmable/immediate output pulse period";
description = "Number of clk_ref clock ticks for pulse period";
prefix = "prog3_pulse_per";
field {
name = "number of ticks (period) field for channel 3";
description = "ticks number (period)";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 4: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 4 Programmable/immediate output pulse length";
......@@ -764,6 +1143,54 @@ peripheral {
};
};
-- DIO CHANNEL 4: Programmable/immediate output pulse period. Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 4 Programmable/immediate output pulse period";
description = "Number of clk_ref clock ticks for pulse period";
prefix = "prog4_pulse_per";
field {
name = "number of ticks (period) field for channel 4";
description = "ticks number (period)";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 5 (IRQ): Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 5 Programmable/immediate output pulse length";
description = "Number of clk_ref clock ticks that output will be active";
prefix = "prog5_pulse";
field {
name = "number of ticks field for channel 5";
description = "ticks number";
prefix = "length";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 5 (IRQ): Programmable/immediate output pulse period. Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 5 Programmable/immediate output pulse period";
description = "Number of clk_ref clock ticks for pulse period";
prefix = "prog5_pulse_per";
field {
name = "number of ticks (period) field for channel 5";
description = "ticks number (period)";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-----------------------------------------
-- IMMEDIATE OUTPUT REGISTERS
......@@ -780,37 +1207,42 @@ peripheral {
description = "It generates a pulse";
prefix = "imm_0";
type = MONOSTABLE;
clock = "clk_asyn_i";
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_1";
description = "It generates a pulse";
prefix = "imm_1";
type = MONOSTABLE;
clock = "clk_asyn_i";
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_2";
description = "It generates a pulse";
prefix = "imm_2";
type = MONOSTABLE;
clock = "clk_asyn_i";
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_3";
description = "It generates a pulse";
prefix = "imm_3";
type = MONOSTABLE;
clock = "clk_asyn_i";
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_4";
description = "It generates a pulse";
prefix = "imm_4";
type = MONOSTABLE;
clock = "clk_asyn_i";
};
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_5";
description = "It generates a pulse";
prefix = "imm_5";
type = MONOSTABLE;
clock = "clk_asyn_i";
};
};
};
};
\ No newline at end of file
......@@ -70,10 +70,10 @@ package wr_dio_pkg is
wbd_width => x"7", -- 8/16/32-bit port granularity
sdb_component => (
addr_first => x"0000000000000000",
addr_last => x"00000000000000ff",
addr_last => x"00000000000003ff",
product => (
vendor_id => x"00000000000075CB", -- SEVEN SOLUTIONS
device_id => x"00000001",
device_id => x"00000003",
version => x"00000002",
date => x"20120709",
name => "WR-DIO-Registers ")));
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -42,13 +42,14 @@
-- 2012-03-08 0.1 JDiaz Added wr_dio_wb
-- 2012-07-05 0.2 JDiaz Modified wr_dio_wb, modified interface
-- 2012-07-20 0.2 JDiaz Include sdb support
-- 2020-09-09 0.3 Jorge Machado Periodic pulse, virtual channel.
-------------------------------------------------------------------------------
-- Memory map:
-- 0x000: DIO-ONEWIRE
-- 0x100: DIO-I2C
-- 0x200: DIO-GPIO
-- 0x300: DIO-TIMING REGISTERS
-- 0x400: SDB-BRIDGE --> MAGIC NUMBER
-- 0x800: SDB-BRIDGE --> MAGIC NUMBER
library ieee;
use ieee.std_logic_1164.all;
......@@ -70,10 +71,10 @@ entity xwr_dio is
dio_clk_i : in std_logic;
dio_pps_i : in std_logic;
dio_in_i : in std_logic_vector(4 downto 0);
dio_out_o : out std_logic_vector(4 downto 0);
dio_oe_n_o : out std_logic_vector(4 downto 0);
dio_term_en_o : out std_logic_vector(4 downto 0);
dio_in_i : in std_logic_vector(5 downto 0);
dio_out_o : out std_logic_vector(5 downto 0);
dio_oe_n_o : out std_logic_vector(5 downto 0);
dio_term_en_o : out std_logic_vector(5 downto 0);
dio_onewire_b : inout std_logic;
dio_sdn_n_o : out std_logic;
dio_sdn_ck_n_o : out std_logic;
......@@ -97,13 +98,20 @@ entity xwr_dio is
TRIG0 : out std_logic_vector(31 downto 0);
TRIG1 : out std_logic_vector(31 downto 0);
TRIG2 : out std_logic_vector(31 downto 0);
TRIG3 : out std_logic_vector(31 downto 0)
TRIG3 : out std_logic_vector(31 downto 0);
-- Leap second
leap_second_value_i : in std_logic_vector(15 downto 0);
leap_second_flag_59_i : in std_logic;
leap_second_flag_61_i : in std_logic;
leap_second_flag_valid_i : in std_logic
);
end xwr_dio;
architecture rtl of xwr_dio is
-------------------------------------------------------------------------------
-- Component only for debugging (in order to generate seconds time)
-------------------------------------------------------------------------------
......@@ -151,7 +159,8 @@ architecture rtl of xwr_dio is
trig_utc_i : in std_logic_vector(39 downto 0);
trig_cycles_i : in std_logic_vector(27 downto 0);
trig_valid_p1_i : in std_logic;
pulse_length_i : in std_logic_vector(27 downto 0)
pulse_length_i : in std_logic_vector(27 downto 0);
pulse_period_i : in std_logic_vector(27 downto 0)
);
end component;
......@@ -208,159 +217,237 @@ architecture rtl of xwr_dio is
);
end component;
component imm_pulse_train_gen
generic(
pulse_period_width : integer := 28
);
port(
clk_ref_i : in std_logic;
rst_n_i : in std_logic;
dio_pulse_immed_stb_i : in std_logic;
pulse_period_i : in std_logic_vector(pulse_period_width-1 downto 0);
pulse_output_o : out std_logic
);
end component;
component wr_dio_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(5 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
wb_int_o : out std_logic;
clk_asyn_i : in std_logic;
-- FIFO write request
dio_tsf0_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf0_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf0_wr_empty_o : out std_logic;
dio_tsf0_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf0_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf0_tag_cycles_i : in std_logic_vector(27 downto 0);
irq_nempty_0_i : in std_logic;
-- FIFO write request
dio_tsf1_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf1_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf1_wr_empty_o : out std_logic;
dio_tsf1_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf1_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf1_tag_cycles_i : in std_logic_vector(27 downto 0);
irq_nempty_1_i : in std_logic;
-- FIFO write request
dio_tsf2_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf2_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf2_wr_empty_o : out std_logic;
dio_tsf2_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf2_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf2_tag_cycles_i : in std_logic_vector(27 downto 0);
irq_nempty_2_i : in std_logic;
-- FIFO write request
dio_tsf3_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf3_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf3_wr_empty_o : out std_logic;
dio_tsf3_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf3_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf3_tag_cycles_i : in std_logic_vector(27 downto 0);
irq_nempty_3_i : in std_logic;
-- FIFO write request
dio_tsf4_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf4_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf4_wr_empty_o : out std_logic;
dio_tsf4_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf4_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf4_tag_cycles_i : in std_logic_vector(27 downto 0);
irq_nempty_4_i : in std_logic;
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 0 seconds-based trigger for pulse generation'
dio_trig0_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 0 seconds-based trigger for pulse generation'
dio_trigh0_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 0 cycles to trigger a pulse generation'
dio_cyc0_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 1 seconds-based trigger for pulse generation'
dio_trig1_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 1 seconds-based trigger for pulse generation'
dio_trigh1_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 1 cycles to trigger a pulse generation'
dio_cyc1_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 2 seconds-based trigger for pulse generation'
dio_trig2_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 2 seconds-based trigger for pulse generation'
dio_trigh2_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 2 cycles to trigger a pulse generation'
dio_cyc2_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 3 seconds-based trigger for pulse generation'
dio_trig3_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 3 seconds-based trigger for pulse generation'
dio_trigh3_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 3 cycles to trigger a pulse generation'
dio_cyc3_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 4 seconds-based trigger for pulse generation'
dio_trig4_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 4 seconds-based trigger for pulse generation'
dio_trigh4_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 4 cycles to trigger a pulse generation'
dio_cyc4_cyc_o : out std_logic_vector(27 downto 0);
-- Port for unsigned field: 'channel' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch0_o : out std_logic_vector(3 downto 0);
dio_iomode_ch0_i : in std_logic_vector(3 downto 0);
dio_iomode_ch0_load_o : out std_logic;
-- Port for unsigned field: 'channel1' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch1_o : out std_logic_vector(3 downto 0);
dio_iomode_ch1_i : in std_logic_vector(3 downto 0);
dio_iomode_ch1_load_o : out std_logic;
-- Port for unsigned field: 'channel2' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch2_o : out std_logic_vector(3 downto 0);
dio_iomode_ch2_i : in std_logic_vector(3 downto 0);
dio_iomode_ch2_load_o : out std_logic;
-- Port for unsigned field: 'channel3' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch3_o : out std_logic_vector(3 downto 0);
dio_iomode_ch3_i : in std_logic_vector(3 downto 0);
dio_iomode_ch3_load_o : out std_logic;
-- Port for unsigned field: 'channel4' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch4_o : out std_logic_vector(3 downto 0);
dio_iomode_ch4_i : in std_logic_vector(3 downto 0);
dio_iomode_ch4_load_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch0_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch1_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch2_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch3_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch4_o : out std_logic;
-- Port for std_logic_vector field: 'trig_rdy field' in reg: 'FMC-DIO time trigger is ready to accept a new trigger generation request'
dio_trig_rdy_i : in std_logic_vector(4 downto 0);
irq_trigger_ready_0_i : in std_logic;
irq_trigger_ready_1_i : in std_logic;
irq_trigger_ready_2_i : in std_logic;
irq_trigger_ready_3_i : in std_logic;
irq_trigger_ready_4_i : in std_logic;
-- Port for std_logic_vector field: 'number of ticks field for channel 0' in reg: 'fmc-dio channel 0 Programmable/immediate output pulse length'
dio_prog0_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 1' in reg: 'fmc-dio channel 1 Programmable/immediate output pulse length'
dio_prog1_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 2' in reg: 'fmc-dio channel 2 Programmable/immediate output pulse length'
dio_prog2_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 3' in reg: 'fmc-dio channel 3 Programmable/immediate output pulse length'
dio_prog3_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 4' in reg: 'fmc-dio channel 4 Programmable/immediate output pulse length'
dio_prog4_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_0' in reg: 'Pulse generate immediately'
dio_pulse_imm_0_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_1' in reg: 'Pulse generate immediately'
dio_pulse_imm_1_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_2' in reg: 'Pulse generate immediately'
dio_pulse_imm_2_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_3' in reg: 'Pulse generate immediately'
dio_pulse_imm_3_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_4' in reg: 'Pulse generate immediately'
dio_pulse_imm_4_o : out std_logic
);
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(6 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
wb_int_o : out std_logic;
clk_asyn_i : in std_logic;
-- Port for std_logic_vector field: 'Version identifier' in reg: 'Version register'
dio_ver_id_o : out std_logic_vector(31 downto 0);
-- FIFO write request
dio_tsf0_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf0_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf0_wr_empty_o : out std_logic;
dio_tsf0_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf0_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf0_tag_cycles_i : in std_logic_vector(27 downto 0);
dio_tsf0_leap_second_value_i : in std_logic_vector(15 downto 0);
dio_tsf0_leap_second_flag_59_i : in std_logic;
dio_tsf0_leap_second_flag_61_i : in std_logic;
dio_tsf0_leap_second_valid_i : in std_logic;
irq_nempty_0_i : in std_logic;
-- FIFO write request
dio_tsf1_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf1_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf1_wr_empty_o : out std_logic;
dio_tsf1_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf1_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf1_tag_cycles_i : in std_logic_vector(27 downto 0);
dio_tsf1_leap_second_value_i : in std_logic_vector(15 downto 0);
dio_tsf1_leap_second_flag_59_i : in std_logic;
dio_tsf1_leap_second_flag_61_i : in std_logic;
dio_tsf1_leap_second_valid_i : in std_logic;
irq_nempty_1_i : in std_logic;
-- FIFO write request
dio_tsf2_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf2_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf2_wr_empty_o : out std_logic;
dio_tsf2_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf2_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf2_tag_cycles_i : in std_logic_vector(27 downto 0);
dio_tsf2_leap_second_value_i : in std_logic_vector(15 downto 0);
dio_tsf2_leap_second_flag_59_i : in std_logic;
dio_tsf2_leap_second_flag_61_i : in std_logic;
dio_tsf2_leap_second_valid_i : in std_logic;
irq_nempty_2_i : in std_logic;
-- FIFO write request
dio_tsf3_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf3_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf3_wr_empty_o : out std_logic;
dio_tsf3_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf3_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf3_tag_cycles_i : in std_logic_vector(27 downto 0);
dio_tsf3_leap_second_value_i : in std_logic_vector(15 downto 0);
dio_tsf3_leap_second_flag_59_i : in std_logic;
dio_tsf3_leap_second_flag_61_i : in std_logic;
dio_tsf3_leap_second_valid_i : in std_logic;
irq_nempty_3_i : in std_logic;
-- FIFO write request
dio_tsf4_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf4_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf4_wr_empty_o : out std_logic;
dio_tsf4_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf4_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf4_tag_cycles_i : in std_logic_vector(27 downto 0);
dio_tsf4_leap_second_value_i : in std_logic_vector(15 downto 0);
dio_tsf4_leap_second_flag_59_i : in std_logic;
dio_tsf4_leap_second_flag_61_i : in std_logic;
dio_tsf4_leap_second_valid_i : in std_logic;
irq_nempty_4_i : in std_logic;
-- FIFO write request
dio_tsf5_wr_req_i : in std_logic;
-- FIFO full flag
dio_tsf5_wr_full_o : out std_logic;
-- FIFO empty flag
dio_tsf5_wr_empty_o : out std_logic;
dio_tsf5_tag_seconds_i : in std_logic_vector(31 downto 0);
dio_tsf5_tag_secondsh_i : in std_logic_vector(7 downto 0);
dio_tsf5_tag_cycles_i : in std_logic_vector(27 downto 0);
dio_tsf5_leap_second_value_i : in std_logic_vector(15 downto 0);
dio_tsf5_leap_second_flag_59_i : in std_logic;
dio_tsf5_leap_second_flag_61_i : in std_logic;
dio_tsf5_leap_second_valid_i : in std_logic;
irq_nempty_5_i : in std_logic;
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 0 seconds-based trigger for pulse generation'
dio_trig0_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 0 seconds-based trigger for pulse generation'
dio_trigh0_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 0 cycles to trigger a pulse generation'
dio_cyc0_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 1 seconds-based trigger for pulse generation'
dio_trig1_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 1 seconds-based trigger for pulse generation'
dio_trigh1_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 1 cycles to trigger a pulse generation'
dio_cyc1_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 2 seconds-based trigger for pulse generation'
dio_trig2_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 2 seconds-based trigger for pulse generation'
dio_trigh2_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 2 cycles to trigger a pulse generation'
dio_cyc2_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 3 seconds-based trigger for pulse generation'
dio_trig3_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 3 seconds-based trigger for pulse generation'
dio_trigh3_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 3 cycles to trigger a pulse generation'
dio_cyc3_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 4 seconds-based trigger for pulse generation'
dio_trig4_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 4 seconds-based trigger for pulse generation'
dio_trigh4_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 4 cycles to trigger a pulse generation'
dio_cyc4_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 5 seconds-based trigger for pulse generation'
dio_trig5_seconds_o : out std_logic_vector(31 downto 0);
-- Port for std_logic_vector field: 'seconds field' in reg: 'fmc-dio 5 seconds-based trigger for pulse generation'
dio_trigh5_seconds_o : out std_logic_vector(7 downto 0);
-- Port for std_logic_vector field: 'cycles field' in reg: 'fmc-dio 5 cycles to trigger a pulse generation'
dio_cyc5_cyc_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'channel0' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch0_o : out std_logic_vector(3 downto 0);
dio_iomode_ch0_i : in std_logic_vector(3 downto 0);
dio_iomode_ch0_load_o : out std_logic;
-- Port for std_logic_vector field: 'channel1' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch1_o : out std_logic_vector(3 downto 0);
dio_iomode_ch1_i : in std_logic_vector(3 downto 0);
dio_iomode_ch1_load_o : out std_logic;
-- Port for std_logic_vector field: 'channel2' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch2_o : out std_logic_vector(3 downto 0);
dio_iomode_ch2_i : in std_logic_vector(3 downto 0);
dio_iomode_ch2_load_o : out std_logic;
-- Port for std_logic_vector field: 'channel3' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch3_o : out std_logic_vector(3 downto 0);
dio_iomode_ch3_i : in std_logic_vector(3 downto 0);
dio_iomode_ch3_load_o : out std_logic;
-- Port for std_logic_vector field: 'channel4' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch4_o : out std_logic_vector(3 downto 0);
dio_iomode_ch4_i : in std_logic_vector(3 downto 0);
dio_iomode_ch4_load_o : out std_logic;
-- Port for std_logic_vector field: 'channel5' in reg: 'FMC-DIO input/output configuration register. '
dio_iomode_ch5_o : out std_logic_vector(3 downto 0);
dio_iomode_ch5_i : in std_logic_vector(3 downto 0);
dio_iomode_ch5_load_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch0_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch1_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch2_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch3_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch4_o : out std_logic;
-- Port for MONOSTABLE field: 'Sincle-cycle strobe' in reg: 'Time-programmable output strobe signal'
dio_latch_time_ch5_o : out std_logic;
-- Port for std_logic_vector field: 'trig_rdy field' in reg: 'FMC-DIO time trigger is ready to accept a new trigger generation request'
dio_trig_rdy_i : in std_logic_vector(5 downto 0);
irq_trigger_ready_0_i : in std_logic;
irq_trigger_ready_1_i : in std_logic;
irq_trigger_ready_2_i : in std_logic;
irq_trigger_ready_3_i : in std_logic;
irq_trigger_ready_4_i : in std_logic;
irq_trigger_ready_5_i : in std_logic;
-- Port for std_logic_vector field: 'number of ticks field for channel 0' in reg: 'fmc-dio channel 0 Programmable/immediate output pulse length'
dio_prog0_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks (period) field for channel 0' in reg: 'fmc-dio channel 0 Programmable/immediate output pulse period'
dio_prog0_pulse_per_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 1' in reg: 'fmc-dio channel 1 Programmable/immediate output pulse length'
dio_prog1_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks (period) field for channel 1' in reg: 'fmc-dio channel 1 Programmable/immediate output pulse period'
dio_prog1_pulse_per_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 2' in reg: 'fmc-dio channel 2 Programmable/immediate output pulse length'
dio_prog2_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks (period) field for channel 2' in reg: 'fmc-dio channel 2 Programmable/immediate output pulse period'
dio_prog2_pulse_per_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 3' in reg: 'fmc-dio channel 3 Programmable/immediate output pulse length'
dio_prog3_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks (period) field for channel 3' in reg: 'fmc-dio channel 3 Programmable/immediate output pulse period'
dio_prog3_pulse_per_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 4' in reg: 'fmc-dio channel 4 Programmable/immediate output pulse length'
dio_prog4_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks (period) field for channel 4' in reg: 'fmc-dio channel 4 Programmable/immediate output pulse period'
dio_prog4_pulse_per_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks field for channel 5' in reg: 'fmc-dio channel 5 Programmable/immediate output pulse length'
dio_prog5_pulse_length_o : out std_logic_vector(27 downto 0);
-- Port for std_logic_vector field: 'number of ticks (period) field for channel 5' in reg: 'fmc-dio channel 5 Programmable/immediate output pulse period'
dio_prog5_pulse_per_o : out std_logic_vector(27 downto 0);
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_0' in reg: 'Pulse generate immediately'
dio_pulse_imm_0_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_1' in reg: 'Pulse generate immediately'
dio_pulse_imm_1_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_2' in reg: 'Pulse generate immediately'
dio_pulse_imm_2_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_3' in reg: 'Pulse generate immediately'
dio_pulse_imm_3_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_4' in reg: 'Pulse generate immediately'
dio_pulse_imm_4_o : out std_logic;
-- Port for asynchronous (clock: clk_asyn_i) MONOSTABLE field: 'pulse_gen_now_5' in reg: 'Pulse generate immediately'
dio_pulse_imm_5_o : out std_logic
);
end component;
......@@ -384,30 +471,37 @@ architecture rtl of xwr_dio is
signal sda_pad_in, sda_pad_out, sda_pad_oen : std_logic;
-- Pulse generator trigger registers signals
type t_seconds_array is array (4 downto 0) of std_logic_vector (39 downto 0);
type t_cycles_array is array (4 downto 0) of std_logic_vector (27 downto 0);
type t_pulselength_array is array (4 downto 0) of std_logic_vector (27 downto 0);
type t_seconds_array is array (5 downto 0) of std_logic_vector (39 downto 0);
type t_cycles_array is array (5 downto 0) of std_logic_vector (27 downto 0);
type t_pulselength_array is array (5 downto 0) of std_logic_vector (27 downto 0);
type t_leap_seconds_array is array (5 downto 0) of std_logic_vector (15 downto 0);
type t_pulseperiod_array is array (5 downto 0) of std_logic_vector (27 downto 0);
signal trig_seconds : t_seconds_array;
signal trig_cycles : t_cycles_array;
signal trig_valid_p1 : std_logic_vector (4 downto 0);
signal trig_valid_p1 : std_logic_vector (5 downto 0);
signal trig_ready : std_logic_vector (4 downto 0);
signal trig_ready : std_logic_vector (5 downto 0);
signal tag_seconds : t_seconds_array;
signal tag_cycles : t_cycles_array;
signal tag_valid_p1 : std_logic_vector (4 downto 0);
signal tag_valid_p1 : std_logic_vector (5 downto 0);
signal pulse_length : t_pulselength_array;
signal pulse_period : t_pulseperiod_array;
-- FIFO signals
signal dio_tsf_wr_req : std_logic_vector (4 downto 0);
signal dio_tsf_wr_full : std_logic_vector (4 downto 0);
signal dio_tsf_wr_empty : std_logic_vector (4 downto 0);
signal dio_tsf_tag_seconds : t_seconds_array;
signal dio_tsf_tag_cycles : t_cycles_array;
signal dio_tsf_wr_req : std_logic_vector (5 downto 0);
signal dio_tsf_wr_full : std_logic_vector (5 downto 0);
signal dio_tsf_wr_empty : std_logic_vector (5 downto 0);
signal dio_tsf_tag_seconds : t_seconds_array;
signal dio_tsf_tag_cycles : t_cycles_array;
signal dio_tsf_leap_second : t_leap_seconds_array;
signal dio_tsf_leap_second_flag_59 : std_logic_vector(5 downto 0);
signal dio_tsf_leap_second_flag_61 : std_logic_vector(5 downto 0);
signal dio_tsf_leap_second_valid : std_logic_vector(5 downto 0);
-- Fifos no-empty interrupts
signal irq_nempty : std_logic_vector (4 downto 0);
signal irq_nempty : std_logic_vector (5 downto 0);
-- DEBUG SIGNALS FOR USING seconds time values from dummy_time instead WRPC
signal tm_seconds : std_logic_vector (39 downto 0);
......@@ -418,9 +512,9 @@ architecture rtl of xwr_dio is
(0 => f_sdb_embed_device(c_xwb_onewire_master_sdb, x"00000000"), -- ONEWIRE
1 => f_sdb_embed_device(c_xwb_i2c_master_sdb, x"00000100"), -- I2C
2 => f_sdb_embed_device(c_xwb_gpio_port_sdb, x"00000200"), -- GPIO
3 => f_sdb_embed_device(c_xwr_dio_wb_sdb, x"00000300") -- DIO REGISTERS
3 => f_sdb_embed_device(c_xwr_dio_wb_sdb, x"00000400") -- DIO REGISTERS
);
constant c_diobar_sdb_address : t_wishbone_address := x"00000400";
constant c_diobar_sdb_address : t_wishbone_address := x"00000800";
signal cbar_master_in : t_wishbone_master_in_array(c_WB_SLAVES_DIO-1 downto 0);
signal cbar_master_out : t_wishbone_master_out_array(c_WB_SLAVES_DIO-1 downto 0);
......@@ -432,19 +526,30 @@ architecture rtl of xwr_dio is
signal wb_dio_slave_out : t_wishbone_slave_out;
-- DIO related signals
signal dio_pulse : std_logic_vector(4 downto 0);
signal dio_pulse_prog : std_logic_vector(4 downto 0);
signal dio_pulse_immed : std_logic_vector(4 downto 0);
signal dio_pulse_immed_stb : std_logic_vector(4 downto 0);
signal dio_iomode_reg : std_logic_vector(19 downto 0);
signal dio_iomode_o : std_logic_vector(19 downto 0);
signal dio_iomode_load_o : std_logic_vector(4 downto 0);
signal wb_dio_irq : std_logic;
signal dio_pulse : std_logic_vector(5 downto 0);
signal dio_pulse_prog : std_logic_vector(5 downto 0);
signal dio_pulse_immed : std_logic_vector(5 downto 0);
signal dio_pulse_immed_periodic : std_logic_vector(5 downto 0);
signal dio_pulse_immed_stb : std_logic_vector(5 downto 0);
signal dio_pulse_immed_result : std_logic_vector(5 downto 0);
signal dio_iomode_reg : std_logic_vector(23 downto 0);
signal dio_iomode_o : std_logic_vector(23 downto 0);
signal dio_iomode_load_o : std_logic_vector(5 downto 0);
signal wb_dio_irq : std_logic;
-- DIO Led signals
signal dio_led_bot_o_ch : std_logic_vector(4 downto 0);
signal dio_prog_interrupt : std_logic;
signal dio_prog_interrupt_reg_d0 : std_logic;
signal dio_prog_interrupt_reg_d1 : std_logic;
-- Register the final output signal to force the IOB and avoid any glitches.
signal dio_out_reg : std_logic_vector(5 downto 0);
signal dio_in_reg : std_logic_vector(5 downto 0);
-------------------------------------------------------------------------------
-- rtl
-------------------------------------------------------------------------------
......@@ -483,8 +588,8 @@ begin
trig_utc_i => trig_seconds(i),
trig_cycles_i => trig_cycles(i),
trig_valid_p1_i => trig_valid_p1(i),
pulse_length_i => pulse_length(i)
);
pulse_length_i => pulse_length(i),
pulse_period_i => pulse_period(i));
U_PULSE_STAMPER : pulse_stamper
......@@ -506,9 +611,71 @@ begin
tag_tai_o => tag_seconds(i),
tag_cycles_o => tag_cycles(i),
tag_valid_o => tag_valid_p1(i));
end generate gen_pulse_modules;
U_pulse_gen : pulse_gen_pl
port map(
clk_ref_i => clk_ref_i,
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
pulse_o => dio_pulse_prog(5),
-- DEBUG
-- tm_time_valid_i => '1',--tm_time_valid_i,
-- tm_utc_i => tm_seconds,--tm_utc_i,
-- tm_cycles_i => tm_cycles, --tm_cycles_i,
tm_time_valid_i => tm_time_valid_i,
tm_utc_i => tm_seconds_i,
tm_cycles_i => tm_cycles_i,
trig_ready_o => trig_ready(5),
trig_utc_i => trig_seconds(5),
trig_cycles_i => trig_cycles(5),
trig_valid_p1_i => trig_valid_p1(5),
pulse_length_i => pulse_length(5),
pulse_period_i => pulse_period(5));
U_PULSE_STAMPER : pulse_stamper
port map(
clk_ref_i => clk_ref_i,
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
pulse_a_i => dio_prog_interrupt_reg_d1,
-- DEBUG
-- tm_time_valid_i => '1',
-- tm_utc_i => tm_seconds,
-- tm_cycles_i => tm_cycles,
tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_seconds_i,
tm_cycles_i => tm_cycles_i,
tag_tai_o => tag_seconds(5),
tag_cycles_o => tag_cycles(5),
tag_valid_o => tag_valid_p1(5));
------------------------------------------------------------------------------
-- PULSE TRAIN GENERATOR
------------------------------------------------------------------------------
gen_pulse_train_modules : for i in 0 to 5 generate
U_imm_pulse_train_gen : imm_pulse_train_gen
generic map(
pulse_period_width => 28
)
port map(
clk_ref_i => clk_ref_i,
rst_n_i => rst_n_i,
dio_pulse_immed_stb_i => dio_pulse_immed_stb(i),
pulse_period_i => pulse_period(i),
pulse_output_o => dio_pulse_immed_periodic(i)
);
end generate gen_pulse_train_modules;
------------------------------------------------------------------------------
-- WB ONEWIRE MASTER
------------------------------------------------------------------------------
......@@ -622,7 +789,16 @@ begin
slave_o.err <= slave_bypass_o.err;
slave_o.rty <= slave_bypass_o.rty;
immediate_output_with_pulse_length : for i in 0 to 4 generate
-- The input of the immediate pulse counter is now a result of an OR between original stb
-- and the generated in the periodic immediate pulse core
dio_pulse_immed_result(0) <= dio_pulse_immed_stb(0) or dio_pulse_immed_periodic(0);
dio_pulse_immed_result(1) <= dio_pulse_immed_stb(1) or dio_pulse_immed_periodic(1);
dio_pulse_immed_result(2) <= dio_pulse_immed_stb(2) or dio_pulse_immed_periodic(2);
dio_pulse_immed_result(3) <= dio_pulse_immed_stb(3) or dio_pulse_immed_periodic(3);
dio_pulse_immed_result(4) <= dio_pulse_immed_stb(4) or dio_pulse_immed_periodic(4);
dio_pulse_immed_result(5) <= dio_pulse_immed_stb(5) or dio_pulse_immed_periodic(5);
immediate_output_with_pulse_length : for i in 0 to 5 generate
immediate_output_component : immed_pulse_counter
generic map (
pulse_length_width => 28
......@@ -630,18 +806,18 @@ begin
port map(
clk_i => clk_ref_i,
rst_n_i => rst_n_i,
pulse_start_i => dio_pulse_immed_stb(i),
pulse_start_i => dio_pulse_immed_result(i),
pulse_length_i => pulse_length(i),
pulse_output_o => dio_pulse_immed(i)
);
end generate immediate_output_with_pulse_length;
gen_pio_assignment : for i in 0 to 4 generate
gpio_in(c_IOMODE_NB*i) <= dio_in_i(i);
dio_pulse(i) <= '1' when dio_pulse_immed(i) = '1' else dio_pulse_prog(i);
gpio_in(c_IOMODE_NB*i) <= dio_in_reg(i);
dio_pulse(i) <= dio_pulse_immed(i) or dio_pulse_prog(i);
dio_oe_n_o(i) <= dio_iomode_reg(c_IOMODE_NB*i+2);
dio_term_en_o(i) <= dio_iomode_reg(c_IOMODE_NB*i+3);
dio_out_o(i) <= gpio_out(c_IOMODE_NB*i) when dio_iomode_reg(c_IOMODE_NB*i+1 downto c_IOMODE_NB*i) = "00" else dio_pulse(i);
dio_out_reg(i) <= gpio_out(c_IOMODE_NB*i) when dio_iomode_reg(c_IOMODE_NB*i+1 downto c_IOMODE_NB*i) = "00" else dio_pulse(i);
--with dio_iomode_reg(c_IOMODE_NB*i+1 downto c_IOMODE_NB*i)
--select dio_out_o(i) <=
......@@ -652,11 +828,35 @@ begin
end generate gen_pio_assignment;
--Register input and output to force the IOB and avoid any glitches
input_output_register : for i in 0 to 5 generate
process(clk_ref_i)
begin
if rising_edge(clk_ref_i) then
dio_out_o(i) <= dio_out_reg(i);
dio_in_reg(i) <= dio_in_i(i);
end if;
end process;
end generate input_output_register;
--Register irq to compensate the delay of the physical outputs
process(clk_ref_i)
begin
if rising_edge(clk_ref_i) then
dio_prog_interrupt_reg_d0 <= dio_prog_interrupt;
dio_prog_interrupt_reg_d1 <= dio_prog_interrupt_reg_d0;
end if;
end process;
--New channel programmed pulse has been connected directly to the input to generate the timestamp of each interrupt
dio_prog_interrupt <= dio_pulse_prog(5) or dio_pulse_immed(5) when dio_iomode_reg(c_IOMODE_NB*5) = '1' else '0';
dio_led_top_o <= dio_iomode_reg(c_IOMODE_NB*0+3) or
dio_iomode_reg(c_IOMODE_NB*1+3) or
dio_iomode_reg(c_IOMODE_NB*2+3) or
dio_iomode_reg(c_IOMODE_NB*3+3) or
dio_iomode_reg(c_IOMODE_NB*4+3);
--dio_iomode_reg(c_IOMODE_NB*5+3); The last channel is virtual, iomode(3) es not needed beacuse is undefined
--dio_led_top_o <= gpio_out(27); --only to test!
......@@ -678,7 +878,7 @@ begin
dio_sdn_ck_n_o <= gpio_out(30);
dio_sdn_n_o <= gpio_out(31);
-- Adapter of wbgen2 salve signals to top wb mode and granularity
-- Adapter of wbgen2 salve to top wb mode and granularity
U_Adapter : wb_slave_adapter
generic map (
g_master_use_struct => true,
......@@ -706,7 +906,7 @@ begin
port map(
rst_n_i => rst_n_i,
clk_sys_i => clk_sys_i,
wb_adr_i => wb_dio_slave_in.adr(5 downto 0),
wb_adr_i => wb_dio_slave_in.adr(6 downto 0),
wb_dat_i => wb_dio_slave_in.dat,
wb_dat_o => wb_dio_slave_out.dat,
wb_cyc_i => wb_dio_slave_in.cyc,
......@@ -718,48 +918,81 @@ begin
-- Crossbar could not propagate interrupt lines of several slaves => signal bypass
wb_int_o => wb_dio_irq,
clk_asyn_i => clk_ref_i,
dio_tsf0_wr_req_i => dio_tsf_wr_req(0),
dio_tsf0_wr_full_o => dio_tsf_wr_full(0),
dio_tsf0_wr_empty_o => dio_tsf_wr_empty(0),
dio_tsf0_tag_seconds_i => dio_tsf_tag_seconds(0)(31 downto 0),
dio_tsf0_tag_secondsh_i => dio_tsf_tag_seconds(0)(39 downto 32),
dio_tsf0_tag_cycles_i => dio_tsf_tag_cycles(0),
irq_nempty_0_i => irq_nempty(0),
dio_tsf1_wr_req_i => dio_tsf_wr_req(1),
dio_tsf1_wr_full_o => dio_tsf_wr_full(1),
dio_tsf1_wr_empty_o => dio_tsf_wr_empty(1),
dio_tsf1_tag_seconds_i => dio_tsf_tag_seconds(1)(31 downto 0),
dio_tsf1_tag_secondsh_i => dio_tsf_tag_seconds(1)(39 downto 32),
dio_tsf1_tag_cycles_i => dio_tsf_tag_cycles(1),
irq_nempty_1_i => irq_nempty(1),
dio_tsf2_wr_req_i => dio_tsf_wr_req(2),
dio_tsf2_wr_full_o => dio_tsf_wr_full(2),
dio_tsf2_wr_empty_o => dio_tsf_wr_empty(2),
dio_tsf2_tag_seconds_i => dio_tsf_tag_seconds(2)(31 downto 0),
dio_tsf2_tag_secondsh_i => dio_tsf_tag_seconds(2)(39 downto 32),
dio_tsf2_tag_cycles_i => dio_tsf_tag_cycles(2),
irq_nempty_2_i => irq_nempty(2),
dio_tsf3_wr_req_i => dio_tsf_wr_req(3),
dio_tsf3_wr_full_o => dio_tsf_wr_full(3),
dio_tsf3_wr_empty_o => dio_tsf_wr_empty(3),
dio_tsf3_tag_seconds_i => dio_tsf_tag_seconds(3)(31 downto 0),
dio_tsf3_tag_secondsh_i => dio_tsf_tag_seconds(3)(39 downto 32),
dio_tsf3_tag_cycles_i => dio_tsf_tag_cycles(3),
irq_nempty_3_i => irq_nempty(3),
dio_tsf4_wr_req_i => dio_tsf_wr_req(4),
dio_tsf4_wr_full_o => dio_tsf_wr_full(4),
dio_tsf4_wr_empty_o => dio_tsf_wr_empty(4),
dio_tsf4_tag_seconds_i => dio_tsf_tag_seconds(4)(31 downto 0),
dio_tsf4_tag_secondsh_i => dio_tsf_tag_seconds(4)(39 downto 32),
dio_tsf4_tag_cycles_i => dio_tsf_tag_cycles(4),
irq_nempty_4_i => irq_nempty(4),
dio_trig0_seconds_o => trig_seconds(0)(31 downto 0),
dio_ver_id_o => open,
dio_tsf0_wr_req_i => dio_tsf_wr_req(0),
dio_tsf0_wr_full_o => dio_tsf_wr_full(0),
dio_tsf0_wr_empty_o => dio_tsf_wr_empty(0),
dio_tsf0_tag_seconds_i => dio_tsf_tag_seconds(0)(31 downto 0),
dio_tsf0_tag_secondsh_i => dio_tsf_tag_seconds(0)(39 downto 32),
dio_tsf0_tag_cycles_i => dio_tsf_tag_cycles(0),
dio_tsf0_leap_second_value_i => dio_tsf_leap_second(0),
dio_tsf0_leap_second_flag_59_i => dio_tsf_leap_second_flag_59(0),
dio_tsf0_leap_second_flag_61_i => dio_tsf_leap_second_flag_61(0),
dio_tsf0_leap_second_valid_i => dio_tsf_leap_second_valid(0),
irq_nempty_0_i => irq_nempty(0),
dio_tsf1_wr_req_i => dio_tsf_wr_req(1),
dio_tsf1_wr_full_o => dio_tsf_wr_full(1),
dio_tsf1_wr_empty_o => dio_tsf_wr_empty(1),
dio_tsf1_tag_seconds_i => dio_tsf_tag_seconds(1)(31 downto 0),
dio_tsf1_tag_secondsh_i => dio_tsf_tag_seconds(1)(39 downto 32),
dio_tsf1_tag_cycles_i => dio_tsf_tag_cycles(1),
dio_tsf1_leap_second_value_i => dio_tsf_leap_second(1),
dio_tsf1_leap_second_flag_59_i => dio_tsf_leap_second_flag_59(1),
dio_tsf1_leap_second_flag_61_i => dio_tsf_leap_second_flag_61(1),
dio_tsf1_leap_second_valid_i => dio_tsf_leap_second_valid(1),
irq_nempty_1_i => irq_nempty(1),
dio_tsf2_wr_req_i => dio_tsf_wr_req(2),
dio_tsf2_wr_full_o => dio_tsf_wr_full(2),
dio_tsf2_wr_empty_o => dio_tsf_wr_empty(2),
dio_tsf2_tag_seconds_i => dio_tsf_tag_seconds(2)(31 downto 0),
dio_tsf2_tag_secondsh_i => dio_tsf_tag_seconds(2)(39 downto 32),
dio_tsf2_tag_cycles_i => dio_tsf_tag_cycles(2),
dio_tsf2_leap_second_value_i => dio_tsf_leap_second(2),
dio_tsf2_leap_second_flag_59_i => dio_tsf_leap_second_flag_59(2),
dio_tsf2_leap_second_flag_61_i => dio_tsf_leap_second_flag_61(2),
dio_tsf2_leap_second_valid_i => dio_tsf_leap_second_valid(2),
irq_nempty_2_i => irq_nempty(2),
dio_tsf3_wr_req_i => dio_tsf_wr_req(3),
dio_tsf3_wr_full_o => dio_tsf_wr_full(3),
dio_tsf3_wr_empty_o => dio_tsf_wr_empty(3),
dio_tsf3_tag_seconds_i => dio_tsf_tag_seconds(3)(31 downto 0),
dio_tsf3_tag_secondsh_i => dio_tsf_tag_seconds(3)(39 downto 32),
dio_tsf3_tag_cycles_i => dio_tsf_tag_cycles(3),
dio_tsf3_leap_second_value_i => dio_tsf_leap_second(3),
dio_tsf3_leap_second_flag_59_i => dio_tsf_leap_second_flag_59(3),
dio_tsf3_leap_second_flag_61_i => dio_tsf_leap_second_flag_61(3),
dio_tsf3_leap_second_valid_i => dio_tsf_leap_second_valid(3),
irq_nempty_3_i => irq_nempty(3),
dio_tsf4_wr_req_i => dio_tsf_wr_req(4),
dio_tsf4_wr_full_o => dio_tsf_wr_full(4),
dio_tsf4_wr_empty_o => dio_tsf_wr_empty(4),
dio_tsf4_tag_seconds_i => dio_tsf_tag_seconds(4)(31 downto 0),
dio_tsf4_tag_secondsh_i => dio_tsf_tag_seconds(4)(39 downto 32),
dio_tsf4_tag_cycles_i => dio_tsf_tag_cycles(4),
dio_tsf4_leap_second_value_i => dio_tsf_leap_second(4),
dio_tsf4_leap_second_flag_59_i => dio_tsf_leap_second_flag_59(4),
dio_tsf4_leap_second_flag_61_i => dio_tsf_leap_second_flag_61(4),
dio_tsf4_leap_second_valid_i => dio_tsf_leap_second_valid(4),
irq_nempty_4_i => irq_nempty(4),
dio_tsf5_wr_req_i => dio_tsf_wr_req(5),
dio_tsf5_wr_full_o => dio_tsf_wr_full(5),
dio_tsf5_wr_empty_o => dio_tsf_wr_empty(5),
dio_tsf5_tag_seconds_i => dio_tsf_tag_seconds(5)(31 downto 0),
dio_tsf5_tag_secondsh_i => dio_tsf_tag_seconds(5)(39 downto 32),
dio_tsf5_tag_cycles_i => dio_tsf_tag_cycles(5),
dio_tsf5_leap_second_value_i => dio_tsf_leap_second(5),
dio_tsf5_leap_second_flag_59_i => dio_tsf_leap_second_flag_59(5),
dio_tsf5_leap_second_flag_61_i => dio_tsf_leap_second_flag_61(5),
dio_tsf5_leap_second_valid_i => dio_tsf_leap_second_valid(5),
irq_nempty_5_i => irq_nempty(5),
dio_trig0_seconds_o => trig_seconds(0)(31 downto 0),
dio_trigh0_seconds_o => trig_seconds(0)(39 downto 32),
dio_cyc0_cyc_o => trig_cycles(0),
......@@ -778,30 +1011,38 @@ begin
dio_trig4_seconds_o => trig_seconds(4)(31 downto 0),
dio_trigh4_seconds_o => trig_seconds(4)(39 downto 32),
dio_cyc4_cyc_o => trig_cycles(4),
dio_trig5_seconds_o => trig_seconds(5)(31 downto 0),
dio_trigh5_seconds_o => trig_seconds(5)(39 downto 32),
dio_cyc5_cyc_o => trig_cycles(5),
dio_iomode_ch0_i => dio_iomode_reg(3 downto 0),
dio_iomode_ch1_i => dio_iomode_reg(7 downto 4),
dio_iomode_ch2_i => dio_iomode_reg(11 downto 8),
dio_iomode_ch3_i => dio_iomode_reg(15 downto 12),
dio_iomode_ch4_i => dio_iomode_reg(19 downto 16),
dio_iomode_ch5_i => dio_iomode_reg(23 downto 20),
dio_iomode_ch0_o => dio_iomode_o(3 downto 0),
dio_iomode_ch1_o => dio_iomode_o(7 downto 4),
dio_iomode_ch2_o => dio_iomode_o(11 downto 8),
dio_iomode_ch3_o => dio_iomode_o(15 downto 12),
dio_iomode_ch4_o => dio_iomode_o(19 downto 16),
dio_iomode_ch5_o => dio_iomode_o(23 downto 20),
dio_iomode_ch0_load_o => dio_iomode_load_o(0),
dio_iomode_ch1_load_o => dio_iomode_load_o(1),
dio_iomode_ch2_load_o => dio_iomode_load_o(2),
dio_iomode_ch3_load_o => dio_iomode_load_o(3),
dio_iomode_ch4_load_o => dio_iomode_load_o(4),
dio_iomode_ch5_load_o => dio_iomode_load_o(5),
dio_latch_time_ch0_o => trig_valid_p1(0),
dio_latch_time_ch1_o => trig_valid_p1(1),
dio_latch_time_ch2_o => trig_valid_p1(2),
dio_latch_time_ch3_o => trig_valid_p1(3),
dio_latch_time_ch4_o => trig_valid_p1(4),
dio_latch_time_ch5_o => trig_valid_p1(5),
dio_trig_rdy_i => trig_ready,
......@@ -810,30 +1051,40 @@ begin
irq_trigger_ready_2_i => trig_ready(2),
irq_trigger_ready_3_i => trig_ready(3),
irq_trigger_ready_4_i => trig_ready(4),
irq_trigger_ready_5_i => trig_ready(5),
dio_prog0_pulse_length_o => pulse_length(0),
dio_prog1_pulse_length_o => pulse_length(1),
dio_prog2_pulse_length_o => pulse_length(2),
dio_prog3_pulse_length_o => pulse_length(3),
dio_prog4_pulse_length_o => pulse_length(4),
dio_prog5_pulse_length_o => pulse_length(5),
dio_prog0_pulse_per_o => pulse_period(0),
dio_prog1_pulse_per_o => pulse_period(1),
dio_prog2_pulse_per_o => pulse_period(2),
dio_prog3_pulse_per_o => pulse_period(3),
dio_prog4_pulse_per_o => pulse_period(4),
dio_prog5_pulse_per_o => pulse_period(5),
dio_pulse_imm_0_o => dio_pulse_immed_stb(0),
dio_pulse_imm_1_o => dio_pulse_immed_stb(1),
dio_pulse_imm_2_o => dio_pulse_immed_stb(2),
dio_pulse_imm_3_o => dio_pulse_immed_stb(3),
dio_pulse_imm_4_o => dio_pulse_immed_stb(4)
);
dio_pulse_imm_4_o => dio_pulse_immed_stb(4),
dio_pulse_imm_5_o => dio_pulse_immed_stb(5));
-- seconds timestamped FIFO-no-empty interrupts
irq_nempty(0) <= not dio_tsf_wr_empty(0);
irq_nempty(1) <= not dio_tsf_wr_empty(1);
irq_nempty(2) <= not dio_tsf_wr_empty(2);
irq_nempty(3) <= not dio_tsf_wr_empty(3);
irq_nempty(5) <= not dio_tsf_wr_empty(5);
--disable interrupts when setup in clock mode.
irq_nempty(4) <= not dio_tsf_wr_empty(4) when (dio_iomode_reg(18 downto 16) /= "110") else '0';
irq_fifos : for i in 0 to 4 generate
irq_fifos : for i in 0 to 5 generate
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
......@@ -841,11 +1092,24 @@ begin
dio_tsf_wr_req(i) <= '0';
dio_tsf_tag_seconds(i) <= (others => '0');
dio_tsf_tag_cycles(i) <= (others => '0');
dio_tsf_leap_second(i) <= (others => '0');
dio_tsf_leap_second_flag_59(i) <= '0';
dio_tsf_leap_second_flag_61(i) <= '0';
dio_tsf_leap_second_valid(i) <= '0';
else
if ((tag_valid_p1(i) = '1') and (dio_tsf_wr_full(i) = '0')) then
dio_tsf_wr_req(i) <= '1';
dio_tsf_tag_seconds(i) <= tag_seconds(i);
dio_tsf_tag_cycles(i) <= tag_cycles(i);
-- Capture the leap second information together with timestamps
-- This does not cover a corner case in which the timestamp is
-- registered just before the leap second event and this code is
-- executed just after... TODO: fixme.
dio_tsf_leap_second(i) <= leap_second_value_i;
dio_tsf_leap_second_flag_59(i) <= leap_second_flag_59_i;
dio_tsf_leap_second_flag_61(i) <= leap_second_flag_61_i;
dio_tsf_leap_second_valid(i) <= leap_second_flag_valid_i;
else
dio_tsf_wr_req(i) <= '0';
end if;
......@@ -864,7 +1128,7 @@ begin
dio_iomode_reg(4*c_IOMODE_NB+3 downto 4*c_IOMODE_NB) <= "0110"; -- mode 4 c
else
-- Set up register iomode for each channel
for i in 0 to 4 loop
for i in 0 to 5 loop
if (dio_iomode_load_o(i) = '1') then
dio_iomode_reg(c_IOMODE_NB*i+3 downto c_IOMODE_NB*i) <= dio_iomode_o(c_IOMODE_NB*i+3 downto c_IOMODE_NB*i);
end if;
......
......@@ -216,8 +216,13 @@ entity dio_common_top is
-- I2C interface for accessing FMC EEPROM. Deprecated, was used in
-- pre-v3.0 releases to store WRPC configuration. Now we use Flash for this.
dio_scl_b : inout std_logic;
dio_sda_b : inout std_logic
dio_sda_b : inout std_logic;
-- Leap second
leap_second_value_i : in std_logic_vector(15 downto 0);
leap_second_flag_59_i : in std_logic;
leap_second_flag_61_i : in std_logic;
leap_second_flag_valid_i : in std_logic
);
end entity dio_common_top;
......@@ -240,10 +245,10 @@ architecture top of dio_common_top is
dio_clk_i : in std_logic;
dio_pps_i : in std_logic;
dio_in_i : in std_logic_vector(4 downto 0);
dio_out_o : out std_logic_vector(4 downto 0);
dio_oe_n_o : out std_logic_vector(4 downto 0);
dio_term_en_o : out std_logic_vector(4 downto 0);
dio_in_i : in std_logic_vector(5 downto 0);
dio_out_o : out std_logic_vector(5 downto 0);
dio_oe_n_o : out std_logic_vector(5 downto 0);
dio_term_en_o : out std_logic_vector(5 downto 0);
dio_onewire_b : inout std_logic;
dio_sdn_n_o : out std_logic;
dio_sdn_ck_n_o : out std_logic;
......@@ -265,7 +270,13 @@ architecture top of dio_common_top is
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
dio_int : out std_logic
dio_int : out std_logic;
-- Leap second
leap_second_value_i : in std_logic_vector(15 downto 0);
leap_second_flag_59_i : in std_logic;
leap_second_flag_61_i : in std_logic;
leap_second_flag_valid_i : in std_logic
);
end component;
......@@ -325,8 +336,8 @@ architecture top of dio_common_top is
signal svec_led : std_logic_vector(15 downto 0);
-- DIO Mezzanine
signal dio_in : std_logic_vector(4 downto 0);
signal dio_out : std_logic_vector(4 downto 0);
signal dio_in : std_logic_vector(5 downto 0);
signal dio_out : std_logic_vector(5 downto 0);
-- Timecode output
signal tm_time_valid : std_logic;
......@@ -349,6 +360,9 @@ architecture top of dio_common_top is
-- VIC-only signals
signal vic_only_irqs : std_logic_vector(3 downto 0);
signal dio_oe_n_o_internal : std_logic_vector(5 downto 0);
signal dio_term_en_o_internal : std_logic_vector(5 downto 0);
begin -- architecture top
......@@ -663,8 +677,8 @@ begin -- architecture top
dio_pps_i => wrc_pps_out,
dio_in_i => dio_in,
dio_out_o => dio_out,
dio_oe_n_o => dio_oe_n_o,
dio_term_en_o => dio_term_en_o,
dio_oe_n_o => dio_oe_n_o_internal,
dio_term_en_o => dio_term_en_o_internal,
dio_onewire_b => dio_onewire_b,
dio_sdn_n_o => dio_sdn_n_o,
dio_sdn_ck_n_o => dio_sdn_ck_n_o,
......@@ -676,9 +690,16 @@ begin -- architecture top
tm_cycles_i => tm_cycles,
slave_i => cnx_slave_in(c_WB_SLAVE_DIO),
slave_o => cnx_slave_out(c_WB_SLAVE_DIO),
dio_int => dio_int
dio_int => dio_int,
leap_second_value_i => leap_second_value_i,
leap_second_flag_59_i => leap_second_flag_59_i,
leap_second_flag_61_i => leap_second_flag_61_i,
leap_second_flag_valid_i => leap_second_flag_valid_i
);
dio_oe_n_o <= dio_oe_n_o_internal(4 downto 0);
dio_term_en_o <= dio_term_en_o_internal(4 downto 0);
vic_vec_int(0) <= dio_int;
NIC_GEN : if g_dio_mode = DIO_NIC generate
......
......@@ -205,12 +205,16 @@ package dio_common_top_pkg is
dio_onewire_b : inout std_logic;
dio_sdn_n_o : out std_logic;
dio_sdn_ck_n_o : out std_logic;
-- I2C interface for accessing FMC EEPROM. Deprecated, was used in
-- pre-v3.0 releases to store WRPC configuration. Now we use Flash for this.
dio_scl_b : inout std_logic;
dio_sda_b : inout std_logic
dio_sda_b : inout std_logic;
-- Leap second
leap_second_value_i : in std_logic_vector(15 downto 0);
leap_second_flag_59_i : in std_logic;
leap_second_flag_61_i : in std_logic;
leap_second_flag_valid_i : in std_logic
);
end component;
......@@ -238,7 +242,7 @@ package dio_common_top_pkg is
constant c_nic_bridge_sdb : t_sdb_bridge :=
f_xwb_bridge_manual_sdb(x"0001ffff", x"00011000");
constant c_wr_dio_bridge_sdb : t_sdb_bridge :=
f_xwb_bridge_product_manual_sdb(x"00000fff", x"00000400", c_xwr_dio_sdb);
f_xwb_bridge_product_manual_sdb(x"00000fff", x"00000800", c_xwr_dio_sdb);
-- Primary wishbone crossbar layout (NIC)
constant c_NIC_WB_LAYOUT : t_sdb_record_array(c_NUM_WB_SLAVES - 1 downto 0) := (
......
......@@ -283,7 +283,11 @@ begin
dio_sdn_n_o => dio_sdn_n_o,
dio_sdn_ck_n_o => dio_sdn_ck_n_o,
dio_scl_b => dio_scl_b,
dio_sda_b => dio_sda_b
dio_sda_b => dio_sda_b,
leap_second_value_i => x"0025", -- leapSeoncs=37 in 2020
leap_second_flag_59_i => '0',
leap_second_flag_61_i => '0',
leap_second_flag_valid_i => '1'
);
end architecture top;
......@@ -15,6 +15,8 @@ export FMC_BUS_ABS
DIRS = $(FMC_BUS_ABS) kernel tools
CFLAGS += $(WR_DIO_CFLAGS)
.PHONY: all clean modules install modules_install $(DIRS)
all clean modules install modules_install: $(DIRS)
......
CFLAGS += -I./dep
irq-demo: irq-demo.c ./dep/*.c
gcc -o irq-demo irq-demo.c ./dep/*.c $(CFLAGS) -lm
clean:
-rm irq-demo
-rm .irq-demo.log
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FILE_LOG_PRIVATE_H__
#define __FILE_LOG_PRIVATE_H__
struct file_log_private {
FILE *fp;
char *path;
};
static int check_file_log_priv(log_device dev);
static struct file_log_private * get_private_info(log_device dev);
static void init_file_log_device(log_device dev);
static void send_to_file_log_device(log_device, const char *msg);
static void deinit_file_log_device(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include "log-device.h"
#include "file-log-private.h"
static struct log_device_iface _file_log_iface =
{
.init_log_device = init_file_log_device,
.send_to_log_device = send_to_file_log_device,
.clear_log_device = NULL,
.deinit_log_device = deinit_file_log_device,
};
static const log_device_interface file_log_iface = &_file_log_iface;
log_device create_file_log_device(const char *path)
{
return create_log_device((void *)path, file_log_iface);
}
static void init_file_log_device(log_device dev)
{
struct file_log_private *priv;
priv = calloc(1, sizeof(*priv));
priv->path = dev->private;
priv->fp = fopen(priv->path, "w+");
dev->private = priv;
}
static void send_to_file_log_device(log_device dev, const char *msg)
{
struct file_log_private *priv;
if(!check_file_log_priv(dev)) {
priv = get_private_info(dev);
if(priv && priv->fp) {
fputs(msg, priv->fp);
fputs("\n", priv->fp);
}
}
}
static void deinit_file_log_device(log_device dev)
{
struct file_log_private *priv;
if(!check_file_log_priv(dev)) {
priv = get_private_info(dev);
if(priv) {
if(priv->fp) {
fclose(priv->fp);
}
free(priv);
}
}
}
static int check_file_log_priv(log_device dev)
{
return (dev->private != NULL) ? 0 : 1;
}
static struct file_log_private * get_private_info(log_device dev)
{
return (struct file_log_private *)dev->private;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FILE_LOG_H__
#define __FILE_LOG_H__
log_device create_file_log_device(const char *file);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FMC_DIO_DEVICE_PRIVATE_H__
#define __FMC_DIO_DEVICE_PRIVATE_H__
#include "usr-timestamp.h"
#include "../../kernel/fmc-dio.h"
#define MAX_TMP_BUF 1024
#define FMC_DIO_N_CH 5
#define NS_IN_A_SEC 1000000000
#define MAX_FMC_DIO_PATH 100
struct fmc_dio_dev {
char dev_name[MAX_FMC_DIO_PATH];
int fd;
log_device *logs;
unsigned int n_logs;
int enabled_log;
unsigned int total_n_ts;
unsigned int partial_n_ts;
struct wr_dio_cmd cmd;
};
static const fmc_dio_device BAD_FMC_DEVICE = NULL;
static int check_fmc_dio_device(fmc_dio_device dev);
static int enable_fmc_dio_device_hw_irq(fmc_dio_device dev,
int ch, int en);
static int setup_fmc_dio_device_hw_irq(fmc_dio_device dev,
unsigned long period,
long count);
static int get_state_fmc_dio_device_hw_irq(fmc_dio_device dev,
int ch, int * state);
static int get_hw_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct usr_timestamp **ts, unsigned int *nts, int flags);
static int get_kernel_leaps_info(fmc_dio_device dev);
static void log_msg(fmc_dio_device dev, const char *msg);
static void LOG(fmc_dio_device dev, const char *fmt, ...);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/timex.h>
#include <sys/ioctl.h>
#include "fmc-dio-device.h"
#include "fmc-dio-device-private.h"
#define FMC_DIO_FLUSH_SLEEP 1
fmc_dio_device create_fmc_dio_device(char *name)
{
fmc_dio_device dev = calloc(1, sizeof(*dev));
if(!dev)
return BAD_FMC_DEVICE;
strncpy(dev->dev_name, name, MAX_FMC_DIO_PATH-1);
return dev;
}
static int check_fmc_dio_device(fmc_dio_device dev)
{
if(dev != BAD_FMC_DEVICE) {
return 0;
}
else {
return 1;
}
}
int open_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->fd = open(dev->dev_name, O_RDWR);
if(dev->fd < 0) {
free(dev);
return -ENODEV;
}
if(ioctl(dev->fd, PRIV_MEZZANINE_ID, (unsigned long) dev->dev_name) < 0 &&
errno != EAGAIN) {
free(dev);
return -EFAULT;
}
return 0;
}
void attach_log_devices_to_fmc_dio_device(fmc_dio_device dev,
log_device *log_devs,
unsigned int n_log_devs)
{
if(check_fmc_dio_device(dev) || !log_devs || n_log_devs == 0)
return;
dev->logs = log_devs;
dev->n_logs = n_log_devs;
}
int enable_log_for_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->enabled_log = 1;
return 0;
}
int disable_log_for_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->enabled_log = 0;
return 0;
}
void close_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return;
close(dev->fd);
free(dev);
}
int enable_fmc_dio_device_irq(fmc_dio_device dev, int ch)
{
int ret;
if(check_fmc_dio_device(dev)) {
return -EINVAL;
}
ret = enable_fmc_dio_device_hw_irq(dev, ch, 1);
return ret;
}
int enable_fmc_dio_device_all_irq(fmc_dio_device dev)
{
int ret = 0;
for(int i = 0 ; i <= FMC_DIO_N_CH ; i++) {
ret = enable_fmc_dio_device_irq(dev, i);
if(ret)
break;
}
return ret;
}
int disable_fmc_dio_device_irq(fmc_dio_device dev, int ch)
{
int ret;
if(check_fmc_dio_device(dev)) {
return -EINVAL;
}
ret = enable_fmc_dio_device_hw_irq(dev, ch, 0);
return ret;
}
int disable_fmc_dio_device_all_irq(fmc_dio_device dev)
{
int ret = 0;
for(int i = 0 ; i <= FMC_DIO_N_CH ; i++) {
ret = disable_fmc_dio_device_irq(dev, i);
if(ret)
break;
}
return ret;
}
static int enable_fmc_dio_device_hw_irq(fmc_dio_device dev,
int ch, int en)
{
if(ch < 0 || ch > FMC_DIO_N_CH) {
return -EINVAL;
}
struct wr_dio_cmd *c = &dev->cmd;
en = (en) ? 1 : 0;
c->command = WR_DIO_CMD_MASK_IRQ;
c->flags = WR_DIO_F_MASK;
c->channel = 1 << ch;
c->value = (en) ? WR_DIO_F_MASK_ENABLE_IRQ :
WR_DIO_F_MASK_DISABLE_IRQ;
if(ioctl(dev->fd, PRIV_MEZZANINE_CMD, c) < 0)
return -EFAULT;
return 0;
}
int setup_fmc_dio_device_irq(fmc_dio_device dev,
unsigned long period,
long count)
{
int ret;
if(check_fmc_dio_device(dev))
return -EINVAL;
ret = setup_fmc_dio_device_hw_irq(dev, period, count);
return ret;
}
static int setup_fmc_dio_device_hw_irq(fmc_dio_device dev,
unsigned long period,
long count)
{
struct wr_dio_cmd *c = &dev->cmd;
int ret;
c->command = WR_DIO_CMD_IRQ;
c->flags = 0x0;
c->flags |= WR_DIO_F_LOOP;
c->flags |= WR_DIO_F_NOW;
c->t[1].tv_nsec = period % NS_IN_A_SEC;
c->t[1].tv_sec = period / NS_IN_A_SEC;
c->value= count;
ret = ioctl(dev->fd, PRIV_MEZZANINE_CMD, c);
if(ret < 0) {
return -EFAULT;
}
return 0;
}
int get_fmc_dio_device_all_irq_state(fmc_dio_device dev, int * state)
{
int ret = 0, state_internal = 0, channel_state = 0;
for(int i = 0 ; i <= FMC_DIO_N_CH ; i++) {
ret = get_fmc_dio_device_irq_state(dev, i, &channel_state);
if(ret)
break;
state_internal |= (channel_state & 0x1) << i;
}
*state = state_internal;
return ret;
}
int get_fmc_dio_device_irq_state(fmc_dio_device dev, int ch, int * state)
{
int ret;
if(check_fmc_dio_device(dev)) {
return -EINVAL;
}
ret = get_fmc_dio_device_hw_irq_state(dev, ch, state);
return ret;
}
int get_fmc_dio_device_hw_irq_state(fmc_dio_device dev, int ch, int * state)
{
if(ch < 0 || ch > FMC_DIO_N_CH) {
return -EINVAL;
}
struct wr_dio_cmd *c = &dev->cmd;
c->command = WR_DIO_CMD_MASK_IRQ;
c->flags = WR_DIO_F_MASK;
c->channel = 1 << ch;
c->value = WR_DIO_F_MASK_READ_IRQ;
if(ioctl(dev->fd, PRIV_MEZZANINE_CMD, c) < 0)
return -EFAULT;
if(c->value == WR_DIO_F_MASK_ENABLE_IRQ)
*state = 1;
else if(c->value == WR_DIO_F_MASK_DISABLE_IRQ)
*state = 0;
else
return -EFAULT;
return 0;
}
int set_fmc_dio_device_all_irq_state(fmc_dio_device dev, int state)
{
int ret = 0;
for(int i = 0 ; i <= FMC_DIO_N_CH ; i++) {
ret = enable_fmc_dio_device_hw_irq(dev, i, (state >> i) & 0x1);
if(ret)
break;
}
return ret;
}
int get_tai_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct usr_timestamp **ts, unsigned int *nts)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
return get_hw_ts_from_fmc_dio_device(dev, ch, ts, nts, WR_DIO_F_WAIT);
}
int get_utc_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct usr_timestamp **ts, unsigned int *nts)
{
int ret;
int kernel_tai;
int usr_tai;
int usr_tai_valid;
int tai;
struct timespec *t;
ret = get_tai_ts_from_fmc_dio_device(dev, ch, ts, nts);
if(ret)
return ret;
kernel_tai = get_kernel_leaps_info(dev);
for(int i = 0 ; i < *nts ; i++) {
t = &((*ts)[i].t);
usr_tai = (*ts)[i].leap_second;
#if defined(IGNORE_USR_LEAPSECOND)
usr_tai_valid = 0;
#else
usr_tai_valid = (*ts)[i].leap_second_valid;
#endif
tai = (usr_tai_valid) ? usr_tai : kernel_tai;
t->tv_sec -= tai;
}
return ret;
}
static int get_hw_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct usr_timestamp **ts, unsigned int *nts, int flags)
{
struct wr_dio_cmd *c = &dev->cmd;
int ret;
c->command = WR_DIO_CMD_STAMP;
c->flags = flags;
c->channel = ch;
ret = ioctl(dev->fd, PRIV_MEZZANINE_CMD, (unsigned long) c);
if(ret < 0) {
return ret;
}
if(c->nstamp <= 0) {
return -EAGAIN;
}
*nts = c->nstamp;
*ts = calloc(c->nstamp, sizeof(struct usr_timestamp));
if(!*ts)
return -ENOMEM;
for(int i = 0 ; i < c->nstamp ; i++) {
(*ts)[i].t = (c->t[i]);
(*ts)[i].leap_second = (c->wr_ts_info_buf[i]).leap_second;
(*ts)[i].leap_second_valid = (c->wr_ts_info_buf[i]).leap_second_valid;
(*ts)[i].flag59 = (c->wr_ts_info_buf[i]).flag59;
(*ts)[i].flag61 = (c->wr_ts_info_buf[i]).flag61;
}
dev->total_n_ts += c->nstamp;
dev->partial_n_ts += c->nstamp;
return 0;
}
void flush_fmc_dio_device_channel(fmc_dio_device dev, int ch)
{
int ret;
struct usr_timestamp *ts;
unsigned int nts;
LOG(dev, "Flushing FMC DIO device, channel %d... ", ch);
sleep(FMC_DIO_FLUSH_SLEEP);
ret = get_hw_ts_from_fmc_dio_device(dev, ch, &ts, &nts, 0);
if(ret == 0)
free(ts);
LOG(dev, "Ok!\n");
}
static int get_kernel_leaps_info(fmc_dio_device dev)
{
struct timex tx = {0};
if (adjtimex(&tx) < 0) {
return -EFAULT;
}
return tx.tai;
}
unsigned int get_total_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return 0;
return dev->total_n_ts;
}
unsigned int get_partial_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return 0;
return dev->partial_n_ts;
}
void reset_partial_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return;
dev->partial_n_ts = 0;
}
static void log_msg(fmc_dio_device dev, const char *msg)
{
if(!dev->logs || dev->n_logs == 0)
return;
if(!dev->enabled_log)
return;
for(int i = 0 ; i < dev->n_logs ; i++)
send_to_log_device(dev->logs[i], msg);
}
static void LOG(fmc_dio_device dev, const char *fmt, ...)
{
va_list ap;
char buffer[MAX_TMP_BUF] = {0};
va_start(ap, fmt);
vsnprintf(buffer, MAX_TMP_BUF-1, fmt, ap);
va_end(ap);
log_msg(dev, buffer);
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FMC_DIO_DEVICE_H__
#define __FMC_DIO_DEVICE_H__
#include "log-device.h"
#include "usr-timestamp.h"
typedef struct fmc_dio_dev * fmc_dio_device;
fmc_dio_device create_fmc_dio_device(char *name);
int open_fmc_dio_device(fmc_dio_device dev);
void close_fmc_dio_device(fmc_dio_device dev);
void attach_log_devices_to_fmc_dio_device(fmc_dio_device dev,
log_device *log_devs,
unsigned int n_log_devs);
int enable_log_for_fmc_dio_device(fmc_dio_device dev);
int disable_log_for_fmc_dio_device(fmc_dio_device dev);
int enable_fmc_dio_device_irq(fmc_dio_device dev, int ch);
int enable_fmc_dio_device_all_irq(fmc_dio_device dev);
int disable_fmc_dio_device_irq(fmc_dio_device dev, int ch);
int disable_fmc_dio_device_all_irq(fmc_dio_device dev);
int setup_fmc_dio_device_irq(fmc_dio_device dev,
unsigned long period,
long count);
int get_fmc_dio_device_all_irq_state(fmc_dio_device dev, int * state);
int get_fmc_dio_device_irq_state(fmc_dio_device dev, int ch, int * state);
int get_fmc_dio_device_hw_irq_state(fmc_dio_device dev, int ch, int * state);
int set_fmc_dio_device_all_irq_state(fmc_dio_device dev, int state);
int get_tai_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct usr_timestamp **ts, unsigned int *nts);
int get_utc_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct usr_timestamp **ts, unsigned int *nts);
void flush_fmc_dio_device_channel(fmc_dio_device dev, int ch);
unsigned int get_total_n_timestamps(fmc_dio_device dev);
unsigned int get_partial_n_timestamps(fmc_dio_device dev);
void reset_partial_n_timestamps(fmc_dio_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __LOG_DEVICE_PRIVATE_H__
#define __LOG_DEVICE_PRIVATE_H__
static const log_device BAD_LOG_DEVICE = NULL;
static int check_log_device(log_device dev);
static int check_log_device_interface(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdlib.h>
#include "log-device.h"
#include "log-device-private.h"
log_device create_log_device(void *args, log_device_interface interface)
{
log_device dev = calloc(1, sizeof(struct log_dev));
if(dev != BAD_LOG_DEVICE && interface != NULL) {
dev->private = args;
dev->ops = interface;
if(dev->ops->init_log_device)
dev->ops->init_log_device(dev);
}
return dev;
}
void send_to_log_device(log_device dev, const char *msg)
{
if(check_log_device_interface(dev))
return;
dev->ops->send_to_log_device(dev, msg);
}
void clear_log_device(log_device dev)
{
if(check_log_device_interface(dev))
return;
if(dev->ops->clear_log_device)
dev->ops->clear_log_device(dev);
}
void destroy_log_device(log_device dev)
{
if(check_log_device_interface(dev))
return;
if(dev->ops->deinit_log_device)
dev->ops->deinit_log_device(dev);
free(dev);
}
static int check_log_device(log_device dev)
{
return (dev == BAD_LOG_DEVICE) ? 1 : 0;
}
static int check_log_device_interface(log_device dev)
{
if(check_log_device(dev))
return 1;
if(!dev->ops)
return 1;
else
return 0;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __LOG_DEVICE_H__
#define __LOG_DEVICE_H__
typedef struct log_device_iface * log_device_interface;
struct log_dev {
log_device_interface ops;
void *private;
};
typedef struct log_dev * log_device;
struct log_device_iface {
void (*init_log_device)(log_device dev);
void (*send_to_log_device)(log_device dev, const char *msg);
void (*deinit_log_device)(log_device dev);
void (*clear_log_device)(log_device dev);
};
log_device create_log_device(void *args, log_device_interface interface);
void send_to_log_device(log_device dev, const char *msg);
void clear_log_device(log_device dev);
void destroy_log_device(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __PRINTF_LOG_PRIVATE_H__
#define __PRINTF_LOG_PRIVATE_H__
static void send_to_printf_log_device(log_device dev, const char *msg);
static void clear_printf_log_device(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stddef.h>
#include <stdio.h>
#include "log-device.h"
#include "printf-log-private.h"
static struct log_device_iface _printf_log_iface =
{
.init_log_device = NULL,
.send_to_log_device = send_to_printf_log_device,
.deinit_log_device = NULL,
.clear_log_device = clear_printf_log_device,
};
static const log_device_interface printf_log_iface = &_printf_log_iface;
static void send_to_printf_log_device(log_device dev, const char *msg)
{
printf("%s\n", msg);
}
static void clear_printf_log_device(log_device dev)
{
printf("\e[1;1H\e[2J");
}
log_device create_printf_log_device(void)
{
return create_log_device(NULL, printf_log_iface);
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __PRINTF_LOG_H__
#define __PRINTF_LOG_H__
#include "log-device.h"
log_device create_printf_log_device(void);
void clear_screen(log_device device);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __STATS_ENGINE_PRIVATE_H__
#define __STATS_ENGINE_PRIVATE_H__
#include "usr-timestamp.h"
#define MAX_TS 1000
#define NS_IN_A_SEC 1000000000
#define MAX_TMP_BUF 1024
#define METRICS_UNIT "s"
struct ts_stats {
double mean;
double std;
double min;
double max;
double peak_to_peak;
unsigned int ts_per_second;
unsigned int ts_total;
};
struct _stats_engine {
struct usr_timestamp usr_ts[MAX_TS];
struct timespec sys_ts[MAX_TS];
double diff_ts[MAX_TS];
struct ts_stats stats;
unsigned int n_ts;
unsigned int current_ts;
unsigned int next_ts;
unsigned int n_iter;
log_device *logs;
unsigned int n_logs;
int enabled_log;
};
const stats_engine BAD_STATS_ENGINE = NULL;
static void update_n_ts_stats_engine(stats_engine engine);
static void update_index_stats_engine(unsigned int *index);
static void log_stats_engine(stats_engine engine, int verbose);
static int check_log_configuration(stats_engine engine);
static void log_msg(stats_engine engine,
const char *msg);
static void log_clear(stats_engine engine);
static void LOG(stats_engine engine, const char *fmt, ...);
static int timespec_subtract(struct timespec *result,
struct timespec *x,
struct timespec *y);
static double compute_min(const double *values,
const unsigned int n_values);
static double compute_max(const double *values,
const unsigned int n_values);
static double compute_peak_to_peak(const double min,
const double max);
static double compute_mean(const double *values,
const unsigned int n_values);
static double compute_stdev(const double *values,
const unsigned int n_values,
const double mean);
static int compute_ts_per_second(const int sec,
const struct usr_timestamp *ts,
const unsigned int n_ts);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#include <errno.h>
#include "stats-engine.h"
#include "stats-engine-private.h"
stats_engine create_stats_engine(void)
{
stats_engine engine = calloc(1, sizeof(*engine));
return engine;
}
int check_stats_engine(stats_engine engine)
{
if(engine != BAD_STATS_ENGINE)
return 0;
else
return 1;
}
void attach_log_devices_to_stats_engine(stats_engine engine,
log_device *log_devs,
unsigned int n_log_devs)
{
if(check_stats_engine(engine) || !log_devs || n_log_devs == 0)
return;
engine->logs = log_devs;
engine->n_logs = n_log_devs;
}
int enable_log_for_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return -EINVAL;
engine->enabled_log = 1;
return 0;
}
int disable_log_for_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return -EINVAL;
return 0;
}
static struct timespec ts_t0 = {0};
static int neg_t0=0;
int add_usr_timestamp_to_stats_engine(stats_engine engine, struct usr_timestamp *ts,clock_type sysclkt)
{
struct timespec system_ts;
if(check_stats_engine(engine))
return -EINVAL;
if(sysclkt==CLOCK_REALTIME)
{
clock_gettime(CLOCK_REALTIME, &system_ts);
}
else
{
clock_gettime(CLOCK_MONOTONIC, &system_ts);
if(ts_t0.tv_sec==0) //Set starting point t0 of monotonic time
{
neg_t0=timespec_subtract(&ts_t0, &(ts->t),&system_ts);
printf("ts_0=%ld . %ld\n",ts_t0.tv_sec,ts_t0.tv_nsec);
}
if(neg_t0) timespec_subtract(&(ts->t), &(ts_t0),&(ts->t));
else timespec_subtract(&(ts->t), &(ts->t),&(ts_t0));
}
engine->sys_ts[engine->next_ts] = system_ts;
engine->usr_ts[engine->next_ts] = *ts;
update_index_stats_engine(&engine->next_ts);
update_n_ts_stats_engine(engine);
return 0;
}
int run_stats_engine(stats_engine engine, int verbose)
{
struct timespec ts;
int neg;
int count_ts;
if(check_stats_engine(engine))
return -EINVAL;
neg = timespec_subtract(&ts, &engine->sys_ts[engine->current_ts],
&(engine->usr_ts[engine->current_ts].t));
engine->diff_ts[engine->current_ts] = ((neg) ? -1.0 : 1.0)*(ts.tv_sec + ((double) ts.tv_nsec / NS_IN_A_SEC));
engine->stats.min = compute_min(engine->diff_ts, engine->n_ts);
engine->stats.max = compute_max(engine->diff_ts, engine->n_ts);
engine->stats.mean = compute_mean(engine->diff_ts, engine->n_ts);
engine->stats.std = compute_stdev(engine->diff_ts, engine->n_ts, engine->stats.mean);
engine->stats.peak_to_peak = compute_peak_to_peak(engine->stats.min, engine->stats.max);
count_ts = compute_ts_per_second(engine->usr_ts[engine->current_ts].t.tv_sec,
engine->usr_ts, engine->n_ts);
if(count_ts != -1)
engine->stats.ts_per_second = count_ts;
engine->stats.ts_total++;
log_stats_engine(engine, verbose);
update_index_stats_engine(&engine->current_ts);
engine->n_iter++;
return 0;
}
void destroy_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return;
free(engine);
}
static void update_n_ts_stats_engine(stats_engine engine)
{
if(engine->n_ts < MAX_TS)
engine->n_ts++;
}
static void update_index_stats_engine(unsigned int *index)
{
if(*index == MAX_TS-1)
*index = 0;
else
(*index)++;
}
static void log_stats_engine(stats_engine engine, int verbose)
{
log_clear(engine);
LOG(engine, "\n===================== STATS ENGINE LOG =====================\n");
if(verbose) {
LOG(engine, "Timestamps in buffer: %d", engine->n_ts);
LOG(engine, "Next timestamp (index): %d\n", engine->next_ts);
for(int i = 0 ; i < engine->n_ts ; i++) {
LOG(engine, "\tsys_ts[%d]: sec %ld, nsec %ld",
i, engine->sys_ts[i].tv_sec,
engine->sys_ts[i].tv_nsec);
LOG(engine, "\tusr_ts[%d]: sec %ld, nsec %ld [ls_valid: %d, ls: %d, l59: %d, l61: %d]",
i, engine->usr_ts[i].t.tv_sec,
engine->usr_ts[i].t.tv_nsec,
engine->usr_ts[i].leap_second_valid,
engine->usr_ts[i].leap_second,
engine->usr_ts[i].flag59,
engine->usr_ts[i].flag61);
LOG(engine, "\tdiff[%d]: %f %s",
i, engine->diff_ts[i], METRICS_UNIT);
}
LOG(engine, "");
}
LOG(engine, "Iterations: %d", engine->n_iter);
LOG(engine, "Metrics => Total timestamps: %d, Timestamps per second: %d\n"
"max: %f %s, min %f %s, peak to peak %f %s\n"
"mean: %f %s, stdev: %f %s",
engine->stats.ts_total, engine->stats.ts_per_second,
engine->stats.max, METRICS_UNIT, engine->stats.min, METRICS_UNIT,
engine->stats.peak_to_peak, METRICS_UNIT,
engine->stats.mean, METRICS_UNIT, engine->stats.std, METRICS_UNIT);
LOG(engine, "\n============================================================\n");
LOG(engine, "Please, press 'q' key + ENTER or CNTRL+C to exit from the demo tool\n");
}
static int check_log_configuration(stats_engine engine)
{
if(!engine->logs || engine->n_logs == 0)
return 1;
if(!engine->enabled_log)
return 1;
return 0;
}
static void log_msg(stats_engine engine, const char *msg)
{
if(check_log_configuration(engine))
return;
for(int i = 0 ; i < engine->n_logs ; i++)
send_to_log_device(engine->logs[i], msg);
}
static void log_clear(stats_engine engine)
{
if(check_log_configuration(engine))
return;
for(int i = 0 ; i < engine->n_logs ; i++)
clear_log_device(engine->logs[i]);
}
static void LOG(stats_engine engine, const char *fmt, ...)
{
va_list ap;
char buffer[MAX_TMP_BUF] = {0};
va_start(ap, fmt);
vsnprintf(buffer, MAX_TMP_BUF-1, fmt, ap);
va_end(ap);
log_msg(engine, buffer);
}
static int timespec_subtract(struct timespec *result,
struct timespec *x,
struct timespec *y)
{
struct timespec xx = *x;
struct timespec yy = *y;
x = &xx; y = &yy;
if (x->tv_nsec > NS_IN_A_SEC-1)
{
x->tv_sec += x->tv_nsec / NS_IN_A_SEC;
x->tv_nsec %= NS_IN_A_SEC;
}
if (y->tv_nsec > NS_IN_A_SEC-1)
{
y->tv_sec += y->tv_nsec / NS_IN_A_SEC;
y->tv_nsec %= NS_IN_A_SEC;
}
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_nsec = x->tv_nsec - y->tv_nsec;
if(result->tv_sec>0 && result->tv_nsec < 0)
{
result->tv_nsec += NS_IN_A_SEC;
result->tv_sec--;
}
else if(result->tv_sec<0 && result->tv_nsec > 0)
{
result->tv_nsec -= NS_IN_A_SEC;
result->tv_sec++;
}
return (result->tv_sec < 0) || (result->tv_nsec<0);
}
static double compute_min(const double *values,
const unsigned int n_values)
{
double min = 0.0;
if(n_values == 0)
return min;
min = values[0];
for(int i = 1 ; i < n_values ; i++) {
if(values[i] < min)
min = values[i];
}
return min;
}
static double compute_peak_to_peak(const double min, const double max)
{
return max-min;
}
static double compute_max(const double *values,
const unsigned int n_values)
{
double max = 0.0;
if(n_values == 0)
return max;
max = values[0];
for(int i = 1 ; i < n_values ; i++) {
if(values[i] > max)
max = values[i];
}
return max;
}
static double compute_mean(const double *values,
const unsigned int n_values)
{
double mean = 0.0;
for(int i = 0 ; i < n_values ; i++) {
mean += values[i];
}
mean /= n_values;
return mean;
}
static double compute_stdev(const double *values,
const unsigned int n_values,
const double mean)
{
double stdev = 0.0;
double aux = 0.0;
for(int i = 0 ; i < n_values ; i++) {
aux += pow((values[i]-mean),2);
}
stdev = sqrt((aux/n_values));
return stdev;
}
static int compute_ts_per_second(const int sec,
const struct usr_timestamp *ts,
const unsigned int n_ts)
{
static int prev_sec = -1;
int count = -1;
if(prev_sec == -1) {
prev_sec = sec;
}
else {
if(prev_sec != sec) {
count = 0;
for(int i = 0 ; i < n_ts ; i++) {
if(ts[i].t.tv_sec == prev_sec)
count++;
}
prev_sec = sec;
}
}
return count;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __STATS_ENGINE_H__
#define __STATS_ENGINE_H__
#include "log-device.h"
#include "usr-timestamp.h"
typedef enum{
REALTIME=0,
MONOTONIC,
} clock_type;
typedef struct _stats_engine *stats_engine;
stats_engine create_stats_engine(void);
int check_stats_engine(stats_engine engine);
void attach_log_devices_to_stats_engine(stats_engine engine,
log_device *log_devs,
unsigned int n_log_devs);
int enable_log_for_stats_engine(stats_engine engine);
int disable_log_for_stats_engine(stats_engine engine);
int add_usr_timestamp_to_stats_engine(stats_engine engine,
struct usr_timestamp *ts,clock_type sysclkt);
int run_stats_engine(stats_engine engine, int verbose);
void destroy_stats_engine(stats_engine engine);
#endif
#ifndef __USR_TIMESTAMP_H__
#define __USR_TIMESTAMP_H__
#include <time.h>
#include <stdint.h>
struct usr_timestamp {
struct timespec t;
uint16_t leap_second;
int leap_second_valid;
int flag59;
int flag61;
};
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __DEMO_IRQ_PRIVATE_H__
#define __DEMO_IRQ_PRIVATE_H__
#include "usr-timestamp.h"
#include "stats-engine.h"
#define PROG_NAME "irq-demo"
#define TEST_FMC_DIO_CH 5
#define TEST_FMC_DIO_COUNT -1
#define TEST_FMC_DIO_PERIOD 100000000
#define STATS_LOG_PATH "./.irq-demo.log"
#define MAX_FMC_DIO_PATH 100
struct _user_args {
char fmc_dev_path[MAX_FMC_DIO_PATH];
unsigned int irq_period;
int verbose;
clock_type clock;
log_device err_log;
};
typedef struct _user_args * user_args;
static void demo_irq_process_loop(fmc_dio_device fmc_dev, stats_engine engine);
static void process_timestamps_to_engine(stats_engine engine, struct usr_timestamp *ts,
unsigned int nts, int last_only);
static user_args create_user_arguments(log_device log);
static int parse_user_arguments(int argc, char *argv[], user_args parsed_args);
static void destroy_user_arguments(user_args args);
static void show_help(void);
static int check_unknown_user_arguments(int optind, int argc, char **argv);
static unsigned int check_user_stop(void);
static void set_stdin_as_nonblocking(void);
static void exit_abruptly(int sig);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include "stats-engine.h"
#include "fmc-dio-device.h"
#include "printf-log.h"
#include "file-log.h"
#include "irq-demo-private.h"
/* Static data for signal handlers */
static fmc_dio_device global_fmc_dev = NULL;
/* Global user arguments */
static user_args global_user_arguments = NULL;
/* Global verbose control */
static int verbose_mode = 0;
/* Previous interrupt state */
static int prev_irq_state = 0;
/*
* irq-demo -f /dev/<fmc-device-file> [-p <irq period>]
* To exit: Please press 'q' in the keyboard or send a stop signal (CNTR+C)
*
* This DEMO shows the behavior of the interrupts for the FMC DIO device. The basic operation
* is to get all the timestamps generated by the FMC DIO channel and compute a basic statistics
* taking into consideration the system time such as time difference, mean and standard deviation.
*
* In order to work properly, it uses several resources that can be found in under dep folder:
* - loggers: General implementation for logs generation. Two kind of loggers are supported now:
* - printf-log: It uses the stdout for messages.
* - file-log: It uses a specific file for messages.
* - fmc-dio-device: Implementation of FMC DIO device functionalities.
* - stats-engine: Statistics engine code. It contains all the logic to compute the different metrics
*/
int main(int argc, char *argv[])
{
fmc_dio_device dev;
log_device gen_log;
log_device stats_log;
user_args user_arguments;
log_device logs[2], err_log;
unsigned int n_logs = 2;
stats_engine sengine;
int ret = 0;
/* Initialize signal handler for force exit */
signal(SIGINT, exit_abruptly);
signal(SIGQUIT, exit_abruptly);
/* Create the loggers: One for stdout and the other for a specific file */
gen_log = create_printf_log_device();
stats_log = create_file_log_device(STATS_LOG_PATH);
/* Loggers are stored in array:
* -[0]: General logger for stdout
* -[1]: File logger for stats
* -err_log: General logger to report main errors
*/
logs[0] = gen_log;
logs[1] = stats_log;
err_log = gen_log;
/* Parse user arguments (FMC DIO dev entry path and optionally irq period) */
user_arguments = create_user_arguments(err_log);
if(parse_user_arguments(argc, argv, user_arguments)) {
/* In case of failure, exit */
ret = 1;
goto out_log;
}
global_user_arguments = user_arguments;
/* Set verbose mode from user command line */
verbose_mode = user_arguments->verbose;
/* Create stats engine to compute timestamps metrics (difference, mean, stdev) */
sengine = create_stats_engine();
if(check_stats_engine(sengine)) {
/* In case of failure, exit */
send_to_log_device(err_log, "Error initializing stats engine\n");
ret = 1;
goto out_user_args;
}
/* Attach loggers to stats engine
* This allows the engine to generate output messages for the stdout and log file
*/
attach_log_devices_to_stats_engine(sengine, logs, n_logs);
/* Enable log for stats engine (by default is disabled) */
enable_log_for_stats_engine(sengine);
/* Create FMC DIO device using user arguments */
dev = create_fmc_dio_device(user_arguments->fmc_dev_path);
if(open_fmc_dio_device(dev)) {
/* In case of failure, exit */
send_to_log_device(err_log, "Error opening FMC DIO device\n");
ret = 1;
goto out_stats_engine;
}
/*
* Attach loggers to FMC DIO device
* This allows the FMC DIO to generate output messages for the stdout and log file
*/
attach_log_devices_to_fmc_dio_device(dev, logs, n_logs);
enable_log_for_fmc_dio_device(dev);
/* Before starting IRQ demo, Interrupts should be properly configured:
* 1) Disable all interrupts
* 2) Enable the TEST_FMC_DIO_CH interrupt line
* 3) Flush TEST_FMC_DIO_CH channel
* 4) Setup specific information for interrupt line (period from user arguments or default one)
*/
get_fmc_dio_device_all_irq_state(dev, &prev_irq_state);
disable_fmc_dio_device_all_irq(dev);
enable_fmc_dio_device_irq(dev, TEST_FMC_DIO_CH);
flush_fmc_dio_device_channel(dev, TEST_FMC_DIO_CH);
setup_fmc_dio_device_irq(dev, user_arguments->irq_period, TEST_FMC_DIO_COUNT);
/* Configure stdin as non-blocking. It is required for the user check exit function */
set_stdin_as_nonblocking();
/* Save FMC DIO dev in globals for the signal handlers */
global_fmc_dev = dev;
/* Main loop of IRQ demo (until user requests to exit) */
demo_irq_process_loop(dev, sengine);
/* Exit sequence */
setup_fmc_dio_device_irq(dev, user_arguments->irq_period, 0);
sleep(1);
/* Disable all interrupts */
set_fmc_dio_device_all_irq_state(dev, prev_irq_state);
out_fmc_dio_device:
/* Close FMC DIO device */
close_fmc_dio_device(dev);
out_stats_engine:
/* Close stats engine */
destroy_stats_engine(sengine);
out_user_args:
/* Free resources for user arguments */
destroy_user_arguments(user_arguments);
out_log:
/* Close loggers */
destroy_log_device(stats_log);
destroy_log_device(gen_log);
return ret;
}
static void demo_irq_process_loop(fmc_dio_device fmc_dev, stats_engine engine)
{
struct usr_timestamp *ts;
unsigned int nts;
int user_stop = 0;
int ret;
/* Process loop:
* - Blocking: get timestamps from FMC DIO device (specific channel under testing)
* - Pass them to the stats engine and generate the statistics
* - Check if user has requested to stop the DEMO
*/
do {
ret = get_utc_ts_from_fmc_dio_device(fmc_dev, TEST_FMC_DIO_CH, &ts, &nts);
if(!ret) {
// Use only the last TS for stats
process_timestamps_to_engine(engine, ts, nts, 1);
}
user_stop = check_user_stop();
} while(!user_stop);
}
static void process_timestamps_to_engine(stats_engine engine, struct usr_timestamp *ts,
unsigned int nts, int last_only)
{
struct usr_timestamp *ts_to_process = ts;
unsigned int nts_to_process = nts;
if(last_only) {
ts_to_process = &ts[nts-1];
nts_to_process = 1;
}
for(int i = 0 ; i < nts_to_process ; i++) {
/* Pass a timestamp to stats engine */
add_usr_timestamp_to_stats_engine(engine, &ts_to_process[i], global_user_arguments->clock);
/* Compute stats taking into consideration all the timestamps inside the engine */
run_stats_engine(engine, verbose_mode);
}
/* Finally, free memory for timestamps (reserved by FMC DIO device) */
free(ts);
}
static user_args create_user_arguments(log_device log)
{
user_args arguments;
arguments = calloc(1, sizeof(*arguments));
arguments->err_log = log;
return arguments;
}
static int parse_user_arguments(int argc, char *argv[], user_args parsed_args)
{
int opt;
parsed_args->irq_period = TEST_FMC_DIO_PERIOD;
parsed_args->verbose = 0;
if(argc == 1) {
show_help();
return 1;
}
while((opt = getopt(argc, argv, "hvf:p:c:")) != -1) {
switch(opt) {
case 'f':
strncpy(parsed_args->fmc_dev_path, optarg, MAX_FMC_DIO_PATH-1);
break;
case 'p':
sscanf(optarg, "%d", &parsed_args->irq_period);
break;
case 'v':
parsed_args->verbose = 1;
break;
case 'c':
if(strcmp(optarg,"MONOTONIC")==0)
parsed_args->clock=MONOTONIC;
else
parsed_args->clock=REALTIME;
break;
case 'h':
show_help();
return 1;
default:
goto out_err;
}
}
if(check_unknown_user_arguments(optind, argc, argv)) {
goto out_err;
}
return 0;
out_err:
show_help();
send_to_log_device(parsed_args->err_log, "Error parsing user arguments\n");
return 1;
}
static void destroy_user_arguments(user_args args)
{
if(args) {
free(args);
}
}
static void show_help(void)
{
printf("%s -f <FMC DIO device path> [options]\n", PROG_NAME);
printf("\t -f <path> \tSet FMC DIO device path\n");
printf("\t -p <period> \tSet IRQ period (in nanoseconds)\n");
printf("\t -c <REALTIME/MONOTONIC> \tSet the clock mode (REALTIME by default)\n");
printf("\t -v \t\tEnable verbose mode\n");
printf("\t -h \t\tShow this help message\n");
printf("Please, press 'q' key + ENTER or CNTRL+C to exit from the demo tool\n");
}
static int check_unknown_user_arguments(int optind, int argc, char **argv)
{
int ret = 0;
if (optind < argc) {
printf ("Unknown options: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
ret = 1;
}
return ret;
}
static unsigned int check_user_stop(void)
{
char c;
c = getchar();
return (c == 'q');
}
static void set_stdin_as_nonblocking(void)
{
fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
}
static void exit_abruptly(int sig)
{
setup_fmc_dio_device_irq(global_fmc_dev, global_user_arguments->irq_period, 0);
sleep(1);
set_fmc_dio_device_all_irq_state(global_fmc_dev, prev_irq_state);
exit(0);
}
......@@ -20,7 +20,10 @@ ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\"
obj-m += wr-dio.o
wr-dio-y = fmc-dio.o
wr-dio-y = ./hw/wr-dio-regs.o
wr-dio-y += ./hw/wr-dio-regs_v1.o
wr-dio-y += ./hw/wr-dio-regs_v2.o
wr-dio-y += fmc-dio.o
wr-dio-y += fmc-dio-internal.o
wr-dio-y += fmc-dio-mdev.o
wr-dio-y += fmc-dio-gpio.o
\ No newline at end of file
......@@ -19,11 +19,14 @@
#include <linux/wait.h>
#include <linux/ktime.h>
#include <linux/atomic.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/fmc.h>
#include <linux/fmc-sdb.h>
#include <linux/delay.h>
#include "fmc-dio.h"
#ifdef DIO_STAT
......@@ -32,79 +35,28 @@
#define fmc_dio_stat 0
#endif
/* We need a clear mapping for the registers of the various bits */
struct regmap {
int trig_l;
int trig_h;
int cycle;
int pulse;
int fifo_tai_l;
int fifo_tai_h;
int fifo_cycle;
int fifo_status;
};
#define R(x) (offsetof(struct DIO_WB, x))
static struct regmap regmap[] = {
{
.trig_l = R(TRIG0),
.trig_h = R(TRIGH0),
.cycle = R(CYC0),
.pulse = R(PROG0_PULSE),
.fifo_tai_l = R(TSF0_R0),
.fifo_tai_h = R(TSF0_R1),
.fifo_cycle = R(TSF0_R2),
.fifo_status = R(TSF0_CSR),
}, {
.trig_l = R(TRIG1),
.trig_h = R(TRIGH1),
.cycle = R(CYC1),
.pulse = R(PROG1_PULSE),
.fifo_tai_l = R(TSF1_R0),
.fifo_tai_h = R(TSF1_R1),
.fifo_cycle = R(TSF1_R2),
.fifo_status = R(TSF1_CSR),
}, {
.trig_l = R(TRIG2),
.trig_h = R(TRIGH2),
.cycle = R(CYC2),
.pulse = R(PROG2_PULSE),
.fifo_tai_l = R(TSF2_R0),
.fifo_tai_h = R(TSF2_R1),
.fifo_cycle = R(TSF2_R2),
.fifo_status = R(TSF2_CSR),
}, {
.trig_l = R(TRIG3),
.trig_h = R(TRIGH3),
.cycle = R(CYC3),
.pulse = R(PROG3_PULSE),
.fifo_tai_l = R(TSF3_R0),
.fifo_tai_h = R(TSF3_R1),
.fifo_cycle = R(TSF3_R2),
.fifo_status = R(TSF3_CSR),
}, {
.trig_l = R(TRIG4),
.trig_h = R(TRIGH4),
.cycle = R(CYC4),
.pulse = R(PROG4_PULSE),
.fifo_tai_l = R(TSF4_R0),
.fifo_tai_h = R(TSF4_R1),
.fifo_cycle = R(TSF4_R2),
.fifo_status = R(TSF4_CSR),
}
};
#define CHANNEL_5_IRQ_EN_MASK 0x100000
#define FMC_DIO_IRQ_MASK \
#define FMC_DIO_IRQ_MASK \
(DIO_EIC_ISR_NEMPTY_0 \
| DIO_EIC_ISR_NEMPTY_1 \
| DIO_EIC_ISR_NEMPTY_2 \
| DIO_EIC_ISR_NEMPTY_1\
| DIO_EIC_ISR_NEMPTY_2\
| DIO_EIC_ISR_NEMPTY_3\
| DIO_EIC_ISR_NEMPTY_4)
#define FMC_DIO_IRQ_MASK_V2 \
(DIO_EIC_ISR_NEMPTY_0 \
| DIO_EIC_ISR_NEMPTY_1\
| DIO_EIC_ISR_NEMPTY_2\
| DIO_EIC_ISR_NEMPTY_3\
| DIO_EIC_ISR_NEMPTY_4\
| DIO_EIC_ISR_NEMPTY_5)
/* This is the structure we need to manage interrupts and loop internally */
#define FMC_DIO_BUFFER_LEN 512
struct dio_channel {
struct timespec tsbuf[FMC_DIO_BUFFER_LEN];
struct wr_timestamp_info wr_ts_info_buf[FMC_DIO_BUFFER_LEN];
int bhead, btail;
wait_queue_head_t q;
......@@ -115,7 +67,7 @@ struct dio_channel {
};
struct dio_device {
struct dio_channel ch[5];
struct dio_channel ch[6];
};
/* Instead of timespec_sub, just subtract the nanos */
......@@ -128,25 +80,27 @@ static inline void fmc_dio_int_ts_sub(struct timespec *ts, int nano)
static void __fmc_dio_int_new_pulse(struct fmc_dio *dev, int ch,
struct timespec *ts)
{
struct DIO_WB __iomem *dio = dev->dio;
void __iomem *base = dio;
void __iomem *base = dev->dio;
struct regmap *map;
map = regmap + ch;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
fmc_dio_int_ts_sub(ts, 8); /* 1 cycle, to account for output latencies */
map = get_regmap(dev->version);
map += ch;
fmc_dio_int_ts_sub(ts, 16); /* 2 cycles, to account for output latencies */
writel(ts->tv_nsec / 8, base + map->cycle);
writel(GET_HI32(ts->tv_sec), base + map->trig_h);
writel(ts->tv_sec, base + map->trig_l);
writel(1 << ch, &dio->R_LATCH);
writel(1 << ch, base + dio.latch_reg);
}
static int fmc_dio_int_cmd_pulse(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
struct DIO_WB __iomem *dio = dev->dio;
void __iomem *base = dio;
void __iomem *base = dev->dio;
struct PPSG_WB __iomem *ppsg = dev->ppsg;
struct dio_device *d = dev->priv;
struct dio_channel *c;
......@@ -154,31 +108,68 @@ static int fmc_dio_int_cmd_pulse(struct fmc_dio *dev,
struct timespec *ts;
uint32_t reg;
int ch;
struct regmap_common dio;
uint32_t pulse_per_loaded;
dio = get_regmap_common(dev->version);
ch = cmd->channel;
if (ch > 4)
return -EINVAL; /* mask not supported */
c = d->ch + ch;
map = regmap + ch;
map = get_regmap(dev->version);
map += ch;
ts = cmd->t;
/* First, configure this bit as DIO output */
reg = readl(&dio->IOMODE);
writel(reg | (1 << 4*ch), &dio->IOMODE);
reg = readl(base + dio.iomode_reg);
writel(reg | (1 << 4*ch), base + dio.iomode_reg);
/* Clear width and period registers */
pulse_per_loaded = readl(base + map->pulse_per);
writel(0, base + map->pulse_per);
writel(1, base + map->pulse); //Set to 1 to avoid 3 second pulse due to compensation into gw
writel(1 << ch, base + dio.latch_reg);
atomic_set(&c->count, 0);
if(cmd->flags & WR_DIO_F_REL)
{
pulse_per_loaded *= 8;
msleep(pulse_per_loaded/1000000);
}
if(cmd->value == 0 && cmd->flags & WR_DIO_F_LOOP)
return 0;
writel(ts[1].tv_nsec / 8, base + map->pulse); /* width */
//if(cmd->value == 0)
// return 0;
if (cmd->flags & WR_DIO_F_NOW) {
/* Generate a pulse train from current time in V2 DIO version*/
if(dev->version == 1) {
if (cmd->flags & WR_DIO_F_LOOP && cmd->value != 1) {
writel(ts[2].tv_nsec / 8, base + map->pulse_per);
c->target_channel = ch;
cmd->value-=2;
atomic_set(&c->count, cmd->value);
}
}
/* if "now" we are done */
writel(1 << ch, &dio->PULSE);
writel(1 << ch, base + dio.pulse_reg);
return 0;
}
/* if relative, add current 40-bit second to timespec */
if (cmd->flags & WR_DIO_F_REL) {
if (cmd->flags & WR_DIO_F_REL) {
uint32_t h1, l, h2;
unsigned long now;
h1 = readl(&ppsg->CNTR_UTCHI);
l = readl(&ppsg->CNTR_UTCLO);
h2 = readl(&ppsg->CNTR_UTCHI);
......@@ -189,27 +180,75 @@ static int fmc_dio_int_cmd_pulse(struct fmc_dio *dev,
ts->tv_sec += now;
}
if (cmd->flags & WR_DIO_F_LOOP) {
if (cmd->flags & WR_DIO_F_LOOP && cmd->value != 1) {
c->target_channel = ch;
if(dev->version == 0) {
c->delay = ts[2];
/* c->count is used after the pulse, so remove the first */
if (cmd->value > 0)
cmd->value--;
}
else {
writel(ts[2].tv_nsec / 8, base + map->pulse_per);
cmd->value-=2;
}
/* c->count is used after the pulse, so remove the first */
if (cmd->value > 0)
cmd->value--;
atomic_set(&c->count, cmd->value);
c->prevts = ts[0]; /* our current setpoint */
c->delay = ts[2];
}
__fmc_dio_int_new_pulse(dev, ch, ts);
return 0;
}
static int fmc_dio_int_cmd_update_width(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
void __iomem *base = dev->dio;
struct dio_device *d = dev->priv;
struct dio_channel *c;
struct regmap *map;
struct timespec *ts;
int ch;
struct regmap_common dio;
uint32_t period;
if(dev->version == 0){
return -EINVAL;
}
dio = get_regmap_common(dev->version);
ch = cmd->channel;
if (ch > 4)
return -EINVAL; /* mask not supported */
c = d->ch + ch;
map = get_regmap(dev->version);
map += ch;
ts = cmd->t;
period = readl(base + map->pulse_per);
if(ts[1].tv_nsec / 8 < period)
{
writel(ts[1].tv_nsec / 8, base + map->pulse);
writel(1 << ch, base + dio.latch_reg);
}
else
return -EINVAL;
return 0;
}
static int fmc_dio_int_cmd_stamp(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
struct dio_device *d = dev->priv;
struct dio_channel *c = 0;
struct timespec *ts = cmd->t;
struct wr_timestamp_info *ts_info = cmd->wr_ts_info_buf;
struct regmap *map;
int mask, ch, last;
int nstamp = 0;
......@@ -221,7 +260,10 @@ static int fmc_dio_int_cmd_stamp(struct fmc_dio *dev,
again:
if (cmd->flags & WR_DIO_F_MASK) {
ch = 0;
last = 4;
if(dev->version == 0)
last = 4;
else
last = 5;
mask = cmd->channel;
} else {
ch = cmd->channel;
......@@ -233,16 +275,21 @@ again:
for (; ch <= last; ch++, c++) {
if (((1 << ch) & mask) == 0)
continue;
map = regmap + ch;
map = get_regmap(dev->version);
map += ch;
while (1) {
if (nstamp == WR_DIO_N_STAMP)
break;
if (c->bhead == c->btail)
break;
*ts = c->tsbuf[c->btail];
*ts_info = c->wr_ts_info_buf[c->btail];
c->btail = (c->btail + 1) % FMC_DIO_BUFFER_LEN;
nstamp++;
ts++;
ts_info++;
}
if (nstamp) {
cmd->channel = ch;
......@@ -253,10 +300,23 @@ again:
/* The user may asketo wait for timestamps, but for 1 channel only */
if (!nstamp && cmd->flags & WR_DIO_F_WAIT) {
int ret_wait;
ch--; c--; /* The for above incremeted them */
try_module_get(THIS_MODULE);
wait_event_interruptible(c->q, c->bhead != c->btail);
if(cmd->wait_mode_flags & WR_DIO_F_WAIT_MODE_TIMEOUT) {
unsigned long tmo = timespec_to_jiffies(&(cmd->wait_mode_timeout));
ret_wait = wait_event_interruptible_timeout(c->q, c->bhead != c->btail, tmo);
if(!ret_wait)
ret_wait = -ETIMEDOUT;
else
ret_wait = 0;
}
else {
ret_wait = wait_event_interruptible(c->q, c->bhead != c->btail);
}
module_put(THIS_MODULE);
if(ret_wait)
return ret_wait;
if (signal_pending(current))
return -ERESTARTSYS;
goto again;
......@@ -270,10 +330,13 @@ again:
static int fmc_dio_int_cmd_inout(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
struct DIO_WB __iomem *dio = dev->dio;
struct fmc_dio_gpio_block __iomem *gpio = dev->gpio;
int mask, ch, last, bits;
uint32_t reg, iomode;
void __iomem *base = dev->dio;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
if (cmd->flags & WR_DIO_F_MASK) {
ch = 0;
......@@ -294,7 +357,7 @@ static int fmc_dio_int_cmd_inout(struct fmc_dio *dev,
bits = cmd->value >> ch;
/* Obtain the current value in iomode */
reg = readl(&dio->IOMODE) & ~(0xF << 4*ch);
reg = readl(base + dio.iomode_reg) & ~(0xF << 4*ch);
/* Select IO mode */
if (bits & WR_DIO_INOUT_DIO) {
......@@ -315,11 +378,141 @@ static int fmc_dio_int_cmd_inout(struct fmc_dio *dev,
/* Appends to iomode TERM and OUTPUT_ENABLE_N bits */
iomode |= (((bits & WR_DIO_INOUT_TERM) != 0) << 3)
| (((bits & WR_DIO_INOUT_OUTPUT) == 0) << 2);
writel(reg | (iomode << 4*ch), &dio->IOMODE);
writel(reg | (iomode << 4*ch), base + dio.iomode_reg);
}
return 0;
}
static int fmc_dio_int_cmd_mask_irq(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
struct fmc_dio_gpio_block __iomem *gpio = dev->gpio;
int mask, ch, last, bits;
uint32_t reg, iomode;
void __iomem *base = dev->dio;
if(dev->version == 0){ //Not implemented in old version
return -EINVAL;
}
struct regmap_common dio;
dio = get_regmap_common(dev->version);
if (cmd->value == WR_DIO_F_MASK_READ_IRQ) {
reg = readl(base + dio.eic_imr_reg);
if(reg & cmd->channel) {
cmd->value = WR_DIO_F_MASK_ENABLE_IRQ;
return 0;
} else {
cmd->value = WR_DIO_F_MASK_DISABLE_IRQ;
return 0;
}
} else if (cmd->value == WR_DIO_F_MASK_ENABLE_IRQ) {
writel(cmd->channel, base + dio.eic_ier_reg);
} else if (cmd->value == WR_DIO_F_MASK_DISABLE_IRQ) {
writel(cmd->channel, base + dio.eic_idr_reg);
} else {
return -1;
}
return 0;
}
static int fmc_dio_int_cmd_irq(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
void __iomem *base = dev->dio;
struct PPSG_WB __iomem *ppsg = dev->ppsg;
struct dio_device *d = dev->priv;
struct dio_channel *c;
struct regmap *map;
struct timespec *ts;
uint32_t reg;
int ch;
struct regmap_common dio;
uint32_t pulse_per_loaded;
if(dev->version != 1)
return -ENOTSUPP;
dio = get_regmap_common(dev->version);
ch = 5;
c = d->ch + ch;
map = get_regmap(dev->version);
map += ch;
ts = cmd->t;
pulse_per_loaded = readl(base + map->pulse_per);
writel(0, base + map->pulse_per);
writel(1, base + map->pulse); //Set to 1 to avoid 3 second pulse due to compensation into gw
writel(1 << ch, base + dio.latch_reg);
atomic_set(&c->count, 0);
if(cmd->flags & WR_DIO_F_REL)
{
pulse_per_loaded *= 8;
msleep(pulse_per_loaded/1000000);
}
if(cmd->value == 0 && cmd->flags & WR_DIO_F_LOOP)
return 0;
/* First, configure the IRQ channel */
reg = readl(base + dio.iomode_reg);
writel((reg | CHANNEL_5_IRQ_EN_MASK), base + dio.iomode_reg);
writel(100, base + map->pulse); /* width */
if (cmd->flags & WR_DIO_F_NOW) {
/* Generate a pulse train from current time*/
if (cmd->flags & WR_DIO_F_LOOP && cmd->value != 1) {
writel(ts[1].tv_nsec / 8, base + map->pulse_per);
c->target_channel = ch;
cmd->value-=2;
atomic_set(&c->count, cmd->value);
}
writel(1 << ch, base + dio.pulse_reg);
return 0;
}
/* if relative, add current 40-bit second to timespec */
if (cmd->flags & WR_DIO_F_REL) {
uint32_t h1, l, h2;
unsigned long now;
h1 = readl(&ppsg->CNTR_UTCHI);
l = readl(&ppsg->CNTR_UTCLO);
h2 = readl(&ppsg->CNTR_UTCHI);
if (h2 != h1)
l = readl(&ppsg->CNTR_UTCLO);
now = l;
SET_HI32(now, h2);
ts->tv_sec += now;
}
if (cmd->flags & WR_DIO_F_LOOP && cmd->value != 1) {
c->target_channel = ch;
/* Configure period */
writel( (ts[1].tv_nsec / 8) + (ts[1].tv_sec * 1000000000 / 8), base + map->pulse_per);
cmd->value-=2;
atomic_set(&c->count, cmd->value);
c->prevts = ts[0]; /* our current setpoint */
}
__fmc_dio_int_new_pulse(dev, ch, ts);
return 0;
}
int fmc_dio_int_ioctl(struct fmc_dio *dev, unsigned int ioctlcmd,
unsigned long arg)
......@@ -359,6 +552,15 @@ int fmc_dio_int_ioctl(struct fmc_dio *dev, unsigned int ioctlcmd,
case WR_DIO_CMD_DAC:
ret = -ENOTSUPP;
goto out;
case WR_DIO_CMD_IRQ:
ret = fmc_dio_int_cmd_irq(dev, cmd);
break;
case WR_DIO_CMD_UPDATE_WIDTH:
ret = fmc_dio_int_cmd_update_width(dev, cmd);
break;
case WR_DIO_CMD_MASK_IRQ:
ret = fmc_dio_int_cmd_mask_irq(dev, cmd);
break;
default:
ret = -EINVAL;
goto out;
......@@ -397,7 +599,6 @@ static void fmc_dio_int_trig_next_pulse(struct fmc_dio *dev, int ch,
irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
{
struct DIO_WB __iomem *dio = dev->dio;
struct fmc_device *fmc = dev->fmc;
void __iomem *base = dev->dio;
struct dio_device *d = dev->priv;
......@@ -405,14 +606,18 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
static int rate_avg;
struct dio_channel *c;
struct timespec *ts;
struct wr_timestamp_info *ts_info;
struct regmap *map;
uint32_t mask, reg;
int ch, chm;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
if (unlikely(!fmc->eeprom)) {
dev_err(fmc->hwdev, "WR-DIO: No mezzanine, disabling irqs\n");
writel(~0, &dio->EIC_IDR);
writel(~0, &dio->EIC_ISR);
writel(~0, base + dio.eic_idr_reg);
writel(~0, base + dio.eic_isr_reg);
return IRQ_NONE;
}
......@@ -439,7 +644,10 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
}
}
mask = readl(&dio->EIC_ISR) & FMC_DIO_IRQ_MASK;
if(dev->version == 0)
mask = readl(base + dio.eic_isr_reg) & FMC_DIO_IRQ_MASK;
else
mask = readl(base + dio.eic_isr_reg) & FMC_DIO_IRQ_MASK_V2;
/* Three indexes: channel, channel-mask, channel pointer */
for (ch = 0, chm = 1, c = d->ch; mask; ch++, chm <<= 1, c++) {
......@@ -450,14 +658,18 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
mask &= ~chm;
/* Pull the FIFOs to the device structure */
map = regmap + ch;
map = get_regmap(dev->version);
map += ch;
ts = NULL;
ts_info = NULL;
while (1) {
reg = readl(base + map->fifo_status);
if (reg & 0x20000) /* empty */
break;
h = c->bhead;
ts = c->tsbuf + h;
ts_info = c->wr_ts_info_buf + h;
c->bhead = (h + 1) % FMC_DIO_BUFFER_LEN;
if (c->bhead == c->btail)
c->btail = (c->btail + 1) % FMC_DIO_BUFFER_LEN;
......@@ -469,13 +681,40 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
SET_HI32(ts->tv_sec, readl(base + map->fifo_tai_h));
ts->tv_sec |= readl(base + map->fifo_tai_l);
ts->tv_nsec = 8 * readl(base + map->fifo_cycle);
/* subtract 5 cycles lost in input sync circuits */
fmc_dio_int_ts_sub(ts, 40);
uint32_t leap_second_reg = readl(base + map->fifo_leap_second);
ts_info->leap_second = leap_second_reg & DIO_TSF_R3_LEAP_SECOND_VALUE_MASK;
ts_info->leap_second_valid = (leap_second_reg >> DIO_TSF_R3_LEAP_SECOND_VALID_SHIFT) & 1;
ts_info->flag59 = (leap_second_reg >> DIO_TSF_R3_LEAP_SECOND_FLAG_59_SHIFT) & 1;
ts_info->flag61 = (leap_second_reg >> DIO_TSF_R3_LEAP_SECOND_FLAG_61_SHIFT) & 1;
/* subtract 4 cycles lost in input sync circuits */
fmc_dio_int_ts_sub(ts, 32);
}
writel(chm, &dio->EIC_ISR); /* ack */
if (ts && atomic_read(&c->count) != 0) {
fmc_dio_int_trig_next_pulse(dev, ch, c, ts);
writel(chm, base + dio.eic_isr_reg); /* ack */
if(dev->version == 0) {
if (ts && atomic_read(&c->count) != 0 ) {
/* Only program new pulse if we are on the DIO V1 */
fmc_dio_int_trig_next_pulse(dev, ch, c, ts);
}
}
else
{
if(atomic_read(&c->count) == 0) {
/* If we are on the DIO V2, clear pulse period register
* when all the pulses have been generated
*/
writel(0, base + map->pulse_per);
writel(1 << ch, base + dio.latch_reg);
}
else {
/* If the count is not-infinite, decrement it */
if (atomic_read(&c->count) > 0)
atomic_dec(&c->count);
}
}
wake_up_interruptible(&c->q);
}
t_end = ktime_get();
......@@ -485,10 +724,13 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
/* Init and exit below are called when a netdevice is created/destroyed */
int fmc_dio_internal_create(struct fmc_dio *dev)
{
struct DIO_WB __iomem *dio = dev->dio;
struct dio_device *d;
void __iomem *base = dev->dio;
int i;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
/* Allocate the data structure and enable interrupts for stamping */
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d)
......@@ -501,15 +743,21 @@ int fmc_dio_internal_create(struct fmc_dio *dev)
* Enable interrupts for FIFO, if there's no mezzanine the
* handler will notice and disable the interrupts
*/
writel(FMC_DIO_IRQ_MASK, &dio->EIC_IER);
if(dev->version == 0)
writel(FMC_DIO_IRQ_MASK, base + dio.eic_ier_reg);
else
writel(FMC_DIO_IRQ_MASK_V2, base + dio.eic_ier_reg);
return 0;
}
void fmc_dio_internal_destroy(struct fmc_dio *dev)
{
struct DIO_WB __iomem *dio = dev->dio;
struct regmap_common dio;
void __iomem *base = dev->dio;
dio = get_regmap_common(dev->version);
writel(~0, &dio->EIC_IDR);
writel(~0, base + dio.eic_idr_reg);
if (dev->priv)
kfree(dev->priv);
}
......
......@@ -55,7 +55,7 @@ static int fmc_dio_resource_map(struct fmc_dio *dio)
{
int i,err;
struct platform_device *dev = dio->pdev;
struct fmc_device *fmc = dio->fmc;
//struct fmc_device *fmc = dio->fmc;
struct resource *r;
void __iomem *mem;
......@@ -170,7 +170,19 @@ static int fmc_dio_pl_probe(struct platform_device *dev)
// Specific board info
dio->board = dev->id_entry->driver_data;
dio->pdev = dev;
dio->version = dio->board;
if(dio->version == FMC_DIO_BOARD_SPEC) {
printk("DIO driver. Detected DIO V1");
}
else if(dio->version == FMC_DIOv2_BOARD_SPEC) {
printk("DIO driver. Detected DIO V2");
}
else{
printk("DIO driver. DIO not detected");
}
/* Map the resources for the FMC DIO */
ret = fmc_dio_resource_map(dio);
if(ret)
......@@ -239,6 +251,10 @@ static const struct platform_device_id fmc_dio_id_table[] = {
.name = "fmc-dio-spec",
.driver_data = FMC_DIO_BOARD_SPEC,
},
{ /* SPEC compatible */
.name = "fmc-diov2-spec",
.driver_data = FMC_DIOv2_BOARD_SPEC,
},
{},
};
......
......@@ -52,6 +52,7 @@ struct fmc_dio_gpio_block {
/* Board constants */
#define FMC_DIO_BOARD_SPEC 0
#define FMC_DIOv2_BOARD_SPEC 1
/**
* @brief FMC DIO structure
......@@ -74,6 +75,8 @@ struct fmc_dio {
int board; /**< Board info */
int version; //*< HDL version */
void *priv; /**< Private data for FMC DIO */
};
......@@ -104,6 +107,9 @@ enum wr_dio_cmd_name {
WR_DIO_CMD_STAMP,
WR_DIO_CMD_DAC,
WR_DIO_CMD_INOUT,
WR_DIO_CMD_IRQ,
WR_DIO_CMD_UPDATE_WIDTH,
WR_DIO_CMD_MASK_IRQ,
};
/*
......@@ -141,13 +147,23 @@ enum wr_dio_cmd_name {
#define WR_DIO_N_STAMP 16 /* At least 5 * 3 */
struct wr_timestamp_info {
uint16_t leap_second;
int leap_second_valid;
int flag59;
int flag61;
};
struct wr_dio_cmd {
uint16_t command; /* from user */
uint16_t channel; /* 0..4 or mask from user */
uint32_t value; /* for DAC or I/O */
uint32_t flags;
uint32_t nstamp; /* from kernel, if IN_STAMP */
struct timespec t[WR_DIO_N_STAMP]; /* may be from user */
struct timespec t[WR_DIO_N_STAMP];
struct wr_timestamp_info wr_ts_info_buf[WR_DIO_N_STAMP];
uint32_t wait_mode_flags;
struct timespec wait_mode_timeout;
};
#define WR_DIO_F_NOW 0x01 /* Output is now, t[0] ignored */
......@@ -155,3 +171,8 @@ struct wr_dio_cmd {
#define WR_DIO_F_MASK 0x04 /* Channel is 0x00..0x1f */
#define WR_DIO_F_LOOP 0x08 /* Output should loop: t[2] is looping*/
#define WR_DIO_F_WAIT 0x10 /* Wait for event */
#define WR_DIO_F_MASK_READ_IRQ 0x20
#define WR_DIO_F_MASK_ENABLE_IRQ 0x40
#define WR_DIO_F_MASK_DISABLE_IRQ 0x80
#define WR_DIO_F_WAIT_MODE_NORM 0x00
#define WR_DIO_F_WAIT_MODE_TIMEOUT 0x01
#include "wr-dio-regs.h"
struct regmap *get_regmap(unsigned int ver)
{
if(ver == 0)
return regmap_v1;
else
return regmap_v2;
}
struct regmap_common get_regmap_common(unsigned int ver)
{
if(ver == 0)
return regmap_common_v1;
else
return regmap_common_v2;
}
\ No newline at end of file
/*
Register definitions for slave core: FMC-DIO-5chttla
* File : wr-dio-regs.h
* Author : auto-generated by wbgen2 from wr-dio-regs.wb
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr-dio-regs.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_WR_DIO
#define __WBGEN2_REGDEFS_WR_DIO
......@@ -26,346 +14,38 @@
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: fmc-dio 0 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 0 seconds-based trigger for pulse generation */
#define DIO_TRIG0_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG0_SECONDS_SHIFT 0
#define DIO_TRIG0_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG0_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 0 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 0 seconds-based trigger for pulse generation */
#define DIO_TRIGH0_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH0_SECONDS_SHIFT 0
#define DIO_TRIGH0_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH0_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 0 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 0 cycles to trigger a pulse generation */
#define DIO_CYC0_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC0_CYC_SHIFT 0
#define DIO_CYC0_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC0_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio 1 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 1 seconds-based trigger for pulse generation */
#define DIO_TRIG1_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG1_SECONDS_SHIFT 0
#define DIO_TRIG1_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG1_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 1 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 1 seconds-based trigger for pulse generation */
#define DIO_TRIGH1_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH1_SECONDS_SHIFT 0
#define DIO_TRIGH1_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH1_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 1 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 1 cycles to trigger a pulse generation */
#define DIO_CYC1_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC1_CYC_SHIFT 0
#define DIO_CYC1_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC1_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio 2 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 2 seconds-based trigger for pulse generation */
#define DIO_TRIG2_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG2_SECONDS_SHIFT 0
#define DIO_TRIG2_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG2_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 2 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 2 seconds-based trigger for pulse generation */
#define DIO_TRIGH2_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH2_SECONDS_SHIFT 0
#define DIO_TRIGH2_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH2_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 2 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 2 cycles to trigger a pulse generation */
#define DIO_CYC2_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC2_CYC_SHIFT 0
#define DIO_CYC2_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC2_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio 3 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 3 seconds-based trigger for pulse generation */
#define DIO_TRIG3_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG3_SECONDS_SHIFT 0
#define DIO_TRIG3_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG3_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 3 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 3 seconds-based trigger for pulse generation */
#define DIO_TRIGH3_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH3_SECONDS_SHIFT 0
#define DIO_TRIGH3_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH3_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 3 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 3 cycles to trigger a pulse generation */
#define DIO_CYC3_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC3_CYC_SHIFT 0
#define DIO_CYC3_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC3_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio 4 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 4 seconds-based trigger for pulse generation */
#define DIO_TRIG4_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG4_SECONDS_SHIFT 0
#define DIO_TRIG4_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG4_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 4 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 4 seconds-based trigger for pulse generation */
#define DIO_TRIGH4_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH4_SECONDS_SHIFT 0
#define DIO_TRIGH4_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH4_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 4 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 4 cycles to trigger a pulse generation */
#define DIO_CYC4_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC4_CYC_SHIFT 0
#define DIO_CYC4_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC4_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FMC-DIO input/output configuration register. */
/* definitions for field: channel0 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH0_MASK WBGEN2_GEN_MASK(0, 4)
#define DIO_IOMODE_CH0_SHIFT 0
#define DIO_IOMODE_CH0_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define DIO_IOMODE_CH0_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for field: channel1 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH1_MASK WBGEN2_GEN_MASK(4, 4)
#define DIO_IOMODE_CH1_SHIFT 4
#define DIO_IOMODE_CH1_W(value) WBGEN2_GEN_WRITE(value, 4, 4)
#define DIO_IOMODE_CH1_R(reg) WBGEN2_GEN_READ(reg, 4, 4)
/* definitions for field: channel2 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH2_MASK WBGEN2_GEN_MASK(8, 4)
#define DIO_IOMODE_CH2_SHIFT 8
#define DIO_IOMODE_CH2_W(value) WBGEN2_GEN_WRITE(value, 8, 4)
#define DIO_IOMODE_CH2_R(reg) WBGEN2_GEN_READ(reg, 8, 4)
/* definitions for field: channel3 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH3_MASK WBGEN2_GEN_MASK(12, 4)
#define DIO_IOMODE_CH3_SHIFT 12
#define DIO_IOMODE_CH3_W(value) WBGEN2_GEN_WRITE(value, 12, 4)
#define DIO_IOMODE_CH3_R(reg) WBGEN2_GEN_READ(reg, 12, 4)
/* definitions for field: channel4 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH4_MASK WBGEN2_GEN_MASK(16, 4)
#define DIO_IOMODE_CH4_SHIFT 16
#define DIO_IOMODE_CH4_W(value) WBGEN2_GEN_WRITE(value, 16, 4)
#define DIO_IOMODE_CH4_R(reg) WBGEN2_GEN_READ(reg, 16, 4)
/* definitions for register: Time-programmable output strobe signal */
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH4 WBGEN2_GEN_MASK(4, 1)
/* definitions for register: FMC-DIO time trigger is ready to accept a new trigger generation request */
/* definitions for field: trig_rdy field in reg: FMC-DIO time trigger is ready to accept a new trigger generation request */
#define DIO_TRIG_RDY_MASK WBGEN2_GEN_MASK(0, 5)
#define DIO_TRIG_RDY_SHIFT 0
#define DIO_TRIG_RDY_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define DIO_TRIG_RDY_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for register: fmc-dio channel 0 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 0 in reg: fmc-dio channel 0 Programmable/immediate output pulse length */
#define DIO_PROG0_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG0_PULSE_LENGTH_SHIFT 0
#define DIO_PROG0_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG0_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio channel 1 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 1 in reg: fmc-dio channel 1 Programmable/immediate output pulse length */
#define DIO_PROG1_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG1_PULSE_LENGTH_SHIFT 0
#define DIO_PROG1_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG1_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio channel 2 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 2 in reg: fmc-dio channel 2 Programmable/immediate output pulse length */
#define DIO_PROG2_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG2_PULSE_LENGTH_SHIFT 0
#define DIO_PROG2_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG2_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio channel 3 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 3 in reg: fmc-dio channel 3 Programmable/immediate output pulse length */
#define DIO_PROG3_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG3_PULSE_LENGTH_SHIFT 0
#define DIO_PROG3_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG3_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio channel 4 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 4 in reg: fmc-dio channel 4 Programmable/immediate output pulse length */
#define DIO_PROG4_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG4_PULSE_LENGTH_SHIFT 0
#define DIO_PROG4_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG4_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: Pulse generate immediately */
/* definitions for field: pulse_gen_now_0 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: pulse_gen_now_1 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: pulse_gen_now_2 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: pulse_gen_now_3 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: pulse_gen_now_4 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for register: Interrupt disable register */
/* definitions for field: dio fifo not-empty 0 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: dio fifo not-empty 1 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: dio fifo not-empty 2 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: dio fifo not-empty 3 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: dio fifo not-empty 4 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Channel 0 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_0 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Channel 1 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_1 WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Channel 2 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_2 WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Channel 3 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_3 WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Channel 4 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_4 WBGEN2_GEN_MASK(9, 1)
/* definitions for register: Interrupt enable register */
/* definitions for field: dio fifo not-empty 0 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: dio fifo not-empty 1 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: dio fifo not-empty 2 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: dio fifo not-empty 3 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: dio fifo not-empty 4 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Channel 0 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_0 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Channel 1 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_1 WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Channel 2 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_2 WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Channel 3 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_3 WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Channel 4 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_4 WBGEN2_GEN_MASK(9, 1)
/* definitions for register: Interrupt mask register */
/* definitions for field: dio fifo not-empty 0 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: dio fifo not-empty 1 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: dio fifo not-empty 2 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: dio fifo not-empty 3 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: dio fifo not-empty 4 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Channel 0 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_0 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Channel 1 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_1 WBGEN2_GEN_MASK(6, 1)
struct regmap {
int trig_l;
int trig_h;
int cycle;
int pulse;
int pulse_per;
int fifo_tai_l;
int fifo_tai_h;
int fifo_cycle;
int fifo_leap_second;
int fifo_status;
};
/* definitions for field: Channel 2 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_2 WBGEN2_GEN_MASK(7, 1)
struct regmap_common {
int ver_;
int iomode_reg;
int latch_reg;
int trig_reg;
int pulse_reg;
int eic_idr_reg;
int eic_ier_reg;
int eic_imr_reg;
int eic_isr_reg;
};
/* definitions for field: Channel 3 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_3 WBGEN2_GEN_MASK(8, 1)
extern struct regmap regmap_v1[];
extern struct regmap regmap_v2[];
/* definitions for field: Channel 4 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_4 WBGEN2_GEN_MASK(9, 1)
extern struct regmap_common regmap_common_v1;
extern struct regmap_common regmap_common_v2;
/* definitions for register: Interrupt status register */
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
/* definitions for field: dio fifo not-empty 0 in reg: Interrupt status register */
#define DIO_EIC_ISR_NEMPTY_0 WBGEN2_GEN_MASK(0, 1)
......@@ -382,308 +62,25 @@
/* definitions for field: dio fifo not-empty 4 in reg: Interrupt status register */
#define DIO_EIC_ISR_NEMPTY_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Channel 0 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_0 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Channel 1 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_1 WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Channel 2 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_2 WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Channel 3 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_3 WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Channel 4 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_4 WBGEN2_GEN_MASK(9, 1)
/* definitions for register: FIFO 'Timestamp FIFO 0' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 0' data output register 0 */
#define DIO_TSF0_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF0_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF0_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF0_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 0' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 0' data output register 1 */
#define DIO_TSF0_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF0_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF0_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF0_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 0' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 0' data output register 2 */
#define DIO_TSF0_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF0_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF0_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF0_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 0' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 0' control/status register */
#define DIO_TSF0_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 0' control/status register */
#define DIO_TSF0_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 0' control/status register */
#define DIO_TSF0_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF0_CSR_USEDW_SHIFT 0
#define DIO_TSF0_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF0_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for field: dio fifo not-empty 5 in reg: Interrupt status register */
#define DIO_EIC_ISR_NEMPTY_5 WBGEN2_GEN_MASK(5, 1)
/* definitions for register: FIFO 'Timestamp FIFO 1' data output register 0 */
/* definitions for field: LeapSecond value in reg: FIFO 'Timestamp FIFO 2' data output register 3 */
#define DIO_TSF_R3_LEAP_SECOND_VALUE_MASK WBGEN2_GEN_MASK(0, 16)
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 1' data output register 0 */
#define DIO_TSF1_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF1_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF1_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF1_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for field: LeapSecond valid in reg: FIFO 'Timestamp FIFO 2' data output register 3 */
#define DIO_TSF_R3_LEAP_SECOND_VALID WBGEN2_GEN_MASK(18, 1)
#define DIO_TSF_R3_LEAP_SECOND_VALID_SHIFT 18
/* definitions for register: FIFO 'Timestamp FIFO 1' data output register 1 */
/* definitions for field: LeapSecond flag 59 in reg: FIFO 'Timestamp FIFO 2' data output register 3 */
#define DIO_TSF_R3_LEAP_SECOND_FLAG_59 WBGEN2_GEN_MASK(16, 1)
#define DIO_TSF_R3_LEAP_SECOND_FLAG_59_SHIFT 16
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 1' data output register 1 */
#define DIO_TSF1_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF1_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF1_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF1_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for field: LeapSecond flag 61 in reg: FIFO 'Timestamp FIFO 2' data output register 3 */
#define DIO_TSF_R3_LEAP_SECOND_FLAG_61 WBGEN2_GEN_MASK(17, 1)
#define DIO_TSF_R3_LEAP_SECOND_FLAG_61_SHIFT 17
/* definitions for register: FIFO 'Timestamp FIFO 1' data output register 2 */
struct regmap_common get_regmap_common(unsigned int ver);
struct regmap *get_regmap(unsigned int ver);
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 1' data output register 2 */
#define DIO_TSF1_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF1_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF1_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF1_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 1' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 1' control/status register */
#define DIO_TSF1_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 1' control/status register */
#define DIO_TSF1_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 1' control/status register */
#define DIO_TSF1_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF1_CSR_USEDW_SHIFT 0
#define DIO_TSF1_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF1_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 2' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 2' data output register 0 */
#define DIO_TSF2_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF2_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF2_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF2_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 2' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 2' data output register 1 */
#define DIO_TSF2_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF2_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF2_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF2_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 2' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 2' data output register 2 */
#define DIO_TSF2_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF2_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF2_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF2_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 2' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 2' control/status register */
#define DIO_TSF2_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 2' control/status register */
#define DIO_TSF2_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 2' control/status register */
#define DIO_TSF2_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF2_CSR_USEDW_SHIFT 0
#define DIO_TSF2_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF2_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 3' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 3' data output register 0 */
#define DIO_TSF3_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF3_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF3_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF3_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 3' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 3' data output register 1 */
#define DIO_TSF3_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF3_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF3_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF3_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 3' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 3' data output register 2 */
#define DIO_TSF3_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF3_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF3_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF3_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 3' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 3' control/status register */
#define DIO_TSF3_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 3' control/status register */
#define DIO_TSF3_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 3' control/status register */
#define DIO_TSF3_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF3_CSR_USEDW_SHIFT 0
#define DIO_TSF3_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF3_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 4' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 4' data output register 0 */
#define DIO_TSF4_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF4_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF4_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF4_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 4' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 4' data output register 1 */
#define DIO_TSF4_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF4_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF4_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF4_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 4' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 4' data output register 2 */
#define DIO_TSF4_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF4_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF4_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF4_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 4' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 4' control/status register */
#define DIO_TSF4_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 4' control/status register */
#define DIO_TSF4_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 4' control/status register */
#define DIO_TSF4_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF4_CSR_USEDW_SHIFT 0
#define DIO_TSF4_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF4_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
PACKED struct DIO_WB {
/* [0x0]: REG fmc-dio 0 seconds-based trigger for pulse generation */
uint32_t TRIG0;
/* [0x4]: REG fmc-dio 0 seconds-based trigger for pulse generation */
uint32_t TRIGH0;
/* [0x8]: REG fmc-dio 0 cycles to trigger a pulse generation */
uint32_t CYC0;
/* [0xc]: REG fmc-dio 1 seconds-based trigger for pulse generation */
uint32_t TRIG1;
/* [0x10]: REG fmc-dio 1 seconds-based trigger for pulse generation */
uint32_t TRIGH1;
/* [0x14]: REG fmc-dio 1 cycles to trigger a pulse generation */
uint32_t CYC1;
/* [0x18]: REG fmc-dio 2 seconds-based trigger for pulse generation */
uint32_t TRIG2;
/* [0x1c]: REG fmc-dio 2 seconds-based trigger for pulse generation */
uint32_t TRIGH2;
/* [0x20]: REG fmc-dio 2 cycles to trigger a pulse generation */
uint32_t CYC2;
/* [0x24]: REG fmc-dio 3 seconds-based trigger for pulse generation */
uint32_t TRIG3;
/* [0x28]: REG fmc-dio 3 seconds-based trigger for pulse generation */
uint32_t TRIGH3;
/* [0x2c]: REG fmc-dio 3 cycles to trigger a pulse generation */
uint32_t CYC3;
/* [0x30]: REG fmc-dio 4 seconds-based trigger for pulse generation */
uint32_t TRIG4;
/* [0x34]: REG fmc-dio 4 seconds-based trigger for pulse generation */
uint32_t TRIGH4;
/* [0x38]: REG fmc-dio 4 cycles to trigger a pulse generation */
uint32_t CYC4;
/* [0x3c]: REG FMC-DIO input/output configuration register. */
uint32_t IOMODE;
/* [0x40]: REG Time-programmable output strobe signal */
uint32_t R_LATCH;
/* [0x44]: REG FMC-DIO time trigger is ready to accept a new trigger generation request */
uint32_t TRIG;
/* [0x48]: REG fmc-dio channel 0 Programmable/immediate output pulse length */
uint32_t PROG0_PULSE;
/* [0x4c]: REG fmc-dio channel 1 Programmable/immediate output pulse length */
uint32_t PROG1_PULSE;
/* [0x50]: REG fmc-dio channel 2 Programmable/immediate output pulse length */
uint32_t PROG2_PULSE;
/* [0x54]: REG fmc-dio channel 3 Programmable/immediate output pulse length */
uint32_t PROG3_PULSE;
/* [0x58]: REG fmc-dio channel 4 Programmable/immediate output pulse length */
uint32_t PROG4_PULSE;
/* [0x5c]: REG Pulse generate immediately */
uint32_t PULSE;
/* [0x60]: REG Interrupt disable register */
uint32_t EIC_IDR;
/* [0x64]: REG Interrupt enable register */
uint32_t EIC_IER;
/* [0x68]: REG Interrupt mask register */
uint32_t EIC_IMR;
/* [0x6c]: REG Interrupt status register */
uint32_t EIC_ISR;
/* [0x70]: REG FIFO 'Timestamp FIFO 0' data output register 0 */
uint32_t TSF0_R0;
/* [0x74]: REG FIFO 'Timestamp FIFO 0' data output register 1 */
uint32_t TSF0_R1;
/* [0x78]: REG FIFO 'Timestamp FIFO 0' data output register 2 */
uint32_t TSF0_R2;
/* [0x7c]: REG FIFO 'Timestamp FIFO 0' control/status register */
uint32_t TSF0_CSR;
/* [0x80]: REG FIFO 'Timestamp FIFO 1' data output register 0 */
uint32_t TSF1_R0;
/* [0x84]: REG FIFO 'Timestamp FIFO 1' data output register 1 */
uint32_t TSF1_R1;
/* [0x88]: REG FIFO 'Timestamp FIFO 1' data output register 2 */
uint32_t TSF1_R2;
/* [0x8c]: REG FIFO 'Timestamp FIFO 1' control/status register */
uint32_t TSF1_CSR;
/* [0x90]: REG FIFO 'Timestamp FIFO 2' data output register 0 */
uint32_t TSF2_R0;
/* [0x94]: REG FIFO 'Timestamp FIFO 2' data output register 1 */
uint32_t TSF2_R1;
/* [0x98]: REG FIFO 'Timestamp FIFO 2' data output register 2 */
uint32_t TSF2_R2;
/* [0x9c]: REG FIFO 'Timestamp FIFO 2' control/status register */
uint32_t TSF2_CSR;
/* [0xa0]: REG FIFO 'Timestamp FIFO 3' data output register 0 */
uint32_t TSF3_R0;
/* [0xa4]: REG FIFO 'Timestamp FIFO 3' data output register 1 */
uint32_t TSF3_R1;
/* [0xa8]: REG FIFO 'Timestamp FIFO 3' data output register 2 */
uint32_t TSF3_R2;
/* [0xac]: REG FIFO 'Timestamp FIFO 3' control/status register */
uint32_t TSF3_CSR;
/* [0xb0]: REG FIFO 'Timestamp FIFO 4' data output register 0 */
uint32_t TSF4_R0;
/* [0xb4]: REG FIFO 'Timestamp FIFO 4' data output register 1 */
uint32_t TSF4_R1;
/* [0xb8]: REG FIFO 'Timestamp FIFO 4' data output register 2 */
uint32_t TSF4_R2;
/* [0xbc]: REG FIFO 'Timestamp FIFO 4' control/status register */
uint32_t TSF4_CSR;
};
#endif
#endif
\ No newline at end of file
#include "wr-dio-regs_v1.h"
#include "wr-dio-regs.h"
#define R(x) (offsetof(struct DIO_WB, x))
struct regmap regmap_v1[] = {
{
.trig_l = R(TRIG0),
.trig_h = R(TRIGH0),
.cycle = R(CYC0),
.pulse = R(PROG0_PULSE),
.pulse_per = 0,
.fifo_tai_l = R(TSF0_R0),
.fifo_tai_h = R(TSF0_R1),
.fifo_cycle = R(TSF0_R2),
.fifo_leap_second = 0,
.fifo_status = R(TSF0_CSR),
}, {
.trig_l = R(TRIG1),
.trig_h = R(TRIGH1),
.cycle = R(CYC1),
.pulse = R(PROG1_PULSE),
.pulse_per = 0,
.fifo_tai_l = R(TSF1_R0),
.fifo_tai_h = R(TSF1_R1),
.fifo_cycle = R(TSF1_R2),
.fifo_leap_second = 0,
.fifo_status = R(TSF1_CSR),
}, {
.trig_l = R(TRIG2),
.trig_h = R(TRIGH2),
.cycle = R(CYC2),
.pulse = R(PROG2_PULSE),
.pulse_per = 0,
.fifo_tai_l = R(TSF2_R0),
.fifo_tai_h = R(TSF2_R1),
.fifo_cycle = R(TSF2_R2),
.fifo_leap_second = 0,
.fifo_status = R(TSF2_CSR),
}, {
.trig_l = R(TRIG3),
.trig_h = R(TRIGH3),
.cycle = R(CYC3),
.pulse = R(PROG3_PULSE),
.pulse_per = 0,
.fifo_tai_l = R(TSF3_R0),
.fifo_tai_h = R(TSF3_R1),
.fifo_cycle = R(TSF3_R2),
.fifo_leap_second = 0,
.fifo_status = R(TSF3_CSR),
}, {
.trig_l = R(TRIG4),
.trig_h = R(TRIGH4),
.cycle = R(CYC4),
.pulse = R(PROG4_PULSE),
.pulse_per = 0,
.fifo_tai_l = R(TSF4_R0),
.fifo_tai_h = R(TSF4_R1),
.fifo_cycle = R(TSF4_R2),
.fifo_leap_second = 0,
.fifo_status = R(TSF4_CSR),
}, {
.trig_l = 0,
.trig_h = 0,
.cycle = 0,
.pulse = 0,
.pulse_per = 0,
.fifo_tai_l = 0,
.fifo_tai_h = 0,
.fifo_cycle = 0,
.fifo_leap_second = 0,
.fifo_status = 0,
}
};
struct regmap_common regmap_common_v1 =
{
.ver_ = 0,
.iomode_reg = R(IOMODE),
.latch_reg = R(R_LATCH),
.trig_reg = R(TRIG),
.pulse_reg = R(PULSE),
.eic_idr_reg = R(EIC_IDR),
.eic_ier_reg = R(EIC_IER),
.eic_imr_reg = R(EIC_IMR),
.eic_isr_reg = R(EIC_ISR),
};
/*
Register definitions for slave core: FMC-DIO-5chttla
* File : wr-dio-regs.h
* Author : auto-generated by wbgen2 from wr-dio-regs.wb
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr-dio-regs.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_WR_DIO_V1
#define __WBGEN2_REGDEFS_WR_DIO_V1
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: fmc-dio 0 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 0 seconds-based trigger for pulse generation */
#define DIO_TRIG0_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG0_SECONDS_SHIFT 0
#define DIO_TRIG0_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG0_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 0 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 0 seconds-based trigger for pulse generation */
#define DIO_TRIGH0_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH0_SECONDS_SHIFT 0
#define DIO_TRIGH0_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH0_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 0 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 0 cycles to trigger a pulse generation */
#define DIO_CYC0_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC0_CYC_SHIFT 0
#define DIO_CYC0_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC0_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio 1 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 1 seconds-based trigger for pulse generation */
#define DIO_TRIG1_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG1_SECONDS_SHIFT 0
#define DIO_TRIG1_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG1_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 1 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 1 seconds-based trigger for pulse generation */
#define DIO_TRIGH1_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH1_SECONDS_SHIFT 0
#define DIO_TRIGH1_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH1_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 1 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 1 cycles to trigger a pulse generation */
#define DIO_CYC1_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC1_CYC_SHIFT 0
#define DIO_CYC1_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC1_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio 2 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 2 seconds-based trigger for pulse generation */
#define DIO_TRIG2_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG2_SECONDS_SHIFT 0
#define DIO_TRIG2_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG2_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 2 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 2 seconds-based trigger for pulse generation */
#define DIO_TRIGH2_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH2_SECONDS_SHIFT 0
#define DIO_TRIGH2_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH2_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 2 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 2 cycles to trigger a pulse generation */
#define DIO_CYC2_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC2_CYC_SHIFT 0
#define DIO_CYC2_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC2_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio 3 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 3 seconds-based trigger for pulse generation */
#define DIO_TRIG3_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG3_SECONDS_SHIFT 0
#define DIO_TRIG3_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG3_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 3 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 3 seconds-based trigger for pulse generation */
#define DIO_TRIGH3_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH3_SECONDS_SHIFT 0
#define DIO_TRIGH3_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH3_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 3 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 3 cycles to trigger a pulse generation */
#define DIO_CYC3_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC3_CYC_SHIFT 0
#define DIO_CYC3_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC3_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio 4 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 4 seconds-based trigger for pulse generation */
#define DIO_TRIG4_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TRIG4_SECONDS_SHIFT 0
#define DIO_TRIG4_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TRIG4_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: fmc-dio 4 seconds-based trigger for pulse generation */
/* definitions for field: seconds field in reg: fmc-dio 4 seconds-based trigger for pulse generation */
#define DIO_TRIGH4_SECONDS_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TRIGH4_SECONDS_SHIFT 0
#define DIO_TRIGH4_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TRIGH4_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: fmc-dio 4 cycles to trigger a pulse generation */
/* definitions for field: cycles field in reg: fmc-dio 4 cycles to trigger a pulse generation */
#define DIO_CYC4_CYC_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_CYC4_CYC_SHIFT 0
#define DIO_CYC4_CYC_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_CYC4_CYC_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FMC-DIO input/output configuration register. */
/* definitions for field: channel0 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH0_MASK WBGEN2_GEN_MASK(0, 4)
#define DIO_IOMODE_CH0_SHIFT 0
#define DIO_IOMODE_CH0_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define DIO_IOMODE_CH0_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for field: channel1 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH1_MASK WBGEN2_GEN_MASK(4, 4)
#define DIO_IOMODE_CH1_SHIFT 4
#define DIO_IOMODE_CH1_W(value) WBGEN2_GEN_WRITE(value, 4, 4)
#define DIO_IOMODE_CH1_R(reg) WBGEN2_GEN_READ(reg, 4, 4)
/* definitions for field: channel2 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH2_MASK WBGEN2_GEN_MASK(8, 4)
#define DIO_IOMODE_CH2_SHIFT 8
#define DIO_IOMODE_CH2_W(value) WBGEN2_GEN_WRITE(value, 8, 4)
#define DIO_IOMODE_CH2_R(reg) WBGEN2_GEN_READ(reg, 8, 4)
/* definitions for field: channel3 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH3_MASK WBGEN2_GEN_MASK(12, 4)
#define DIO_IOMODE_CH3_SHIFT 12
#define DIO_IOMODE_CH3_W(value) WBGEN2_GEN_WRITE(value, 12, 4)
#define DIO_IOMODE_CH3_R(reg) WBGEN2_GEN_READ(reg, 12, 4)
/* definitions for field: channel4 in reg: FMC-DIO input/output configuration register. */
#define DIO_IOMODE_CH4_MASK WBGEN2_GEN_MASK(16, 4)
#define DIO_IOMODE_CH4_SHIFT 16
#define DIO_IOMODE_CH4_W(value) WBGEN2_GEN_WRITE(value, 16, 4)
#define DIO_IOMODE_CH4_R(reg) WBGEN2_GEN_READ(reg, 16, 4)
/* definitions for register: Time-programmable output strobe signal */
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Sincle-cycle strobe in reg: Time-programmable output strobe signal */
#define DIO_LATCH_TIME_CH4 WBGEN2_GEN_MASK(4, 1)
/* definitions for register: FMC-DIO time trigger is ready to accept a new trigger generation request */
/* definitions for field: trig_rdy field in reg: FMC-DIO time trigger is ready to accept a new trigger generation request */
#define DIO_TRIG_RDY_MASK WBGEN2_GEN_MASK(0, 5)
#define DIO_TRIG_RDY_SHIFT 0
#define DIO_TRIG_RDY_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define DIO_TRIG_RDY_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for register: fmc-dio channel 0 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 0 in reg: fmc-dio channel 0 Programmable/immediate output pulse length */
#define DIO_PROG0_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG0_PULSE_LENGTH_SHIFT 0
#define DIO_PROG0_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG0_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio channel 1 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 1 in reg: fmc-dio channel 1 Programmable/immediate output pulse length */
#define DIO_PROG1_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG1_PULSE_LENGTH_SHIFT 0
#define DIO_PROG1_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG1_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio channel 2 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 2 in reg: fmc-dio channel 2 Programmable/immediate output pulse length */
#define DIO_PROG2_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG2_PULSE_LENGTH_SHIFT 0
#define DIO_PROG2_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG2_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio channel 3 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 3 in reg: fmc-dio channel 3 Programmable/immediate output pulse length */
#define DIO_PROG3_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG3_PULSE_LENGTH_SHIFT 0
#define DIO_PROG3_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG3_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: fmc-dio channel 4 Programmable/immediate output pulse length */
/* definitions for field: number of ticks field for channel 4 in reg: fmc-dio channel 4 Programmable/immediate output pulse length */
#define DIO_PROG4_PULSE_LENGTH_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_PROG4_PULSE_LENGTH_SHIFT 0
#define DIO_PROG4_PULSE_LENGTH_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_PROG4_PULSE_LENGTH_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: Pulse generate immediately */
/* definitions for field: pulse_gen_now_0 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: pulse_gen_now_1 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: pulse_gen_now_2 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: pulse_gen_now_3 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: pulse_gen_now_4 in reg: Pulse generate immediately */
#define DIO_PULSE_IMM_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for register: Interrupt disable register */
/* definitions for field: dio fifo not-empty 0 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: dio fifo not-empty 1 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: dio fifo not-empty 2 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: dio fifo not-empty 3 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: dio fifo not-empty 4 in reg: Interrupt disable register */
#define DIO_EIC_IDR_NEMPTY_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Channel 0 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_0 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Channel 1 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_1 WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Channel 2 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_2 WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Channel 3 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_3 WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Channel 4 trigger ready interrupt in reg: Interrupt disable register */
#define DIO_EIC_IDR_TRIGGER_READY_4 WBGEN2_GEN_MASK(9, 1)
/* definitions for register: Interrupt enable register */
/* definitions for field: dio fifo not-empty 0 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: dio fifo not-empty 1 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: dio fifo not-empty 2 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: dio fifo not-empty 3 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: dio fifo not-empty 4 in reg: Interrupt enable register */
#define DIO_EIC_IER_NEMPTY_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Channel 0 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_0 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Channel 1 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_1 WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Channel 2 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_2 WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Channel 3 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_3 WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Channel 4 trigger ready interrupt in reg: Interrupt enable register */
#define DIO_EIC_IER_TRIGGER_READY_4 WBGEN2_GEN_MASK(9, 1)
/* definitions for register: Interrupt mask register */
/* definitions for field: dio fifo not-empty 0 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_0 WBGEN2_GEN_MASK(0, 1)
/* definitions for field: dio fifo not-empty 1 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_1 WBGEN2_GEN_MASK(1, 1)
/* definitions for field: dio fifo not-empty 2 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_2 WBGEN2_GEN_MASK(2, 1)
/* definitions for field: dio fifo not-empty 3 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_3 WBGEN2_GEN_MASK(3, 1)
/* definitions for field: dio fifo not-empty 4 in reg: Interrupt mask register */
#define DIO_EIC_IMR_NEMPTY_4 WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Channel 0 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_0 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Channel 1 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_1 WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Channel 2 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_2 WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Channel 3 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_3 WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Channel 4 trigger ready interrupt in reg: Interrupt mask register */
#define DIO_EIC_IMR_TRIGGER_READY_4 WBGEN2_GEN_MASK(9, 1)
/* definitions for field: Channel 0 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_0 WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Channel 1 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_1 WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Channel 2 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_2 WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Channel 3 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_3 WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Channel 4 trigger ready interrupt in reg: Interrupt status register */
#define DIO_EIC_ISR_TRIGGER_READY_4 WBGEN2_GEN_MASK(9, 1)
/* definitions for register: FIFO 'Timestamp FIFO 0' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 0' data output register 0 */
#define DIO_TSF0_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF0_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF0_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF0_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 0' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 0' data output register 1 */
#define DIO_TSF0_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF0_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF0_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF0_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 0' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 0' data output register 2 */
#define DIO_TSF0_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF0_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF0_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF0_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 0' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 0' control/status register */
#define DIO_TSF0_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 0' control/status register */
#define DIO_TSF0_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 0' control/status register */
#define DIO_TSF0_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF0_CSR_USEDW_SHIFT 0
#define DIO_TSF0_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF0_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 1' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 1' data output register 0 */
#define DIO_TSF1_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF1_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF1_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF1_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 1' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 1' data output register 1 */
#define DIO_TSF1_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF1_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF1_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF1_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 1' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 1' data output register 2 */
#define DIO_TSF1_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF1_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF1_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF1_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 1' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 1' control/status register */
#define DIO_TSF1_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 1' control/status register */
#define DIO_TSF1_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 1' control/status register */
#define DIO_TSF1_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF1_CSR_USEDW_SHIFT 0
#define DIO_TSF1_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF1_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 2' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 2' data output register 0 */
#define DIO_TSF2_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF2_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF2_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF2_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 2' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 2' data output register 1 */
#define DIO_TSF2_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF2_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF2_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF2_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 2' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 2' data output register 2 */
#define DIO_TSF2_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF2_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF2_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF2_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 2' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 2' control/status register */
#define DIO_TSF2_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 2' control/status register */
#define DIO_TSF2_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 2' control/status register */
#define DIO_TSF2_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF2_CSR_USEDW_SHIFT 0
#define DIO_TSF2_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF2_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 3' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 3' data output register 0 */
#define DIO_TSF3_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF3_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF3_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF3_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 3' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 3' data output register 1 */
#define DIO_TSF3_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF3_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF3_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF3_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 3' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 3' data output register 2 */
#define DIO_TSF3_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF3_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF3_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF3_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 3' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 3' control/status register */
#define DIO_TSF3_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 3' control/status register */
#define DIO_TSF3_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 3' control/status register */
#define DIO_TSF3_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF3_CSR_USEDW_SHIFT 0
#define DIO_TSF3_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF3_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 4' data output register 0 */
/* definitions for field: seconds time in reg: FIFO 'Timestamp FIFO 4' data output register 0 */
#define DIO_TSF4_R0_TAG_SECONDS_MASK WBGEN2_GEN_MASK(0, 32)
#define DIO_TSF4_R0_TAG_SECONDS_SHIFT 0
#define DIO_TSF4_R0_TAG_SECONDS_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define DIO_TSF4_R0_TAG_SECONDS_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: FIFO 'Timestamp FIFO 4' data output register 1 */
/* definitions for field: seconds time H in reg: FIFO 'Timestamp FIFO 4' data output register 1 */
#define DIO_TSF4_R1_TAG_SECONDSH_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF4_R1_TAG_SECONDSH_SHIFT 0
#define DIO_TSF4_R1_TAG_SECONDSH_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF4_R1_TAG_SECONDSH_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: FIFO 'Timestamp FIFO 4' data output register 2 */
/* definitions for field: Sub-second accuracy in reg: FIFO 'Timestamp FIFO 4' data output register 2 */
#define DIO_TSF4_R2_TAG_CYCLES_MASK WBGEN2_GEN_MASK(0, 28)
#define DIO_TSF4_R2_TAG_CYCLES_SHIFT 0
#define DIO_TSF4_R2_TAG_CYCLES_W(value) WBGEN2_GEN_WRITE(value, 0, 28)
#define DIO_TSF4_R2_TAG_CYCLES_R(reg) WBGEN2_GEN_READ(reg, 0, 28)
/* definitions for register: FIFO 'Timestamp FIFO 4' control/status register */
/* definitions for field: FIFO full flag in reg: FIFO 'Timestamp FIFO 4' control/status register */
#define DIO_TSF4_CSR_FULL WBGEN2_GEN_MASK(16, 1)
/* definitions for field: FIFO empty flag in reg: FIFO 'Timestamp FIFO 4' control/status register */
#define DIO_TSF4_CSR_EMPTY WBGEN2_GEN_MASK(17, 1)
/* definitions for field: FIFO counter in reg: FIFO 'Timestamp FIFO 4' control/status register */
#define DIO_TSF4_CSR_USEDW_MASK WBGEN2_GEN_MASK(0, 8)
#define DIO_TSF4_CSR_USEDW_SHIFT 0
#define DIO_TSF4_CSR_USEDW_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define DIO_TSF4_CSR_USEDW_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
PACKED struct DIO_WB {
/* [0x0]: REG fmc-dio 0 seconds-based trigger for pulse generation */
uint32_t TRIG0;
/* [0x4]: REG fmc-dio 0 seconds-based trigger for pulse generation */
uint32_t TRIGH0;
/* [0x8]: REG fmc-dio 0 cycles to trigger a pulse generation */
uint32_t CYC0;
/* [0xc]: REG fmc-dio 1 seconds-based trigger for pulse generation */
uint32_t TRIG1;
/* [0x10]: REG fmc-dio 1 seconds-based trigger for pulse generation */
uint32_t TRIGH1;
/* [0x14]: REG fmc-dio 1 cycles to trigger a pulse generation */
uint32_t CYC1;
/* [0x18]: REG fmc-dio 2 seconds-based trigger for pulse generation */
uint32_t TRIG2;
/* [0x1c]: REG fmc-dio 2 seconds-based trigger for pulse generation */
uint32_t TRIGH2;
/* [0x20]: REG fmc-dio 2 cycles to trigger a pulse generation */
uint32_t CYC2;
/* [0x24]: REG fmc-dio 3 seconds-based trigger for pulse generation */
uint32_t TRIG3;
/* [0x28]: REG fmc-dio 3 seconds-based trigger for pulse generation */
uint32_t TRIGH3;
/* [0x2c]: REG fmc-dio 3 cycles to trigger a pulse generation */
uint32_t CYC3;
/* [0x30]: REG fmc-dio 4 seconds-based trigger for pulse generation */
uint32_t TRIG4;
/* [0x34]: REG fmc-dio 4 seconds-based trigger for pulse generation */
uint32_t TRIGH4;
/* [0x38]: REG fmc-dio 4 cycles to trigger a pulse generation */
uint32_t CYC4;
/* [0x3c]: REG FMC-DIO input/output configuration register. */
uint32_t IOMODE;
/* [0x40]: REG Time-programmable output strobe signal */
uint32_t R_LATCH;
/* [0x44]: REG FMC-DIO time trigger is ready to accept a new trigger generation request */
uint32_t TRIG;
/* [0x48]: REG fmc-dio channel 0 Programmable/immediate output pulse length */
uint32_t PROG0_PULSE;
/* [0x4c]: REG fmc-dio channel 1 Programmable/immediate output pulse length */
uint32_t PROG1_PULSE;
/* [0x50]: REG fmc-dio channel 2 Programmable/immediate output pulse length */
uint32_t PROG2_PULSE;
/* [0x54]: REG fmc-dio channel 3 Programmable/immediate output pulse length */
uint32_t PROG3_PULSE;
/* [0x58]: REG fmc-dio channel 4 Programmable/immediate output pulse length */
uint32_t PROG4_PULSE;
/* [0x5c]: REG Pulse generate immediately */
uint32_t PULSE;
/* [0x60]: REG Interrupt disable register */
uint32_t EIC_IDR;
/* [0x64]: REG Interrupt enable register */
uint32_t EIC_IER;
/* [0x68]: REG Interrupt mask register */
uint32_t EIC_IMR;
/* [0x6c]: REG Interrupt status register */
uint32_t EIC_ISR;
/* [0x70]: REG FIFO 'Timestamp FIFO 0' data output register 0 */
uint32_t TSF0_R0;
/* [0x74]: REG FIFO 'Timestamp FIFO 0' data output register 1 */
uint32_t TSF0_R1;
/* [0x78]: REG FIFO 'Timestamp FIFO 0' data output register 2 */
uint32_t TSF0_R2;
/* [0x7c]: REG FIFO 'Timestamp FIFO 0' control/status register */
uint32_t TSF0_CSR;
/* [0x80]: REG FIFO 'Timestamp FIFO 1' data output register 0 */
uint32_t TSF1_R0;
/* [0x84]: REG FIFO 'Timestamp FIFO 1' data output register 1 */
uint32_t TSF1_R1;
/* [0x88]: REG FIFO 'Timestamp FIFO 1' data output register 2 */
uint32_t TSF1_R2;
/* [0x8c]: REG FIFO 'Timestamp FIFO 1' control/status register */
uint32_t TSF1_CSR;
/* [0x90]: REG FIFO 'Timestamp FIFO 2' data output register 0 */
uint32_t TSF2_R0;
/* [0x94]: REG FIFO 'Timestamp FIFO 2' data output register 1 */
uint32_t TSF2_R1;
/* [0x98]: REG FIFO 'Timestamp FIFO 2' data output register 2 */
uint32_t TSF2_R2;
/* [0x9c]: REG FIFO 'Timestamp FIFO 2' control/status register */
uint32_t TSF2_CSR;
/* [0xa0]: REG FIFO 'Timestamp FIFO 3' data output register 0 */
uint32_t TSF3_R0;
/* [0xa4]: REG FIFO 'Timestamp FIFO 3' data output register 1 */
uint32_t TSF3_R1;
/* [0xa8]: REG FIFO 'Timestamp FIFO 3' data output register 2 */
uint32_t TSF3_R2;
/* [0xac]: REG FIFO 'Timestamp FIFO 3' control/status register */
uint32_t TSF3_CSR;
/* [0xb0]: REG FIFO 'Timestamp FIFO 4' data output register 0 */
uint32_t TSF4_R0;
/* [0xb4]: REG FIFO 'Timestamp FIFO 4' data output register 1 */
uint32_t TSF4_R1;
/* [0xb8]: REG FIFO 'Timestamp FIFO 4' data output register 2 */
uint32_t TSF4_R2;
/* [0xbc]: REG FIFO 'Timestamp FIFO 4' control/status register */
uint32_t TSF4_CSR;
};
#endif
#include "wr-dio-regs_v2.h"
#include "wr-dio-regs.h"
#define R(x) (offsetof(struct DIO_WB, x))
struct regmap regmap_v2[] = {
{
.trig_l = R(TRIG0),
.trig_h = R(TRIGH0),
.cycle = R(CYC0),
.pulse = R(PROG0_PULSE),
.pulse_per = R(PROG0_PULSE_PER),
.fifo_tai_l = R(TSF0_R0),
.fifo_tai_h = R(TSF0_R1),
.fifo_cycle = R(TSF0_R2),
.fifo_leap_second = R(TSF0_R3),
.fifo_status = R(TSF0_CSR),
}, {
.trig_l = R(TRIG1),
.trig_h = R(TRIGH1),
.cycle = R(CYC1),
.pulse = R(PROG1_PULSE),
.pulse_per = R(PROG1_PULSE_PER),
.fifo_tai_l = R(TSF1_R0),
.fifo_tai_h = R(TSF1_R1),
.fifo_cycle = R(TSF1_R2),
.fifo_leap_second = R(TSF1_R3),
.fifo_status = R(TSF1_CSR),
}, {
.trig_l = R(TRIG2),
.trig_h = R(TRIGH2),
.cycle = R(CYC2),
.pulse = R(PROG2_PULSE),
.pulse_per = R(PROG2_PULSE_PER),
.fifo_tai_l = R(TSF2_R0),
.fifo_tai_h = R(TSF2_R1),
.fifo_cycle = R(TSF2_R2),
.fifo_leap_second = R(TSF2_R3),
.fifo_status = R(TSF2_CSR),
}, {
.trig_l = R(TRIG3),
.trig_h = R(TRIGH3),
.cycle = R(CYC3),
.pulse = R(PROG3_PULSE),
.pulse_per = R(PROG3_PULSE_PER),
.fifo_tai_l = R(TSF3_R0),
.fifo_tai_h = R(TSF3_R1),
.fifo_cycle = R(TSF3_R2),
.fifo_leap_second = R(TSF3_R3),
.fifo_status = R(TSF3_CSR),
}, {
.trig_l = R(TRIG4),
.trig_h = R(TRIGH4),
.cycle = R(CYC4),
.pulse = R(PROG4_PULSE),
.pulse_per = R(PROG4_PULSE_PER),
.fifo_tai_l = R(TSF4_R0),
.fifo_tai_h = R(TSF4_R1),
.fifo_cycle = R(TSF4_R2),
.fifo_leap_second = R(TSF4_R3),
.fifo_status = R(TSF4_CSR),
}, {
.trig_l = R(TRIG5),
.trig_h = R(TRIGH5),
.cycle = R(CYC5),
.pulse = R(PROG5_PULSE),
.pulse_per = R(PROG5_PULSE_PER),
.fifo_tai_l = R(TSF5_R0),
.fifo_tai_h = R(TSF5_R1),
.fifo_cycle = R(TSF5_R2),
.fifo_leap_second = R(TSF5_R3),
.fifo_status = R(TSF5_CSR),
}
};
struct regmap_common regmap_common_v2 =
{
.ver_ = R(VER),
.iomode_reg = R(IOMODE),
.latch_reg = R(R_LATCH),
.trig_reg = R(TRIG),
.pulse_reg = R(PULSE),
.eic_idr_reg = R(EIC_IDR),
.eic_ier_reg = R(EIC_IER),
.eic_imr_reg = R(EIC_IMR),
.eic_isr_reg = R(EIC_ISR),
};
/*
Register definitions for slave core: FMC-DIO-5chttla
* File : wr-dio-regs.h
* Author : auto-generated by wbgen2 from wr_dio.wb
* Created : Tue Apr 28 15:59:03 2020
* Version : 0x00000002
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr_dio.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_WR_DIO_V2
#define __WBGEN2_REGDEFS_WR_DIO_V2
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <inttypes.h>
#endif
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
/* version definition */
#define WBGEN2_DIO_VERSION 0x00000002
PACKED struct DIO_WB {
/* [0x0]: REG Version register */
uint32_t VER;
/* [0x4]: REG fmc-dio 0 seconds-based trigger for pulse generation */
uint32_t TRIG0;
/* [0x8]: REG fmc-dio 0 seconds-based trigger for pulse generation */
uint32_t TRIGH0;
/* [0xc]: REG fmc-dio 0 cycles to trigger a pulse generation */
uint32_t CYC0;
/* [0x10]: REG fmc-dio 1 seconds-based trigger for pulse generation */
uint32_t TRIG1;
/* [0x14]: REG fmc-dio 1 seconds-based trigger for pulse generation */
uint32_t TRIGH1;
/* [0x18]: REG fmc-dio 1 cycles to trigger a pulse generation */
uint32_t CYC1;
/* [0x1c]: REG fmc-dio 2 seconds-based trigger for pulse generation */
uint32_t TRIG2;
/* [0x20]: REG fmc-dio 2 seconds-based trigger for pulse generation */
uint32_t TRIGH2;
/* [0x24]: REG fmc-dio 2 cycles to trigger a pulse generation */
uint32_t CYC2;
/* [0x28]: REG fmc-dio 3 seconds-based trigger for pulse generation */
uint32_t TRIG3;
/* [0x2c]: REG fmc-dio 3 seconds-based trigger for pulse generation */
uint32_t TRIGH3;
/* [0x30]: REG fmc-dio 3 cycles to trigger a pulse generation */
uint32_t CYC3;
/* [0x34]: REG fmc-dio 4 seconds-based trigger for pulse generation */
uint32_t TRIG4;
/* [0x38]: REG fmc-dio 4 seconds-based trigger for pulse generation */
uint32_t TRIGH4;
/* [0x3c]: REG fmc-dio 4 cycles to trigger a pulse generation */
uint32_t CYC4;
/* [0x40]: REG fmc-dio 5 seconds-based trigger for pulse generation */
uint32_t TRIG5;
/* [0x44]: REG fmc-dio 5 seconds-based trigger for pulse generation */
uint32_t TRIGH5;
/* [0x48]: REG fmc-dio 5 cycles to trigger a pulse generation */
uint32_t CYC5;
/* [0x4c]: REG FMC-DIO input/output configuration register. */
uint32_t IOMODE;
/* [0x50]: REG Time-programmable output strobe signal */
uint32_t R_LATCH;
/* [0x54]: REG FMC-DIO time trigger is ready to accept a new trigger generation request */
uint32_t TRIG;
/* [0x58]: REG fmc-dio channel 0 Programmable/immediate output pulse length */
uint32_t PROG0_PULSE;
/* [0x5c]: REG fmc-dio channel 0 Programmable/immediate output pulse period */
uint32_t PROG0_PULSE_PER;
/* [0x60]: REG fmc-dio channel 1 Programmable/immediate output pulse length */
uint32_t PROG1_PULSE;
/* [0x64]: REG fmc-dio channel 1 Programmable/immediate output pulse period */
uint32_t PROG1_PULSE_PER;
/* [0x68]: REG fmc-dio channel 2 Programmable/immediate output pulse length */
uint32_t PROG2_PULSE;
/* [0x6c]: REG fmc-dio channel 2 Programmable/immediate output pulse period */
uint32_t PROG2_PULSE_PER;
/* [0x70]: REG fmc-dio channel 3 Programmable/immediate output pulse length */
uint32_t PROG3_PULSE;
/* [0x74]: REG fmc-dio channel 3 Programmable/immediate output pulse period */
uint32_t PROG3_PULSE_PER;
/* [0x78]: REG fmc-dio channel 4 Programmable/immediate output pulse length */
uint32_t PROG4_PULSE;
/* [0x7c]: REG fmc-dio channel 4 Programmable/immediate output pulse period */
uint32_t PROG4_PULSE_PER;
/* [0x80]: REG fmc-dio channel 5 Programmable/immediate output pulse length */
uint32_t PROG5_PULSE;
/* [0x84]: REG fmc-dio channel 5 Programmable/immediate output pulse period */
uint32_t PROG5_PULSE_PER;
/* [0x88]: REG Pulse generate immediately */
uint32_t PULSE;
/* padding to: 40 words */
uint32_t __padding_0[5];
/* [0xa0]: REG Interrupt disable register */
uint32_t EIC_IDR;
/* [0xa4]: REG Interrupt enable register */
uint32_t EIC_IER;
/* [0xa8]: REG Interrupt mask register */
uint32_t EIC_IMR;
/* [0xac]: REG Interrupt status register */
uint32_t EIC_ISR;
/* [0xb0]: REG FIFO 'Timestamp FIFO 0' data output register 0 */
uint32_t TSF0_R0;
/* [0xb4]: REG FIFO 'Timestamp FIFO 0' data output register 1 */
uint32_t TSF0_R1;
/* [0xb8]: REG FIFO 'Timestamp FIFO 0' data output register 2 */
uint32_t TSF0_R2;
/* [0xbc]: REG FIFO 'Timestamp FIFO 0' data output register 3 */
uint32_t TSF0_R3;
/* [0xc0]: REG FIFO 'Timestamp FIFO 0' control/status register */
uint32_t TSF0_CSR;
/* [0xc4]: REG FIFO 'Timestamp FIFO 1' data output register 0 */
uint32_t TSF1_R0;
/* [0xc8]: REG FIFO 'Timestamp FIFO 1' data output register 1 */
uint32_t TSF1_R1;
/* [0xcc]: REG FIFO 'Timestamp FIFO 1' data output register 2 */
uint32_t TSF1_R2;
/* [0xd0]: REG FIFO 'Timestamp FIFO 1' data output register 3 */
uint32_t TSF1_R3;
/* [0xd4]: REG FIFO 'Timestamp FIFO 1' control/status register */
uint32_t TSF1_CSR;
/* [0xd8]: REG FIFO 'Timestamp FIFO 2' data output register 0 */
uint32_t TSF2_R0;
/* [0xdc]: REG FIFO 'Timestamp FIFO 2' data output register 1 */
uint32_t TSF2_R1;
/* [0xe0]: REG FIFO 'Timestamp FIFO 2' data output register 2 */
uint32_t TSF2_R2;
/* [0xe4]: REG FIFO 'Timestamp FIFO 2' data output register 3 */
uint32_t TSF2_R3;
/* [0xe8]: REG FIFO 'Timestamp FIFO 2' control/status register */
uint32_t TSF2_CSR;
/* [0xec]: REG FIFO 'Timestamp FIFO 3' data output register 0 */
uint32_t TSF3_R0;
/* [0xf0]: REG FIFO 'Timestamp FIFO 3' data output register 1 */
uint32_t TSF3_R1;
/* [0xf4]: REG FIFO 'Timestamp FIFO 3' data output register 2 */
uint32_t TSF3_R2;
/* [0xf8]: REG FIFO 'Timestamp FIFO 3' data output register 3 */
uint32_t TSF3_R3;
/* [0xfc]: REG FIFO 'Timestamp FIFO 3' control/status register */
uint32_t TSF3_CSR;
/* [0x100]: REG FIFO 'Timestamp FIFO 4' data output register 0 */
uint32_t TSF4_R0;
/* [0x104]: REG FIFO 'Timestamp FIFO 4' data output register 1 */
uint32_t TSF4_R1;
/* [0x108]: REG FIFO 'Timestamp FIFO 4' data output register 2 */
uint32_t TSF4_R2;
/* [0x10c]: REG FIFO 'Timestamp FIFO 4' data output register 3 */
uint32_t TSF4_R3;
/* [0x110]: REG FIFO 'Timestamp FIFO 4' control/status register */
uint32_t TSF4_CSR;
/* [0x114]: REG FIFO 'Timestamp FIFO 5' data output register 0 */
uint32_t TSF5_R0;
/* [0x118]: REG FIFO 'Timestamp FIFO 5' data output register 1 */
uint32_t TSF5_R1;
/* [0x11c]: REG FIFO 'Timestamp FIFO 5' data output register 2 */
uint32_t TSF5_R2;
/* [0x120]: REG FIFO 'Timestamp FIFO 5' data output register 3 */
uint32_t TSF5_R3;
/* [0x124]: REG FIFO 'Timestamp FIFO 5' control/status register */
uint32_t TSF5_CSR;
};
#endif
......@@ -93,11 +93,12 @@ static int scan_pulse(int argc, char **argv)
prgname, argv[0], argv[2]);
return -1;
}
if (cmd->t[1].tv_sec) {
fprintf(stderr, "%s: %s: duration must be < 1s (got \"%s\")\n",
if (cmd->t[1].tv_sec || !cmd->t[1].tv_nsec) {
fprintf(stderr, "%s: %s: duration must be < 1s and > 0s (got \"%s\")\n",
prgname, argv[0], argv[2]);
return -1;
}
/* Next argument is the "when", position 0 in ioctl timestamp array */
if (!strcmp(argv[3], "now")) {
......@@ -126,6 +127,24 @@ static int scan_pulse(int argc, char **argv)
prgname, argv[0], argv[4]);
return -1;
}
if (cmd->t[2].tv_nsec < 1000000)
{
fprintf(stderr, "%s: %s: Frequency is greater than 1 kHz or higher than 1 s\n",
prgname, argv[0]);
return -1;
}
if(cmd->t[2].tv_nsec % 8)
{
fprintf(stderr, "%s: %s: Period value is not a multiple of reference frequency \n",
prgname, argv[0]);
return -1;
}
if (cmd->t[1].tv_nsec >= cmd->t[2].tv_nsec)
{
fprintf(stderr, "%s: %s: Pulse length can not be greater than period \n",
prgname, argv[0]);
return -1;
}
if (sscanf(argv[5], "%i%c", &cmd->value, &c) != 1) {
fprintf(stderr, "%s: %s: invalid count \"%s\"\n",
prgname, argv[0], argv[5]);
......@@ -141,6 +160,44 @@ static int scan_pulse(int argc, char **argv)
return 0;
}
static int scan_width(int argc, char **argv)
{
char c;
if (argc != 3) {
fprintf(stderr, "%s: %s: wrong number of arguments\n",
prgname, argv[0]);
fprintf(stderr, "Use: %s <channel> <duration> \n", argv[0]);
return -1;
}
if (sscanf(argv[1], "%hi%c", &cmd->channel, &c) != 1
|| cmd->channel > 4) {
fprintf(stderr, "%s: %s: not a channel number \"%s\"\n",
prgname, argv[0], argv[1]);
return -1;
}
/* Duration is first time argument but position 1 for ioctl */
if (parse_ts(argv[2], cmd->t + 1) < 0) {
fprintf(stderr, "%s: %s: invalid time \"%s\"\n",
prgname, argv[0], argv[2]);
return -1;
}
if (cmd->t[1].tv_sec || !cmd->t[1].tv_nsec) {
fprintf(stderr, "%s: %s: duration must be < 1s and > 0s (got \"%s\")\n",
prgname, argv[0], argv[2]);
return -1;
}
if (ioctl(fd, PRIV_MEZZANINE_CMD, (unsigned long) cmd) < 0) {
fprintf(stderr, "%s: ioctl(PRIV_MEZZANINE_CMD(%s)): %s.\n"
"The new pulse width must be coherent with the previously programmed period\n",
prgname, devname, strerror(errno));
return -1;
}
return 0;
}
static int scan_stamp(int argc, char **argv, int ismask)
{
int i, ch;
......@@ -151,16 +208,17 @@ static int scan_stamp(int argc, char **argv, int ismask)
cmd->flags = WR_DIO_F_WAIT;
argc = 2;
}
fprintf(stderr,"scan stamp argc %d\n", argc);
if (argc == 1) {
ismask = 1;
ch = 0x1f;
ch = 0x3f;
} else if (argc == 2) {
if (sscanf(argv[1], "%i%c", &ch, &c) != 1) {
fprintf(stderr, "%s: %s: not a channel \"%s\"\n",
prgname, argv[0], argv[1]);
exit(1);
}
if (ch < 0 || ch > 31 || (!ismask && ch > 4)) {
if (ch < 0 || ch > 31 || (!ismask && ch > 5)) {
fprintf(stderr, "%s: %s: out of range channel \"%s\"\n",
prgname, argv[0], argv[1]);
exit(1);
......@@ -190,8 +248,9 @@ static int scan_stamp(int argc, char **argv, int ismask)
return -1;
}
for (i = 0; i < cmd->nstamp; i++)
printf("ch %i, %9li.%09li\n", cmd->channel,
(long)cmd->t[i].tv_sec, cmd->t[i].tv_nsec);
printf("ch %i, %9li.%09li (leap second: value=%d, valid=%01x, flag59=%01x, flag61=%01x) \n", cmd->channel,
(long)cmd->t[i].tv_sec, cmd->t[i].tv_nsec, cmd->wr_ts_info_buf[i].leap_second, cmd->wr_ts_info_buf[i].leap_second_valid,
cmd->wr_ts_info_buf[i].flag59, cmd->wr_ts_info_buf[i].flag61);
}
return 0;
}
......@@ -305,6 +364,130 @@ static int scan_inout(int argc, char **argv)
return 0;
}
static int scan_mask_irq(int argc, char **argv)
{
int i, ch;
char c;
uint32_t value_internal;
cmd->flags = WR_DIO_F_MASK;
cmd->channel = 0;
cmd->value = 0;
if (argc == 2) {
cmd->value = WR_DIO_F_MASK_READ_IRQ;
} else if (argc == 3){
if (argv[2][0] == 'Y') {
cmd->value = WR_DIO_F_MASK_ENABLE_IRQ;
}
else if (argv[2][0] == 'y') {
cmd->value = WR_DIO_F_MASK_DISABLE_IRQ;
}
else
fprintf(stderr, "%s: mask_irq: invalid argument "
"\"%s\"\n", prgname, argv[2]);
} else {
fprintf(stderr, "%s: %s: wrong number of arguments\n",
prgname, argv[0]);
fprintf(stderr, " Use: %s <channel> "
"[<Y/y>]\n", argv[0]);
return -1;
}
if (sscanf(argv[1], "%i", &ch) != 1 || ch < 0 || ch > 5) {
fprintf(stderr, "%s: mask_irq: invalid channel "
"\"%s\"\n", prgname, argv[1]);
return -1;
}
cmd->channel |= 1 << ch;
value_internal = cmd->value; //Save value to read mask
if (ioctl(fd, PRIV_MEZZANINE_CMD, cmd) < 0) {
fprintf(stderr, "%s: ioctl(PRIV_MEZZANINE_CMD(%s)): %s\n",
prgname, devname, strerror(errno));
return -1;
}
if ( value_internal == WR_DIO_F_MASK_READ_IRQ ) {
if(cmd->value == WR_DIO_F_MASK_ENABLE_IRQ)
printf("Ch %i interrupt enabled\n",ch);
else
printf("Ch %i interrupt disabled\n",ch);
}
return 0;
}
static int scan_irq(int argc, char **argv)
{
char c;
if (argc != 2 && argc != 4) {
fprintf(stderr, "%s: %s: wrong number of arguments\n",
prgname, argv[0]);
fprintf(stderr, " Use: %s <when> "
"[<period> <count>]\n", argv[0]);
return -1;
}
/* Next argument is the "when", position 0 in ioctl timestamp array */
if (!strcmp(argv[1], "now")) {
cmd->flags |= WR_DIO_F_NOW;
} else {
char *s2 = argv[1];
if (s2[0] == '+') {
cmd->flags |= WR_DIO_F_REL;
s2++;
}
if (parse_ts(s2, cmd->t) < 0) {
fprintf(stderr, "%s: invalid time \"%s\"\n",
prgname, argv[1]);
return -1;
}
}
/* If argc is 4, we have period and count */
if (argc == 4) {
cmd->flags |= WR_DIO_F_LOOP;
if (parse_ts(argv[2], cmd->t + 1) < 0) {
fprintf(stderr, "%s: %s: invalid time \"%s\"\n",
prgname, argv[0], argv[1]);
return -1;
}
if(cmd->t[1].tv_nsec < 1000000 || cmd->t[1].tv_sec > 2)
{
fprintf(stderr, "%s: %s: Frequency is greater than 1 kHz and lower than 0.5 Hz\n",
prgname, argv[0]);
return -1;
}
if(cmd->t[1].tv_nsec % 8)
{
fprintf(stderr, "%s: %s: Period value is not a multiple of reference frequency \n",
prgname, argv[0]);
return -1;
}
if (sscanf(argv[3], "%i%c", &cmd->value, &c) != 1) {
fprintf(stderr, "%s: %s: invalid count \"%s\"\n",
prgname, argv[0], argv[3]);
return -1;
}
}
if (ioctl(fd, PRIV_MEZZANINE_CMD, (unsigned long) cmd) < 0) {
fprintf(stderr, "%s: ioctl(PRIV_MEZZANINE_CMD(%s)): %s\n",
prgname, devname, strerror(errno));
return -1;
}
return 0;
}
static void print_version(char *pname)
{
printf("%s %s\n", pname, git_version);
......@@ -356,6 +539,8 @@ int main(int argc, char **argv)
*
* mode <01234>
* mode <ch> <mode> [...]
*
* irq <seconds>.<fraction> [<period> <count>]
*/
if (!strcmp(argv[0], "pulse")) {
cmd->command = WR_DIO_CMD_PULSE;
......@@ -363,6 +548,7 @@ int main(int argc, char **argv)
exit(1);
} else if (!strcmp(argv[0], "stamp")) {
cmd->command = WR_DIO_CMD_STAMP;
fprintf(stderr,"Calling scan_stamp\n");
if (scan_stamp(argc, argv, 0 /* no mask */) < 0)
exit(1);
} else if (!strcmp(argv[0], "stampm")) {
......@@ -373,6 +559,18 @@ int main(int argc, char **argv)
cmd->command = WR_DIO_CMD_INOUT;
if (scan_inout(argc, argv) < 0)
exit(1);
} else if (!strcmp(argv[0], "irq")) {
cmd->command = WR_DIO_CMD_IRQ;
if (scan_irq(argc, argv) < 0)
exit(1);
} else if (!strcmp(argv[0], "update_width")) {
cmd->command = WR_DIO_CMD_UPDATE_WIDTH;
if (scan_width(argc, argv) < 0)
exit(1);
} else if (!strcmp(argv[0], "mask_irq")) {
cmd->command = WR_DIO_CMD_MASK_IRQ;
if (scan_mask_irq(argc, argv) < 0)
exit(1);
} else {
fprintf(stderr, "%s: unknown command \"%s\"\n", prgname,
argv[0]);
......
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