Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
M
Mock Turtle
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
Mock Turtle
Commits
a4fa5915
Commit
a4fa5915
authored
Apr 05, 2019
by
Federico Vaga
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'release/v4.0.0.beta2'
parents
c87ca048
533062b6
Show whitespace changes
Inline
Side-by-side
Showing
77 changed files
with
2202 additions
and
649 deletions
+2202
-649
.gitignore
.gitignore
+1
-0
Makefile
demos/alarm_clock/firmware/fw-01/Makefile
+6
-5
TBuild
demos/alarm_clock/firmware/fw-01/TBuild
+3
-0
Makefile
demos/data_generator/firmware/fw-01/Makefile
+6
-5
TBuild
demos/data_generator/firmware/fw-01/TBuild
+3
-0
Makefile
demos/fmc-spec-carrier/software/firmware/fw-01/Makefile
+5
-14
TBuild
demos/fmc-spec-carrier/software/firmware/fw-01/TBuild
+13
-0
Makefile
demos/fmc-spec-carrier/software/firmware/fw-02/Makefile
+5
-15
TBuild
demos/fmc-spec-carrier/software/firmware/fw-02/TBuild
+14
-0
Makefile
demos/fmc-svec-carrier/software/firmware/fw-01/Makefile
+5
-14
TBuild
demos/fmc-svec-carrier/software/firmware/fw-01/TBuild
+13
-0
Makefile
demos/fmc-svec-carrier/software/firmware/fw-02/Makefile
+5
-15
TBuild
demos/fmc-svec-carrier/software/firmware/fw-02/TBuild
+14
-0
Makefile
demos/hello_world/firmware/fw-01/Makefile
+6
-5
TBuild
demos/hello_world/firmware/fw-01/TBuild
+3
-0
Makefile
demos/hello_world_framework/firmware/fw-01/Makefile
+6
-5
TBuild
demos/hello_world_framework/firmware/fw-01/TBuild
+3
-0
firmware-library.rst
doc/software/firmware-library.rst
+3
-1
index-fw.rst
doc/software/index-fw.rst
+30
-13
linux-driver.rst
doc/software/linux-driver.rst
+5
-7
linux-library.rst
doc/software/linux-library.rst
+0
-15
Makefile
software/Makefile
+1
-0
Makefile
software/firmware/Makefile
+48
-34
mockturtle-framework.c
software/firmware/framework/mockturtle-framework.c
+0
-4
mockturtle-framework.h
software/firmware/framework/mockturtle-framework.h
+0
-1
mockturtle-rt.h
software/firmware/lib/mockturtle-rt.h
+4
-0
Makefile
software/include/hw/Makefile
+1
-1
mockturtle_addresses.h
software/include/hw/mockturtle_addresses.h
+2
-0
mockturtle.h
software/include/mockturtle.h
+11
-40
Makefile
software/kernel/Makefile
+2
-0
mockturtle-compat.c
software/kernel/mockturtle-compat.c
+50
-0
mockturtle-compat.h
software/kernel/mockturtle-compat.h
+20
-0
mockturtle-core.c
software/kernel/mockturtle-core.c
+4
-2
mockturtle-dbg.c
software/kernel/mockturtle-dbg.c
+59
-0
mockturtle-drv.h
software/kernel/mockturtle-drv.h
+22
-11
mockturtle-hmq.c
software/kernel/mockturtle-hmq.c
+147
-158
Makefile
software/lib/Makefile
+3
-2
PyMockTurtle.py
software/lib/PyMockTurtle/PyMockTurtle/PyMockTurtle.py
+12
-14
__init__.py
software/lib/PyMockTurtle/PyMockTurtle/__init__.py
+3
-1
setup.py
software/lib/PyMockTurtle/setup.py
+1
-1
libmockturtle-internal.h
software/lib/libmockturtle-internal.h
+1
-2
libmockturtle.c
software/lib/libmockturtle.c
+98
-186
libmockturtle.h
software/lib/libmockturtle.h
+3
-7
.gitignore
software/tools/.gitignore
+1
-0
Makefile
software/tools/Makefile
+7
-5
mockturtle-gdbserver.c
software/tools/mockturtle-gdbserver.c
+1234
-0
Makefile
tests/firmware/Makefile
+1
-0
Makefile
tests/firmware/config_rom/Makefile
+6
-5
TBuild
tests/firmware/config_rom/TBuild
+3
-0
Makefile
tests/firmware/cpu-byte-addressing/Makefile
+6
-5
TBuild
tests/firmware/cpu-byte-addressing/TBuild
+3
-0
Makefile
tests/firmware/cpu-loop/Makefile
+6
-5
TBuild
tests/firmware/cpu-loop/TBuild
+3
-0
Makefile
tests/firmware/cpu-notify/Makefile
+6
-5
TBuild
tests/firmware/cpu-notify/TBuild
+3
-0
Makefile
tests/firmware/hmq-async-recv/Makefile
+6
-5
TBuild
tests/firmware/hmq-async-recv/TBuild
+3
-0
hmq-async-recv.c
tests/firmware/hmq-async-recv/hmq-async-recv.c
+1
-0
Makefile
tests/firmware/hmq-async-send/Makefile
+6
-5
TBuild
tests/firmware/hmq-async-send/TBuild
+3
-0
Makefile
tests/firmware/hmq-purge/Makefile
+6
-5
TBuild
tests/firmware/hmq-purge/TBuild
+3
-0
Kconfig
tests/firmware/hmq-sync/Kconfig
+19
-0
Makefile
tests/firmware/hmq-sync/Makefile
+8
-0
TBuild
tests/firmware/hmq-sync/TBuild
+3
-0
mt_defconfig
tests/firmware/hmq-sync/configs/mt_defconfig
+35
-0
hmq-sync.c
tests/firmware/hmq-sync/hmq-sync.c
+41
-0
Makefile
tests/firmware/rmq-udp-send/Makefile
+5
-8
TBuild
tests/firmware/rmq-udp-send/TBuild
+5
-0
Makefile
tests/firmware/rt-frm/Makefile
+6
-5
TBuild
tests/firmware/rt-frm/TBuild
+3
-0
Makefile
tests/firmware/serial/Makefile
+6
-7
TBuild
tests/firmware/serial/TBuild
+3
-0
Makefile
tests/firmware/sim-verif/Makefile
+6
-5
TBuild
tests/firmware/sim-verif/TBuild
+3
-0
test_config.py
tests/test_config.py
+2
-2
test_hmq.py
tests/test_hmq.py
+109
-4
No files found.
.gitignore
View file @
a4fa5915
GPATH
GRTAGS
GTAGS
Makefile.specific
demos/alarm_clock/firmware/fw-01/Makefile
View file @
a4fa5915
OBJS
=
fw-ac.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-ac
TRTL
?=
../../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
demos/alarm_clock/firmware/fw-01/TBuild
0 → 100644
View file @
a4fa5915
OBJS = fw-ac.o
OBJS += # add other object files that you need
OUTPUT = fw-ac
demos/data_generator/firmware/fw-01/Makefile
View file @
a4fa5915
OBJS
=
fw-dg.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-dg
TRTL
?=
../../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
demos/data_generator/firmware/fw-01/TBuild
0 → 100644
View file @
a4fa5915
OBJS = fw-dg.o
OBJS += # add other object files that you need
OUTPUT = fw-dg
demos/fmc-spec-carrier/software/firmware/fw-01/Makefile
View file @
a4fa5915
include
../../../project.mk
OBJS
=
fw-spec.o
OBJS
+=
common/fw-spec-smem-code.o
OBJDIR
+=
common
OUTPUT
=
fw-spec-1
TRTL
?=
../../../../../
TRTL_SW
=
$(TRTL)
/software
EXTRA_CFLAGS
+=
-I
../../include
EXTRA_CFLAGS
+=
-I
../common
EXTRA_CFLAGS
+=
-DFPGA_APPLICATION_ID
=
APPLICATION_ID
EXTRA_CFLAGS
+=
-DRT_APPLICATION_ID
=
$(RT_APPLICATION_ID_CPU1)
TRTL_FW
=
$(TRTL)
/software/firmware
vpath
%.c
../
all
:
include
$(TRTL_SW)/firmware/Makefile
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
demos/fmc-spec-carrier/software/firmware/fw-01/TBuild
0 → 100644
View file @
a4fa5915
include $(src)/../../../project.mk
OBJS = fw-spec.o
OBJS += common/fw-spec-smem-code.o
OBJDIR += common
OUTPUT = fw-spec-1
EXTRA_CFLAGS += -I$(src)/../../include
EXTRA_CFLAGS += -I$(src)/../common
EXTRA_CFLAGS += -DFPGA_APPLICATION_ID=APPLICATION_ID
EXTRA_CFLAGS += -DRT_APPLICATION_ID=$(RT_APPLICATION_ID_CPU1)
vpath %.c $(src)../
demos/fmc-spec-carrier/software/firmware/fw-02/Makefile
View file @
a4fa5915
include
../../../project.mk
OBJS
=
fw-spec.o
OBJS
+=
common/fw-spec-smem-code.o
OBJDIR
+=
common
OUTPUT
=
fw-spec-2
TRTL
?=
../../../../../
TRTL_SW
=
$(TRTL)
/software
EXTRA_CFLAGS
+=
-I
../../include
EXTRA_CFLAGS
+=
-I
../common
EXTRA_CFLAGS
+=
-DFPGA_APPLICATION_ID
=
$(APPLICATION_ID)
EXTRA_CFLAGS
+=
-DRT_APPLICATION_ID
=
$(RT_APPLICATION_ID_CPU2)
EXTRA_CFLAGS
+=
-DLIBRT_DEBUG_VERBOSE
-DLIBRT_DEBUG
TRTL_FW
=
$(TRTL)
/software/firmware
vpath
%.c
../
all
:
include
$(TRTL_SW)/firmware/Makefile
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
demos/fmc-spec-carrier/software/firmware/fw-02/TBuild
0 → 100644
View file @
a4fa5915
include $(src)../../../project.mk
OBJS = fw-spec.o
OBJS += common/fw-spec-smem-code.o
OBJDIR += common
OUTPUT = fw-spec-2
EXTRA_CFLAGS += -I$(src)/../../include
EXTRA_CFLAGS += -I$(src)/../common
EXTRA_CFLAGS += -DFPGA_APPLICATION_ID=$(APPLICATION_ID)
EXTRA_CFLAGS += -DRT_APPLICATION_ID=$(RT_APPLICATION_ID_CPU2)
EXTRA_CFLAGS += -DLIBRT_DEBUG_VERBOSE -DLIBRT_DEBUG
vpath %.c $(src)/../
demos/fmc-svec-carrier/software/firmware/fw-01/Makefile
View file @
a4fa5915
include
../../../project.mk
OBJS
=
fw-svec.o
OBJS
+=
common/fw-svec-smem-code.o
OBJDIR
+=
common
OUTPUT
=
fw-svec-1
TRTL
?=
../../../../../
TRTL_SW
=
$(TRTL)
/software
EXTRA_CFLAGS
+=
-I
../../include
EXTRA_CFLAGS
+=
-I
../common
EXTRA_CFLAGS
+=
-DFPGA_APPLICATION_ID
=
APPLICATION_ID
EXTRA_CFLAGS
+=
-DRT_APPLICATION_ID
=
$(RT_APPLICATION_ID_CPU1)
TRTL_FW
=
$(TRTL)
/software/firmware
vpath
%.c
../
all
:
include
$(TRTL_SW)/firmware/Makefile
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
demos/fmc-svec-carrier/software/firmware/fw-01/TBuild
0 → 100644
View file @
a4fa5915
include $(src)/../../../project.mk
OBJS = fw-svec.o
OBJS += common/fw-svec-smem-code.o
OBJDIR += common
OUTPUT = fw-svec-1
EXTRA_CFLAGS += -I$(src)/../../include
EXTRA_CFLAGS += -I$(src)/../common
EXTRA_CFLAGS += -DFPGA_APPLICATION_ID=APPLICATION_ID
EXTRA_CFLAGS += -DRT_APPLICATION_ID=$(RT_APPLICATION_ID_CPU1)
vpath %.c $(src)/../
demos/fmc-svec-carrier/software/firmware/fw-02/Makefile
View file @
a4fa5915
include
../../../project.mk
OBJS
=
fw-svec.o
OBJS
+=
common/fw-svec-smem-code.o
OBJDIR
+=
common
OUTPUT
=
fw-svec-2
TRTL
?=
../../../../../
TRTL_SW
=
$(TRTL)
/software
EXTRA_CFLAGS
+=
-I
../../include
EXTRA_CFLAGS
+=
-I
../common
EXTRA_CFLAGS
+=
-DFPGA_APPLICATION_ID
=
$(APPLICATION_ID)
EXTRA_CFLAGS
+=
-DRT_APPLICATION_ID
=
$(RT_APPLICATION_ID_CPU2)
EXTRA_CFLAGS
+=
-DLIBRT_DEBUG_VERBOSE
-DLIBRT_DEBUG
TRTL_FW
=
$(TRTL)
/software/firmware
vpath
%.c
../
all
:
include
$(TRTL_SW)/firmware/Makefile
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
demos/fmc-svec-carrier/software/firmware/fw-02/TBuild
0 → 100644
View file @
a4fa5915
include $(src)/../../../project.mk
OBJS = fw-svec.o
OBJS += common/fw-svec-smem-code.o
OBJDIR += common
OUTPUT = fw-svec-2
EXTRA_CFLAGS += -I$(src)/../../include
EXTRA_CFLAGS += -I$(src)/../common
EXTRA_CFLAGS += -DFPGA_APPLICATION_ID=$(APPLICATION_ID)
EXTRA_CFLAGS += -DRT_APPLICATION_ID=$(RT_APPLICATION_ID_CPU2)
EXTRA_CFLAGS += -DLIBRT_DEBUG_VERBOSE -DLIBRT_DEBUG
vpath %.c $(src)/../
demos/hello_world/firmware/fw-01/Makefile
View file @
a4fa5915
OBJS
=
fw-hello.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-hello
TRTL
?=
../../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
demos/hello_world/firmware/fw-01/TBuild
0 → 100644
View file @
a4fa5915
OBJS = fw-hello.o
OBJS += # add other object files that you need
OUTPUT = fw-hello
demos/hello_world_framework/firmware/fw-01/Makefile
View file @
a4fa5915
OBJS
=
fw-hellofrm.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-hellofrm
TRTL
?=
../../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
demos/hello_world_framework/firmware/fw-01/TBuild
0 → 100644
View file @
a4fa5915
OBJS = fw-hellofrm.o
OBJS += # add other object files that you need
OUTPUT = fw-hellofrm
doc/software/firmware-library.rst
View file @
a4fa5915
...
...
@@ -132,7 +132,9 @@ The typical procedure to send (output) messages over is the following.
#. *claim* a mq in order to get exclusive access to it;
#. *map* the claimed mq slot in order to get the buffer where to write;
#. *map* the claimed mq slot in order to get the buffer where to write. Keep
in mind that the memory is not initialized, so you probably need to set
correctly all header fields;
#. *write* your message;
...
...
doc/software/index-fw.rst
View file @
a4fa5915
...
...
@@ -43,11 +43,10 @@ memory) or you need much better performances: don't use this framework.
All the Mock Turtle firmware source code can be found in the directory
``/path/to/mockturtle/software/firmware/``.
Mock Turtle has a generic ``Makefile`` that you should include in your
``Makefile`` in order to import all the Mock Turtle building rules.::
TRTL ?= /path/to/mcokturtle/
TRTL_SW = $(TRTL)/software
Mock Turtle has a generic building system which can be used to produce
Mock Turtle firmware applications. What you have to do is to prepare a
file named ``TBuild`` next to your firmware source files. In this file
you have to specify what to build, for example::
# Mandatory
OBJS = source1.o
...
...
@@ -56,15 +55,10 @@ Mock Turtle has a generic ``Makefile`` that you should include in your
OUTPUT = firmware-name
# Optional (prefer default when possible)
CFLAGS_OPT := -O1
CFLAGS_DBG := -ggdb
EXTRA_CFLGAS :=
EXTRA_CFLAGS :=
MOCKTURTLE_LDSCRIPT := myfirmware.ld
# INCLUDE GENERIC Makefile
include $(TRTL_SW)/firmware/Makefile
Here the list of supported Makefile environment variables
Here the list of supported TBuild variables
OBJS
(Mandatory) List of object files to generate from sources with
...
...
@@ -74,10 +68,33 @@ OBJS
OUTPUT
(Mandatory) Final binary name (the firmware).
EXTRA_CFLAGS
(Optional) Additional compiler options.
MOCKTURTLE_LDSCRIPT
(Optional
) Local path to the linker script.
(Optional) Local path to the linker script.
The default is the standard Mock Turtle linker script.
You can build such firmware application by calling ``make`` from the
application directory (where the ``TBuild`` file is) like this::
make -C <path-to-mockturtle-project>/software/firmware M=$PWD
Or alternatively, you can copy the following lines in a Makefile::
TRTL_FW = $(TRTL)/software/firmware
all:
# Redirect all rules to MockTurtle
%:
$(MAKE) -C $(TRTL_FW) M=$(shell /bin/pwd) $@
Then, you will compile your application with the following command
from the application directory (where the ``TBuild`` file is)::
make TRTL=<path-to-mockturtle-project>
Memory resources on Mock Turtle are very limited and the full framework
may take more space than needed. For this reason Mock Turtle has
*Kconfig* support which allows you to interactivly enable/disable both
...
...
doc/software/linux-driver.rst
View file @
a4fa5915
...
...
@@ -207,17 +207,15 @@ The Mock Turtle driver exports a *char device* for each Mock Turtle HMQ.
All HMQ instances will appear as child of a :ref:`sw:drv:core`; in
*/dev/mockturtle/* you will have devices named ``trtl-%04x-%02d-%02d``
(trtl-<device-id>-<cpu-index>-<hmq-index>). The main purpose of this
interface is to exchange messages and configure filters. These devices
are bidirectional, so you can: ``write(2)`` to send messaged;
``read(2)`` to receive messages; ``poll(2)`` or ``select(2)`` to wait
for the interface to become accessible.
interface is to exchange messages. These devices are bidirectional,
so you can: ``write(2)`` to send messaged; ``read(2)`` to receive messages;
``poll(2)`` or ``select(2)`` to wait for the interface to become accessible.
This *char device* provides a set of ``ioctl(2)`` commands:
.. doxygendefine:: TRTL_IOCTL_MSG_FILTER_ADD
.. doxygendefine:: TRTL_IOCTL_MSG_FILTER_CLEAN
.. doxygendefine:: TRTL_IOCTL_HMQ_SYNC_SET
.. doxygendefine:: TRTL_IOCTL_MSG_SYNC_ABORT
You can find the HMQ *sysfs* attributes at::
...
...
doc/software/linux-library.rst
View file @
a4fa5915
...
...
@@ -153,21 +153,6 @@ side so that the complete flush happens synchronously.
.. doxygenfunction:: trtl_hmq_flush
The Mock Turtle driver has a basic message filtering mechanism. Each
user can add a set of filters on any host message queue. Mock Turtle
will deliver to the user only those messages which pass the filter.
Rembember that this is a user filter, this means that on the same
host message queue, different users can have different filters.
.. doxygenfunction:: trtl_hmq_filter_add
.. doxygenfunction:: trtl_hmq_filter_clean
.. doxygenenum:: trtl_msg_filter_operation_type
.. doxygenstruct:: trtl_msg_filter
:members:
Then, there are the functions to exchange messages with firmware
running on Mock Turtle. This API offers a minimum set of function
to allow users to send/receive synchronous/asynchronous messages.
...
...
software/Makefile
View file @
a4fa5915
-include
Makefile.specific
# include parent_common.mk for buildsystem's defines
# use absolute path for REPO_PARENT
CURDIR
:=
$(
shell
/bin/pwd
)
...
...
software/firmware/Makefile
View file @
a4fa5915
-include
Makefile.specific
-include
$(CURDIR)/.config
src
:=
$(M)
/
-include
$(src)/Makefile.specific
-include
$(src)/.config
include
$(src)/TBuild
# Validation
ifndef
OUTPUT
$(error
Missing
variable
OUTPUT)
else
build_output
=
$(src)
/
$(OUTPUT)
endif
ifndef
OBJS
$(error
Missing
variable
OBJS)
endif
# and don't touch the rest unless you know what you're doing.
INSTALL_PREFIX
?=
.
...
...
@@ -7,11 +22,12 @@ PATH_COMMON_RT ?= .
PATH_COMMON_H
?=
../include
TRTL
?=
../../
TRTL_SW
?=
$(TRTL)
/software
TRTL_FW
?=
$(TRTL_SW)
/firmware
TRTL_HDL
?=
$(TRTL)
/hdl/rtl
RT_GIT_VERSION
=
0x
$(
shell
git rev-parse
--short
=
8 HEAD
||
echo
"0"
)
# empty if git is not there
# header file generated from the .config
AUTOCONF
=
$(
CURDIR
)
/
$(BUILDDIR)
/include/generated/autoconf.h
AUTOCONF
=
$(
src
)
/
$(BUILDDIR)
/include/generated/autoconf.h
CROSS_COMPILE_TARGET
?=
riscv32-elf-
# FIXME the mult/div is broken, for the time being remove it completely
...
...
@@ -21,10 +37,12 @@ CFLAGS += -mabi=ilp32 -march=rv32im -ffunction-sections -fdata-sections
LDFLAGS
+=
-lgcc
-lc
-Wl
,--gc-sections
# provide search patch for sources
vpath
%.c
$(TRTL)/software/firmware
vpath
%.S
$(TRTL)/software/firmware
vpath
%.c
$(TRTL_FW)
vpath
%.S
$(TRTL_FW)
vpath
%.c
$(src)
vpath
%.S
$(src)
BUILDDIR
:=
build
BUILDDIR
:=
$(src)
/
build
# auto dependency generation from
# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
...
...
@@ -42,10 +60,10 @@ STRIP = $(CROSS_COMPILE_TARGET)strip
CFLAGS
+=
-Wall
-D__TRTL_FIRMWARE__
-DARCH
=
urv
CFLAGS
+=
-I
.
CFLAGS
+=
-I
$(BUILDDIR)
/include
CFLAGS
+=
-I
$(TRTL
)
/software/firmware
CFLAGS
+=
-I
$(TRTL
)
/software/firmware
/lib
CFLAGS
+=
-I
$(TRTL
)
/software/firmware
/framework
CFLAGS
+=
-I
$(TRTL
)
/software
/include
CFLAGS
+=
-I
$(TRTL
_FW)
CFLAGS
+=
-I
$(TRTL
_FW)
/lib
CFLAGS
+=
-I
$(TRTL
_FW)
/framework
CFLAGS
+=
-I
$(TRTL
_SW)
/include
CFLAGS
+=
-DGIT_VERSION
=
$(RT_GIT_VERSION)
# used for firmware by trtl-project-creator
...
...
@@ -76,11 +94,11 @@ OBJS_BUILD = $(addprefix $(BUILDDIR)/, $(OBJS))
OBJDIR_BUILD
=
$
(
addprefix
$(BUILDDIR)
/,
$(OBJDIR)
)
OBJDIR_BUILD
+=
$(BUILDDIR)
MOCKTURTLE_LDSCRIPT
?=
$(TRTL
)
/software/firmware
/urv/mockturtle.ld
MOCKTURTLE_LDSCRIPT
?=
$(TRTL
_FW)
/urv/mockturtle.ld
.PHONY
:
all clean cleanall
check-def
.PHONY
:
all clean cleanall
all
:
$(
OUTPUT
).bin
all
:
$(
build_output
).bin
WBGEN_FILES
=
mt_cpu_csr.wb mt_cpu_lr.wb
WBGEN_HEADERS
=
mockturtle_cpu_csr.h mockturtle_cpu_lr.h
...
...
@@ -93,16 +111,9 @@ $(TRTL_SW)/include/hw/mockturtle_cpu_csr.h: $(TRTL_HDL)/cpu/mt_cpu_csr.wb
$(TRTL_SW)/include/hw/mockturtle_cpu_lr.h
:
$(TRTL_HDL)/cpu/mt_cpu_lr.wb
# target to let wbgen2 to generate headers
$(addprefix $(TRTL_SW)/include/hw/,$(WBGEN_HEADERS))
:
| check-def
$(addprefix $(TRTL_SW)/include/hw/,$(WBGEN_HEADERS))
:
make
-C
$(TRTL_SW)
headers
# check needed env variables
check-def
:
ifndef
OUTPUT
@echo
"OUTPUT variable is mandatory"
@exit
1
endif
# create dirs for object files
$(OBJDIR_BUILD)
:
mkdir
-p
$@
...
...
@@ -112,12 +123,13 @@ $(OBJDIR_BUILD):
$(OBJS_BUILD)
:
| $(AUTOCONF)
$(OBJS_BUILD)
:
| $(OBJDIR_BUILD)
$(OUTPUT).elf
:
$(addprefix $(TRTL_SW)/include/hw/
,
$(WBGEN_HEADERS)) $(MOCKTURTLE_LDSCRIPT) $(OBJS_BUILD) | check-def
${
CC
}
$(CFLAGS)
$(LDFLAGS)
-o
$(OUTPUT)
.elf
-nostartfiles
$(OBJS_BUILD)
-T
$(MOCKTURTLE_LDSCRIPT)
$(build_output).elf
:
$(addprefix $(TRTL_SW)/include/hw/
,
$(WBGEN_HEADERS)) $(MOCKTURTLE_LDSCRIPT) $(OBJS_BUILD)
$
(
warning
$(OBJS_BUILD)
)
${
CC
}
$(CFLAGS)
$(LDFLAGS)
-o
$(build_output)
.elf
-nostartfiles
$(OBJS_BUILD)
-T
$(MOCKTURTLE_LDSCRIPT)
$(
OUTPUT).bin
:
$(OUTPUT).elf | check-de
f
${
OBJCOPY
}
--remove-section
.smem
-O
binary
$(
OUTPUT)
.elf
$(OUTPUT
)
.bin
$(SIZE)
$(
OUTPUT
)
.elf
$(
build_output).bin
:
$(build_output).el
f
${
OBJCOPY
}
--remove-section
.smem
-O
binary
$(
build_output)
.elf
$(build_output
)
.bin
$(SIZE)
$(
build_output
)
.elf
$(BUILDDIR)/urv/emulate.o
:
urv/emulate.c
${
CC
}
$(DEPFLAGS)
$(CFLAGS)
-march
=
rv32i
-c
$<
-o
$@
...
...
@@ -126,13 +138,15 @@ $(BUILDDIR)/urv/emulate.o: urv/emulate.c
$(BUILDDIR)/%.o
:
%.c
${
CC
}
$(DEPFLAGS)
$(CFLAGS)
$(LDFLAGS)
-c
$<
-o
$@
$(POSTCOMPILE)
$
(
warning
$<
----
$@
)
@
echo
""
$(BUILDDIR)/%.o
:
%.S
${
CC
}
$(DEPFLAGS)
$(CFLAGS)
$(LDFLAGS)
-c
$<
-o
$@
$(POSTCOMPILE)
clean
:
rm
-f
$(
OUTPUT)
.bin
$(OUTPUT
)
.elf
rm
-f
$(
build_output)
.bin
$(build_output
)
.elf
rm
-rf
$(BUILDDIR)
clean-dot-config
:
...
...
@@ -141,7 +155,7 @@ clean-dot-config:
cleanall
:
clean clean-dot-config
install
:
@
cp
$(
OUTPUT
)
.bin
$(INSTALL_PREFIX)
@
cp
$(
build_output
)
.bin
$(INSTALL_PREFIX)
# inlude *.d files from the build directory
include
$(wildcard
$(patsubst
%,%/.d/*.d,$(basename
$(OBJDIR_BUILD))))
...
...
@@ -150,20 +164,20 @@ include $(wildcard $(patsubst %,%/.d/*.d,$(basename $(OBJDIR_BUILD))))
# following targets from Makefile.kconfig
# this one is used to generate autoconf.h file
$(AUTOCONF) silentoldconfig
:
.config | $(BUILDDIR)
export
KCONFIG_CONFIG
=
$(
CURDIR
)
/.config
;
\
$(MAKE)
quiet
=
quiet_
KBUILD_KCONFIG
=
$(
CURDIR)
/Kconfig
projtree
=
$(CURDIR)
/
$(BUILDDIR)
-C
$(TRTL)
/software/firmware
-f
Makefile.kconfig silentoldconfig
export
KCONFIG_CONFIG
=
$(
src
)
/.config
;
\
$(MAKE)
quiet
=
quiet_
KBUILD_KCONFIG
=
$(
src)
/Kconfig
projtree
=
$(BUILDDIR)
-C
$(TRTL_FW)
-f
Makefile.kconfig silentoldconfig
scripts_basic config
:
$(MAKE)
quiet
=
quiet_
KBUILD_KCONFIG
=
$(
CURDIR)
/Kconfig
projtree
=
$(CURDIR)
-C
$(TRTL)
/software/firmware
-f
Makefile.kconfig
$@
$(MAKE)
quiet
=
quiet_
KBUILD_KCONFIG
=
$(
src)
/Kconfig
projtree
=
$(src)
-C
$(TRTL_FW)
-f
Makefile.kconfig
$@
%config
:
$(MAKE)
quiet
=
quiet_
KBUILD_KCONFIG
=
$(
CURDIR)
/Kconfig
projtree
=
$(CURDIR)
-C
$(TRTL)
/software/firmware
-f
Makefile.kconfig
$@
$(MAKE)
quiet
=
quiet_
KBUILD_KCONFIG
=
$(
src)
/Kconfig
projtree
=
$(src)
-C
$(TRTL_FW)
-f
Makefile.kconfig
$@
defconfig
:
$(MAKE)
quiet
=
quiet_
KBUILD_KCONFIG
=
$(
CURDIR)
/Kconfig
projtree
=
$(CURDIR)
-C
$(TRTL)
/software/firmware
-f
Makefile.kconfig mt_defconfig
$(MAKE)
quiet
=
quiet_
KBUILD_KCONFIG
=
$(
src)
/Kconfig
projtree
=
$(src)
-C
$(TRTL_FW)
-f
Makefile.kconfig mt_defconfig
.config
:
;
# Explicit rule for .config
# needed since -include XXX triggers build for XXX
$(
CURDIR
)/.config
:
;
$(
src
)/.config
:
;
software/firmware/framework/mockturtle-framework.c
View file @
a4fa5915
...
...
@@ -303,7 +303,6 @@ static inline int rt_action_run(enum trtl_mq_type type,
msg_out
.
header
->
msg_id
=
0
;
msg_out
.
header
->
len
=
0
;
msg_out
.
header
->
sync_id
=
msg
->
header
->
sync_id
;
msg_out
.
header
->
seq
=
app
.
seq
++
;
err
=
action
(
msg
,
&
msg_out
);
if
(
err
)
...
...
@@ -408,7 +407,6 @@ int trtl_fw_mq_send_uint32(enum trtl_mq_type type,
msg
.
header
->
flags
=
0
;
msg
.
header
->
msg_id
=
msg_id
;
msg
.
header
->
len
=
n
;
msg
.
header
->
seq
=
app
.
seq
++
;
va_start
(
ap
,
n
);
for
(
i
=
0
;
i
<
msg
.
header
->
len
;
++
i
)
...
...
@@ -455,7 +453,6 @@ int trtl_fw_mq_send_buf(enum trtl_mq_type type,
msg
.
header
->
flags
=
0
;
msg
.
header
->
msg_id
=
msg_id
;
msg
.
header
->
len
=
n
/
4
;
msg
.
header
->
seq
=
app
.
seq
++
;
memcpy
(
msg
.
payload
,
data
,
n
);
mq_send
(
type
,
idx_mq
);
...
...
@@ -603,7 +600,6 @@ int trtl_fw_init(void)
{
int
err
;
app
.
seq
=
0
;
app
.
cfgrom
=
trtl_config_rom_get
();
err
=
trtl_fw_init_action
(
&
app
);
...
...
software/firmware/framework/mockturtle-framework.h
View file @
a4fa5915
...
...
@@ -88,7 +88,6 @@ struct trtl_fw_application {
trtl_fw_action_t
**
actions
;
/**< list of custum actions */
unsigned
int
n_actions
;
/**< number of custum actions */
unsigned
int
seq
;
/** sequence number reference */
const
struct
trtl_config_rom
*
cfgrom
;
/**< configuration ROM */
/* Operations */
...
...
software/firmware/lib/mockturtle-rt.h
View file @
a4fa5915
...
...
@@ -400,6 +400,8 @@ static inline uint32_t mq_readl(enum trtl_mq_type type, uint32_t reg)
* @param[in] type MQ type to use
* @param[in] slot slot number
* @return pointer to the input buffer
*
* Note: uninitialized memory
*/
static
inline
void
*
mq_map_out_buffer
(
enum
trtl_mq_type
type
,
int
slot
)
{
...
...
@@ -426,6 +428,8 @@ static inline void *mq_map_in_buffer(enum trtl_mq_type type, int slot)
* @param[in] type MQ type to use
* @param[in] slot slot number
* @return pointer to the output header
*
* Note: uninitialized memory
*/
static
inline
void
*
mq_map_out_header
(
enum
trtl_mq_type
type
,
int
slot
)
{
...
...
software/include/hw/Makefile
View file @
a4fa5915
HEADERS
:=
mockturtle_cpu_csr.h
HEADERS
+=
mockturtle_cpu_lr.h
TRTL
=
../../..
TRTL
?
=
../../..
TRTL_HDL
=
$(TRTL)
/hdl/rtl/
WBGEN2
?=
wbgen2
...
...
software/include/hw/mockturtle_addresses.h
View file @
a4fa5915
...
...
@@ -6,6 +6,8 @@
/* Host addresses. */
#define TRTL_ADDR_OFFSET_HMQ 0x00000000
#define TRTL_ADDR_OFFSET_CSR 0x0000C000
/* FIXME update memorymap to have DBG PAGE_ALIGNED */
#define TRTL_ADDR_OFFSET_DBG TRTL_ADDR_OFFSET_CSR
#define TRTL_ADDR_OFFSET_CONFIG_ROM 0x0000E000
#define TRTL_ADDR_OFFSET_SHM 0x00010000
...
...
software/include/mockturtle.h
View file @
a4fa5915
...
...
@@ -179,35 +179,6 @@ enum trtl_smem_modifier {
TRTL_SMEM_TYPE_TST_SET
,
/**< atomic test and set */
};
/**
* @enum trtl_msg_filter_operation_type
* List of available filter's operations
*/
enum
trtl_msg_filter_operation_type
{
TRTL_MSG_FILTER_AND
,
TRTL_MSG_FILTER_OR
,
TRTL_MSG_FILTER_EQ
,
TRTL_MSG_FILTER_NEQ
,
__TRTL_MSG_FILTER_MAX
,
};
#define TRTL_MSG_FILTER_FLAG_HEADER (0)
#define TRTL_MSG_FILTER_FLAG_PAYLOAD (1 << 0)
/**
* It describe a filter to apply to messages
*/
struct
trtl_msg_filter
{
unsigned
long
flags
;
/**< options for the filter */
uint32_t
operation
;
/**< kind of operation to perform */
uint32_t
word_offset
;
/**< offset of the word to check */
uint32_t
mask
;
/**< mask to apply before the operation */
uint32_t
value
;
/**< second operand of the operation */
};
/**
* Descriptor of the IO operation on Shared Memory
*/
...
...
@@ -225,8 +196,8 @@ struct trtl_smem_io {
*/
enum
trtl_ioctl_commands
{
TRTL_SMEM_IO
,
/**< access to shared memory */
TRTL_MSG_
FILTER_ADD
,
/**< add a message filter
*/
TRTL_
MSG_FILTER_CLEAN
,
/**< remove all filter
s */
TRTL_MSG_
SYNC_ABORT
,
/**< abort sync message
*/
TRTL_
HMQ_SYNC_SET
,
/**< Mark HMQ user context as synchronou
s */
};
...
...
@@ -235,19 +206,19 @@ enum trtl_ioctl_commands {
struct trtl_smem_io)
/**
* The IOCTL command to
add a filter to an HMQ
* The IOCTL command to
set HMQ user context to SYNC
*/
#define TRTL_IOCTL_
MSG_FILTER_ADD _IOW(TRTL_IOCTL_MAGIC,
\
TRTL_MSG_FILTER_ADD,
\
struct trtl_msg_filter
)
#define TRTL_IOCTL_
HMQ_SYNC_SET _IOW(TRTL_IOCTL_MAGIC,
\
TRTL_HMQ_SYNC_SET,
\
unsigned int
)
/**
* The IOCTL command to remove all filters from an HMQ
* The IOCTL command to abort a sync message. Usefull when the answer is
* not coming
*/
#define TRTL_IOCTL_MSG_FILTER_CLEAN _IOW(TRTL_IOCTL_MAGIC, \
TRTL_MSG_FILTER_CLEAN, \
struct trtl_msg_filter)
#define TRTL_IOCTL_MSG_SYNC_ABORT _IOW(TRTL_IOCTL_MAGIC, \
TRTL_MSG_SYNC_ABORT, \
unsigned int)
/**
* Messages descriptor for host
...
...
software/kernel/Makefile
View file @
a4fa5915
...
...
@@ -26,6 +26,8 @@ mockturtle-y += mockturtle-cpu.o
mockturtle-y
+=
mockturtle-hmq.o
mockturtle-y
+=
mockturtle-tty.o
mockturtle-y
+=
mockturtle-dbg.o
mockturtle-y
+=
mockturtle-dbg.o
mockturtle-y
+=
mockturtle-compat.o
all modules
:
...
...
software/kernel/mockturtle-compat.c
0 → 100644
View file @
a4fa5915
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2014-2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/version.h>
#include <linux/mm.h>
#include "mockturtle-compat.h"
#if KERNEL_VERSION(3, 9, 0) > LINUX_VERSION_CODE
/* Copied from v3.10 */
int
vm_iomap_memory
(
struct
vm_area_struct
*
vma
,
phys_addr_t
start
,
unsigned
long
len
)
{
unsigned
long
vm_len
,
pfn
,
pages
;
/* Check that the physical memory area passed in looks valid */
if
(
start
+
len
<
start
)
return
-
EINVAL
;
/*
* You *really* shouldn't map things that aren't page-aligned,
* but we've historically allowed it because IO memory might
* just have smaller alignment.
*/
len
+=
start
&
~
PAGE_MASK
;
pfn
=
start
>>
PAGE_SHIFT
;
pages
=
(
len
+
~
PAGE_MASK
)
>>
PAGE_SHIFT
;
if
(
pfn
+
pages
<
pfn
)
return
-
EINVAL
;
/* We start the mapping 'vm_pgoff' pages into the area */
if
(
vma
->
vm_pgoff
>
pages
)
return
-
EINVAL
;
pfn
+=
vma
->
vm_pgoff
;
pages
-=
vma
->
vm_pgoff
;
/* Can we fit all of the mapping? */
vm_len
=
vma
->
vm_end
-
vma
->
vm_start
;
if
(
vm_len
>>
PAGE_SHIFT
>
pages
)
return
-
EINVAL
;
/* Ok, let it rip */
return
io_remap_pfn_range
(
vma
,
vma
->
vm_start
,
pfn
,
vm_len
,
vma
->
vm_page_prot
);
}
void
__iomem
*
devm_ioremap_resource
(
struct
device
*
dev
,
struct
resource
*
res
)
{
return
devm_request_and_ioremap
(
dev
,
res
);
}
#endif
software/kernel/mockturtle-compat.h
0 → 100644
View file @
a4fa5915
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#ifndef __TRTL_COMPAT_H__
#define __TRTL_COMPAT_H__
#include <linux/version.h>
#include <linux/device.h>
#include <linux/ioport.h>
#if KERNEL_VERSION(3, 9, 0) > LINUX_VERSION_CODE
int
vm_iomap_memory
(
struct
vm_area_struct
*
vma
,
phys_addr_t
start
,
unsigned
long
len
);
void
__iomem
*
devm_ioremap_resource
(
struct
device
*
dev
,
struct
resource
*
res
);
#endif
#endif
software/kernel/mockturtle-core.c
View file @
a4fa5915
...
...
@@ -7,6 +7,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/idr.h>
#include <linux/init.h>
...
...
@@ -29,6 +30,7 @@
#include <hw/mockturtle_queue.h>
#include "mockturtle-drv.h"
#include "mockturtle-compat.h"
static
DEFINE_IDA
(
trtl_ida
);
...
...
@@ -497,7 +499,7 @@ static unsigned int trtl_max_irq_loop(struct trtl_dev *trtl)
int
i
,
k
;
for
(
i
=
0
;
i
<
trtl
->
cfgrom
.
n_cpu
;
++
i
)
{
for
(
k
=
0
;
k
<
trtl
->
cfgrom
.
n_
cpu
;
++
k
)
{
for
(
k
=
0
;
k
<
trtl
->
cfgrom
.
n_
hmq
[
i
]
;
++
k
)
{
size
=
TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES
(
trtl
->
cfgrom
.
hmq
[
i
][
k
].
sizes
);
if
(
size
>
max
)
max
=
size
;
...
...
@@ -529,7 +531,7 @@ int trtl_probe(struct platform_device *pdev)
platform_set_drvdata
(
pdev
,
trtl
);
r
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
TRTL_MEM_BASE
);
trtl
->
base_core
=
devm_
request_and_ioremap
(
&
pdev
->
dev
,
r
);
trtl
->
base_core
=
devm_
ioremap_resource
(
&
pdev
->
dev
,
r
);
if
(
!
trtl
->
base_core
)
return
-
EADDRNOTAVAIL
;
trtl
->
base_csr
=
trtl
->
base_core
+
TRTL_ADDR_OFFSET_CSR
;
...
...
software/kernel/mockturtle-dbg.c
View file @
a4fa5915
...
...
@@ -8,9 +8,11 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/seq_file.h>
#include <linux/mm.h>
#include <hw/mockturtle_cpu_csr.h>
#include "mockturtle-drv.h"
#include "mockturtle-compat.h"
static
int
trtl_dbg_info_seq_read
(
struct
seq_file
*
s
,
void
*
data
)
{
...
...
@@ -54,12 +56,16 @@ static int trtl_dbg_info_seq_read(struct seq_file *s, void *data)
hmq
->
index
);
seq_printf
(
s
,
" name: %s
\n
"
,
dev_name
(
&
hmq
->
dev
));
seq_printf
(
s
,
" buf-in-max: %d
\n
"
,
hmq
->
buf_in
.
entries
);
list_for_each_entry
(
usr
,
&
hmq
->
list_usr
,
list
)
{
seq_printf
(
s
,
" buf-in-r: %d (user %p)
\n
"
,
usr
->
idx_r
,
usr
);
}
seq_printf
(
s
,
" buf-in-w: %d
\n
"
,
hmq
->
buf_in
.
idx_w
);
seq_printf
(
s
,
" buf-out-max: %d
\n
"
,
hmq
->
buf_out
.
entries
);
seq_printf
(
s
,
" buf-out-r: %d
\n
"
,
hmq
->
buf_out
.
idx_r
);
seq_printf
(
s
,
" buf-out-w: %d
\n
"
,
...
...
@@ -83,6 +89,47 @@ static const struct file_operations trtl_dbg_info_ops = {
.
release
=
single_release
,
};
#define TRTL_DBG_PORT_SIZE PAGE_SIZE
/* FIXME */
static
int
trtl_dbg_debugger_mmap
(
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
struct
trtl_dev
*
trtl
=
file
->
private_data
;
unsigned
long
vsize
;
int
ret
;
struct
platform_device
*
pdev
=
to_platform_device
(
trtl
->
dev
.
parent
);
struct
resource
*
r
;
if
(
vma
->
vm_pgoff
>
0
)
{
dev_err
(
&
trtl
->
dev
,
"Debug Port mapping does not accept offsets
\n
"
);
return
-
EINVAL
;
}
vsize
=
vma
->
vm_end
-
vma
->
vm_start
;
if
(
vsize
>
TRTL_DBG_PORT_SIZE
)
{
dev_err
(
&
trtl
->
dev
,
"Debug Port mapping can't map more that %lu bytes (%lu)
\n
"
,
TRTL_DBG_PORT_SIZE
,
vsize
);
return
-
EINVAL
;
}
vma
->
vm_flags
|=
VM_IO
|
VM_DONTCOPY
|
VM_DONTEXPAND
;
vma
->
vm_page_prot
=
pgprot_noncached
(
vma
->
vm_page_prot
);
r
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
TRTL_MEM_BASE
);
return
vm_iomap_memory
(
vma
,
r
->
start
+
TRTL_ADDR_OFFSET_DBG
,
TRTL_DBG_PORT_SIZE
);
return
ret
;
}
static
const
struct
file_operations
trtl_dbg_debugger_ops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
simple_open
,
.
mmap
=
trtl_dbg_debugger_mmap
,
};
/**
* It creates the debug info file
...
...
@@ -90,6 +137,8 @@ static const struct file_operations trtl_dbg_info_ops = {
*/
void
trtl_debugfs_init
(
struct
trtl_dev
*
trtl
)
{
char
name
[
20
];
trtl
->
dbg_dir
=
debugfs_create_dir
(
dev_name
(
&
trtl
->
dev
),
NULL
);
if
(
IS_ERR_OR_NULL
(
trtl
->
dbg_dir
))
{
dev_err
(
&
trtl
->
dev
,
"Cannot create debugfs
\n
"
);
...
...
@@ -106,6 +155,16 @@ void trtl_debugfs_init(struct trtl_dev *trtl)
PTR_ERR
(
trtl
->
dbg_info
));
trtl
->
dbg_info
=
NULL
;
}
snprintf
(
name
,
20
,
"%s-dbg"
,
dev_name
(
&
trtl
->
dev
));
trtl
->
debugger
=
debugfs_create_file
(
name
,
0664
,
trtl
->
dbg_dir
,
trtl
,
&
trtl_dbg_debugger_ops
);
if
(
IS_ERR_OR_NULL
(
trtl
->
debugger
))
{
dev_err
(
&
trtl
->
dev
,
"Cannot create debugfs file: %ld
\n
"
,
PTR_ERR
(
trtl
->
debugger
));
trtl
->
debugger
=
NULL
;
}
}
...
...
software/kernel/mockturtle-drv.h
View file @
a4fa5915
...
...
@@ -75,11 +75,6 @@ static inline uint32_t trtl_get_sequence(struct trtl_msg *msg)
return
msg
->
data
[
1
];
}
struct
trtl_msg_filter_element
{
struct
trtl_msg_filter
filter
;
struct
list_head
list
;
};
struct
trtl_memory_ops
{
u32
(
*
read
)(
void
*
addr
);
void
(
*
write
)(
u32
value
,
void
*
addr
);
...
...
@@ -117,6 +112,7 @@ struct mturtle_hmq_buffer {
spinlock_t
lock
;
unsigned
int
idx_w
;
unsigned
int
idx_r
;
unsigned
int
entries
;
struct
trtl_msg
*
msg
;
struct
trtl_msg
msg_tmp
;
unsigned
int
count
;
...
...
@@ -177,13 +173,22 @@ struct trtl_hmq {
struct
mturtle_hmq_buffer
buf_out
;
};
/**
* User do only sync messages
*/
#define TRTL_HMQ_USER_FLAG_SYNC BIT(0)
/**
* User is waiting for a sync answer message
*/
#define TRTL_HMQ_USER_FLAG_SYNC_WAIT BIT(1)
/**
* It describes the consumer of the output slot
* @list: to keep it in our local queue
* @hmq: reference to opened HMQ
* @lock: to protect filters
* @list_filters: list of filters to apply
* @n_filters: number of filters
* @lock: to protect flags, wait_id
* @idx_r: index read pointer for the message circular buffer. This is
* protected by the input buffer lock. Accessing this field means that
* you are accessing the buffer input, and in order to do that you need
...
...
@@ -194,9 +199,9 @@ struct trtl_hmq_user {
struct
list_head
list
;
struct
trtl_hmq
*
hmq
;
spinlock_t
lock
;
struct
list_head
list_filters
;
unsigned
int
n_filters
;
unsigned
long
flags
;
unsigned
int
idx_r
;
uint16_t
wait_id
;
};
...
...
@@ -244,7 +249,8 @@ struct trtl_cpu {
* @irq_mask: IRQ mask in use
* @message_sequence: message sequence number
* @lock_cpu_sel:
* @lock_hmq_sel:
* @lock_hmq_sel: protects the HMQ usage which is based on selection. It
* protects also last_seq which is related to HMQ messages
* @cfgrom: synthesis configuration ROM
* @tty_driver:
* @memops:
...
...
@@ -252,6 +258,9 @@ struct trtl_cpu {
* @dbg_info: information
* @max_irq_loop: maximum number of messages that can be retrieved with a
* single IRQ. It regulates the HMQ IRQ handler
* @last_seq: last sequence number used. The same seq number cannot be used
* on different HMQ on the same CPU
* @debugger: debugfs interface for gdbserver
*/
struct
trtl_dev
{
struct
device
dev
;
...
...
@@ -272,6 +281,8 @@ struct trtl_dev {
struct
dentry
*
dbg_dir
;
struct
dentry
*
dbg_info
;
unsigned
int
max_irq_loop
;
uint32_t
last_seq
;
struct
dentry
*
debugger
;
};
static
inline
u32
trtl_ioread
(
struct
trtl_dev
*
trtl
,
void
*
addr
)
...
...
software/kernel/mockturtle-hmq.c
View file @
a4fa5915
...
...
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
...
...
@@ -22,13 +21,75 @@
#include <hw/mockturtle_cpu_csr.h>
#include "mockturtle-drv.h"
static
int
hmq_buf_max_msg
=
16
;
module_param_named
(
hmq_buf_max_msg
,
hmq_buf_max_msg
,
int
,
0444
);
MODULE_PARM_DESC
(
hmq_buf_max_msg
,
"Maximum number of messages buffered for input and for output."
);
static
void
trtl_message_push
(
struct
trtl_hmq
*
hmq
,
struct
trtl_msg
*
msg
);
static
bool
trtl_hmq_user_is_sync
(
struct
trtl_hmq_user
*
user
)
{
return
(
user
->
flags
&
TRTL_HMQ_USER_FLAG_SYNC
);
}
static
bool
trtl_hmq_user_is_waiting
(
struct
trtl_hmq_user
*
user
)
{
return
(
user
->
flags
&
TRTL_HMQ_USER_FLAG_SYNC_WAIT
);
}
static
bool
trtl_msg_is_ack
(
struct
trtl_msg
*
msg
)
{
return
(
msg
->
hdr
.
flags
&
TRTL_HMQ_HEADER_FLAG_ACK
);
}
static
bool
trtl_hmq_user_msg_is_answer
(
struct
trtl_hmq_user
*
user
,
struct
trtl_msg
*
msg
)
{
return
(
user
->
wait_id
==
msg
->
hdr
.
sync_id
);
}
/**
* Set the user in waiting mode for a sync answer
* @user user
* @sync_id synchronous message identifier
*
* Return: 0 on success otherwise a negative error number
*/
static
void
trtl_hmq_user_sync_wait_set
(
struct
trtl_hmq_user
*
user
,
uint16_t
id
)
{
spin_lock
(
&
user
->
lock
);
user
->
flags
|=
TRTL_HMQ_USER_FLAG_SYNC_WAIT
;
user
->
wait_id
=
id
;
spin_unlock
(
&
user
->
lock
);
}
/**
* User received the messages, do not wait anymore
* @user user
*/
static
void
trtl_hmq_user_sync_wait_clr
(
struct
trtl_hmq_user
*
user
)
{
spin_lock
(
&
user
->
lock
);
user
->
flags
&=
~
TRTL_HMQ_USER_FLAG_SYNC_WAIT
;
spin_unlock
(
&
user
->
lock
);
}
/**
* Get a valid sequence number
* @trtl: trtl device
*
* Return a valid sequence number
*/
static
int
trtl_msg_seq_get
(
struct
trtl_dev
*
trtl
)
{
unsigned
long
flags
;
int
seq
;
spin_lock_irqsave
(
&
trtl
->
lock_hmq_sel
,
flags
);
seq
=
trtl
->
last_seq
++
;
spin_unlock_irqrestore
(
&
trtl
->
lock_hmq_sel
,
flags
);
return
seq
;
}
/**
* It is an opaque type. It is used to avoid mistakes when using features
* that requires the HMQ selection. If you do not provide this type (which is
...
...
@@ -309,60 +370,25 @@ static void trtl_hmq_flush(struct trtl_hmq *hmq)
mutex_unlock
(
&
hmq
->
mtx
);
}
/**
*
It applies filters on a given message.
* @user
HMQ user instance from which we take filters
* @msg
the message to filter
*
Tell if user accepts the given message
* @user
: HMQ user
* @msg
: message
*
* Return:
1 if the message passes all filters, otherwise 0
* Return:
true if the user can read the message, otherwise false
*/
static
int
trtl_hmq_filter_check
(
struct
trtl_hmq_user
*
user
,
static
bool
trtl_hmq_user_filter_one
(
struct
trtl_hmq_user
*
user
,
struct
trtl_msg
*
msg
)
{
struct
trtl_msg_filter_element
*
fltel
,
*
tmp
;
unsigned
int
passed
=
1
;
uint32_t
word
,
*
data
=
msg
->
data
,
*
head
=
(
uint32_t
*
)
&
msg
->
hdr
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
user
->
lock
,
flags
);
list_for_each_entry_safe
(
fltel
,
tmp
,
&
user
->
list_filters
,
list
)
{
/* If one of the previous filter failed, then stop */
if
(
!
passed
)
break
;
if
(
fltel
->
filter
.
flags
&
TRTL_MSG_FILTER_FLAG_PAYLOAD
)
word
=
data
[
fltel
->
filter
.
word_offset
];
else
word
=
head
[
fltel
->
filter
.
word_offset
];
switch
(
fltel
->
filter
.
operation
)
{
case
TRTL_MSG_FILTER_AND
:
word
&=
fltel
->
filter
.
mask
;
if
(
word
!=
fltel
->
filter
.
value
)
passed
=
0
;
break
;
case
TRTL_MSG_FILTER_OR
:
word
|=
fltel
->
filter
.
mask
;
if
(
word
!=
fltel
->
filter
.
value
)
passed
=
0
;
break
;
case
TRTL_MSG_FILTER_EQ
:
if
(
word
!=
fltel
->
filter
.
value
)
passed
=
0
;
break
;
case
TRTL_MSG_FILTER_NEQ
:
if
(
word
==
fltel
->
filter
.
value
)
passed
=
0
;
break
;
if
(
trtl_hmq_user_is_sync
(
user
))
{
return
trtl_hmq_user_is_waiting
(
user
)
&&
trtl_msg_is_ack
(
msg
)
&&
trtl_hmq_user_msg_is_answer
(
user
,
msg
);
}
}
spin_unlock_irqrestore
(
&
user
->
lock
,
flags
);
return
passed
;
return
!
trtl_msg_is_ack
(
msg
)
;
}
/**
* It clears the content of the HMQ
*/
...
...
@@ -512,6 +538,11 @@ static const struct attribute_group *trtl_hmq_groups[] = {
NULL
,
};
static
unsigned
int
trtl_hmq_buf_idx_get
(
struct
mturtle_hmq_buffer
*
buf
,
unsigned
int
idx_r_absolute
)
{
return
idx_r_absolute
&
(
buf
->
entries
-
1
);
}
/**
* It simply opens a HMQ device
...
...
@@ -531,7 +562,6 @@ static int trtl_hmq_open(struct inode *inode, struct file *file)
user
->
hmq
=
hmq
;
spin_lock_init
(
&
user
->
lock
);
INIT_LIST_HEAD
(
&
user
->
list_filters
);
/* Add new user to the list */
spin_lock_irqsave
(
&
hmq
->
lock
,
flags
);
...
...
@@ -573,15 +603,20 @@ static int trtl_hmq_release(struct inode *inode, struct file *f)
* @buf: source buffer
* Return: 0 on success, otherwise a negative error number
*/
static
int
trtl_hmq_write_one
(
struct
trtl_hmq
*
hmq
,
static
int
trtl_hmq_write_one
(
struct
trtl_hmq
_user
*
user
,
const
char
__user
*
ubuf
)
{
struct
trtl_hmq
*
hmq
=
user
->
hmq
;
struct
trtl_dev
*
trtl
=
to_trtl_dev
(
hmq
->
dev
.
parent
->
parent
);
struct
trtl_msg
*
msg
;
int
err
=
0
,
copy_size
;
size_t
size
;
struct
mturtle_hmq_buffer
*
buf
=
&
hmq
->
buf_out
;
unsigned
long
flags
;
if
(
trtl_hmq_user_is_sync
(
user
)
&&
trtl_hmq_user_is_waiting
(
user
))
return
-
EBUSY
;
/* Here we can safely sleep */
size
=
TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD
(
hmq
->
cfg
->
sizes
);
copy_size
=
sizeof
(
struct
trtl_hmq_header
);
...
...
@@ -597,15 +632,24 @@ static int trtl_hmq_write_one(struct trtl_hmq *hmq,
return
-
EINVAL
;
}
buf
->
msg_tmp
.
hdr
.
seq
=
trtl_msg_seq_get
(
trtl
);
if
(
trtl_hmq_user_is_sync
(
user
))
{
uint16_t
sync_id
=
buf
->
msg_tmp
.
hdr
.
seq
&
0xFFFF
;
buf
->
msg_tmp
.
hdr
.
flags
|=
TRTL_HMQ_HEADER_FLAG_SYNC
;
buf
->
msg_tmp
.
hdr
.
sync_id
=
sync_id
;
trtl_hmq_user_sync_wait_set
(
user
,
sync_id
);
}
/* don't sleep here */
spin_lock_irqsave
(
&
buf
->
lock
,
flags
);
if
((
buf
->
idx_w
-
buf
->
idx_r
)
>=
hmq_buf_max_msg
)
{
if
((
buf
->
idx_w
-
buf
->
idx_r
)
>=
buf
->
entries
)
{
err
=
-
EAGAIN
;
}
else
{
/* copy only the message */
copy_size
=
sizeof
(
struct
trtl_hmq_header
)
+
(
buf
->
msg_tmp
.
hdr
.
len
)
*
sizeof
(
uint32_t
);
msg
=
&
buf
->
msg
[
buf
->
idx_w
++
&
(
hmq_buf_max_msg
-
1
)];
msg
=
&
buf
->
msg
[
trtl_hmq_buf_idx_get
(
buf
,
buf
->
idx_w
++
)];
memcpy
(
msg
,
&
buf
->
msg_tmp
,
copy_size
);
}
spin_unlock_irqrestore
(
&
buf
->
lock
,
flags
);
...
...
@@ -638,7 +682,7 @@ static ssize_t trtl_hmq_write(struct file *f, const char __user *buf,
count
=
0
;
mutex_lock
(
&
hmq
->
mtx
);
for
(
i
=
0
;
i
<
n_msg
;
i
++
,
curbuf
+=
sizeof
(
struct
trtl_msg
))
{
err
=
trtl_hmq_write_one
(
hmq
,
curbuf
);
err
=
trtl_hmq_write_one
(
user
,
curbuf
);
if
(
err
)
break
;
}
...
...
@@ -666,86 +710,6 @@ static ssize_t trtl_hmq_write(struct file *f, const char __user *buf,
return
count
?
count
:
err
;
}
/**
* Add a filter rule to a given file-descriptor
*/
static
int
trtl_ioctl_msg_filter_add
(
struct
trtl_hmq_user
*
user
,
void
__user
*
uarg
)
{
struct
trtl_msg_filter_element
*
fltel
;
uint32_t
size
;
int
err
=
0
;
unsigned
long
flags
;
fltel
=
kmalloc
(
sizeof
(
struct
trtl_msg_filter_element
),
GFP_KERNEL
);
if
(
!
fltel
)
return
-
ENOMEM
;
/* Copy the message from user space*/
err
=
copy_from_user
(
&
fltel
->
filter
,
uarg
,
sizeof
(
struct
trtl_msg_filter
));
if
(
err
)
goto
err
;
/* validate filter */
if
(
fltel
->
filter
.
operation
>=
__TRTL_MSG_FILTER_MAX
)
{
err
=
-
EINVAL
;
goto
err
;
}
size
=
TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD
(
user
->
hmq
->
cfg
->
sizes
);
if
((
fltel
->
filter
.
flags
&
TRTL_MSG_FILTER_FLAG_PAYLOAD
)
&&
fltel
->
filter
.
word_offset
>=
size
)
{
dev_err
(
&
user
->
hmq
->
dev
,
"Invalid filter: word offset %d greater than maximum payload size %d
\n
"
,
fltel
->
filter
.
word_offset
,
size
);
err
=
-
EINVAL
;
goto
err
;
}
size
=
TRTL_CONFIG_ROM_MQ_SIZE_HEADER
(
user
->
hmq
->
cfg
->
sizes
);
if
(
!
(
fltel
->
filter
.
flags
&
TRTL_MSG_FILTER_FLAG_PAYLOAD
)
&&
fltel
->
filter
.
word_offset
>=
size
)
{
dev_err
(
&
user
->
hmq
->
dev
,
"Invalid filter: word offset %d greater than maximum header size %d
\n
"
,
fltel
->
filter
.
word_offset
,
size
);
err
=
-
EINVAL
;
goto
err
;
}
/* Store filter */
spin_lock_irqsave
(
&
user
->
lock
,
flags
);
list_add_tail
(
&
fltel
->
list
,
&
user
->
list_filters
);
user
->
n_filters
++
;
spin_unlock_irqrestore
(
&
user
->
lock
,
flags
);
return
0
;
err:
kfree
(
fltel
);
return
err
;
}
/**
* FIXME: to be tested
* Remove all filter rules form a given file-descriptor
*/
static
void
trtl_ioctl_msg_filter_clean
(
struct
trtl_hmq_user
*
user
,
void
__user
*
uarg
)
{
struct
trtl_msg_filter_element
*
fltel
,
*
tmp
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
user
->
lock
,
flags
);
list_for_each_entry_safe
(
fltel
,
tmp
,
&
user
->
list_filters
,
list
)
{
list_del
(
&
fltel
->
list
);
kfree
(
fltel
);
user
->
n_filters
--
;
}
spin_unlock_irqrestore
(
&
user
->
lock
,
flags
);
}
/**
* Set of special operations that can be done on the HMQ
*/
...
...
@@ -768,17 +732,27 @@ static long trtl_hmq_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return
-
EFAULT
;
/* Perform commands */
mutex_lock
(
&
user
->
hmq
->
mtx
);
switch
(
cmd
)
{
case
TRTL_IOCTL_MSG_FILTER_ADD
:
err
=
trtl_ioctl_msg_filter_add
(
user
,
uarg
);
case
TRTL_IOCTL_MSG_SYNC_ABORT
:
if
(
trtl_hmq_user_is_sync
(
user
))
{
if
(
trtl_hmq_user_is_waiting
(
user
))
trtl_hmq_user_sync_wait_clr
(
user
);
}
else
{
err
=
-
EPERM
;
}
break
;
case
TRTL_MSG_FILTER_CLEAN
:
trtl_ioctl_msg_filter_clean
(
user
,
uarg
);
case
TRTL_IOCTL_HMQ_SYNC_SET
:
spin_lock
(
&
user
->
lock
);
user
->
flags
|=
TRTL_HMQ_USER_FLAG_SYNC
;
spin_unlock
(
&
user
->
lock
);
break
;
default:
pr_warn
(
"trtl: invalid ioctl command %d
\n
"
,
cmd
);
return
-
EINVAL
;
err
=
-
EINVAL
;
break
;
}
mutex_unlock
(
&
user
->
hmq
->
mtx
);
return
err
;
}
...
...
@@ -813,16 +787,21 @@ static ssize_t trtl_hmq_read(struct file *f, char __user *ubuf,
while
(
!
err
&&
i
<
n_msg
&&
buf
->
idx_w
!=
usr
->
idx_r
)
{
spin_lock_irqsave
(
&
buf
->
lock
,
flags
);
msg
=
&
buf
->
msg
[
usr
->
idx_r
++
&
(
hmq_buf_max_msg
-
1
)];
if
(
!
trtl_hmq_filter_check
(
usr
,
msg
))
{
msg
=
&
buf
->
msg
[
trtl_hmq_buf_idx_get
(
buf
,
usr
->
idx_r
++
)];
if
(
!
trtl_hmq_user_filter_one
(
usr
,
msg
))
{
spin_unlock_irqrestore
(
&
buf
->
lock
,
flags
);
continue
;
}
copy_size
=
sizeof
(
struct
trtl_hmq_header
);
copy_size
+=
(
msg
->
hdr
.
len
*
4
);
memcpy
(
&
buf
->
msg_tmp
,
msg
,
copy_size
);
spin_unlock_irqrestore
(
&
buf
->
lock
,
flags
);
if
(
trtl_hmq_user_is_sync
(
usr
))
trtl_hmq_user_sync_wait_clr
(
usr
);
/* now we copy to user space and we can safely sleep */
if
(
copy_to_user
(
ubuf
+
count
,
&
buf
->
msg_tmp
,
copy_size
))
{
err
=
-
EFAULT
;
...
...
@@ -837,6 +816,7 @@ static ssize_t trtl_hmq_read(struct file *f, char __user *ubuf,
return
count
?
count
:
err
;
}
/**
* It filters out messages until a valid one
* @usr: pointer to a user HMQ instance
...
...
@@ -851,8 +831,8 @@ static void trtl_hmq_user_filter(struct trtl_hmq_user *usr)
spin_lock_irqsave
(
&
buf
->
lock
,
flags
);
/* Loop until we find a valid message for the user */
while
(
buf
->
idx_w
!=
usr
->
idx_r
)
{
msg
=
&
buf
->
msg
[
usr
->
idx_r
&
(
hmq_buf_max_msg
-
1
)];
if
(
trtl_hmq_
filter_check
(
usr
,
msg
))
msg
=
&
buf
->
msg
[
trtl_hmq_buf_idx_get
(
buf
,
usr
->
idx_r
)];
if
(
trtl_hmq_
user_filter_one
(
usr
,
msg
))
break
;
usr
->
idx_r
++
;
}
...
...
@@ -902,7 +882,7 @@ const struct file_operations trtl_hmq_fops = {
*/
static
void
trtl_message_pop
(
struct
trtl_hmq
*
hmq
,
struct
trtl_msg
*
msg
)
{
struct
trtl_dev
*
trtl
=
to_trtl_dev
(
hmq
->
dev
.
parent
);
struct
trtl_dev
*
trtl
=
to_trtl_dev
(
hmq
->
dev
.
parent
->
parent
);
struct
trtl_hmq_ctx
*
ctx
;
size_t
copy_size
=
TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD
(
hmq
->
cfg
->
sizes
);
unsigned
long
flags
;
...
...
@@ -920,6 +900,8 @@ static void trtl_message_pop(struct trtl_hmq *hmq, struct trtl_msg *msg)
trtl_hmq_data_read
(
ctx
,
msg
->
data
,
msg
->
hdr
.
len
);
trtl_hmq_command
(
ctx
,
TRTL_MQ_CMD_DISCARD
,
0
);
spin_unlock_irqrestore
(
&
trtl
->
lock_hmq_sel
,
flags
);
msg
->
hdr
.
seq
=
trtl_msg_seq_get
(
trtl
);
}
...
...
@@ -937,7 +919,7 @@ static void trtl_message_pop_to_buf(struct trtl_hmq *hmq)
spin_lock_irqsave
(
&
buf
->
lock
,
flags
);
msg
=
&
buf
->
msg
[
buf
->
idx_w
++
&
(
hmq_buf_max_msg
-
1
)];
msg
=
&
buf
->
msg
[
trtl_hmq_buf_idx_get
(
buf
,
buf
->
idx_w
++
)];
trtl_message_pop
(
hmq
,
msg
);
spin_unlock_irqrestore
(
&
buf
->
lock
,
flags
);
...
...
@@ -946,8 +928,7 @@ static void trtl_message_pop_to_buf(struct trtl_hmq *hmq)
}
/**
* It handles an output interrupt. It means that the CPU is outputting
* data for us, so we must read it.
* It handles an incoming interrupt, messages coming from the soft-CPU
*/
static
void
trtl_irq_handler_input
(
struct
trtl_hmq
*
hmq
)
{
...
...
@@ -962,7 +943,7 @@ static void trtl_irq_handler_input(struct trtl_hmq *hmq)
*/
list_for_each_entry_safe
(
usr
,
tmp
,
&
hmq
->
list_usr
,
list
)
{
spin_lock_irqsave
(
&
buf
->
lock
,
flags
);
if
(
usr
->
idx_r
+
hmq_buf_max_msg
>
buf
->
idx_w
)
{
if
(
usr
->
idx_r
+
buf
->
entries
>
buf
->
idx_w
)
{
spin_unlock_irqrestore
(
&
buf
->
lock
,
flags
);
continue
;
}
...
...
@@ -991,7 +972,7 @@ static uint64_t trtl_hmq_irq_status_in(struct trtl_dev *trtl)
/**
* It handles the HMQ interrupts
for messages coming
from the soft-CPU
* It handles the HMQ interrupts
incoming messages
from the soft-CPU
*/
irqreturn_t
trtl_irq_handler_in
(
int
irq_core_base
,
void
*
arg
)
{
...
...
@@ -1035,7 +1016,7 @@ dispatch_irq:
*/
static
void
trtl_message_push
(
struct
trtl_hmq
*
hmq
,
struct
trtl_msg
*
msg
)
{
struct
trtl_dev
*
trtl
=
to_trtl_dev
(
hmq
->
dev
.
parent
);
struct
trtl_dev
*
trtl
=
to_trtl_dev
(
hmq
->
dev
.
parent
->
parent
);
struct
trtl_hmq_ctx
*
ctx
;
unsigned
long
flags
;
size_t
size
;
...
...
@@ -1076,7 +1057,7 @@ static void trtl_message_push_from_buf(struct trtl_hmq *hmq)
spin_lock_irqsave
(
&
buf
->
lock
,
flags
);
if
(
likely
(
buf
->
idx_w
!=
buf
->
idx_r
))
{
msg
=
&
buf
->
msg
[
buf
->
idx_r
++
&
(
hmq_buf_max_msg
-
1
)];
msg
=
&
buf
->
msg
[
trtl_hmq_buf_idx_get
(
buf
,
buf
->
idx_r
++
)];
trtl_message_push
(
hmq
,
msg
);
buf
->
count
++
;
}
...
...
@@ -1105,7 +1086,7 @@ static uint64_t trtl_hmq_irq_status_out(struct trtl_dev *trtl)
/**
* It handles the HMQ interrupts for
messages coming from
the soft-CPU
* It handles the HMQ interrupts for
outgoing messages to
the soft-CPU
*/
irqreturn_t
trtl_irq_handler_out
(
int
irq_core_base
,
void
*
arg
)
{
...
...
@@ -1173,7 +1154,6 @@ int trtl_probe_hmq(struct trtl_cpu *cpu, unsigned int hmq_idx)
struct
trtl_dev
*
trtl
=
to_trtl_dev
(
cpu
->
dev
.
parent
);
struct
trtl_hmq
*
hmq
=
&
cpu
->
hmq
[
hmq_idx
];
int
err
;
size_t
size
;
hmq
->
index
=
hmq_idx
;
...
...
@@ -1214,12 +1194,17 @@ int trtl_probe_hmq(struct trtl_cpu *cpu, unsigned int hmq_idx)
goto
out_dev
;
/* Allocate buffers */
size
=
sizeof
(
struct
trtl_msg
)
*
hmq_buf_max_msg
;
hmq
->
buf_in
.
msg
=
devm_kzalloc
(
&
hmq
->
dev
,
size
,
GFP_KERNEL
);
hmq
->
buf_in
.
entries
=
TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES
(
hmq
->
cfg
->
sizes
);
hmq
->
buf_in
.
msg
=
kcalloc
(
hmq
->
buf_in
.
entries
,
sizeof
(
struct
trtl_msg
),
GFP_KERNEL
);
if
(
!
hmq
->
buf_in
.
msg
)
goto
out_msg_in
;
hmq
->
buf_out
.
msg
=
devm_kzalloc
(
&
hmq
->
dev
,
size
,
GFP_KERNEL
);
hmq
->
buf_out
.
entries
=
TRTL_CONFIG_ROM_MQ_SIZE_ENTRIES
(
hmq
->
cfg
->
sizes
);
hmq
->
buf_out
.
msg
=
kcalloc
(
hmq
->
buf_out
.
entries
,
sizeof
(
struct
trtl_msg
),
GFP_KERNEL
);
if
(
!
hmq
->
buf_out
.
msg
)
goto
out_msg_out
;
...
...
@@ -1230,6 +1215,7 @@ int trtl_probe_hmq(struct trtl_cpu *cpu, unsigned int hmq_idx)
return
0
;
out_msg_out:
kfree
(
hmq
->
buf_in
.
msg
);
out_msg_in:
device_unregister
(
&
hmq
->
dev
);
out_dev:
...
...
@@ -1247,5 +1233,8 @@ void trtl_remove_hmq(struct trtl_cpu *cpu, unsigned int hmq_idx)
trtl_hmq_flush
(
hmq
);
kfree
(
hmq
->
buf_in
.
msg
);
kfree
(
hmq
->
buf_out
.
msg
);
device_unregister
(
&
hmq
->
dev
);
}
software/lib/Makefile
View file @
a4fa5915
...
...
@@ -8,7 +8,8 @@ REPO_PARENT ?= ../..
-include
$(REPO_PARENT)/parent_common.mk
TRTL
?=
../
TRTL
?=
../../
TRTL_SW
=
$(TRTL)
/software
LIBS
=
libmockturtle.so
LIB
=
libmockturtle.a
...
...
@@ -16,7 +17,7 @@ LOBJ := libmockturtle.o
LOBJ
+=
libmockturtle-rt-msg.o
CFLAGS
+=
-Wall
-Werror
-ggdb
-fPIC
CFLAGS
+=
-I
.
-I
$(TRTL)
/include
$(EXTRACFLAGS)
CFLAGS
+=
-I
.
-I
$(TRTL
_SW
)
/include
$(EXTRACFLAGS)
LDFLAGS
=
-L
.
-lmockturtle
ARFLAGS
=
rc
...
...
software/lib/PyMockTurtle/PyMockTurtle/PyMockTurtle.py
View file @
a4fa5915
...
...
@@ -15,6 +15,7 @@ TRTL_CONFIG_ROM_MAX_CPU = 8
TRTL_CONFIG_ROM_MAX_HMQ
=
8
TRTL_CONFIG_ROM_MAX_RMQ
=
8
ETRTL_MSG_SYNC_FAILED_RECV_TIMEOUT
=
83638
class
TrtlConfigMq
(
Structure
):
"""
...
...
@@ -109,6 +110,8 @@ class TrtlHmqHeader(Structure):
return
False
return
True
def
__str__
(
self
):
return
"rt_app_id: 0x{:x}, flags: 0x{:x}, msg_id: 0x{:x}, len: {:d}, sync_id: {:d}, seq: {:d}"
.
format
(
self
.
rt_app_id
,
self
.
flags
,
self
.
msg_id
,
self
.
len
,
self
.
sync_id
,
self
.
seq
)
class
TrtlMessage
(
Structure
):
"""
...
...
@@ -135,6 +138,9 @@ class TrtlMessage(Structure):
break
return
True
def
__str__
(
self
):
return
"{:s}, payload: ##"
.
format
(
str
(
self
.
header
))
class
TrtlFirmwareVersion
(
Structure
):
"""
...
...
@@ -309,15 +315,6 @@ class TrtlDevice(object):
self
.
libtrtl
.
trtl_fw_variable_set
.
restype
=
c_int
self
.
libtrtl
.
trtl_fw_variable_set
.
errcheck
=
self
.
__errcheck_int
# self.libtrtl.trtl_hmq_filter_add.argtypes = [c_void_p]
# self.libtrtl.trtl_hmq_filter_clean.argtypes = [c_void_p]
# # Return
# self.libtrtl.trtl_hmq_filter_add.restype = c_int
# self.libtrtl.trtl_hmq_filter_clean.restype = c_int
# # Error
# self.libtrtl.trtl_hmq_filter_add.errcheck = self.__errcheck_int
# self.libtrtl.trtl_hmq_filter_clean.errcheck = self.__errcheck_int
def
__errcheck_pointer
(
self
,
ret
,
func
,
args
):
"""Generic error handler for functions returning pointers"""
if
ret
is
None
:
...
...
@@ -555,16 +552,16 @@ class TrtlHmq(object):
:param timeout: time to wait before returning
:type timeout: int
:return: an asynchronous message
:return: an asynchronous message
or None
:rtype: TrtlMessage
:raises OSError: from C library errors
"""
set_errno
(
0
)
msg
=
TrtlMessage
()
self
.
libtrtl
.
trtl_msg_async_recv
(
self
.
trtl_dev
.
tkn
,
ret
=
self
.
libtrtl
.
trtl_msg_async_recv
(
self
.
trtl_dev
.
tkn
,
self
.
idx_cpu
,
self
.
idx_hmq
,
pointer
(
msg
),
1
)
return
msg
return
None
if
ret
==
0
else
msg
def
sync_msg
(
self
,
msg_s
,
timeout
=
1000
):
"""
...
...
@@ -578,6 +575,7 @@ class TrtlHmq(object):
:rtype: TrtlMessage
:raises OSError: from C library errors
"""
set_errno
(
0
)
msg_r
=
TrtlMessage
()
self
.
libtrtl
.
trtl_msg_sync
(
self
.
trtl_dev
.
tkn
,
self
.
idx_cpu
,
self
.
idx_hmq
,
...
...
software/lib/PyMockTurtle/PyMockTurtle/__init__.py
View file @
a4fa5915
...
...
@@ -13,7 +13,8 @@ from .PyMockTurtle import TrtlHmqHeader, TrtlMessage, TrtlConfig, \
TrtlFirmwareVariable
,
\
TRTL_CONFIG_ROM_MAX_CPU
,
\
TRTL_CONFIG_ROM_MAX_HMQ
,
\
TRTL_CONFIG_ROM_MAX_RMQ
TRTL_CONFIG_ROM_MAX_RMQ
,
\
ETRTL_MSG_SYNC_FAILED_RECV_TIMEOUT
__all__
=
(
"TrtlDevice"
,
...
...
@@ -29,4 +30,5 @@ __all__ = (
"TRTL_CONFIG_ROM_MAX_CPU"
,
"TRTL_CONFIG_ROM_MAX_HMQ"
,
"TRTL_CONFIG_ROM_MAX_RMQ"
,
"ETRTL_MSG_SYNC_FAILED_RECV_TIMEOUT"
,
)
software/lib/PyMockTurtle/setup.py
View file @
a4fa5915
...
...
@@ -9,7 +9,7 @@ setup(name='PyMockTurtle',
author_email
=
'federico.vaga@cern.ch'
,
maintainer
=
"Federico Vaga"
,
maintainer_email
=
"federico.vaga@cern.ch"
,
url
=
'http://www.ohwr.org/projects/mock-turtle
-sw
'
,
url
=
'http://www.ohwr.org/projects/mock-turtle'
,
packages
=
[
'PyMockTurtle'
],
license
=
'LGPLv2'
,
)
software/lib/libmockturtle-internal.h
View file @
a4fa5915
...
...
@@ -31,9 +31,8 @@ struct trtl_desc {
int
fd_dev
;
/**< File Descriptor of the device */
int
fd_cpu
[
TRTL_MAX_CPU
];
/**< File Descriptor of the CPUs */
int
fd_hmq
[
TRTL_MAX_CPU
][
TRTL_MAX_MQ_CHAN
];
/**< File Descriptors for the HMQ */
int
fd_hmq_sync
[
TRTL_MAX_CPU
][
TRTL_MAX_MQ_CHAN
];
/**< File Descriptors for the HMQ in sync mode */
struct
trtl_config_rom
cfgrom
;
/**< synthesis configuration */
struct
trtl_dev
*
trtl_sync
;
/**< token for synchronous operations */
};
#endif
software/lib/libmockturtle.c
View file @
a4fa5915
...
...
@@ -51,37 +51,6 @@ static const char * const trtl_error_str[] = {
NULL
,
};
/**
* Enumeration for predefined filters
*/
enum
trtl_msg_filter_predefined
{
TRTL_MSG_FILTER_ASYNC
=
0
,
/**< filter for ASYNC messages */
TRTL_MSG_FILTER_SYNC
,
/**< filter for SYNC messages */
};
/**
* List predefined filters used within the library
*/
static
struct
trtl_msg_filter
filters
[]
=
{
[
TRTL_MSG_FILTER_ASYNC
]
=
{
.
flags
=
TRTL_MSG_FILTER_FLAG_HEADER
,
.
operation
=
TRTL_MSG_FILTER_AND
,
.
word_offset
=
0
,
/* ATTENTION: flags in the message header */
.
mask
=
(
TRTL_HMQ_HEADER_FLAG_SYNC
|
TRTL_HMQ_HEADER_FLAG_ACK
)
<<
16
,
.
value
=
0
,
},
[
TRTL_MSG_FILTER_SYNC
]
=
{
.
flags
=
TRTL_MSG_FILTER_FLAG_HEADER
,
.
operation
=
TRTL_MSG_FILTER_AND
,
.
word_offset
=
0
,
/* ATTENTION: flags in the message header */
.
mask
=
TRTL_HMQ_HEADER_FLAG_ACK
<<
16
,
.
value
=
TRTL_HMQ_HEADER_FLAG_ACK
<<
16
,
},
};
static
int
trtl_sysfs_read
(
char
*
path
,
void
*
buf
,
size_t
len
);
static
int
trtl_sysfs_write
(
char
*
path
,
void
*
buf
,
size_t
len
);
...
...
@@ -207,15 +176,13 @@ void trtl_list_free(char **list)
free
(
list
);
}
/**
* It opens a TRTL device using a string descriptor. The descriptor correspond
* to the main char device name of the Mock-Turtle.
* @param[in] device name of the device to open
*
* @return TRTL token, NULL on error and errno is appropriately set
* @return the TRTL token, NULL on error and errno is appropriately set
*/
st
atic
struct
trtl_dev
*
__
trtl_open
(
const
char
*
device
)
st
ruct
trtl_dev
*
trtl_open
(
const
char
*
device
)
{
struct
trtl_desc
*
trtl
;
char
path
[
TRTL_PATH_LEN
+
TRTL_NAME_LEN
];
...
...
@@ -263,6 +230,20 @@ static struct trtl_dev *__trtl_open(const char *device)
if
(
fd
<
0
)
goto
out_hmq_fd
;
trtl
->
fd_hmq
[
i
][
k
]
=
fd
;
fd
=
open
(
path
,
O_RDWR
);
if
(
fd
<
0
)
{
close
(
trtl
->
fd_hmq
[
i
][
k
]);
goto
out_hmq_fd
;
}
trtl
->
fd_hmq_sync
[
i
][
k
]
=
fd
;
err
=
ioctl
(
trtl
->
fd_hmq_sync
[
i
][
k
],
TRTL_IOCTL_HMQ_SYNC_SET
,
1
);
if
(
err
)
{
close
(
trtl
->
fd_hmq
[
i
][
k
]);
close
(
trtl
->
fd_hmq_sync
[
i
][
k
]);
goto
out_hmq_fd
;
}
}
}
...
...
@@ -274,6 +255,7 @@ out_hmq_fd:
while
(
i
>=
0
)
{
while
(
--
k
>=
0
)
{
close
(
trtl
->
fd_hmq
[
i
][
k
]);
close
(
trtl
->
fd_hmq_sync
[
i
][
k
]);
}
--
i
;
}
...
...
@@ -283,52 +265,6 @@ out_stat:
return
NULL
;
}
/**
* It opens a TRTL device using a string descriptor. The descriptor correspond
* to the main char device name of the Mock-Turtle.
* @param[in] device name of the device to open
* @return the TRTL token, NULL on error and errno is appropriately set
*/
struct
trtl_dev
*
trtl_open
(
const
char
*
device
)
{
struct
trtl_desc
*
wdesc
;
struct
trtl_dev
*
trtl
;
int
ret
,
i
,
k
;
trtl
=
__trtl_open
(
device
);
if
(
!
trtl
)
return
NULL
;
/* quick hack to have a separete buffering for
synchronous messages */
wdesc
=
(
struct
trtl_desc
*
)
trtl
;
wdesc
->
trtl_sync
=
__trtl_open
(
device
);
if
(
!
wdesc
->
trtl_sync
)
goto
err_open_sync
;
/* set up the filters in order to have synchorouns messages on
a different buffer */
for
(
i
=
0
;
i
<
wdesc
->
cfgrom
.
n_cpu
;
++
i
)
{
for
(
k
=
0
;
k
<
wdesc
->
cfgrom
.
n_hmq
[
i
];
++
k
)
{
ret
=
trtl_hmq_filter_add
(
trtl
,
i
,
k
,
&
filters
[
TRTL_MSG_FILTER_ASYNC
]);
if
(
ret
<
0
)
goto
err_filter
;
ret
=
trtl_hmq_filter_add
(
wdesc
->
trtl_sync
,
i
,
k
,
&
filters
[
TRTL_MSG_FILTER_SYNC
]);
if
(
ret
<
0
)
goto
err_filter
;
}
}
return
trtl
;
err_filter:
trtl_close
(
wdesc
->
trtl_sync
);
err_open_sync:
trtl_close
(
trtl
);
return
NULL
;
}
/**
* It opens a TRTL device using its device_id. The Mock-Turtle
...
...
@@ -882,40 +818,6 @@ int trtl_cpu_is_enable(struct trtl_dev *trtl, unsigned int index,
}
/**
* It adds a new filter to the given hmq descriptor
* @param[in] trtl device token
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @param[in] filter filter to add
* @return 0 on success, -1 otherwise and errno is set appropriately
*/
int
trtl_hmq_filter_add
(
struct
trtl_dev
*
trtl
,
unsigned
int
idx_cpu
,
unsigned
int
idx_hmq
,
struct
trtl_msg_filter
*
filter
)
{
return
ioctl
(
trtl_hmq_fd
(
trtl
,
idx_cpu
,
idx_hmq
),
TRTL_IOCTL_MSG_FILTER_ADD
,
filter
);
}
/**
* It removes all filters from the given hmq descriptor
* @param[in] trtl device token
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @return 0 on success, -1 otherwise and errno is set appropriately
*/
int
trtl_hmq_filter_clean
(
struct
trtl_dev
*
trtl
,
unsigned
int
idx_cpu
,
unsigned
int
idx_hmq
)
{
return
ioctl
(
trtl_hmq_fd
(
trtl
,
idx_cpu
,
idx_hmq
),
TRTL_IOCTL_MSG_FILTER_CLEAN
,
NULL
);
}
/**
* It returns the device name
* @param[in] trtl device token
...
...
@@ -960,6 +862,38 @@ int trtl_hmq_fd(struct trtl_dev *trtl,
return
wdesc
->
fd_hmq
[
idx_cpu
][
idx_hmq
];
}
/**
* It returns the HMQ File Descriptor
* @param[in] trtl device token
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @return the file descriptor
*/
int
trtl_hmq_fd_sync
(
struct
trtl_dev
*
trtl
,
unsigned
int
idx_cpu
,
unsigned
int
idx_hmq
)
{
struct
trtl_desc
*
wdesc
=
(
struct
trtl_desc
*
)
trtl
;
return
wdesc
->
fd_hmq_sync
[
idx_cpu
][
idx_hmq
];
}
static
int
trtl_msg_read
(
int
fd
,
struct
trtl_msg
*
msg
,
unsigned
int
n
)
{
size_t
size
=
sizeof
(
*
msg
);
int
ret
;
ret
=
read
(
fd
,
msg
,
size
*
n
);
if
(
ret
<
0
)
return
ret
;
if
(
ret
%
size
)
{
/* most likely a driver problem */
errno
=
ETRTL_INVALID_MESSAGE
;
return
-
1
;
}
return
(
ret
/
size
);
}
/**
* It reads messages from a given HMQ
...
...
@@ -977,10 +911,7 @@ int trtl_msg_async_recv(struct trtl_dev *trtl,
struct
trtl_msg
*
msg
,
unsigned
int
n
)
{
struct
trtl_desc
*
wdesc
=
(
struct
trtl_desc
*
)
trtl
;
int
ret
,
size
,
fd
;
fd
=
wdesc
->
fd_hmq
[
idx_cpu
][
idx_hmq
];
int
fd
=
trtl_hmq_fd
(
trtl
,
idx_cpu
,
idx_hmq
);
/* validation */
if
(
fd
<
0
)
{
...
...
@@ -988,12 +919,18 @@ int trtl_msg_async_recv(struct trtl_dev *trtl,
return
-
1
;
}
/* Get a message from the driver */
size
=
sizeof
(
struct
trtl_msg
);
ret
=
read
(
fd
,
msg
,
size
*
n
);
return
trtl_msg_read
(
fd
,
msg
,
n
);
}
static
int
trtl_msg_write
(
int
fd
,
struct
trtl_msg
*
msg
,
unsigned
int
n
)
{
size_t
size
=
sizeof
(
*
msg
);
int
ret
;
ret
=
write
(
fd
,
msg
,
size
*
n
);
if
(
ret
<
0
)
return
ret
;
if
(
ret
%
size
of
(
struct
trtl_msg
)
)
{
return
-
1
;
if
(
ret
%
size
)
{
/* most likely a driver problem */
errno
=
ETRTL_INVALID_MESSAGE
;
return
-
1
;
...
...
@@ -1001,8 +938,6 @@ int trtl_msg_async_recv(struct trtl_dev *trtl,
return
(
ret
/
size
);
}
/**
* It writes messages to a given HMQ
* @param[in] trtl device token
...
...
@@ -1019,31 +954,32 @@ int trtl_msg_async_send(struct trtl_dev *trtl,
struct
trtl_msg
*
msg
,
unsigned
int
n
)
{
struct
trtl_desc
*
wdesc
=
(
struct
trtl_desc
*
)
trtl
;
int
ret
,
size
,
fd
;
fd
=
wdesc
->
fd_hmq
[
idx_cpu
][
idx_hmq
];
int
fd
=
trtl_hmq_fd
(
trtl
,
idx_cpu
,
idx_hmq
);
/* validation */
if
(
fd
<
0
)
{
errno
=
ETRTL_HMQ_CLOSE
;
return
-
1
;
}
/* Get a message from the driver */
size
=
sizeof
(
struct
trtl_msg
);
ret
=
write
(
fd
,
msg
,
size
*
n
);
if
(
ret
<
0
)
return
-
1
;
if
(
ret
%
sizeof
(
struct
trtl_msg
))
{
/* most likely a driver problem */
errno
=
ETRTL_INVALID_MESSAGE
;
return
-
1
;
}
return
(
ret
/
size
);
return
trtl_msg_write
(
fd
,
msg
,
n
);
}
/**
* It adds a new filter to the given hmq descriptor
* @param[in] trtl device token
* @param[in] idx_cpu CPU index
* @param[in] idx_hmq HMQ index
* @param[in] err error code
* @return 0 on success, -1 otherwise and errno is set appropriately
*/
int
trtl_msg_sync_abort
(
struct
trtl_dev
*
trtl
,
unsigned
int
idx_cpu
,
unsigned
int
idx_hmq
,
unsigned
int
err
)
{
return
ioctl
(
trtl_hmq_fd_sync
(
trtl
,
idx_cpu
,
idx_hmq
),
TRTL_IOCTL_MSG_SYNC_ABORT
,
err
);
}
/**
* It sends and receives a synchronous message. It is up to the user to set the
...
...
@@ -1066,79 +1002,55 @@ int trtl_msg_sync(struct trtl_dev *trtl,
struct
trtl_msg
*
msg_r
,
int
timeout
)
{
struct
trtl_desc
*
wdesc
=
(
struct
trtl_desc
*
)
trtl
;
struct
polltrtl
p
;
#if 0
struct trtl_msg_filter f_sync = {
.flags = TRTL_MSG_FILTER_FLAG_HEADER,
.operation = TRTL_MSG_FILTER_AND,
.word_offset = 1, /* ATTENTION: sync_id in the message header */
.mask = 0xFFFF0000,
};
#endif
int
ret
;
msg_s
->
hdr
.
flags
|=
TRTL_HMQ_HEADER_FLAG_SYNC
;
#if 0
/* FIXME: commented out as the filter is never removed.
The filter shouldn't be needed as the synchronous messages are
always sent sequentially - if there is only one process. */
f_sync.value = (msg_s->hdr.sync_id << 16);
ret = trtl_hmq_filter_add(wdesc->trtl_sync, idx_cpu, idx_hmq,
&f_sync);
if (ret < 0)
return -1;
#endif
struct
pollfd
p
;
int
ret
,
fd
;
/* send message */
ret
=
trtl_msg_async_send
(
wdesc
->
trtl_sync
,
idx_cpu
,
idx_hmq
,
msg_s
,
1
);
fd
=
trtl_hmq_fd_sync
(
trtl
,
idx_cpu
,
idx_hmq
);
ret
=
trtl_msg_write
(
fd
,
msg_s
,
1
);
if
(
ret
<
0
)
return
-
1
;
goto
err
;
if
(
ret
==
0
)
{
errno
=
ETRTL_MSG_SYNC_FAILED_SEND
;
return
-
1
;
goto
err
;
}
/* wait answer */
p
.
trtl
=
wdesc
->
trtl_sync
;
p
.
idx_cpu
=
idx_cpu
;
p
.
idx_hmq
=
idx_hmq
;
p
.
fd
=
fd
;
p
.
events
=
POLLIN
|
POLLERR
;
ret
=
trtl_msg_
poll
(
&
p
,
1
,
timeout
);
ret
=
poll
(
&
p
,
1
,
timeout
);
if
(
ret
<
0
)
return
-
1
;
/* I (git blame) know, this if is over-complicated */
if
(
ret
==
0
)
{
errno
=
ETRTL_MSG_SYNC_FAILED_RECV_TIMEOUT
;
return
-
1
;
goto
err_abort
;
}
if
((
p
.
revents
&
POLLERR
))
{
errno
=
ETRTL_MSG_SYNC_FAILED_RECV_POLLERR
;
return
-
1
;
goto
err_abort
;
}
if
(
!
(
p
.
revents
&
POLLIN
))
{
errno
=
ETRTL_MSG_SYNC_FAILED_RECV
;
return
-
1
;
goto
err_abort
;
}
/* read the answer */
ret
=
trtl_msg_
async_recv
(
wdesc
->
trtl_sync
,
idx_cpu
,
idx_hmq
,
msg_r
,
1
);
ret
=
trtl_msg_
read
(
fd
,
msg_r
,
1
);
if
(
ret
<
0
)
return
-
1
;
goto
err
;
if
(
ret
==
0
)
{
errno
=
ETRTL_MSG_SYNC_FAILED_RECV
;
return
-
1
;
}
/* paranoid check, the driver should be right */
if
(
msg_s
->
hdr
.
sync_id
!=
msg_r
->
hdr
.
sync_id
)
{
errno
=
ETRTL_MSG_SYNC_FAILED_INVAL
;
return
-
1
;
goto
err
;
}
return
0
;
err_abort:
trtl_msg_sync_abort
(
trtl
,
idx_cpu
,
idx_hmq
,
errno
);
err:
return
-
1
;
}
...
...
software/lib/libmockturtle.h
View file @
a4fa5915
...
...
@@ -151,14 +151,10 @@ static inline int trtl_cpu_restart(struct trtl_dev *trtl, unsigned int index)
* @{
*/
extern
int
trtl_hmq_filter_add
(
struct
trtl_dev
*
trtl
,
unsigned
int
idx_cpu
,
unsigned
int
idx_hmq
,
struct
trtl_msg_filter
*
filter
);
extern
int
trtl_hmq_filter_clean
(
struct
trtl_dev
*
trtl
,
extern
int
trtl_hmq_fd
(
struct
trtl_dev
*
trtl
,
unsigned
int
idx_cpu
,
unsigned
int
idx_hmq
);
extern
int
trtl_hmq_fd
(
struct
trtl_dev
*
trtl
,
extern
int
trtl_hmq_fd
_sync
(
struct
trtl_dev
*
trtl
,
unsigned
int
idx_cpu
,
unsigned
int
idx_hmq
);
extern
int
trtl_msg_async_send
(
struct
trtl_dev
*
trtl
,
...
...
software/tools/.gitignore
View file @
a4fa5915
...
...
@@ -7,3 +7,4 @@ mockturtle-smem
mockturtle-ping
mockturtle-variable
mockturtle-buffer
mockturtle-gdbserver
\ No newline at end of file
software/tools/Makefile
View file @
a4fa5915
...
...
@@ -8,14 +8,15 @@ REPO_PARENT ?= ../..
-include
$(REPO_PARENT)/parent_common.mk
DESTDIR
?=
/usr/local
TRTL
?=
../
TRTL
?=
../../
TRTL_SW
=
$(TRTL)
/software
GIT_VERSION
:=
$(
shell
git describe
--dirty
--long
--tags
)
CFLAGS
+=
-Wall
-Werror
-ggdb
-I
$(TRTL)
/lib
CFLAGS
+=
-I
$(TRTL)
/include
CFLAGS
+=
-Wall
-Werror
-ggdb
-I
$(TRTL
_SW
)
/lib
CFLAGS
+=
-I
$(TRTL
_SW
)
/include
CFLAGS
+=
$(EXTRACFLAGS)
LDLIBS
+=
-Wl
,-Bstatic
-L
$(TRTL)
/lib
-lmockturtle
LDLIBS
+=
-Wl
,-Bstatic
-L
$(TRTL
_SW
)
/lib
-lmockturtle
LDLIBS
+=
-Wl
,-Bdynamic
-lpthread
PROGS
:=
mockturtle-count
PROGS
+=
lsmockturtle
...
...
@@ -26,6 +27,7 @@ PROGS += mockturtle-smem
PROGS
+=
mockturtle-ping
PROGS
+=
mockturtle-variable
PROGS
+=
mockturtle-buffer
PROGS
+=
mockturtle-gdbserver
all
:
$(PROGS)
...
...
@@ -33,7 +35,7 @@ install:
install
-d
$(DESTDIR)
/bin
install
-D
$(PROGS)
$(DESTDIR)
/bin
%
:
%.c $(TRTL
)
/libmockturtle.a
%
:
%.c $(TRTL
_SW)/lib
/libmockturtle.a
$(CC)
$(CFLAGS)
$^
-o
$@
$(LDLIBS)
# make nothing for modules_install, but avoid errors
...
...
software/tools/mockturtle-gdbserver.c
0 → 100644
View file @
a4fa5915
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <stdbool.h>
#include <time.h>
#include <assert.h>
#include <limits.h>
#include <hw/mockturtle_cpu_csr.h>
#define TRTL_DBG_PORT_SIZE pagesize
#define TRTL_GDB_PACKET_SIZE_MAX 2048
static
long
pagesize
;
static
int
verbose
;
static
int
swapping
;
/**
* struct trtl_gdb_packet - GDB packet
* @data: message exchanged with GDB
* @size: length in bytes
*/
struct
trtl_gdb_packet
{
char
data
[
TRTL_GDB_PACKET_SIZE_MAX
];
size_t
size
;
};
/**
* struct trtl_dbg_port - descriptor to handle connection
* @addr: Mock Turtle virtual address
* @cpu: CPU index
* @fd: socket file descriptor
*/
struct
trtl_dbg_port
{
void
*
addr
;
uint8_t
cpu
;
int
fd
;
};
typedef
int
(
trtl_gdb_command_t
)(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
);
/**
* Help message
*/
static
void
help
(
void
)
{
fputs
(
"
\n
"
,
stderr
);
fputs
(
"mockturtle-gdbserver -D 0x<hex-number> -i <number>
\n\n
"
,
stderr
);
fputs
(
"-D device identificator
\n
"
,
stderr
);
fputs
(
"-i CPU index (default 0)
\n
"
,
stderr
);
fputs
(
"-p GDB port (default 7471)
\n
"
,
stderr
);
fputs
(
"-s 32bit endianness swapping (default not active)
\n
"
,
stderr
);
fputs
(
"-v verbose output (add more for more verbosity)
\n
"
,
stderr
);
fputs
(
"-h show this message
\n
"
,
stderr
);
fputs
(
"
\n
"
,
stderr
);
fputs
(
"The options '-s' should be used when there is an
\n
"
,
stderr
);
fputs
(
"endianness conversion to be done to communicate
\n
"
,
stderr
);
fputs
(
"with the debug port.
\n
"
,
stderr
);
fflush
(
stderr
);
}
/**
* Change byte order but only when user asks for it
* @val: value
*
* Return: value in swapped order
*
* It uses a global variable that is set by the user
*/
static
uint32_t
__io_swap32
(
uint32_t
val
)
{
if
(
!
swapping
)
return
val
;
fputs
(
"Swapping
\n
"
,
stdout
);
return
((
val
>>
24
)
&
0x000000FF
)
|
((
val
>>
8
)
&
0x0000FF00
)
|
((
val
<<
8
)
&
0x00FF0000
)
|
((
val
<<
24
)
&
0xFF000000
);
}
/**
* Read value from the Debug Port
*/
static
uint32_t
trtl_dbg_readl
(
struct
trtl_dbg_port
*
dbg
,
uint32_t
reg
)
{
char
*
addr
=
dbg
->
addr
;
return
__io_swap32
(
*
((
uint32_t
*
)(
addr
+
reg
)));
}
/**
* Write value to the Debug Port
*/
static
void
trtl_dbg_writel
(
struct
trtl_dbg_port
*
dbg
,
uint32_t
reg
,
uint32_t
val
)
{
char
*
addr
=
dbg
->
addr
;
*
((
uint32_t
*
)(
addr
+
reg
))
=
__io_swap32
(
val
);
}
/**
* Read mail-box
* @dbg: debug port
*
* Return value read
*/
static
uint32_t
trtl_dbg_read_mbx
(
struct
trtl_dbg_port
*
dbg
)
{
uint32_t
reg
;
reg
=
MT_CPU_CSR_REG_DBG_CORE0_MBX
;
reg
+=
sizeof
(
uint32_t
)
*
dbg
->
cpu
;
return
trtl_dbg_readl
(
dbg
,
reg
);
}
/**
* Write mail-box
* @dbg: debug port
* @val: value to write
*/
static
void
trtl_dbg_write_mbx
(
struct
trtl_dbg_port
*
dbg
,
uint32_t
val
)
{
uint32_t
reg
;
reg
=
MT_CPU_CSR_REG_DBG_CORE0_MBX
;
reg
+=
sizeof
(
uint32_t
)
*
dbg
->
cpu
;
trtl_dbg_writel
(
dbg
,
reg
,
val
);
}
/**
* Execute one instructions
* @dbg: debug port
* @insn: instruction to execute
*/
static
void
trtl_dbg_exec_insn
(
struct
trtl_dbg_port
*
dbg
,
uint32_t
insn
)
{
uint32_t
reg
;
reg
=
MT_CPU_CSR_REG_DBG_CORE0_INSN
;
reg
+=
sizeof
(
uint32_t
)
*
dbg
->
cpu
;
trtl_dbg_writel
(
dbg
,
reg
,
insn
);
}
/**
* Execute instruction to copy a register to the mail-box
* @dbg: debug port
* @reg: register index
*/
static
void
trtl_dbg_exec_reg_to_mbx
(
struct
trtl_dbg_port
*
dbg
,
uint32_t
reg
)
{
trtl_dbg_exec_insn
(
dbg
,
0x7D001073
|
(
reg
<<
15
));
}
/**
* Execute instruction to the mail-box to a register
* @dbg: debug port
* @reg: register index
*/
static
void
trtl_dbg_exec_mbx_to_reg
(
struct
trtl_dbg_port
*
dbg
,
uint32_t
reg
)
{
trtl_dbg_exec_insn
(
dbg
,
0x7D002073
|
(
reg
<<
7
));
}
/**
* Execute NOP instruction
* @dbg: debug port
*/
static
void
trtl_dbg_exec_nop
(
struct
trtl_dbg_port
*
dbg
)
{
trtl_dbg_exec_insn
(
dbg
,
0x00000013
);
}
/**
* Check if MockTurtle CPU is in debug mode
* @dbg: debug port
*
* Return true when it is in debug mode
*/
static
bool
trtl_dbg_in_debug_mode
(
struct
trtl_dbg_port
*
dbg
)
{
uint32_t
status
;
status
=
trtl_dbg_readl
(
dbg
,
MT_CPU_CSR_REG_DBG_STATUS
);
return
((
status
>>
dbg
->
cpu
)
&
1
);
}
/**
* Set MockTurtle CPU in debug mode
* @dbg: debug port
*
* Return 0 on success, -1 on error and errno is appropriately set
*/
static
int
trtl_dbg_debug_mode_force_set
(
struct
trtl_dbg_port
*
dbg
)
{
int
retry
;
if
(
trtl_dbg_in_debug_mode
(
dbg
))
return
0
;
trtl_dbg_writel
(
dbg
,
MT_CPU_CSR_REG_DBG_FORCE
,
(
1
<<
dbg
->
cpu
));
/* wait to debug to be ready max ~5s */
retry
=
5000
;
while
(
retry
>=
0
)
{
struct
timespec
ts
=
{
0
,
1000000
};
nanosleep
(
&
ts
,
NULL
);
if
(
trtl_dbg_in_debug_mode
(
dbg
))
break
;
retry
--
;
}
trtl_dbg_writel
(
dbg
,
MT_CPU_CSR_REG_DBG_FORCE
,
0
);
if
(
retry
<
0
)
{
errno
=
ETIME
;
return
-
1
;
}
return
0
;
}
/**
* Read from a CPU register
* @dbg: debug port
* @reg: register number [0, 31]
*
* Return: the register content
*/
static
uint32_t
trtl_dbg_read_reg
(
struct
trtl_dbg_port
*
dbg
,
int
reg
)
{
assert
(
reg
>=
0
&&
reg
<
32
);
trtl_dbg_exec_reg_to_mbx
(
dbg
,
reg
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
return
trtl_dbg_read_mbx
(
dbg
);
}
/**
* Write in a CPU register
* @dbg: debug port
* @reg: register number [0, 31]
* @val: value
*/
static
void
trtl_dbg_write_reg
(
struct
trtl_dbg_port
*
dbg
,
int
reg
,
uint32_t
val
)
{
assert
(
reg
>=
0
&&
reg
<
32
);
trtl_dbg_write_mbx
(
dbg
,
val
);
trtl_dbg_exec_mbx_to_reg
(
dbg
,
reg
);
}
/**
* Copy PC to RA register
* @dbg: debug port
*
* Return PC value
*/
static
uint32_t
trtl_dbg_pc_read_via_ra
(
struct
trtl_dbg_port
*
dbg
)
{
trtl_dbg_exec_insn
(
dbg
,
0x000000ef
);
/* ra = pc + 4 */
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_reg_to_mbx
(
dbg
,
1
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
return
(
trtl_dbg_read_mbx
(
dbg
)
-
4
)
&
0xFFFFFFFF
;
}
/**
* Write PC using RA content register
* @dbg: debug port
*/
static
void
trtl_dbg_pc_write_via_ra
(
struct
trtl_dbg_port
*
dbg
)
{
trtl_dbg_exec_insn
(
dbg
,
0x00008067
);
/* ret */
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
}
/**
* Increase PC by 4
* @dbg: debug port
*/
static
void
trtl_dbg_pc_advance_4
(
struct
trtl_dbg_port
*
dbg
)
{
trtl_dbg_exec_insn
(
dbg
,
0x00000263
);
/* beqz zero, +4 */
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
}
/**
* Continue command
*/
static
int
trtl_gdb_handle_c
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
if
(
in
->
size
>
1
)
{
out
->
size
=
0
;
return
0
;
}
trtl_dbg_exec_insn
(
dbg
,
0x00100073
);
/* ebreak */
while
(
1
)
{
struct
pollfd
p
=
{
.
fd
=
dbg
->
fd
,
.
events
=
POLLIN
,
.
revents
=
0
,
};
int
ret
;
if
(
trtl_dbg_in_debug_mode
(
dbg
))
{
/*
* TODO not clear but check twice due to possible
* race if the ebreak is not yet executed
*/
if
(
trtl_dbg_in_debug_mode
(
dbg
))
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"S05"
);
break
;
}
}
ret
=
poll
(
&
p
,
1
,
1000
);
if
(
ret
>
0
)
{
/* GDB wants something from us */
ret
=
trtl_dbg_debug_mode_force_set
(
dbg
);
if
(
ret
<
0
)
fprintf
(
stderr
,
"Failed to set debug mode
\n
"
);
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"S02"
);
break
;
}
}
return
0
;
}
/**
* Detach
*/
static
int
trtl_gdb_handle_D
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
trtl_dbg_exec_insn
(
dbg
,
0x00100073
);
/* ebreak */
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"OK"
);
return
0
;
}
/**
* Read all registers
*/
static
int
trtl_gdb_handle_g
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
uint32_t
regs
[
32
],
pc
;
int
i
;
out
->
size
=
0
;
for
(
i
=
0
;
i
<
32
;
++
i
)
{
regs
[
i
]
=
trtl_dbg_read_reg
(
dbg
,
i
);
out
->
size
+=
snprintf
(
out
->
data
+
out
->
size
,
TRTL_GDB_PACKET_SIZE_MAX
,
"%08"
PRIx32
,
htonl
(
regs
[
i
]));
}
pc
=
trtl_dbg_pc_read_via_ra
(
dbg
);
out
->
size
+=
snprintf
(
out
->
data
+
out
->
size
,
TRTL_GDB_PACKET_SIZE_MAX
,
"%08"
PRIx32
,
htonl
(
pc
));
trtl_dbg_write_reg
(
dbg
,
1
,
regs
[
1
]);
return
0
;
}
/**
* Write all register
*/
static
int
trtl_gdb_handle_G
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
uint32_t
regs
[
33
];
/* 32 register, 1 PC */
int
i
;
if
(
in
->
size
!=
(
1
+
33
*
8
))
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"E01"
);
return
0
;
}
for
(
i
=
0
;
i
<
33
;
++
i
)
{
int
ret
=
sscanf
(
in
->
data
+
1
+
i
*
8
,
"%08"
SCNx32
,
&
regs
[
i
]);
if
(
ret
!=
1
)
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"E02"
);
return
0
;
}
}
trtl_dbg_write_reg
(
dbg
,
1
,
ntohl
(
regs
[
32
]));
trtl_dbg_pc_write_via_ra
(
dbg
);
for
(
i
=
0
;
i
<
32
;
++
i
)
trtl_dbg_write_reg
(
dbg
,
i
,
ntohl
(
regs
[
i
]));
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"OK"
);
return
0
;
}
/**
* Set thread for subsequent operations
*
* Partially supported
*/
static
int
trtl_gdb_handle_H
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
/* we just want to keep GDB quiet */
if
(
strncmp
(
in
->
data
,
"Hg0"
,
3
)
==
0
)
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"OK"
);
else
out
->
size
=
0
;
return
0
;
}
/**
* Kill
*
* Not supported yet
*
* kill leave the CPU in its current state. In the next connection it
* will restart exactly from that point and the core remains stopped.
*/
static
int
trtl_gdb_handle_k
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
return
0
;
}
/**
* Write data to memory
*/
static
int
trtl_gdb_handle_M
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
uint32_t
addr
,
n
;
uint32_t
a0
,
a1
;
char
*
indata
;
int
ret
;
indata
=
strchr
(
in
->
data
,
':'
);
if
(
!
indata
)
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"E01"
);
return
0
;
}
indata
++
;
/* skip ':' */
ret
=
sscanf
(
in
->
data
+
1
,
"%"
SCNx32
",%"
SCNx32
":"
,
&
addr
,
&
n
);
if
(
ret
!=
2
)
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"E02"
);
return
0
;
}
if
(
n
*
2
!=
in
->
size
-
(
indata
-
in
->
data
))
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"E03"
);
return
0
;
}
a0
=
trtl_dbg_read_reg
(
dbg
,
10
);
a1
=
trtl_dbg_read_reg
(
dbg
,
11
);
trtl_dbg_write_reg
(
dbg
,
10
,
addr
);
if
(
addr
%
4
==
0
)
{
for
(;
n
>=
4
;
n
-=
4
,
indata
+=
8
)
{
uint32_t
w
;
ret
=
sscanf
(
indata
,
"%08"
SCNx32
,
&
w
);
if
(
ret
!=
1
)
break
;
trtl_dbg_write_reg
(
dbg
,
11
,
ntohl
(
w
));
/* sw a1, 0(a0) */
trtl_dbg_exec_insn
(
dbg
,
0x00B52023
);
/* addi a0, a0, 4 */
trtl_dbg_exec_insn
(
dbg
,
0x00450513
);
}
}
for
(;
n
>
0
;
--
n
,
indata
+=
2
)
{
uint32_t
b
;
ret
=
sscanf
(
indata
,
"%02"
SCNx32
,
&
b
);
if
(
ret
!=
1
)
break
;
trtl_dbg_write_reg
(
dbg
,
11
,
b
);
/* sb a1, 0(a0) */
trtl_dbg_exec_insn
(
dbg
,
0x00B50023
);
/* addi a0, a0, 4 */
trtl_dbg_exec_insn
(
dbg
,
0x00150513
);
}
trtl_dbg_write_reg
(
dbg
,
10
,
a0
);
trtl_dbg_write_reg
(
dbg
,
11
,
a1
);
if
(
n
>
0
)
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"E04"
);
else
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"OK"
);
return
0
;
}
/**
* Read data from memory
*/
static
int
trtl_gdb_handle_m
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
uint32_t
addr
,
n
;
uint32_t
a0
,
a1
;
int
ret
;
ret
=
sscanf
(
in
->
data
+
1
,
"%x,%x"
,
&
addr
,
&
n
);
if
(
ret
!=
2
)
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"E01"
);
return
0
;
}
a0
=
trtl_dbg_read_reg
(
dbg
,
10
);
a1
=
trtl_dbg_read_reg
(
dbg
,
11
);
trtl_dbg_write_reg
(
dbg
,
10
,
addr
);
out
->
size
=
0
;
for
(;
n
>
0
;
--
n
)
{
uint8_t
b
;
trtl_dbg_exec_insn
(
dbg
,
0x00054583
);
/* lbu a1, 0(a0) */
trtl_dbg_exec_insn
(
dbg
,
0x00150513
);
/* addi a0, a0, 1 */
b
=
trtl_dbg_read_reg
(
dbg
,
11
);
out
->
size
+=
snprintf
(
out
->
data
+
out
->
size
,
TRTL_GDB_PACKET_SIZE_MAX
,
"%02"
PRIx8
,
b
);
}
trtl_dbg_write_reg
(
dbg
,
10
,
a0
);
trtl_dbg_write_reg
(
dbg
,
11
,
a1
);
return
0
;
}
/**
* Read a specific register
*/
static
int
trtl_gdb_handle_p
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
unsigned
int
val
;
int
ret
;
ret
=
sscanf
(
in
->
data
+
1
,
"%x"
,
&
val
);
if
(
ret
!=
1
)
{
out
->
size
=
0
;
return
0
;
}
printf
(
"0x%x
\n
"
,
val
);
if
(
val
==
(
0x301
+
65
))
/* MISA CSR */
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"%08x"
,
(
1
<<
30
)
|
(
1
<<
(
'I'
-
65
)));
else
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"E01"
);
return
0
;
}
/**
* Write a specific register
*
*
* Not supported yet
*/
static
int
trtl_gdb_handle_P
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
out
->
size
=
0
;
return
0
;
}
/**
* Answer to qSupported request
*/
static
int
trtl_gdb_handle_q_supported
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"PacketSize=%x"
,
TRTL_GDB_PACKET_SIZE_MAX
);
return
0
;
}
static
int
trtl_gdb_handle_qm
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"S05"
);
return
0
;
}
static
int
trtl_gdb_handle_q
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
if
(
strncmp
(
in
->
data
,
"qSupported:"
,
11
)
==
0
)
return
trtl_gdb_handle_q_supported
(
dbg
,
out
,
in
);
else
if
(
strncmp
(
in
->
data
,
"qm"
,
2
)
==
0
)
return
trtl_gdb_handle_qm
(
dbg
,
out
,
in
);
out
->
size
=
0
;
return
0
;
}
/**
* Single step
*/
static
int
trtl_gdb_handle_s
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
uint32_t
pc
,
npc
,
ra
,
insn
;
if
(
in
->
size
>
1
)
{
out
->
size
=
0
;
return
0
;
}
ra
=
trtl_dbg_read_reg
(
dbg
,
1
);
pc
=
trtl_dbg_pc_read_via_ra
(
dbg
);
trtl_dbg_write_reg
(
dbg
,
1
,
pc
);
trtl_dbg_exec_insn
(
dbg
,
0x0000A083
)
;
/* lw ra,0(ra) */
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
insn
=
trtl_dbg_read_reg
(
dbg
,
1
);
trtl_dbg_write_reg
(
dbg
,
1
,
ra
);
if
(
verbose
)
fprintf
(
stdout
,
"execute: %08"
PRIx32
" at pc=%08"
PRIx32
,
insn
,
pc
);
trtl_dbg_exec_insn
(
dbg
,
insn
);
trtl_dbg_exec_nop
(
dbg
);
trtl_dbg_exec_nop
(
dbg
);
switch
(
insn
&
0x77
)
{
case
0x67
:
/* jump */
/* Nothing to do, PC is always updated */
break
;
case
0x63
:
/* branch */
ra
=
trtl_dbg_read_reg
(
dbg
,
1
);
npc
=
trtl_dbg_pc_read_via_ra
(
dbg
);
trtl_dbg_write_reg
(
dbg
,
1
,
ra
);
if
(
npc
==
pc
)
trtl_dbg_pc_advance_4
(
dbg
);
break
;
default:
trtl_dbg_pc_advance_4
(
dbg
);
break
;
}
out
->
size
=
snprintf
(
out
->
data
,
TRTL_GDB_PACKET_SIZE_MAX
,
"S05"
);
return
0
;
}
/**
* vAttach command
*
* Not supported yet
*/
static
int
trtl_gdb_handle_v_attach
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
out
->
size
=
0
;
return
0
;
}
/**
* vCont command
*
* Not supported yet
*/
static
int
trtl_gdb_handle_v_cont
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
out
->
size
=
0
;
return
0
;
}
/**
* vCtrlC command
*
* Not supported yet
*/
static
int
trtl_gdb_handle_v_ctrlc
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
out
->
size
=
0
;
return
0
;
}
/**
* v<name> commands
*/
static
int
trtl_gdb_handle_v
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
int
ret
=
0
;
if
(
strncmp
(
in
->
data
,
"vAttach"
,
7
)
==
0
)
ret
=
trtl_gdb_handle_v_attach
(
dbg
,
out
,
in
);
else
if
(
strncmp
(
in
->
data
,
"vCont"
,
5
)
==
0
)
ret
=
trtl_gdb_handle_v_cont
(
dbg
,
out
,
in
);
else
if
(
strncmp
(
in
->
data
,
"vCtrlC"
,
6
)
==
0
)
ret
=
trtl_gdb_handle_v_ctrlc
(
dbg
,
out
,
in
);
else
if
(
strncmp
(
in
->
data
,
"vMustReplyEmpty:"
,
16
)
==
0
)
out
->
size
=
0
;
else
out
->
size
=
0
;
return
ret
;
}
/**
* Write binary data to memory
*
* Not supported yet
*/
static
int
trtl_gdb_handle_X
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
out
->
size
=
0
;
return
0
;
}
static
trtl_gdb_command_t
*
gdb_packet_exec
[]
=
{
[
'c'
]
=
trtl_gdb_handle_c
,
[
'D'
]
=
trtl_gdb_handle_D
,
[
'g'
]
=
trtl_gdb_handle_g
,
[
'G'
]
=
trtl_gdb_handle_G
,
[
'H'
]
=
trtl_gdb_handle_H
,
[
'k'
]
=
trtl_gdb_handle_k
,
[
'M'
]
=
trtl_gdb_handle_M
,
[
'm'
]
=
trtl_gdb_handle_m
,
[
'p'
]
=
trtl_gdb_handle_p
,
[
'P'
]
=
trtl_gdb_handle_P
,
[
'q'
]
=
trtl_gdb_handle_q
,
[
's'
]
=
trtl_gdb_handle_s
,
[
'v'
]
=
trtl_gdb_handle_v
,
[
'v'
]
=
trtl_gdb_handle_v
,
[
'X'
]
=
trtl_gdb_handle_X
,
[
'?'
]
=
trtl_gdb_handle_qm
,
};
/**
* Process incoming packet and generate the outcoming
* @out: outgoing packet
* @in: incoming packet
*
* Return: 0 on success, otherwise -1 and errno is appropriately set
*
* The function does not receive or send packets, it only processes them;
* the caller will handle recv(2) and send(2)
*/
static
int
gdb_command
(
struct
trtl_dbg_port
*
dbg
,
struct
trtl_gdb_packet
*
out
,
struct
trtl_gdb_packet
*
in
)
{
int
cmd
=
in
->
data
[
0
];
trtl_gdb_command_t
*
exec
;
if
(
in
->
size
==
0
)
return
-
1
;
exec
=
gdb_packet_exec
[
cmd
];
if
(
exec
)
return
exec
(
dbg
,
out
,
in
);
out
->
size
=
0
;
return
0
;
}
static
void
trtl_debugger_print_packet
(
struct
trtl_gdb_packet
*
pkt
,
const
char
*
dir
)
{
int
i
,
start
,
end
;
switch
(
verbose
)
{
case
0
:
return
;
case
1
:
start
=
1
;
end
=
pkt
->
size
-
3
;
break
;
default:
start
=
0
;
end
=
pkt
->
size
;
break
;
}
fputs
(
dir
,
stdout
);
fputc
(
' '
,
stdout
);
for
(
i
=
start
;
i
<
end
;
++
i
)
fputc
(
pkt
->
data
[
i
],
stdout
);
fputc
(
'\n'
,
stdout
);
fflush
(
stdout
);
}
/**
* Calculate mod 256 checksum
* @data: input data
* @n: number of bytes
*
* Return: checksum value
*/
static
uint8_t
trtl_debugger_checksum
(
uint8_t
*
data
,
size_t
n
)
{
uint8_t
checksum
=
0
;
int
i
;
for
(
i
=
0
;
i
<
n
;
++
i
)
checksum
+=
data
[
i
];
return
checksum
&
0xFF
;
}
/**
* Receive a GDB packet
* @fd: socket file descriptor
* @pkt: packet
*
* Return: 0 on success, otherwise -1 and errno is appropriately set
*/
static
int
__trtl_debugger_recv
(
int
fd
,
struct
trtl_gdb_packet
*
pkt
)
{
pkt
->
size
=
0
;
do
{
char
c
;
int
ret
;
struct
pollfd
p
=
{
.
fd
=
fd
,
.
events
=
POLLIN
,
.
revents
=
0
,
};
ret
=
poll
(
&
p
,
1
,
1000
);
if
(
ret
<
0
)
return
ret
;
if
(
ret
==
0
)
continue
;
ret
=
recv
(
fd
,
&
c
,
1
,
0
);
if
(
ret
<
0
)
return
-
1
;
if
(
ret
==
0
)
{
errno
=
ENOTCONN
;
return
-
1
;
}
/* FIXME should we control more ? */
if
(
pkt
->
size
==
0
&&
c
!=
'$'
)
continue
;
/* wait for the beginning */
pkt
->
data
[
pkt
->
size
]
=
c
;
pkt
->
size
++
;
if
(
verbose
>
2
)
{
fprintf
(
stdout
,
"Building message: [%zu]: %s
\n
"
,
pkt
->
size
,
pkt
->
data
);
}
if
(
pkt
->
size
>
TRTL_GDB_PACKET_SIZE_MAX
-
1
)
{
/* -1 to leave space for the string terminator */
errno
=
EINVAL
;
return
-
1
;
}
}
while
(
!
(
pkt
->
size
>
3
&&
pkt
->
data
[
pkt
->
size
-
3
]
==
'#'
));
return
0
;
}
/**
* Receive a GDB packet
* @fd: socket file descriptor
* @pkt: packet
*
* Return: 0 on success, otherwise -1 and errno is appropriately set
*/
static
int
trtl_debugger_recv
(
int
fd
,
struct
trtl_gdb_packet
*
pkt
)
{
uint8_t
checksum_l
,
checksum_r
;
char
ack
[
1
];
int
ret
;
ret
=
__trtl_debugger_recv
(
fd
,
pkt
);
if
(
ret
<
0
)
return
ret
;
trtl_debugger_print_packet
(
pkt
,
"->"
);
checksum_l
=
trtl_debugger_checksum
((
uint8_t
*
)(
pkt
->
data
+
1
),
pkt
->
size
-
4
);
ret
=
sscanf
(
pkt
->
data
+
pkt
->
size
-
2
,
"%02"
SCNx8
,
&
checksum_r
);
if
(
ret
!=
1
)
{
fprintf
(
stderr
,
"Received invalid checksum
\n
"
);
return
-
1
;
}
/* Remove checksum and special characters $payload#checksum */
pkt
->
size
-=
4
;
memmove
(
pkt
->
data
,
pkt
->
data
+
1
,
pkt
->
size
);
pkt
->
data
[
pkt
->
size
]
=
0
;
if
(
checksum_l
==
checksum_r
)
{
ack
[
0
]
=
'+'
;
}
else
{
ack
[
0
]
=
'-'
;
if
(
verbose
)
fprintf
(
stderr
,
"Invalid checksum ' (L) %x != (R) %x'
\n
"
,
checksum_l
,
checksum_r
);
}
ret
=
send
(
fd
,
ack
,
1
,
0
);
if
(
ret
!=
1
)
{
fputs
(
"Failed to send acknowledge
\n
"
,
stderr
);
errno
=
EIO
;
return
-
1
;
}
return
0
;
}
/**
* Send a GDB packet
* @fd: socket file descriptor
* @pkt: packet
*
* Return: 0 on success, otherwise -1 and errno is appropriately set
*/
static
int
trtl_debugger_send
(
int
fd
,
struct
trtl_gdb_packet
*
pkt
)
{
uint8_t
checksum_l
;
int
ret
;
checksum_l
=
trtl_debugger_checksum
((
uint8_t
*
)
pkt
->
data
,
pkt
->
size
);
/* Add checksum and special characters $payload#checksum */
memmove
(
pkt
->
data
+
1
,
pkt
->
data
,
pkt
->
size
);
pkt
->
data
[
0
]
=
'$'
;
snprintf
(
pkt
->
data
+
1
+
pkt
->
size
,
TRTL_GDB_PACKET_SIZE_MAX
,
"#%02x"
,
checksum_l
);
pkt
->
size
+=
4
;
/* 1 $, 1 #, 2 checksum */
trtl_debugger_print_packet
(
pkt
,
"<-"
);
ret
=
send
(
fd
,
pkt
->
data
,
pkt
->
size
,
0
);
if
(
ret
<
0
)
return
-
1
;
if
(
ret
!=
pkt
->
size
)
{
errno
=
EIO
;
return
-
1
;
}
return
0
;
}
/**
* Run GDB server
* @addr: MMAP address
*
* Return: 0 on success, otherwise -1 and errno is appropriately set
*/
static
int
trtl_debugger_run
(
struct
trtl_dbg_port
*
dbg
)
{
bool
run
=
true
;
int
ret
;
struct
trtl_gdb_packet
*
pkt
,
*
in
,
*
out
;
pkt
=
calloc
(
2
,
sizeof
(
struct
trtl_gdb_packet
));
if
(
!
pkt
)
{
fprintf
(
stderr
,
"Memory allocation failed: %s
\n
"
,
strerror
(
errno
));
return
-
1
;
}
in
=
&
pkt
[
0
];
out
=
&
pkt
[
1
];
ret
=
trtl_dbg_debug_mode_force_set
(
dbg
);
if
(
ret
<
0
)
return
-
1
;
fputs
(
"Start receiving messages from GDB"
,
stdout
);
fflush
(
stdout
);
while
(
run
)
{
memset
(
in
,
0
,
sizeof
(
*
in
));
memset
(
out
,
0
,
sizeof
(
*
out
));
ret
=
trtl_debugger_recv
(
dbg
->
fd
,
in
);
if
(
ret
)
{
if
(
errno
==
ENOTCONN
)
run
=
false
;
else
fprintf
(
stderr
,
"Failed to receive message: %s
\n
"
,
strerror
(
errno
));
continue
;
}
ret
=
gdb_command
(
dbg
,
out
,
in
);
if
(
ret
<
0
)
continue
;
ret
=
trtl_debugger_send
(
dbg
->
fd
,
out
);
if
(
ret
)
{
fprintf
(
stderr
,
"Failed to send message: %s
\n
"
,
strerror
(
errno
));
}
}
free
(
pkt
);
return
0
;
}
#define MEMPATH_LEN 128
int
main
(
int
argc
,
char
*
argv
[])
{
uint32_t
dev_id
=
0
;
int
gdb_port
=
7471
;
int
c
,
ret
,
fd
,
sfd
,
ret_exit
=
EXIT_SUCCESS
,
optval
;
char
mempath
[
MEMPATH_LEN
];
struct
trtl_dbg_port
dbg
;
struct
sockaddr_in
server_addr
;
struct
sockaddr_in
client_addr
;
socklen_t
client_len
=
sizeof
(
client_addr
);
pagesize
=
sysconf
(
_SC_PAGE_SIZE
);
memset
(
&
dbg
,
0
,
sizeof
(
dbg
));
while
((
c
=
getopt
(
argc
,
argv
,
"hi:D:p:vs"
))
!=
-
1
)
{
switch
(
c
)
{
case
'h'
:
case
'?'
:
help
();
exit
(
EXIT_SUCCESS
);
break
;
case
'i'
:
ret
=
sscanf
(
optarg
,
"%"
SCNd8
,
&
dbg
.
cpu
);
if
(
ret
!=
1
)
{
help
();
exit
(
EXIT_FAILURE
);
}
break
;
case
'D'
:
ret
=
sscanf
(
optarg
,
"0x%x"
,
&
dev_id
);
if
(
ret
!=
1
)
{
help
();
exit
(
EXIT_FAILURE
);
}
break
;
case
'p'
:
ret
=
sscanf
(
optarg
,
"%d"
,
&
gdb_port
);
if
(
ret
!=
1
)
{
help
();
exit
(
EXIT_FAILURE
);
}
break
;
case
'v'
:
verbose
++
;
break
;
case
's'
:
swapping
=
1
;
break
;
}
}
if
(
dev_id
==
0
)
{
fprintf
(
stderr
,
"Invalid device ID '0x%"
PRIx32
"'
\n
"
,
dev_id
);
exit
(
EXIT_FAILURE
);
}
snprintf
(
mempath
,
MEMPATH_LEN
,
"/sys/kernel/debug/trtl-%04"
PRIx32
"/trtl-%04"
PRIx32
"-dbg"
,
dev_id
,
dev_id
);
fd
=
open
(
mempath
,
O_RDWR
|
O_SYNC
);
if
(
fd
<
0
)
{
fprintf
(
stderr
,
"Can't open '%s': %s
\n
"
,
mempath
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
goto
out
;
}
dbg
.
addr
=
mmap
(
NULL
,
TRTL_DBG_PORT_SIZE
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fd
,
0x0
);
if
(
dbg
.
addr
==
MAP_FAILED
)
{
fprintf
(
stderr
,
"Failed to map Mock Turtle debug: %s
\n
"
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
goto
out_map
;
}
sfd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
sfd
<
0
)
{
fprintf
(
stderr
,
"Failed to open a socket: %s
\n
"
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
goto
out_sock
;
}
optval
=
1
;
ret
=
setsockopt
(
sfd
,
SOL_SOCKET
,
SO_REUSEADDR
,
&
optval
,
sizeof
(
optval
));
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Failed to set REUSEADDR option: %s
\n
"
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
goto
out_sockopt
;
}
server_addr
.
sin_family
=
AF_INET
;
server_addr
.
sin_addr
.
s_addr
=
INADDR_ANY
;
server_addr
.
sin_port
=
htons
(
gdb_port
);
ret
=
bind
(
sfd
,
(
struct
sockaddr
*
)
&
server_addr
,
sizeof
(
server_addr
));
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Failed to bind to an *:%d: %s
\n
"
,
gdb_port
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
goto
out_bind
;
}
ret
=
listen
(
sfd
,
1
);
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Failed to listen: %s
\n
"
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
goto
out_bind
;
}
dbg
.
fd
=
accept
(
sfd
,
(
struct
sockaddr
*
)
&
client_addr
,
&
client_len
);
if
(
dbg
.
fd
<
0
)
{
fprintf
(
stderr
,
"Failed to accept: %s
\n
"
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
goto
out_bind
;
}
fprintf
(
stdout
,
"Accepted connection from %s
\n
"
,
inet_ntoa
(
client_addr
.
sin_addr
));
ret
=
trtl_debugger_run
(
&
dbg
);
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Mock Turtle debugger failed: %s
\n
"
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
}
out_bind:
close
(
sfd
);
out_sockopt:
out_sock:
ret
=
munmap
(
NULL
,
TRTL_DBG_PORT_SIZE
);
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Failed to unmap Mock Turtle debug: %s
\n
"
,
strerror
(
errno
));
ret_exit
=
EXIT_FAILURE
;
goto
out_map
;
}
out_map:
close
(
fd
);
out:
exit
(
ret_exit
);
}
tests/firmware/Makefile
View file @
a4fa5915
...
...
@@ -7,6 +7,7 @@ DIRS += config_rom
DIRS
+=
sim-verif
DIRS
+=
hmq-async-recv
DIRS
+=
hmq-async-send
DIRS
+=
hmq-sync
DIRS
+=
hmq-purge
DIRS
+=
rmq-udp-send
DIRS
+=
rt-frm
...
...
tests/firmware/config_rom/Makefile
View file @
a4fa5915
OBJS
=
config_rom.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-config-rom
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/config_rom/TBuild
0 → 100644
View file @
a4fa5915
OBJS = config_rom.o
OBJS += # add other object files that you need
OUTPUT = fw-config-rom
tests/firmware/cpu-byte-addressing/Makefile
View file @
a4fa5915
OBJS
=
byte-addressing.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-byte-addressing
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/cpu-byte-addressing/TBuild
0 → 100644
View file @
a4fa5915
OBJS = byte-addressing.o
OBJS += # add other object files that you need
OUTPUT = fw-byte-addressing
tests/firmware/cpu-loop/Makefile
View file @
a4fa5915
OBJS
=
cpu-loop.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-loop
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/cpu-loop/TBuild
0 → 100644
View file @
a4fa5915
OBJS = cpu-loop.o
OBJS += # add other object files that you need
OUTPUT = fw-loop
tests/firmware/cpu-notify/Makefile
View file @
a4fa5915
OBJS
=
notify.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-notify
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/cpu-notify/TBuild
0 → 100644
View file @
a4fa5915
OBJS = notify.o
OBJS += # add other object files that you need
OUTPUT = fw-notify
tests/firmware/hmq-async-recv/Makefile
View file @
a4fa5915
OBJS
=
hmq-async-recv.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-hmq-async-recv
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/hmq-async-recv/TBuild
0 → 100644
View file @
a4fa5915
OBJS = hmq-async-recv.o
OBJS += # add other object files that you need
OUTPUT = fw-hmq-async-recv
tests/firmware/hmq-async-recv/hmq-async-recv.c
View file @
a4fa5915
...
...
@@ -23,6 +23,7 @@ int main()
mq_claim
(
TRTL_HMQ
,
hmq
);
hdr
=
mq_map_out_header
(
TRTL_HMQ
,
hmq
);
memset
(
hdr
,
0
,
sizeof
(
*
hdr
));
msg
=
mq_map_out_buffer
(
TRTL_HMQ
,
hmq
);
hdr
->
len
=
n_word
;
for
(
i
=
0
;
i
<
hdr
->
len
;
i
++
)
...
...
tests/firmware/hmq-async-send/Makefile
View file @
a4fa5915
OBJS
=
hmq-async-send.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-hmq-async-send
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/hmq-async-send/TBuild
0 → 100644
View file @
a4fa5915
OBJS = hmq-async-send.o
OBJS += # add other object files that you need
OUTPUT = fw-hmq-async-send
tests/firmware/hmq-purge/Makefile
View file @
a4fa5915
OBJS
=
hmq-purge.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-hmq-purge
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/hmq-purge/TBuild
0 → 100644
View file @
a4fa5915
OBJS = hmq-purge.o
OBJS += # add other object files that you need
OUTPUT = fw-hmq-purge
tests/firmware/hmq-sync/Kconfig
0 → 100644
View file @
a4fa5915
mainmenu "hmq_async_send test configuration"
comment "Project specific configuration"
config FPGA_APPLICATION_ID
int "FPGA application ID"
default 0
help
Help text
config RT_APPLICATION_ID
int "RT application ID"
default 0
help
Help text
# include Mock Turtle's Kconfig
source "Kconfig.mt"
tests/firmware/hmq-sync/Makefile
0 → 100644
View file @
a4fa5915
TRTL
?=
../../../
TRTL_FW
=
$(TRTL)
/software/firmware
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/hmq-sync/TBuild
0 → 100644
View file @
a4fa5915
OBJS = hmq-sync.o
OBJS += # add other object files that you need
OUTPUT = fw-hmq-sync
tests/firmware/hmq-sync/configs/mt_defconfig
0 → 100644
View file @
a4fa5915
#
# Automatically generated file; DO NOT EDIT.
# hmq_async_send test configuration
#
#
# Project specific configuration
#
CONFIG_FPGA_APPLICATION_ID=0
CONFIG_RT_APPLICATION_ID=0
#
# Mock Turtle configuration
#
CONFIG_CFLAGS_OPT="-O0"
CONFIG_CFLAGS_EXTRA="-ggdb"
# CONFIG_MOCKTURTLE_SIMULATION is not set
#
# Mock Turtle framework configuration
#
# CONFIG_MOCKTURTLE_FRAMEWORK_ENABLE is not set
CONFIG_MOCKTURTLE_FRAMEWORK_ACTION_ENABLE=y
# CONFIG_MOCKTURTLE_FRAMEWORK_VARIABLE_ENABLE is not set
# CONFIG_MOCKTURTLE_FRAMEWORK_BUFFER_ENABLE is not set
CONFIG_MOCKTURTLE_FRAMEWORK_PING_ENABLE=y
CONFIG_MOCKTURTLE_FRAMEWORK_VERSION_ENABLE=y
#
# Mock Turtle library configuration
#
CONFIG_MOCKTURTLE_LIBRARY_PRINT_ENABLE=y
# CONFIG_MOCKTURTLE_LIBRARY_PRINT_DEBUG_ENABLE is not set
CONFIG_MOCKTURTLE_LIBRARY_PRINT_ERROR_ENABLE=y
# CONFIG_MOCKTURTLE_LIBRARY_PRINT_MESSAGE_ENABLE is not set
tests/firmware/hmq-sync/hmq-sync.c
0 → 100644
View file @
a4fa5915
#include <mockturtle-rt.h>
int
main
()
{
int
cpu
,
hmq
;
const
struct
trtl_config_rom
*
cfgrom
=
trtl_config_rom_get
();
struct
trtl_fw_msg
msg
,
msg_s
;
struct
payload
*
p
;
uint32_t
status
;
pr_debug
(
"TEST for: async send, sync
\r\n
"
);
cpu
=
trtl_get_core_id
();
while
(
1
)
{
for
(
hmq
=
0
;
hmq
<
cfgrom
->
n_hmq
[
cpu
];
++
hmq
)
{
mq_map_in_message
(
TRTL_HMQ
,
hmq
,
&
msg
);
mq_map_out_message
(
TRTL_HMQ
,
hmq
,
&
msg_s
);
status
=
mq_poll_in_wait
(
TRTL_HMQ
,
1
<<
hmq
,
1
);
if
(
!
status
)
continue
;
if
(
!
(
msg
.
header
->
flags
&
TRTL_HMQ_HEADER_FLAG_SYNC
))
continue
;
/* For sync answer test */
pr_debug
(
"SEND MESSAGES SYNC ANSWER
\r\n
"
);
mq_claim
(
TRTL_HMQ
,
hmq
);
memcpy
(
msg_s
.
header
,
msg
.
header
,
sizeof
(
struct
trtl_hmq_header
));
msg_s
.
header
->
flags
&=
~
TRTL_HMQ_HEADER_FLAG_SYNC
;
msg_s
.
header
->
flags
|=
TRTL_HMQ_HEADER_FLAG_ACK
;
memcpy
(
msg_s
.
payload
,
msg
.
payload
,
msg
.
header
->
len
*
4
);
mq_send
(
TRTL_HMQ
,
hmq
);
mq_discard
(
TRTL_HMQ
,
hmq
);
}
}
pp_printf
(
"OK
\r\n
"
);
return
0
;
}
tests/firmware/rmq-udp-send/Makefile
View file @
a4fa5915
-include
../Makefile.specific
OBJS
=
rmq-udp-send.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-rmq-udp-send
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
CFLAGS_OPT
=
-O0
# disable optimization
all
:
include
$(TRTL_SW)/firmware/Makefile
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/rmq-udp-send/TBuild
0 → 100644
View file @
a4fa5915
OBJS = rmq-udp-send.o
OBJS += # add other object files that you need
OUTPUT = fw-rmq-udp-send
CFLAGS_OPT = -O0 # disable optimization
tests/firmware/rt-frm/Makefile
View file @
a4fa5915
OBJS
=
rt-frm.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-rt-frm
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/rt-frm/TBuild
0 → 100644
View file @
a4fa5915
OBJS = rt-frm.o
OBJS += # add other object files that you need
OUTPUT = fw-rt-frm
tests/firmware/serial/Makefile
View file @
a4fa5915
-include
../Makefile.specific
OBJS
=
serial.o
OBJS
+=
# add other object files that you need
OUTPUT
=
fw-serial
TRTL
?=
../../../
TRTL_SW
=
$(TRTL)
/software
TRTL_FW
=
$(TRTL)
/software/firmware
all
:
include
$(TRTL_SW)/firmware/Makefile
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/serial/TBuild
0 → 100644
View file @
a4fa5915
OBJS = serial.o
OBJS += # add other object files that you need
OUTPUT = fw-serial
tests/firmware/sim-verif/Makefile
View file @
a4fa5915
OBJS
=
sim-verif.o
OBJS
+=
# add other object files that you need
OUTPUT
=
sim-verif
TRTL
?=
../../../
TRTL_
SW
=
$(TRTL)
/soft
ware
TRTL_
FW
=
$(TRTL)
/software/firm
ware
include
$(TRTL_SW)/firmware/Makefile
all
:
# Redirect all rules to MockTurtle
%
:
$(MAKE)
-C
$(TRTL_FW)
M
=
$(
shell
/bin/pwd
)
$@
tests/firmware/sim-verif/TBuild
0 → 100644
View file @
a4fa5915
OBJS = sim-verif.o
OBJS += # add other object files that you need
OUTPUT = sim-verif
tests/test_config.py
View file @
a4fa5915
...
...
@@ -14,7 +14,7 @@ class TestConfig(object):
def
test_valid_host
(
self
,
trtl_device
,
cfg
):
assert
trtl_device
.
rom
.
signature
==
cfg
.
signature
assert
trtl_device
.
rom
.
app_id
==
cfg
.
app_id
assert
((
trtl_device
.
rom
.
app_id
==
cfg
.
app_id
)
or
(
trtl_device
.
rom
.
app_id
==
cfg
.
app_id
|
0x10001
))
# SVEC or SPEC DEMO
assert
trtl_device
.
rom
.
n_cpu
==
cfg
.
n_cpu
def
test_valid_softcpu
(
self
,
trtl_cpu
,
cfg
,
firmware_file_config
):
...
...
@@ -27,5 +27,5 @@ class TestConfig(object):
msg
=
trtl_cpu
.
hmq
[
0
]
.
recv_msg
()
assert
msg
.
payload
[
0
]
==
cfg
.
signature
assert
msg
.
payload
[
5
]
==
cfg
.
app_id
assert
((
msg
.
payload
[
5
]
==
cfg
.
app_id
)
or
(
msg
.
payload
[
5
]
==
cfg
.
app_id
|
0x10001
))
assert
msg
.
payload
[
6
]
==
cfg
.
n_cpu
tests/test_hmq.py
View file @
a4fa5915
...
...
@@ -3,6 +3,8 @@ import PyMockTurtle
import
pytest
import
serial
import
time
import
multiprocessing
import
errno
@
pytest
.
fixture
def
trtl_binary_hmq_purge
(
trtl_firmware_dir
):
...
...
@@ -25,6 +27,25 @@ def trtl_binary_hmq_sync(trtl_firmware_dir):
"firmware/hmq-sync/fw-hmq-sync.bin"
)
def
do_sync_mult
(
q
,
hmq_orig
,
msg
):
try
:
dev
=
PyMockTurtle
.
TrtlDevice
(
hmq_orig
.
trtl_dev
.
device_id
)
hmq
=
dev
.
cpu
[
hmq_orig
.
idx_cpu
]
.
hmq
[
hmq_orig
.
idx_hmq
]
q
.
put
(
hmq
.
sync_msg
(
msg
))
except
Exception
as
e
:
print
(
e
)
q
.
put
(
None
)
def
do_sync_no_multone
(
q
,
hmq
):
try
:
msg_r
=
hmq
.
sync_msg
(
PyMockTurtle
.
TrtlMessage
())
q
.
put
(
0
)
except
OSError
as
err
:
q
.
put
(
err
.
errno
)
except
Exception
as
e
:
print
(
e
)
q
.
put
(
None
)
class
TestHmq
(
object
):
confirm
=
'OK
\r\n
'
...
...
@@ -98,20 +119,103 @@ class TestHmq(object):
trtl_cpu
.
load_application_file
(
trtl_binary_hmq_async_recv
)
trtl_cpu
.
enable
()
time
.
sleep
(
0.1
)
time
.
sleep
(
0.5
)
for
hmq
in
trtl_cpu
.
hmq
:
tot
=
trtl_cpu
.
trtl_dev
.
rom
.
hmq
[
trtl_cpu
.
idx_cpu
][
hmq
.
idx_hmq
]
.
entries
sa
=
hmq
.
get_stats
()
assert
sb
[
hmq
][
"message_received"
]
+
tot
==
sa
[
"message_received"
]
for
hmq
in
trtl_cpu
.
hmq
:
tot
=
trtl_cpu
.
trtl_dev
.
rom
.
hmq
[
trtl_cpu
.
idx_cpu
][
hmq
.
idx_hmq
]
.
entries
for
n
in
range
(
tot
):
msg
=
hmq
.
recv_msg
()
assert
msg
is
not
None
payload
=
list
(
msg
.
payload
)
for
i
,
val
in
enumerate
(
payload
):
if
i
>=
msg
.
header
.
len
:
break
assert
i
==
val
def
__do_sync_msg
(
self
,
hmq
,
trtl_msg
):
msg_r_a
=
[]
# I do not understand why I can't make Pool() working.
# it complains about hmq
# with multiprocessing.Pool(processes=len(trtl_msg)) as p:
# msg_r_a = p.starmap(do_sync_msg,
# [(hmq, msg) for msg in trtl_msg])
proc
=
[]
for
msg
in
trtl_msg
:
q
=
multiprocessing
.
Queue
()
proc
.
append
((
q
,
multiprocessing
.
Process
(
target
=
do_sync_msg
,
args
=
(
q
,
hmq
,
msg
))))
for
q
,
p
in
proc
:
p
.
start
()
for
q
,
p
in
proc
:
msg_r_a
.
append
(
q
.
get
())
p
.
join
()
return
msg_r_a
@
pytest
.
mark
.
parametrize
(
"nproc"
,
range
(
1
,
5
))
def
test_sync_no_multone
(
self
,
trtl_cpu
,
nproc
):
"""The driver should not accept more than 1 sync message at time
from the same user. The test is successful when the driver refused
a second message"""
trtl_cpu
.
disable
();
for
hmq
in
trtl_cpu
.
hmq
:
proc
=
[]
for
n
in
range
(
nproc
):
q
=
multiprocessing
.
Queue
()
p
=
multiprocessing
.
Process
(
target
=
do_sync_no_multone
,
args
=
(
q
,
hmq
))
proc
.
append
((
q
,
p
))
p
.
start
()
count_busy
=
0
count_timeout
=
0
for
q
,
p
in
proc
:
err
=
q
.
get
()
p
.
join
()
assert
err
!=
0
if
err
==
errno
.
EBUSY
:
count_busy
=
count_busy
+
1
if
err
==
PyMockTurtle
.
ETRTL_MSG_SYNC_FAILED_RECV_TIMEOUT
:
count_timeout
=
count_timeout
+
1
assert
count_timeout
==
1
assert
count_busy
==
nproc
-
1
assert
count_timeout
+
count_busy
==
nproc
def
test_sync_mult
(
self
,
trtl_cpu
,
trtl_msg
,
trtl_binary_hmq_sync
):
"""Test Multiprocess sync messages. The firmware will copy back
the message as answer"""
trtl_cpu
.
load_application_file
(
trtl_binary_hmq_sync
)
trtl_cpu
.
enable
()
for
hmq
in
trtl_cpu
.
hmq
:
proc
=
[]
sb
=
hmq
.
get_stats
()
for
msg
in
trtl_msg
:
q
=
multiprocessing
.
Queue
()
p
=
multiprocessing
.
Process
(
target
=
do_sync_mult
,
args
=
(
q
,
hmq
,
msg
))
proc
.
append
((
q
,
p
,
msg
))
p
.
start
()
for
q
,
p
,
msg
in
proc
:
msg_r
=
q
.
get
()
p
.
join
()
assert
msg_r
is
not
None
assert
msg_r
.
header
.
rt_app_id
==
msg
.
header
.
rt_app_id
assert
msg_r
.
header
.
msg_id
==
msg
.
header
.
msg_id
assert
msg_r
.
header
.
len
==
msg
.
header
.
len
assert
msg_r
.
header
.
flags
==
PyMockTurtle
.
TrtlHmqHeader
.
TRTL_HMQ_HEADER_FLAG_ACK
for
v1
,
v2
in
zip
(
msg
.
payload
,
msg_r
.
payload
):
assert
v1
==
v2
sa
=
hmq
.
get_stats
()
assert
sb
[
hmq
][
"message_received"
]
+
tot
==
sa
[
"message_received"
]
assert
sb
[
"message_sent"
]
+
len
(
trtl_msg
)
==
sa
[
"message_sent"
]
assert
sb
[
"message_received"
]
+
len
(
trtl_msg
)
==
sa
[
"message_received"
]
def
test_sync
(
self
,
trtl_cpu
,
trtl_msg
,
trtl_binary_hmq_async_send
):
"""It sends the test messages on all available HMQ.
...
...
@@ -131,8 +235,9 @@ class TestHmq(object):
assert
msg_r
.
header
.
rt_app_id
==
msg
.
header
.
rt_app_id
assert
msg_r
.
header
.
msg_id
==
msg
.
header
.
msg_id
assert
msg_r
.
header
.
len
==
msg
.
header
.
len
assert
msg_r
.
header
.
sync_id
==
msg
.
header
.
sync_id
assert
msg
.
header
.
flags
==
PyMockTurtle
.
TrtlHmqHeader
.
TRTL_HMQ_HEADER_FLAG_SYNC
assert
msg_r
.
header
.
flags
==
PyMockTurtle
.
TrtlHmqHeader
.
TRTL_HMQ_HEADER_FLAG_ACK
for
v1
,
v2
in
zip
(
msg
.
payload
,
msg_r
.
payload
):
assert
v1
==
v2
msg_r
=
hmq
.
recv_msg
()
assert
msg_r
is
None
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment