Merge remote-tracking branch 'upstream/master' into sockeye
authorDaniel Schwyn <schwyda@student.ethz.ch>
Mon, 24 Jul 2017 08:27:44 +0000 (10:27 +0200)
committerDaniel Schwyn <schwyda@student.ethz.ch>
Mon, 24 Jul 2017 08:27:58 +0000 (10:27 +0200)
Signed-off-by: Daniel Schwyn <schwyda@student.ethz.ch>

22 files changed:
doc/025-sockeye/Hakefile [new file with mode: 0644]
doc/025-sockeye/Sockeye.tex [new file with mode: 0644]
doc/025-sockeye/example.soc [new file with mode: 0644]
doc/style/barrelfish.bib
hake/RuleDefs.hs
socs/Hakefile [new file with mode: 0644]
socs/cortex/cortexA9.soc [new file with mode: 0644]
socs/omap44xx.soc [new file with mode: 0644]
socs/omap44xx/cortexA9-subsystem.soc [new file with mode: 0644]
tools/sockeye/Hakefile [new file with mode: 0644]
tools/sockeye/Main.hs [new file with mode: 0644]
tools/sockeye/SockeyeAST.hs [new file with mode: 0644]
tools/sockeye/SockeyeASTDecodingNet.hs [new file with mode: 0644]
tools/sockeye/SockeyeASTParser.hs [new file with mode: 0644]
tools/sockeye/SockeyeBackendProlog.hs [new file with mode: 0644]
tools/sockeye/SockeyeChecker.hs [new file with mode: 0644]
tools/sockeye/SockeyeNetBuilder.hs [new file with mode: 0644]
tools/sockeye/SockeyeParser.hs [new file with mode: 0644]
usr/skb/Hakefile
usr/skb/programs/decodingNet.pl [new file with mode: 0644]
usr/skb/programs/decodingNetQueries.pl [new file with mode: 0644]
usr/skb/programs/decodingNetSKB.pl [new file with mode: 0644]

diff --git a/doc/025-sockeye/Hakefile b/doc/025-sockeye/Hakefile
new file mode 100644 (file)
index 0000000..4790050
--- /dev/null
@@ -0,0 +1,26 @@
+----------------------------------------------------------------------
+-- Copyright (c) 2017, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /doc/TN-025-Sockeye.pdf
+--
+----------------------------------------------------------------------
+
+let
+    sockeyeToProlog = [ "example" ]
+    sockeyeRule f = Rule [ sockeyeProgLoc,
+                           In SrcTree "src" (f ++ ".soc"),
+                           Str "-o",
+                           Out "docs" (f ++ ".pl")
+                         ]
+    prologFromSockeye = [ Dep BuildTree "docs" (f ++ ".pl") | f <- sockeyeToProlog]
+in
+[ buildTechNoteWithDeps "Sockeye.tex" "TN-025-Sockeye.pdf" True False [] 
+    prologFromSockeye
+]
+++
+[sockeyeRule f | f <- sockeyeToProlog]
diff --git a/doc/025-sockeye/Sockeye.tex b/doc/025-sockeye/Sockeye.tex
new file mode 100644 (file)
index 0000000..75bce15
--- /dev/null
@@ -0,0 +1,376 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copyright (c) 2017, ETH Zurich.
+% All rights reserved.
+%
+% This file is distributed under the terms in the attached LICENSE file.
+% If you do not find this file, copies can be found by writing to:
+% ETH Zurich D-INFK, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\providecommand{\pgfsyspdfmark}[3]{}
+
+\documentclass[a4paper,11pt,twoside]{report}
+\usepackage{amsmath}
+\usepackage{bftn}
+\usepackage{calc}
+\usepackage{verbatim}
+\usepackage{xspace}
+\usepackage{pifont}
+\usepackage{pxfonts}
+\usepackage{textcomp}
+
+\usepackage{multirow}
+\usepackage{listings}
+\usepackage{todonotes}
+\usepackage{hyperref}
+
+\title{Sockeye in Barrelfish}
+\author{Barrelfish project}
+% \date{\today}   % Uncomment (if needed) - date is automatic
+\tnnumber{025}
+\tnkey{Sockeye}
+
+
+\lstdefinelanguage{Sockeye}{
+    morekeywords={is,are,accept,map,over,to,at},
+    sensitive=true,
+    morecomment=[l]{//},
+    morecomment=[s]{/*}{*/},
+    morestring=[b]",
+}
+
+\presetkeys{todonotes}{inline}{}
+
+\begin{document}
+\maketitle      % Uncomment for final draft
+
+\begin{versionhistory}
+\vhEntry{0.1}{15.06.2017}{DS}{Initial Version}
+\end{versionhistory}
+
+% \intro{Abstract}    % Insert abstract here
+% \intro{Acknowledgements}  % Uncomment (if needed) for acknowledgements
+\tableofcontents    % Uncomment (if needed) for final draft
+% \listoffigures    % Uncomment (if needed) for final draft
+% \listoftables     % Uncomment (if needed) for final draft
+\cleardoublepage
+\setcounter{secnumdepth}{2}
+
+\newcommand{\fnname}[1]{\textit{\texttt{#1}}}%
+\newcommand{\datatype}[1]{\textit{\texttt{#1}}}%
+\newcommand{\varname}[1]{\texttt{#1}}%
+\newcommand{\keywname}[1]{\textbf{\texttt{#1}}}%
+\newcommand{\pathname}[1]{\texttt{#1}}%
+\newcommand{\tabindent}{\hspace*{3ex}}%
+\newcommand{\Sockeye}{\lstinline[language=Sockeye]}
+\newcommand{\Prolog}{\lstinline[language=Prolog]}
+\newcommand{\ccode}{\lstinline[language=C]}
+
+\lstset{
+  basicstyle=\ttfamily \small,
+  keywordstyle=\bfseries,
+  flexiblecolumns=false,
+  basewidth={0.5em,0.45em},
+  boxpos=t,
+  captionpos=b,
+  frame=single,
+  breaklines=true,
+  postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space}
+}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Introduction and usage}
+\label{chap:introduction}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\emph{Sockeye}\footnote{Sockeye salmon (Oncorhynchus nerka), also called red salmon, kokanee salmon, or blueback salmon, is an anadromous species of salmon found in the Northern Pacific Ocean and rivers discharging into it. This species is a Pacific salmon that is primarily red in hue during spawning. They can grow up to 84 cm in length and weigh 2.3 to 7 kg. 
+Source: \href{https://en.wikipedia.org/wiki/Sockeye_salmon}{Wikipedia}}
+is a domain specific language to describe SoCs (Systems on a Chip).
+It is an implementation of the language introduced in \cite{achermann:mars17} but adds some features to address issues encountered in practise.
+
+\todo{Add short introduction on decoding nets.}
+
+The Sockeye compiler is written in Haskell using the Parsec parsing library. It
+generates Prolog files from the Sockeye files. These Prolog files contain facts that represent a decoding net as defined in \cite{achermann:mars17}.
+The Prolog files can then be loaded into Barrelfish's System Knowledgebase (SKB).
+
+The source code for Sockeye can be found in \pathname{SOURCE/tools/sockeye}.
+
+
+\section{Command line options}
+
+\begin{verbatim}
+$ sockeye [options] file
+\end{verbatim}
+
+
+The available options are:
+\begin{description}
+\item[-P] Generate a Prolog file that can be loaded into the SKB.
+\item[-C] Just perform checks, do not compile.
+\item[-o] \varname{filename} The path to the output file (including the file extension)
+\item[-h] show usage information
+\end{description}
+
+The backend (capital letter options) specified last takes precedence.
+
+The Sockeye file to compile is given via the \textit{file} parameter.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Lexical Conventions}
+\label{chap:lexer}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The Sockeye parser follows a similar convention as opted by modern day 
+programming languages like C and Java. Hence, Sockeye uses a Java-style-like
+parser based on the Haskell Parsec Library. The following conventions are used:
+
+\begin{description}
+\item[Encoding] The file should be encoded using plain text.
+\item[Whitespace:]  As in C and Java, Sockeye considers sequences of
+  space, newline, tab, and carriage return characters to be
+  whitespace.  Whitespace is generally not significant. 
+
+\item[Comments:] Sockeye supports C-style comments.  Single line comments
+  start with \texttt{//} and continue until the end of the line.
+  Multiline comments are enclosed between \texttt{/*} and \texttt{*/};
+  anything inbetween is ignored and treated as white space.
+  Nested comments are not supported.
+
+\item[Identifiers:] Valid Sockeye identifiers are sequences of numbers
+  (0-9), letters (a-z, A-Z), the underscore character ``\texttt{\_}'' and the dash character ``\textendash''. They
+  must start with a letter.
+  \begin{align*}
+  identifier & \rightarrow letter (letter \mid digit \mid \text{\_} \mid \text{\textendash})^{\textrm{*}} \\
+  letter & \rightarrow (\textsf{A \ldots Z} \mid  \textsf{a \ldots z})\\
+  digit & \rightarrow (\textsf{0 \ldots 9})
+       \end{align*}
+
+\item[Case sensitivity:] Sockeye is case sensitive hence identifiers \Sockeye{node1} and \Sockeye{Node2} are not the same.
+  
+\item[Integer Literals:] A Sockeye integer literal is a sequence of
+  digits, optionally preceded by a radix specifier.  As in C, decimal (base 10)
+  literals have no specifier and hexadecimal literals start with
+  \texttt{0x}. Octal literals start with \texttt{0o}.
+
+\begin{align*}
+decimal & \rightarrow (\textsf{0 \ldots 9})^{\textrm{1}}\\
+hexadecimal & \rightarrow (\textsf{0x})(\textsf{0 \ldots 9} \mid \textsf{A \ldots F} \mid \textsf{a \ldots f})^{\textrm{1}}\\
+octal & \rightarrow (\textsf{0o})(\textsf{0 \ldots 7})^{\textrm{1}}\\
+\end{align*}
+
+\item[Reserved words:] The following are reserved words in Sockeye:
+\begin{verbatim}
+is, are, accept, map, over, to, at
+\end{verbatim}
+
+\end{description}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Decoding Net Declaration}
+\label{chap:declaration}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+In this chapter we define the layout of a Sockeye file. Each Sockeye file contains the declaration of a single decoding net.
+An SoC can be split into multiple decoding nets e.g. one for the address spaces and another one for the interrupt routes.
+However a node in a decoding net can not reference a node in a different decoding net (see also Section~\ref{sec:modularity} for further information).
+
+\section{Syntax}
+
+\subsection{Syntax Specification}
+We use EBNF to specify the Sockeye syntax. Terminals are \textbf{bold}.
+The non-terminals \textit{iden}, \textit{integer} and \textit{decimal} correspond to identifiers, integer literals and decimal literals from Chapter~\ref{chap:lexer}.
+
+\subsection{Net specification}
+A net consists of one or more node declarations.
+A node declaration contains one or more identifiers and the node specification.
+The order in which the nodes are declared does not matter.
+
+\begin{align*}
+\textit{net}_s & \mathop{=}
+       \Big\{
+               \textit{iden}\ \textbf{is}\ \textit{node}_s\
+       \Big|\
+               \bigl\{ \textit{iden}\bigr\}\ \textbf{are}\ \textit{node}_s
+       \Big\} \\
+\end{align*}
+
+\paragraph{Example}
+\begin{syntax}
+       node1 \textbf{is} \ldots
+
+       node2
+       node3 \textbf{are} \ldots
+\end{syntax}
+
+\subsection{Node specifications}
+A node specification consists of a type, a set of accepted addresses, a set of translated addresses and an overlay.
+All of these are optional.
+
+\begin{align*}
+\textit{node}_s & \mathop{=}
+       \Big[
+               \textit{type}
+       \Big]\  
+       \Big[
+               \textbf{accept [}\ \big\{\textit{block}_s\big\}\ \textbf{]}\ 
+       \Big]\ 
+       \Big[
+               \textbf{map [}\ \big\{\textit{map}_s\big\}\ \textbf{]}\ 
+       \Big]\ 
+       \Big[
+               \textbf{over}\ \textit{iden}
+       \Big] \\
+\end{align*}
+
+\paragraph{Example}
+\begin{syntax}
+       node1 \textbf{is} \textit{<type>} \textbf{accept} [\ldots]
+       node2 \textbf{is} \textbf{map} [\ldots] \textbf{over} node1
+\end{syntax}
+
+\subsection{Node type}
+Currently there are two types: \Sockeye{device} and \Sockeye{memory}. A third internal type \Sockeye{other} is given to nodes for which no type is specified.
+The \verb|device|-type specifies that the accepted addresses are device registers while the \Sockeye{memory}-type is for memory nodes like RAM or ROM.
+
+\begin{align*}
+\textit{type} & \mathop{=}
+       \textbf{device}\
+       |\
+       \textbf{memory} \\
+\end{align*}
+
+\paragraph{Example}
+\begin{syntax}
+       node1 \textbf{is} memory \textbf{accept} [\ldots]
+       node2 \textbf{is} device \textbf{accept} [\ldots]
+\end{syntax}
+
+\subsection{Addresses}
+Addresses can be given as hexadecimal, octal or decimal integers.
+\begin{align*}
+\textit{addr} & \mathop{=} \textit{integer} \\
+\end{align*}
+
+\clearpage
+\subsection{Block specification}{}
+A block is specified by its start and end address.
+If the start and end address are the same, the end address can be omitted.
+Sockeye also supports specifying a block as its base address and the number of address bits the block spans:
+A block from \texttt{0x0} to \texttt{0xFFF} with a size of 4kB can be specified as \Sockeye|0x0/12|.
+
+\begin{align*}
+\textit{block}_s & \mathop{=} \textit{addr}\
+       \Big[
+               \textbf{-}\ \textit{addr}\ 
+       \Big|\
+               \textbf{/}decimal
+       \Big] \\
+\end{align*}
+
+\paragraph{Example}
+\begin{syntax}
+       node1 is \textbf{accept} [0x42-0x51]
+       node2 is \textbf{accept} [0x42]      // \textit{same as \textup{0x42-0x42}}
+       node3 is \textbf{accept} [0x0/12]    // \textit{same as \textup{0x00-0xFFF}}
+\end{syntax}
+
+\subsection{Map specification}
+A map specification is a source address block, a target node identifier and optionally a target base address to which the source block is translated within the target node.
+If no target base address is given, the block is translated to the same addresses within the target node.
+Multiple translation targets can be specified by giving a comma-separated list of targets.
+
+\begin{align*}
+\textit{map}_s & \mathop{=}
+\textit{block}_s\ \textbf{to}\ \textit{iden}\ 
+       \Big[
+               \textbf{at}\ \textit{addr}
+       \Big]\
+       \Big\{
+               \textbf{,}\ \textit{iden}\ 
+               \Big[
+                       \textbf{at}\ \textit{addr}
+               \Big]
+       \Big\} \\
+\end{align*}
+
+\paragraph{Example}
+\begin{syntax}
+       /* \textit{Translate \textup{0x0-0xFF} to \textup{node2} at \textup{0x300-0x3FF}:} */
+       node1 is \textbf{map} [0x0/8 \textbf{to} node2 \textbf{at} 0x300] 
+
+       /* \textit{This is the same as \textup{0x300/8 \textbf{to} node1 \textbf{at} 0x300}:} */
+       node2 is \textbf{map} [0x300/8 \textbf{to} node1]
+
+       /* \textit{Multiple translation targets, \textup{0x0-0xFF} is translated to
+          - \textup{node1} at \textup{0x0-0xFF}
+          - \textup{node2} at \textup{0x300-0x3FF}:} */
+       node3 is \textbf{map} [0x0/8 \textbf{to} node1, node2 \textbf{at} 0x300]
+\end{syntax}
+
+\section{Example Specification}
+Listing~\ref{lst:sockeye_example} shows an example Sockeye specification.
+
+\lstinputlisting[caption={Example Sockeye specification}, label={lst:sockeye_example}, language=Sockeye]{example.soc}
+
+The specification for the Texas Instruments OMAP4460 SoC used on the PandaboardES can serve as a real world example. It is located in \pathname{SOURCE/socs/omap4460.soc}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Checks on the AST}
+\label{chap:checks}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+The Sockeye compiler performs some sanity checks on the parsed AST.
+
+\section{No Duplicate Identifiers}
+This check makes sure that there aren't two node declarations with the same identifier.
+
+\section{No References to Undefined Nodes}
+This check makes sure that all nodes referenced in translation sets and overlays are declared in the same file.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Prolog Mapping for Sockeye}
+\label{chap:prolog}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+The Sockeye compiler generates \(\text{ECL}^i\text{PS}^e\)-Prolog\footnote{\href{http://eclipseclp.org/}{http://eclipseclp.org/}} to be used within the SKB.
+A decoding net is expressed by the predicate \Prolog{net/2}. The first argument to the predicate is the node identifier represented as a Prolog atom.
+The second argument is the node specification, a Prolog functor with the name \Prolog{node} and an arity of four. The arguments of the functor are the node type, the list of accepted addresses, the list of translated addresses and the overlay.
+
+The node type is one of three atoms: \Prolog{device}, \Prolog{memory} or \Prolog{other}.
+The accepted addresses are a list of address blocks where each block is represented through the functor \Prolog{block/2} with the start and end addresses as arguments.
+The translated addresses are a list of mappings to other nodes, represented by the functor \Prolog{map/3} where the first argument is the translated address block, the second one is the node identifier of the target node and the third one is the base address for the mapping in the target node.
+The overlay is represented as an atom which is either the node identifier of the overlay node or \Prolog{'@none'} for nodes with no overlay.
+
+There is a predicate clause for \Prolog{net/2} for every node specified. 
+Listings~\ref{lst:prolog_example} shows the generated Prolog code for the Sockeye example in Listing~\ref{lst:sockeye_example}.
+
+\lstinputlisting[caption={Generated Prolog code},label={lst:prolog_example},language=Prolog]{example.pl}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Limitations}
+\label{chap:limitations}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section{Modularity}
+\label{sec:modularity}
+\todo{Add description of challenges}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Compiling Sockeye files with Hake}
+\label{chap:hake}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SoC descriptions are placed in the directory \pathname{SOURCE/socs} with the file extension \pathname{.soc}.
+Each Sockeye file has to be added to the list of SoCs in the Hakefile in the same directory.
+The Hake rule for Sockeye files compiles all the listed files to \pathname{BUILD/sockeyefacts/<filename>.pl} if they are specified as a dependency in some Hakefile.
+To add a compiled Sockeye specification to the SKB RAM-disk, the filename can be added to the \varname{sockeyeFiles} list in the SKBs Hakefile.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\bibliographystyle{abbrv}
+\bibliography{defs,barrelfish}
+
+\end{document}
\ No newline at end of file
diff --git a/doc/025-sockeye/example.soc b/doc/025-sockeye/example.soc
new file mode 100644 (file)
index 0000000..2e058ed
--- /dev/null
@@ -0,0 +1,12 @@
+device1
+device2 are device accept [0x0/12]
+
+RAM is memory accept [0x0/16]
+
+Interconnect is map [
+       0x00000/12 to device1 at 0
+       0x02000/12 to device2 at 0
+       0x10000/16 to RAM at 0
+]
+
+CPU is over Interconnect
\ No newline at end of file
index 24dade9..157f765 100644 (file)
@@ -131,6 +131,15 @@ Note that this file will not compile without defs.bib; ie. you need to do:
   number =      {Revision 0.21},
   month =       {October}}
 
+@inproceedings{achermann:mars17,
+  title = {Formalizing Memory Accesses and Interrupts},
+  author = {Reto Achermann and Lukas Humbel and David Cock and Timothy Roscoe},
+  booktitle = proc # {2nd Workshop on Models for Formal Analysis of Real Systems},
+  year = 2017,
+  location = {Upsala, Sweden},
+  pages = {66--116}
+} 
+
 @inproceedings{adya:stackripping:usenix02,
   author = {Atul Adya and John Howell and Marvin Theimer and William J. Bolosky
             and John R. Douceur},
index 444562f..9313d23 100644 (file)
@@ -778,6 +778,28 @@ skateGenSchemas opts schema =
       ]]
 
 
+--
+-- Build SKB facts from Sockeye file
+--
+sockeyeProgLoc = In InstallTree "tools" "/bin/sockeye"
+sockeyeSocFileLoc d = In SrcTree "src" ("/socs" </> (d ++ ".soc"))
+sockeyeFactFilePath d = "/sockeyefacts" </> (d ++ ".pl")
+sockeyeFactFileLoc d = In BuildTree "" $ sockeyeFactFilePath d
+
+sockeye :: String -> HRule
+sockeye net = 
+    let
+        factFile = sockeyeFactFilePath net
+        depFile = dependFilePath factFile
+    in Rules
+        [ Rule
+            [ sockeyeProgLoc
+            , Str "-o", Out "" factFile
+            , Str "-d", Out "" depFile
+            , sockeyeSocFileLoc net
+            ]
+        , Include (Out "" depFile)
+        ]
 
 --
 -- Build a Fugu library
diff --git a/socs/Hakefile b/socs/Hakefile
new file mode 100644 (file)
index 0000000..ac5d30e
--- /dev/null
@@ -0,0 +1,15 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2017, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for devices/
+--
+--------------------------------------------------------------------------
+
+[ sockeye f
+  | f <- [ "omap44xx" ]
+]
diff --git a/socs/cortex/cortexA9.soc b/socs/cortex/cortexA9.soc
new file mode 100644 (file)
index 0000000..d5cc89d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich.
+ * Attn: Systems Group.
+ */
+
+module CortexA9-Core(addr periphbase) {
+    input CPU/32
+    output SCU/8, Global_Timer/8
+    output GIC_PROC/8, GIC_DISTR/12
+    output L2/32
+
+    PERIPHBASE is map [
+            0x0000-0x00FC to SCU
+            0x0100/8 to GIC_PROC
+            0x0200/8 to Global_Timer
+            0x0600/8 to Private_Timers
+            0x1000/12 to GIC_DISTR
+        ]
+
+    CPU is map [
+            periphbase/13 to PERIPHBASE
+        ]
+        over L2/32
+
+    Private_Timers is device accept [0x0/8]
+}
+
+module CortexA9-MPCore(nat cores, addr periphbase) {
+    input CPU_{[1..cores]}/32
+    output L2/32
+
+    SCU is device accept [0x0-0xFC]
+    Global_Timer is device accept [0x0/8]
+
+    GIC_PROC is device accept [0x0/8]
+    GIC_DISTR is device accept [0x0/12]
+
+    CortexA9-Core(periphbase) as Core_{c in [1..cores]} with
+        CPU_{c} > CPU
+        SCU < SCU
+        Global_Timer < Global_Timer
+        GIC_PROC < GIC_PROC
+        GIC_DISTR < GIC_DISTR
+        L2 < L2
+}
\ No newline at end of file
diff --git a/socs/omap44xx.soc b/socs/omap44xx.soc
new file mode 100644 (file)
index 0000000..d9dc289
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2017, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich.
+ * Attn: Systems Group.
+ */
+
+/**
+ * Physical memory map for TI OMAP4460 SoC
+ *
+ * This is derived from:
+ * OMAP4460 Multimedia Device Silicon Revision 1.x Technical Reference
+ * Manual Version Q
+ *
+ */
+
+import omap44xx/cortexA9-subsystem
+
+/*
+ * 2.2 L3 Memory space mapping
+ */
+/* Q0 */
+SRAM is memory accept [0x0/30]
+
+/* Q1 */
+L3_OCM_RAM is memory accept [0x0-0xDFFF]
+
+/* Q2 */
+SDRAM is memory accept [0x0/30]
+
+/* TODO: Tiler view */
+
+L3 is map [
+        0x00000000/30 to SRAM
+        /* 0x40000000-0x4002FFFF reserved */
+        /* 0x40030000-0x4003BFFF Cortex-A9 ROM */
+        /* 0x4003C000-0x400FFFFF reserved */ //TRM: 0x40034000-0x400FFFFF?
+        /* 0x40100000/20 L4_ABE private access for Cortex A9
+        /* 0x40200000/20 reserved */
+        0x40300000-0x4030DFFF to L3_OCM_RAM
+        /* 0x4030E000-0x43FFFFFF reserved */
+        0x44000000/26 to L3_config
+        0x48000000/24 to L4_PER at 0x48000000
+        0x49000000/24 to L4_ABE
+        0x4A000000/24 to L4_CFG at 0x4A000000
+        /* 0x4B000000/24 reserved */
+        0x4C000000/24 to EMIF1
+        0x4D000000/24 to EMIF2
+        0x4E000000/25 to DMM
+        0x50000000/25 to GPMC
+        0x52000000/25 to ISS
+        0x54000000/24 to L3_EMU at 0x54000000
+        0x55000000/24 to CORTEXM3
+        0x56000000/25 to SGX
+        0x58000000/24 to Display
+        /* 0x59000000/24 reserved */
+        // 0x5A000000/24 IVA-HD configuration
+        // 0x5B000000/24 IVA-HD SL2
+        /* 0x5C000000/26 reserved */
+        // 0x60000000/28 Tiler address mapping
+        0x80000000/30 to SDRAM
+      ]
+
+/*
+ * 2.2.1 L3_EMU Memory Space Mapping
+ */
+L3_EMU is map [
+            0x54000000/20 to MIPI_STM_0
+            0x54100000/18 to MIPI_STM_1
+            0x54140000/13 to A9_CPU0_debug_PMU
+            0x54142000/13 to A9_CPU1_debug_PMU
+            /* 0x54144000/14 reserved */
+            0x54148000/12 to CTI0
+            0x54149000/12 to CTI1
+            /* 0x5414A000/13 reserved */
+            0x5414C000/12 to PTM0
+            0x5414D000/12 to PTM1
+            /* 0x5414E000/13 reserved */
+            0x54158000/12 to A9_CS-TF
+            0x54159000/12 to DAP_PC
+            /* 0x5415A000-0x5415EFFF reserved */
+            0x5416F000/12 to APB
+            0x54160000/12 to DRM
+            0x54161000/12 to MIPI_STM
+            0x54162000/12 to CS-ETB
+            0x54163000/12 to CS-TPIU
+            0x54164000/12 to CS-TF
+            /* 0x54165000/13 reserved */
+            // 0x54167000/12 Technology specific registers
+            /* 0x54168000-0x5417FFFF reserved */
+            // 0x54180000/12 Technology specific registers
+            /* 0x54181000-0x541FFFFF reserved */
+            // XXX: What about 0x54200000-0x54FFFFFF?
+          ]
+
+/*
+ * 2.3.1 L4_CFG Memory Space Mapping
+ */
+SAR_ROM is device accept [0x0/13]
+
+L4_CFG is map [
+            0x4A000000/11 to CFG_AP
+            0x4A000800/11 to CFG_LA
+            0x4A001000/12 to CFG_IP0
+            0x4A002000/12 to SYSCTRL_GENERAL_CORE
+            // 0x4A003000/12 L4 interconnect
+            0x4A004000/12 to CM1
+            // 0x4A005000/12 L4 interconnect
+            /* 0x4A006000/13 reserved
+            0x4A008000/13 to CM2
+            // 0x4A00A000/12 L4 interconnect
+            /* 0x4A00B000-0x4A055FFF reserved */
+            0x4A056000/12 to SDMA
+            // 0x4A057000/12 L4 interconnect
+            0x4A058000/12 to HSI
+            // 0x4A05C000/12 L4 interconnect
+            /* 0x4A05D000/12 reserved */
+            0x4A05E000/13 to SAR_ROM
+            // 0x4A060000/12 L4 interconnect
+            /* 0x4A061000/12 reserved */
+            0x4A062000/12 to HSUSBTLL
+            // 0x4A063000/12 L4 interconnect
+            0x4A064000/12 to HSUSBHOST
+            // 0x4A065000/12 L4 interconnect
+            0x4A066000/12 to DSP at 0x01C20000
+            // 0x4A067000/12 L4 interconnect
+            /* 0x4A068000-0x4A0A8FFF reserved */
+            0x4A0A9000/12 to FSUSBHOST
+            // 0x4A0AA000/12 L4 interconnect
+            0x4A0AB000/12 to HSUSBOTG
+            // 0x4A0AC000/12 L4 interconnect
+            0x4A0AD000/12 to USBPHY
+            // 0x4A0AE000/12 L4 interconnect
+            /* 0x4A0AF000-0x4A0D8FFF reserved */
+            0x4A0D9000/12 to SR_MPU
+            // 0x4A0DA000/12 L4 interconnect
+            0x4A0DB000/12 to SR_IVA
+            // 0x4A0DC000/12 L4 interconnect
+            0x4A0DD000/12 to SR_CORE
+            // 0x4A0DE000/12 L4 interconnect
+            /* 0x4A0DF000-0x4A0F3FFF reserved */
+            0x4A0F4000/12 to System_Mailbox
+            // 0x4A0F5000/12 L4 interconnect
+            0x4A0F6000/12 to Spinlock
+            // 0x4A0F7000/12 L4 interconnect
+            /* 0x4A0F8000/15 reserved */
+            0x4A100000/12 to SYSCTRL_PADCONF_CORE
+            // 0x4A101000/12 L4 interconnect
+            0x4A102000/12 to OCP-WP
+            // 0x4A103000/12 L4 interconnect
+            /* 0x4A104000-0x4A109FFF reserved */
+            0x4A10A000/12 to FDIF
+            // 0x4A10B000/12 L4 interconnect
+            /* 0x4A10C000-0x4A203FFF reserved */
+            0x4A204000/12 to C2C_INIT_firewall
+            // 0x4A205000/12 L4 interconnect
+            0x4A206000/12 to C2C_TARGET_firewall
+            // 0x4A207000/12 L4 interconnect
+            /* 0x4A208000/13 reserved */
+            0x4A20A000/12 to MA_firewall
+            // 0x4A20B000/12 L4 interconnect
+            0x4A20C000/12 to EMIF_firewall
+            // 0x4A20D000/12 L4 interconnect
+            /* 0x4A20E000/13 reserved */
+            0x4A210000/12 to GPMC_firewall
+            // 0x4A211000/12 L4 interconnect
+            0x4A212000/12 to L3_OCMC_RAM_firewall
+            // 0x4A213000/12 L4 interconnect
+            0x4A214000/12 to SGX_firewall
+            // 0x4A215000/12 L4 interconnect
+            0x4A216000/12 to ISS_firewall
+            // 0x4A217000/12 L4 interconnect
+            0x4A218000/12 to M3_firewall
+            // 0x4A219000/12 L4 interconnect
+            /* 0x4A21A000/13 reserved */
+            0x4A21C000/12 to DSS_firewall
+            // 0x4A21D000/12 L4 interconnect
+            0x4A21E000/12 to SL2_firewall
+            // 0x4A21F000/12 L4 interconnect
+            0x4A220000/12 to IVA-HD_firewall
+            // 0x4A221000/12 L4 interconnect
+            /* 0x4A222000/14 reserved */
+            0x4A226000/12 to L4-EMU_firewall
+            // 0x4A227000/12 L4 interconnect
+            0x4A228000/12 to L4-ABE_firewall
+            // 0x4A229000/12 L4 interconnect
+            /* 0x4A22A000-0x4A2FFFFF reserved */
+            0x4A300000/18 to L4_WKUP at 0x4A300000
+            // 0x4A340000/12 L4 interconnect
+            /* 0x4A341000-0x4AFFFFFF reserved */
+          ]
+
+
+/*
+ * 2.3.2 L4_WKUP Memory Space Mapping
+ */
+SAR_RAM1 is memory accept [0x0/12]
+SAR_RAM2 is memory accept [0x0/10]
+SAR_RAM3 is memory accept [0x0/11]
+SAR_RAM4 is memory accept [0x0/10]
+
+L4_WKUP is map [
+                0x4A300000/11 to WKUP_AP
+                0x4A300800/11 to WKUP_LA
+                0x4A301000/12 to WKUP_IP0
+                /* 0x4A302000/13 reserved */
+                0x4A304000/12 to S32KTIMER
+                // 0x4A305000/12 L4 interconnect
+                0x4A306000/13 to PRM
+                // 0x4A308000/12 L4 interconnect
+                /* 0x4A309000/12 reserved */
+                0x4A30A000/12 to SCRM
+                // 0x4A30B000/12 L4 interconnect
+                0x4A30C000/12 to SYSCTRL_GENERAL_WKUP
+                // 0x4A30D000/12 L4 interconnect
+                /* 0x4A30E000/13 reserved */
+                0x4A310000/12 to GPIO1
+                // 0x4A311000/12 L4 interconnect
+                /* 0x4A312000/13 reserved */
+                0x4A314000/12 to WDTIMER2
+                // 0x4A315000/12 L4 interconnect
+                /* 0x4A316000/13 reserved */
+                0x4A318000/12 to GPTIMER1
+                // 0x4A319000/12 L4 interconnect
+                /* 0x4A31A000/13 reserved (XXX: 'Module - Address space 0'?) */
+                0x4A31C000/12 to Keyboard
+                // 0x4A31D000/12 L4 interconnect
+                0x4A31E000/12 to SYSCTRL_PADCONF_WKUP
+                // 0x4A31F000/12 L4 interconnect
+                /* 0x4A320000-0x4A325FFF reserved */
+                0x4A326000/12 to SAR_RAM1
+                0x4A327000/10 to SAR_RAM2
+                /* 0x4A327400-0x4A327FFF reserved */
+                0x4A328000/11 to SAR_RAM3
+                /* 0x4A328800-0x4A328FFF reserved */
+                0x4A329000/10 to SAR_RAM4
+                /* 0x4A329400-0x4A329FFF reserved */
+                // 0x4A32A000/12 L4 interconnect
+                /* 0x4A32B000-0x4A33FFFF reserved */
+           ]
+
+/*
+ * 2.3.3 L4_PER Memory Space Mapping
+ */
+L4_PER is map [
+            0x48000000/11 to PER_AP
+            0x48000800/11 to PER_LA
+            0x48001000/10 to PER_IP0
+            0x48001400/10 to PER_IP1
+            0x48001800/10 to PER_IP2
+            0x48001C00/10 to PER_IP3
+            /* 0x48002000-0x4801FFFF reserved */
+            0x48020000/12 to UART3
+            // 0x48021000/12 L4 interconnect
+            /* 0x48022000/16 reserved */
+            0x48032000/12 to GPTIMER2
+            // 0x48033000/12 L4 interconnect
+            0x48034000/12 to GPTIMER3
+            // 0x48035000/12 L4 interconnect
+            0x48036000/12 to GPTIMER4
+            // 0x48037000/12 L4 interconnect
+            /* 0x48038000-0x4803DFFF reserved */
+            0x4803E000/12 to GPTIMER9
+            // 0x4803F000/12 L4 interconnect
+            0x48040000/16 to Display
+            // 0x48050000/12 L4 interconnect
+            /* 0x48051000/14 reserved */
+            0x48055000/12 to GPIO2
+            // 0x48056000/12 L4 interconnect
+            0x48057000/12 to GPIO3
+            // 0x48058000/12 L4 interconnect
+            0x48059000/12 to GPIO4
+            // 0x4805A000/12 L4 interconnect
+            0x4805B000/12 to GPIO5
+            // 0x4805C000/12 L4 interconnect
+            0x4805D000/12 to GPIO6
+            // 0x4805E000/12 L4 interconnect
+            /* 0x4805F000/12 reserved */
+            0x48060000/12 to I2C3
+            // 0x48061000/12 L4 interconnect
+            /* 0x48062000/15 reserved */
+            0x4806A000/12 to UART1
+            // 0x4806B000/12 L4 interconnect
+            0x4806C000/12 to UART2
+            // 0x4806D000/12 L4 interconnect
+            0x4806E000/12 to UART4
+            // 0x4806F000/12 L4 interconnect
+            0x48070000/12 to I2C1
+            // 0x48071000/12 L4 interconnect
+            0x48072000/12 to I2C2
+            // 0x48073000/12 L4 interconnect
+            /* 0x48074000/13 reserved */
+            0x48076000/12 to SLIMBUS2
+            // 0x48077000/12 L4 interconnect
+            0x48078000/12 to ELM
+            // 0x48079000/12 L4 interconnect
+            /* 0x4807A000-0x48085FFF reserved */
+            0x48086000/12 to GPTIMER10
+            // 0x48087000/12 L4 interconnect
+            0x48088000/12 to GPTIMER11
+            // 0x48089000/12 L4 interconnect
+            /* 0x4808A000-0x48095FFF reserved */
+            0x48096000/12 to McBSP4
+            // 0x48097000/12 L4 interconnect
+            0x48098000/12 to McSPI1
+            // 0x48099000/12 L4 interconnect
+            0x4809A000/12 to McSPI2
+            // 0x4809B000/12 L4 interconnect
+            0x4809C000/12 to HSMMC1
+            // 0x4809D000/12 L4 interconnect
+            /* 0x4809E000-0x480ACFFF reserved */
+            0x480AD000/12 to MMC_SD3
+            // 0x480AE000/12 L4 interconnect
+            /* 0x480AF000-0x480B1FFF reserved */
+            0x480B2000/12 to HDQ
+            // 0x480B3000/12 L4 interconnect
+            0x480B4000/12 to HSMMC2
+            // 0x480B5000/12 L4 interconnect
+            /* 0x480B6000/13 reserved */
+            0x480B8000/12 to McSPI3
+            // 0x480B9000/12 L4 interconnect
+            0x480BA000/12 to McSPI4
+            // 0x480BB000/12 L4 interconnect
+            /* 0x480BC000-0x480D0FFF reserved */
+            0x480D1000/12 to MMC_SD4
+            // 0x480D2000/12 L4 interconnect
+            /* 0x480D3000/13 reserved */
+            0x480D5000/12 to MMC_SD5
+            // 0x480D6000/12 L4 interconnect
+            /* 0x480D7000-0x4834FFFF reserved */
+            0x48350000/12 to I2C4
+            // 0x48351000/12 L4 interconnect
+            /* 0x48352000-0x48FFFFFF reserved */
+          ]
+
+/*
+ * 2.3.4 L4_ABE Memory Space Mapping
+ */
+DMEM,
+CMEM,
+SMEM are memory accept [0x0/16]
+
+L4_ABE is accept [0x00000/14] // XXX: First 16KB do what?
+          map [
+            /* 0x04000-0x021FFF reserved */
+            0x22000/12 to McBSP1
+            // 0x23000/12 L4 interconnect
+            0x24000/12 to McBSP2
+            // 0x25000/12 L4 interconnect
+            0x26000/12 to McBSP3
+            // 0x27000/12 L4 interconnect
+            0x28000/12 to McASP
+            // 0x29000/12 L4 interconnect
+            0x2A000/12 to McASP_DATA
+            // 0x2B000/12 L4 interconnect
+            0x2C000/12 to SLIMBUS1
+            // 0x2D000/12 L4 interconnect
+            0x2E000/12 to DMIC
+            // 0x2F000/12 L4 interconnect
+            0x30000/12 to WDTIMER3
+            // 0x31000/12 L4 interconnect
+            0x32000/12 to McPDM
+            // 0x33000/12 L4 interconnect
+            /* 0x34000/14 reserved */
+            0x38000/12 to GPTIMER5
+            // 0x39000/12 L4 interconnect
+            0x3A000/12 to GPTIMER6
+            // 0x3B000/12 L4 interconnect
+            0x3C000/12 to GPTIMER7
+            // 0x3D000/12 L4 interconnect
+            0x3E000/12 to GPTIMER8
+            // 0x3F000/12 L4 interconnect
+            /* 0x40000/18 reserved */
+            0x80000/16 to DMEM
+            // 0x90000/12 L4 interconnect
+            /* 0x91000-0x9FFFF reserved */
+            0xA0000/16 to CMEM
+            // 0xB0000/12 L4 interconnect
+            /* 0xB1000-0xBFFFF reserved */
+            0xC0000/16 to SMEM
+            // 0xD0000/12 L4 interconnect
+            /* 0xD1000/17 reserved */
+            0xF1000/12 to AESS
+            // 0xF2000/12 L4 interconnect
+            /* 0xF3000-0xFFFFF reserved */
+          ]
+
+/*
+ * Cortex A9 Memory Space Mapping
+ */
+CortexA9-Subsystem as CortexA9_SS with
+    CORTEXA9_{c in [1..2]} > CPU_{c}
+    L3 < L3
+    L4_ABE < L4_ABE
+
+/*
+ * 2.4 Dual Cortex-M3 Subsystem Memory Space Mapping
+ */
+CORTEXM3_ROM is memory accept [0x0/14]
+CORTEXM3_RAM is memory accept [0x0/16]
+
+// TODO: address space not accessible from L3
+CORTEXM3 is map [
+                    0x00000000-0x54FFFFFF to L3
+                    0x55000000/14 to CORTEXM3_ROM
+                    0x55020000/16 to CORTEXM3_RAM
+                    /* 0x55030000/16 reserved */
+                    0x55040000/18 to ISS at 0x10000 // XXX: Not accessible from L3?
+                    0x55080000/12 to M3_MMU
+                    0x55081000/12 to M3_WUGEN
+                    /* 0x55082000-0x55FFFFFF reserved */
+                    0x56000000/25 to L3
+                ]
+
+/*
+ * 2.5 DSP Subsystem Memory Space Mapping
+ */
+ // TODO: address space not accessible from L4_CFG
+ DSP is map [
+            0x01C20000/12 to SYSC
+        ]
+
+/*
+ * 2.6 Display Subsystem Memory Space Mapping
+ */
+Display is map [
+                // 0x0000/12 Display subsystem registers
+                0x1000/12 to DISPC
+                0x2000/12 to RFBI
+                0x3000/12 to VENC
+                0x4000/12 to DSI1
+                0x5000/12 to DSI2
+                0x6000/12 to HDMI
+                0x7000/12 to HDCP
+           ]
+
+/*
+ * 3 Power, Reset and Clock Management
+ */
+/*
+/* 3.11.1 PRM Instance Summary */
+INTRCONN_SOCKET_PRM is device accept [0x0/8]
+CKGEN_PRM is device accept [0x0/8]
+MPU_PRM is device accept [0x0/8]
+DSP_PRM is device accept [0x0/8]
+ABE_PRM is device accept [0x0/8]
+ALWAYS_ON_PRM is device accept [0x0/8]
+CORE_PRM is device accept [0x0/11]
+IVAHD_PRM is device accept [0x0/8]
+CAM_PRM is device accept [0x0/8]
+DSS_PRM is device accept [0x0/8]
+SGX_PRM is device accept [0x0/8]
+L3INIT_PRM is device accept [0x0/8]
+L4PER_PRM is device accept [0x0/9]
+WKUP_PRM is device accept [0x0/8]
+WKUP_CM is device accept [0x0/8]
+EMU_PRM is device accept [0x0/8]
+EMU_CM is device accept [0x0/8]
+DEVICE_PRM is device accept [0x0/8]
+INSTR_PRM is device accept [0x0/8]
+PRM is map [
+            0x0000/8 to INTRCONN_SOCKET_PRM
+            0x0100/8 to CKGEN_PRM
+            0x0300/8 to MPU_PRM
+            0x0400/8 to DSP_PRM
+            0x0500/8 to ABE_PRM
+            0x0600/8 to ALWAYS_ON_PRM
+            0x0700/11 to CORE_PRM
+            0x0F00/8 to IVAHD_PRM
+            0x1000/8 to CAM_PRM
+            0x1100/8 to DSS_PRM
+            0x1200/8 to SGX_PRM
+            0x1300/8 to L3INIT_PRM
+            0x1400/9 to L4PER_PRM
+            0x1700/8 to WKUP_PRM
+            0x1800/8 to WKUP_CM
+            0x1900/8 to EMU_PRM
+            0x1A00/8 to EMU_CM
+            0x1B00/8 to DEVICE_PRM
+            0x1F00/8 to INSTR_PRM
+       ]
+
+/* 3.11.21 CM1 Instance Summary */
+INTERCONN_SOCKET_CM1 is device accept [0x0/8]
+CKGEN_CM1 is device accept [0x0/9]
+CM1 is map [
+        0x000/8 to INTERCONN_SOCKET_CM1
+        0x100/9 to CKGEN_CM1
+       ]
+
+/* 3.11.29 CM2 Instance Summary */
+INTRCONN_SOCKET_CM2 is device accept [0x0/8]
+CKGEN_CM2 is device accept [0x0/8]
+ALWAYS_ON_CM2 is device accept [0x0/8]
+CORE_CM2 is device accept [0x0/11]
+IVAHD_CM2 is device accept [0x0/8]
+CAM_CM2 is device accept [0x0/8]
+DSS_CM2 is device accept [0x0/8]
+SGX_CM2 is device accept [0x0/8]
+L3INIT_CM2 is device accept [0x0/8]
+L4PER_CM2 is device accept [0x0/9]
+RESTORE_CM2 is device accept [0x0/8]
+INSTR_CM2 is device accept [0x0/8]
+CM2 is map [
+        0x0000/8 to INTRCONN_SOCKET_CM2
+        0x0100/8 to CKGEN_CM2
+        0x0600/8 to ALWAYS_ON_CM2
+        0x0700/11 to CORE_CM2
+        0x0F00/8 to IVAHD_CM2
+        0x1000/8 to CAM_CM2
+        0x1200/8 to SGX_CM2
+        0x1300/8 to L3INIT_CM2
+        0x1400/9 to L4PER_CM2
+        0x1E00/8 to RESTORE_CM2
+        0x1F00/8 to INSTR_CM2
+       ]
+
+/* 3.12 SCRM Register Manual */
+SCRM is device accept [0x0/12]
+
+/* 3.13 SR Register Manual */
+SR_MPU is device accept [0x0/8]
+SR_IVA is device accept [0x0/8]
+SR_CORE is device accept [0x0/8]
+
+/*
+ * 5 DSP Subsystem
+ */
+SYS_INTC is device accept [0x0/16]
+SYS_PD is device accept [0x0/16]
+EDM is device accept [0x0/12]
+TPCC is device accept [0x0/16]
+TPTC0,
+TPTC1 are device accept [0x0/10]
+SYSC is device accept [0x0/12]
+WUGEN is device accept [0x0/12]
+L1_SCACHE,
+L2_SCACHE are device accept [0x0/8]
+SCACHE_SCTM is device accept [0x0/9]
+SCACHE_MMU is device accept [0x0/11]
+
+/*
+ * 6 IVA-HD Subsystem
+ */
+SYSCTRL is device accept [0x0/10]
+
+/*
+ * 7 Dual Cortex-M3 MPU Subsystem
+ */
+M3_WUGEN is device accept [0x0/12]
+
+/*
+ * 8 Imaging Subsystem
+ */
+ISS_TOP is device accept [0x0/8]
+ISP5 is device accept [0x0/16]
+SIMCOP is device accept [0x0/17]
+ISS is map [
+            0x00000/8 to ISS_TOP
+            // TODO: Interfaces
+            0x10000/17 to ISP5
+            0x20000/17 to SIMCOP
+          ]
+
+/*
+ * 9 Face Detect
+ */
+FDIF is device accept [0x0/12]
+
+/*
+ * 10 Display Subsystem
+ */
+DISPC,
+RFBI,
+VENC,
+DSI1,
+DSI2,
+HDMI,
+HDCP are device accept [0x0/12]
+
+/*
+ * 11 2D/3D Graphics Accelerator
+ */
+SGX is device accept [0x0/25]
+
+/*
+ * 12 Audio Backend
+ */
+AESS is device accept [0x0/12]
+
+/*
+ * 13 Interconnect
+ */
+/* 13.2 L3 Interconnect */
+L3_config is device accept [0x0/26]
+C2C_INIT_firewall is device accept [0x0/12] // not in TRM, from omap44xx_map.h
+C2C_TARGET_firewall is device accept [0x0/12] // not in TRM, from omap44xx_map.h
+MA_firewall is device accept[0x0/12]
+EMIF_firewall is device accept [0x0/12]
+GPMC_firewall is device accept [0x0/12]
+L3_OCMC_RAM_firewall is device accept [0x0/12]
+SGX_firewall is device accept [0x0/12]
+ISS_firewall is device accept [0x0/12]
+M3_firewall is device accept [0x0/12]
+DSS_firewall is device accept [0x0/12]
+SL2_firewall is device accept [0x0/12]
+IVA-HD_firewall is device accept [0x0/12]
+L4-EMU_firewall is device accept [0x0/12]
+L4-ABE_firewall is device accept [0x0/12]
+
+/* 13.3 L4 Interconnects */
+PER_AP is device accept [0x0/11]
+PER_LA is device accept [0x0/11]
+PER_IP0 is device accept [0x0/10]
+PER_IP1 is device accept [0x0/10]
+PER_IP2 is device accept [0x0/10]
+PER_IP3 is device accept [0x0/10]
+
+CFG_AP is device accept [0x0/11]
+CFG_LA is device accept [0x0/11]
+CFG_IP0 is device accept [0x0/12]
+
+WKUP_AP is device accept [0x0/11]
+WKUP_LA is device accept [0x0/11]
+WKUP_IP0 is device accept [0x0/12]
+
+/*
+ * 15 Memory Subsystem
+ */
+DMM is device accept [0x0/25]
+EMIF1,
+EMIF2 are device accept [0x4D000000/24]
+GPMC is device accept [0x0/25]
+ELM is device accept [0x48078000/12]
+
+/*
+ * 16 SDMA
+ */
+SDMA is device accept [0x0/12]
+
+/*
+ * 17 Interrupt Controllers
+ */
+// TODO
+
+/*
+ * 18 Control Module
+ */
+SYSCTRL_GENERAL_CORE,
+SYSCTRL_GENERAL_WKUP,
+SYSCTRL_PADCONF_CORE,
+SYSCTRL_PADCONF_WKUP are device accept [0x0/12]
+
+
+/*
+ * 19 Mailbox
+ */
+System_Mailbox,
+IVAHD_Mailbox are device accept[0x0/12]
+
+/*
+ * 20 Memory Management Units
+ */
+M3_MMU,
+DSP_MMU are device accept [0x0/12]
+
+/*
+ * 21 Spinlock
+ */
+Spinlock is device accept [0x0/12]
+
+/*
+ * 22 Timers
+ */
+/* 22.2 General Purpose Timers */
+GPTIMER{[1..11]} are device accept [0x0/12]
+
+/* 22.3 Watchdog Timers */
+WDTIMER{[2..3]} are device accept [0x0/12]
+
+/* 22.4 32-KHz Synchronized Timer */
+S32KTIMER is device accept [0x0/12]
+
+/*
+ * 23 Serial Communication Interface
+ */
+
+/* 23.1 Multimaster High-Speed I2C Controller */
+I2C{[1..4]} are device accept [0x0/8]
+
+/* 23.2 HDQ/1-Wire */
+HDQ is device accept [0x0/12]
+
+/* 23.3.1 UART/IrDA/CIR */
+UART{[1..4]} are device accept [0x0/10]
+
+/* 23.4 Mulitchannel Serial Port Interface */
+McSPI{[1..4]} are device accept [0x0/12]
+
+/* 23.5 Multichannel Buffered Serial Port */
+McBSP{[1..4]} are device accept [0x0/12]
+
+/* 23.6 Multichannel PDM Controller */
+McPDM is device accept [0x0/12]
+
+/* 23.7 Digital Microphone Module */
+DMIC is device accept [0x0/12]
+
+/* 23.8 Multichannel Audio Serial Port */
+McASP is device accept [0x0/12]
+McASP_DATA is device accept [0x0/12]
+
+/* 23.9 Serial Low-Power Inter-Chip Media Bus Controller */
+SLIMBUS{[1..2]} are device accept [0x0/12]
+
+/* 23.10 MIPI-HSI */
+HSI_TOP is device accept [0x0-0x1400]
+HSI_DMA_CHANNELS is device accept [0x0/10]
+HSI_PORTS is device accept [0x0/13]
+
+HSI is map [
+        0x0000-0x1400 to HSI_TOP
+        0x1800/10 to HSI_DMA_CHANNELS
+        0x000/13 to HSI_PORTS
+       ]
+
+/* 23.11 High-Speed Multiport USB Host Subsystem */
+HSUSBTLL is device accept [0x0/12]
+HSUSBHOST is device accept [0x0/12]
+
+/* 23.12 High-Speed USB OTG Controller */
+HSUSBOTG is device accept [0x0/12]
+USBPHY is device accept [0x0/12]
+
+/* 23.13 Full-speed USB Host Controller */
+FSUSBHOST is device accept[0x0/12]
+
+/*
+ * 24 MMC/SD/SDIO
+ */
+HSMMC{[1..2]},
+MMC_SD{[3..5]} are device accept [0x0/12]
+
+/*
+ * 25 General Purpose Interface
+ */
+GPIO{[1..6]} are device accept [0x0/12]
+
+/*
+ * 26 Keyboard Controller
+ */
+Keyboard is device accept [0x0/12]
+
+/*
+ * 28.10 On-Chip Debug Support Memory Mapping
+ */
+MIPI_STM_0 is device accept [0x0/20]
+MIPI_STM_1 is device accept [0x0/18]
+A9_CPU0_debug_PMU is device accept [0x0/13]
+A9_CPU1_debug_PMU is device accept [0x0/13]
+CTI0 is device accept [0x0/12]
+CTI1 is device accept [0x0/12]
+PTM0 is device accept [0x0/12]
+PTM1 is device accept [0x0/12]
+A9_CS-TF is device accept [0x0/12]
+DAP_PC is device accept [0x0/12]
+APB is device accept [0x0/12]
+DRM is device accept [0x0/12]
+MIPI_STM is device accept [0x0/12]
+CS-ETB is device accept [0x0/12]
+CS-TPIU is device accept [0x0/12]
+CS-TF is device accept [0x0/12]
+
+OCP-WP is device accept [0x0/12]
+
+PMI is device accept [0x0/8]
\ No newline at end of file
diff --git a/socs/omap44xx/cortexA9-subsystem.soc b/socs/omap44xx/cortexA9-subsystem.soc
new file mode 100644 (file)
index 0000000..033c8a9
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich.
+ * Attn: Systems Group.
+ */
+
+/**
+ * CortexA9 subsystem of TI OMAP4460 SoC
+ *
+ * This is derived from:
+ * OMAP4460 Multimedia Device Silicon Revision 1.x Technical Reference
+ * Manual Version Q
+ *
+ * Section 4
+ *
+ */
+
+import ../cortex/cortexA9
+
+module CortexA9-Subsystem {
+    input CPU_{[1..2]}/32
+    output L3/32, L4_ABE/20
+
+    ROM is memory accept [0x0-0xBFFF]
+
+    PL310 is device accept [0x0/12]
+    CORTEXA9_SOCKET_PRCM is device accept [0x0/9]
+    CORTEXA9_PRM is device accept [0x0/9]
+    CORTEXA9_CPU{[0..1]} are device accept [0x0/10]
+    CORTEXA9_WUGEN is device accept [0x0/12]
+    CMU is device accept [0x0/16]
+    Interconnect_config is device accept [0x0/12]
+    MA is device accept [0x0/12]
+
+    Interconnect is map [
+        0x40030000-0x4003BFFF to ROM
+        0x40100000/20 to L4_ABE
+        0x48242000/12 to PL310
+        0x48243000/9 to CORTEXA9_SOCKET_PRCM
+        0x48243200/9 to CORTEXA9_PRM
+        0x48243400/10 to CORTEXA9_CPU0
+        0x48243800/10 to CORTEXA9_CPU1
+        0x48281000/12 to CORTEXA9_WUGEN
+        0x48290000/16 to CMU
+        0x482A0000/12 to Interconnect_config
+        0x482AF000/12 to MA
+    ] over L3/32
+    
+
+    CortexA9-MPCore(2, 0x48240000) as MPU with
+        CPU_{c in [1..2]} > CPU_{c}
+        Interconnect < L2
+}
diff --git a/tools/sockeye/Hakefile b/tools/sockeye/Hakefile
new file mode 100644 (file)
index 0000000..7a4ada4
--- /dev/null
@@ -0,0 +1,14 @@
+----------------------------------------------------------------------
+-- Copyright (c) 2017, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. 
+-- Attn: Systems Group.
+--
+-- Hakefile for /tools/sockeye
+--
+----------------------------------------------------------------------
+
+[ compileHaskell "sockeye" "Main.hs" (find withSuffices [ ".hs" ]) ]
\ No newline at end of file
diff --git a/tools/sockeye/Main.hs b/tools/sockeye/Main.hs
new file mode 100644 (file)
index 0000000..46cfc0f
--- /dev/null
@@ -0,0 +1,237 @@
+{-
+  SockeyeMain.hs: Sockeye
+
+  Copyright (c) 2017, ETH Zurich.
+
+  All rights reserved.
+
+  This file is distributed under the terms in the attached LICENSE file.
+  If you do not find this file, copies can be found by writing to:
+  ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+  Attn: Systems Group.
+-}
+
+module Main where
+
+import Control.Monad
+
+import Data.List (intercalate)
+import qualified Data.Map as Map
+
+import System.Console.GetOpt
+import System.Exit
+import System.Environment
+import System.FilePath
+import System.IO
+
+import qualified SockeyeASTParser as ParseAST
+import qualified SockeyeAST as AST
+import qualified SockeyeASTDecodingNet as NetAST
+
+import SockeyeParser
+import SockeyeChecker
+import SockeyeNetBuilder
+
+import qualified SockeyeBackendProlog as Prolog
+
+{- Exit codes -}
+usageError :: ExitCode
+usageError = ExitFailure 1
+
+parseError :: ExitCode
+parseError = ExitFailure 2
+
+checkError :: ExitCode
+checkError = ExitFailure 3
+
+buildError :: ExitCode
+buildError = ExitFailure 4
+
+{- Compilation targets -}
+data Target = Prolog
+
+{- Possible options for the Sockeye Compiler -}
+data Options = Options { optInputFile  :: FilePath
+                       , optTarget     :: Target
+                       , optOutputFile :: FilePath
+                       , optDepFile    :: Maybe FilePath
+                       }
+
+{- Default options -}
+defaultOptions :: Options
+defaultOptions = Options { optInputFile  = ""
+                         , optTarget     = Prolog
+                         , optOutputFile = ""
+                         , optDepFile    = Nothing
+                         }
+
+{- Set the input file name -}
+optSetInputFileName :: FilePath -> Options -> Options
+optSetInputFileName f o = o { optInputFile = f }
+
+{- Set the target -}
+optSetTarget :: Target -> Options -> Options
+optSetTarget t o = o { optTarget = t }
+
+{- Set the output file name -}
+optSetOutputFile :: FilePath -> Options -> Options
+optSetOutputFile f o = o { optOutputFile = f }
+
+{- Set the dependency file name -}
+optSetDepFile :: FilePath -> Options -> Options
+optSetDepFile f o = o { optDepFile = Just f }
+
+{- Prints usage information possibly with usage errors -}
+usage :: [String] -> IO ()
+usage errors = do
+    prg <- getProgName
+    let usageString = "Usage: " ++ prg ++ " [options] file\nOptions:"
+    case errors of
+        [] -> return ()
+        _  -> hPutStrLn stderr $ concat errors
+    hPutStrLn stderr $ usageInfo usageString options
+    hPutStrLn stderr "The backend (capital letter options) specified last takes precedence."
+
+
+{- Setup option parser -}
+options :: [OptDescr (Options -> IO Options)]
+options = 
+    [ Option "P" ["Prolog"]
+        (NoArg (\opts -> return $ optSetTarget Prolog opts))
+        "Generate a prolog file that can be loaded into the SKB (default)."
+    , Option "o" ["output-file"]
+        (ReqArg (\f opts -> return $ optSetOutputFile f opts) "FILE")
+        "Output file in which to store the compilation result (required)."
+    , Option "d" ["dep-file"]
+        (ReqArg (\f opts -> return $ optSetDepFile f opts) "FILE")
+        "Generate a dependency file for GNU make"
+    , Option "h" ["help"]
+        (NoArg (\_ -> do
+                    usage []
+                    exitWith ExitSuccess))
+        "Show help."
+    ]
+
+{- evaluates the compiler options -}
+compilerOpts :: [String] -> IO (Options)
+compilerOpts argv = do
+    opts <- case getOpt Permute options argv of
+        (actions, fs, []) -> do
+            opts <- foldl (>>=) (return defaultOptions) actions
+            case fs of
+                []  -> do
+                    usage ["No input file\n"]
+                    exitWith usageError
+                [f] -> return $ optSetInputFileName f opts
+                _   -> do
+                    usage ["Multiple input files not supported\n"]
+                    exitWith usageError
+
+        (_, _, errors) -> do
+            usage errors
+            exitWith $ usageError
+    case optOutputFile opts of
+        "" -> do
+            usage ["No output file\n"]
+            exitWith $ usageError
+        _  -> return opts
+
+{- Parse Sockeye and resolve imports -}
+parseSpec :: FilePath -> IO (ParseAST.SockeyeSpec, [FilePath])
+parseSpec file = do
+    let
+        rootImport = ParseAST.Import file
+    specMap <- parseWithImports "" Map.empty rootImport
+    let
+        specs = Map.elems specMap
+        deps = Map.keys specMap
+        topLevelSpec = specMap Map.! file
+        modules = concat $ map ParseAST.modules specs
+        spec = topLevelSpec
+            { ParseAST.imports = []
+            , ParseAST.modules = modules
+            }
+    return (spec, deps)
+        
+    where
+        parseWithImports pwd importMap (ParseAST.Import filePath) = do
+            let
+                dir = case pwd of
+                    "" -> takeDirectory filePath
+                    _  -> pwd </> takeDirectory filePath
+                fileName = takeFileName filePath
+                file = if '.' `elem` fileName
+                    then dir </> fileName
+                    else dir </> fileName <.> "soc"
+            if file `Map.member` importMap
+                then return importMap
+                else do
+                    ast <- parseFile file
+                    let
+                        specMap = Map.insert file ast importMap
+                        imports = ParseAST.imports ast
+                    foldM (parseWithImports dir) specMap imports
+
+{- Runs the parser on a single file -}
+parseFile :: FilePath -> IO (ParseAST.SockeyeSpec)
+parseFile file = do
+    src <- readFile file
+    case parseSockeye file src of
+        Left err -> do
+            hPutStrLn stderr $ "Parse error at " ++ show err
+            exitWith parseError
+        Right ast -> return ast
+
+{- Runs the checker -}
+checkAST :: ParseAST.SockeyeSpec -> IO AST.SockeyeSpec
+checkAST parsedAst = do
+    case checkSockeye parsedAst of 
+        Left fail -> do
+            hPutStr stderr $ show fail
+            exitWith checkError
+        Right intermAst -> return intermAst
+
+{- Builds the decoding net from the Sockeye AST -}
+buildNet :: AST.SockeyeSpec -> IO NetAST.NetSpec
+buildNet ast = do
+    case sockeyeBuildNet ast of 
+        Left fail -> do
+            hPutStr stderr $ show fail
+            exitWith buildError
+        Right netAst -> return netAst
+
+{- Compiles the AST with the appropriate backend -}
+compile :: Target -> NetAST.NetSpec -> IO String
+compile Prolog ast = return $ Prolog.compile ast
+
+{- Writes a dependency file for GNU make -}
+dependencyFile :: FilePath -> FilePath -> [FilePath] -> IO String
+dependencyFile outFile depFile deps = do
+    let
+        targets = outFile ++ " " ++ depFile ++ ":"
+        lines = targets:deps
+    return $ intercalate " \\\n " lines
+
+{- Outputs the compilation result -}
+output :: FilePath -> String -> IO ()
+output outFile out = writeFile outFile out
+
+main = do
+    args <- getArgs
+    opts <- compilerOpts args
+    let
+        inFile = optInputFile opts
+        outFile = optOutputFile opts
+        depFile = optDepFile opts
+        target = optTarget opts
+    (parsedAst, deps) <- parseSpec inFile
+    case depFile of
+        Nothing -> return ()
+        Just f  -> do
+            out <- dependencyFile outFile f deps
+            output f out
+    ast <- checkAST parsedAst
+    netAst <- buildNet ast
+    out <- compile (optTarget opts) netAst
+    output outFile out
+    
\ No newline at end of file
diff --git a/tools/sockeye/SockeyeAST.hs b/tools/sockeye/SockeyeAST.hs
new file mode 100644 (file)
index 0000000..535ddf3
--- /dev/null
@@ -0,0 +1,155 @@
+{-
+  SockeyeAST.hs: AST for Sockeye
+
+  Part of Sockeye
+
+  Copyright (c) 2017, ETH Zurich.
+
+  All rights reserved.
+
+  This file is distributed under the terms in the attached LICENSE file.
+  If you do not find this file, copies can be found by writing to:
+  ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+  Attn: Systems Group.
+-}
+
+module SockeyeAST where
+
+import Data.Map (Map)
+
+newtype SockeyeSpec = SockeyeSpec
+    { modules :: Map String Module }
+    deriving (Show)
+
+data Module = Module
+    { paramNames   :: [String]
+    , paramTypeMap :: Map String ModuleParamType
+    , inputPorts   :: [Port]
+    , outputPorts  :: [Port]
+    , nodeDecls    :: [NodeDecl]
+    , moduleInsts  :: [ModuleInst]
+    } deriving (Show)
+
+data ModuleParamType 
+    = NaturalParam
+    | AddressParam
+    deriving (Eq)
+
+instance Show ModuleParamType where
+    show NaturalParam = "nat"
+    show AddressParam = "addr"
+
+data Port
+    = InputPort 
+        { portId    :: Identifier
+        , portWidth :: !Integer
+        }
+    | OutputPort
+        { portId    :: Identifier
+        , portWidth :: !Integer
+        }
+    | MultiPort (For Port)
+    deriving (Show)
+
+data ModuleInst
+    = ModuleInst
+        { namespace  :: Identifier
+        , moduleName :: String
+        , arguments  :: Map String ModuleArg
+        , inPortMap  :: [PortMap]
+        , outPortMap :: [PortMap]
+        }
+    | MultiModuleInst (For ModuleInst)
+    deriving (Show)
+
+data ModuleArg
+    = AddressArg !Integer
+    | NaturalArg !Integer
+    | ParamArg !String
+    deriving (Show)
+
+data PortMap
+    = PortMap
+        { mappedId   :: Identifier
+        , mappedPort :: Identifier
+        }
+    | MultiPortMap (For PortMap)
+    deriving (Show)
+
+data NodeDecl
+    = NodeDecl
+        { nodeId   :: Identifier
+        , nodeSpec :: NodeSpec
+        }
+    | MultiNodeDecl (For NodeDecl)
+    deriving (Show)
+
+data Identifier
+    = SimpleIdent !String
+    | TemplateIdent
+        { prefix  :: !String
+        , varName :: !String
+        , suffix  :: Maybe Identifier
+        }
+    deriving (Show)
+
+data NodeSpec = NodeSpec
+    { nodeType  :: Maybe NodeType
+    , accept    :: [BlockSpec]
+    , translate :: [MapSpec]
+    , reserved  :: [BlockSpec]
+    , overlay   :: Maybe OverlaySpec
+    } deriving (Show)
+
+data NodeType
+    = Memory
+    | Device
+    deriving (Show)
+
+data BlockSpec 
+    = SingletonBlock
+        { base :: Address }
+    | RangeBlock
+        { base  :: Address
+        , limit :: Address
+        }
+    | LengthBlock
+        { base :: Address
+        , bits :: !Integer
+        }
+    deriving (Show)
+
+data MapSpec 
+    = MapSpec
+        { block    :: BlockSpec
+        , destNode :: Identifier
+        , destBase :: Maybe Address
+        } deriving (Show)
+
+data OverlaySpec
+    = OverlaySpec
+        { over  :: Identifier
+        , width :: !Integer
+        } deriving (Show)
+
+data Address
+    = LiteralAddress !Integer
+    | ParamAddress !String
+    deriving (Show)
+
+data For a 
+    = For
+        { varRanges :: Map String ForRange
+        , body      :: a
+        } deriving (Show)
+
+data ForRange
+    = ForRange
+    { start :: ForLimit
+    , end   :: ForLimit
+    } deriving (Show)
+
+data ForLimit 
+    = LiteralLimit !Integer
+    | ParamLimit !String
+    deriving (Show)
diff --git a/tools/sockeye/SockeyeASTDecodingNet.hs b/tools/sockeye/SockeyeASTDecodingNet.hs
new file mode 100644 (file)
index 0000000..e3aadcf
--- /dev/null
@@ -0,0 +1,72 @@
+{-
+  SockeyeASTDecodingNet.hs: Decoding net AST for Sockeye
+
+  Part of Sockeye
+
+  Copyright (c) 2017, ETH Zurich.
+
+  All rights reserved.
+
+  This file is distributed under the terms in the attached LICENSE file.
+  If you do not find this file, copies can be found by writing to:
+  ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+  Attn: Systems Group.
+-}
+
+module SockeyeASTDecodingNet where
+
+import Data.List (intercalate)
+import Data.Map (Map)
+
+newtype NetSpec =
+    NetSpec
+        { net :: Map NodeId NodeSpec }
+    deriving (Show)
+
+data NodeId = NodeId
+    { namespace :: Namespace
+    , name      :: !String
+    } deriving (Eq, Ord)
+
+instance Show NodeId where
+    show (NodeId namespace name) = 
+        case ns namespace of
+            [] -> name
+            _  -> concat [show namespace, ".", name]
+
+newtype Namespace = Namespace
+    { ns :: [String] }
+    deriving (Eq, Ord)
+
+instance Show Namespace where
+    show (Namespace ns) = intercalate "." $ reverse ns
+
+data NodeSpec
+    = NodeSpec
+        { nodeType  :: NodeType
+        , accept    :: [BlockSpec]
+        , translate :: [MapSpec]
+        }
+    deriving (Show)
+
+data NodeType
+    = Memory
+    | Device
+    | Other
+    deriving (Show)
+
+data BlockSpec = BlockSpec
+    { base  :: Address
+    , limit :: Address
+    } deriving (Show)
+
+data MapSpec = MapSpec
+    { srcBlock :: BlockSpec
+    , destNode :: NodeId
+    , destBase :: Address
+    } deriving (Show)
+
+newtype Address =
+    Address
+        { address :: Integer }
+    deriving (Show)
diff --git a/tools/sockeye/SockeyeASTParser.hs b/tools/sockeye/SockeyeASTParser.hs
new file mode 100644 (file)
index 0000000..686f4ce
--- /dev/null
@@ -0,0 +1,124 @@
+{-
+    SockeyeASTParser.hs: AST for the Sockeye parser
+
+    Part of Sockeye
+
+    Copyright (c) 2017, ETH Zurich.
+
+    All rights reserved.
+
+    This file is distributed under the terms in the attached LICENSE file.
+    If you do not find this file, copies can be found by writing to:
+    ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+    Attn: Systems Group.
+-}
+
+module SockeyeASTParser 
+( module SockeyeASTParser
+, module SockeyeAST
+) where
+
+import SockeyeAST
+    ( Identifier(SimpleIdent, TemplateIdent)
+    , prefix, varName, suffix
+    , ModuleParamType(NaturalParam, AddressParam)
+    , ModuleArg(AddressArg, NaturalArg, ParamArg)
+    , NodeSpec(NodeSpec)
+    , nodeType, accept, translate, reserved, overlay
+    , NodeType(Memory, Device)
+    , BlockSpec(SingletonBlock, RangeBlock, LengthBlock)
+    , base, limit, bits
+    , MapSpec(MapSpec)
+    , OverlaySpec(OverlaySpec)
+    , over, width
+    , block, destNode, destBase
+    , Address(LiteralAddress, ParamAddress)
+    , ForLimit(LiteralLimit, ParamLimit)
+    )
+
+data SockeyeSpec = SockeyeSpec
+    { imports :: [Import]
+    , modules :: [Module]
+    , net     :: [NetSpec]
+    } deriving (Show)
+
+
+data Import = Import 
+    { filePath :: !FilePath }
+    deriving (Show)
+
+data Module = Module
+    { name       :: String
+    , parameters :: [ModuleParam]
+    , moduleBody :: ModuleBody
+    } deriving (Show)
+
+data ModuleParam = ModuleParam
+    { paramName :: !String
+    , paramType :: ModuleParamType
+    } deriving (Show)
+
+data ModuleBody = ModuleBody
+    { ports     :: [PortDef]
+    , moduleNet :: [NetSpec]
+    } deriving (Show)
+
+data PortDef
+    = InputPortDef
+        { portId    :: Identifier
+        , portWidth :: !Integer
+        }
+    | OutputPortDef
+        { portId    :: Identifier
+        , portWidth :: !Integer
+        }
+    | MultiPortDef (For PortDef)
+    deriving (Show)
+
+data NetSpec
+    = NodeDeclSpec NodeDecl
+    | ModuleInstSpec ModuleInst
+    deriving (Show)
+
+data ModuleInst
+    = ModuleInst
+        { moduleName   :: String
+        , namespace    :: Identifier
+        , arguments    :: [ModuleArg]
+        , portMappings :: [PortMap]
+        }
+    | MultiModuleInst (For ModuleInst)
+    deriving (Show)
+
+data PortMap
+    = InputPortMap
+        { mappedId   :: Identifier
+        , mappedPort :: Identifier
+        }
+    | OutputPortMap
+        { mappedId   :: Identifier
+        , mappedPort :: Identifier
+        }
+    | MultiPortMap (For PortMap)
+    deriving (Show)
+
+data NodeDecl
+    = NodeDecl
+        { nodeId   :: Identifier
+        , nodeSpec :: NodeSpec
+        }
+    | MultiNodeDecl (For NodeDecl)
+    deriving (Show)
+
+data For a 
+    = For
+        { varRanges :: [ForVarRange]
+        , body      :: a
+        } deriving (Show)
+
+data ForVarRange
+    = ForVarRange
+    { var   :: !String
+    , start :: ForLimit
+    , end   :: ForLimit
+    } deriving (Show)
diff --git a/tools/sockeye/SockeyeBackendProlog.hs b/tools/sockeye/SockeyeBackendProlog.hs
new file mode 100644 (file)
index 0000000..d819d38
--- /dev/null
@@ -0,0 +1,113 @@
+{-
+  SockeyeBackendProlog.hs: Backend for generating Prolog facts for Sockeye
+
+  Part of Sockeye
+
+  Copyright (c) 2017, ETH Zurich.
+
+  All rights reserved.
+
+  This file is distributed under the terms in the attached LICENSE file.
+  If you do not find this file, copies can be found by writing to:
+  ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+  Attn: Systems Group.
+-}
+
+module SockeyeBackendProlog
+( compile ) where
+
+import Data.Char
+import Data.List
+import qualified Data.Map as Map
+import Numeric (showHex)
+
+import qualified SockeyeASTDecodingNet as AST
+
+compile :: AST.NetSpec -> String
+compile = generate
+
+{- Code Generator -}
+class PrologGenerator a where
+    generate :: a -> String
+
+instance PrologGenerator AST.NetSpec where
+    generate (AST.NetSpec net) = let
+        mapped = Map.mapWithKey toFact net
+        facts = Map.elems mapped
+        in unlines facts
+        where
+            toFact nodeId nodeSpec = let
+                atom = generate nodeId
+                node = generate nodeSpec
+                in predicate "net" [atom, node] ++ "."
+
+instance PrologGenerator AST.NodeId where
+    generate ast = let
+        name = AST.name ast
+        namespace = AST.namespace ast
+        in predicate "nodeId" [atom name, generate namespace]
+
+instance PrologGenerator AST.Namespace where
+    generate ast = let
+        ns = AST.ns ast
+        in list $ map atom ns
+
+instance PrologGenerator AST.NodeSpec where
+    generate ast = let
+        nodeType = generate $ AST.nodeType ast
+        accept = generate $ AST.accept ast
+        translate = generate $ AST.translate ast
+        in predicate "node" [nodeType, accept, translate]
+
+instance PrologGenerator AST.BlockSpec where
+    generate blockSpec = let
+        base = generate $ AST.base blockSpec
+        limit = generate $ AST.limit blockSpec
+        in predicate "block" [base, limit]
+
+instance PrologGenerator AST.MapSpec where
+    generate mapSpec = let
+        src  = generate $ AST.srcBlock mapSpec
+        dest = generate $ AST.destNode mapSpec
+        base = generate $ AST.destBase mapSpec
+        in predicate "map" [src, dest, base]
+
+instance PrologGenerator AST.NodeType where
+    generate AST.Memory = atom "memory"
+    generate AST.Device = atom "device"
+    generate AST.Other  = atom "other"
+
+instance PrologGenerator AST.Address where
+    generate (AST.Address addr) = "16'" ++ showHex addr ""
+
+instance PrologGenerator a => PrologGenerator [a] where
+    generate ast = let
+        mapped = map generate ast
+        in list mapped
+
+{- Helper functions -}
+atom :: String -> String
+atom "" = ""
+atom name@(c:cs)
+    | isLower c && allAlphaNum cs = name
+    | otherwise = quotes name
+    where
+        allAlphaNum cs = foldl (\acc c -> isAlphaNum c && acc) True cs
+
+predicate :: String -> [String] -> String
+predicate name args = name ++ (parens $ intercalate "," args)
+
+list :: [String] -> String
+list elems = brackets $ intercalate "," elems
+
+enclose :: String -> String -> String -> String
+enclose start end string = start ++ string ++ end
+
+parens :: String -> String
+parens = enclose "(" ")"
+
+brackets :: String -> String
+brackets = enclose "[" "]"
+
+quotes :: String -> String
+quotes = enclose "'" "'"
\ No newline at end of file
diff --git a/tools/sockeye/SockeyeChecker.hs b/tools/sockeye/SockeyeChecker.hs
new file mode 100644 (file)
index 0000000..ad27ba0
--- /dev/null
@@ -0,0 +1,544 @@
+{-
+    SockeyeChecker.hs: AST checker for Sockeye
+
+    Part of Sockeye
+
+    Copyright (c) 2017, ETH Zurich.
+
+    All rights reserved.
+
+    This file is distributed under the terms in the attached LICENSE file.
+    If you do not find this file, copies can be found by writing to:
+    ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+    Attn: Systems Group.
+-}
+
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+
+module SockeyeChecker
+( checkSockeye ) where
+
+import Data.List (nub)
+import qualified Data.Map as Map
+import Data.Set (Set)
+import qualified Data.Set as Set
+import Data.Either
+
+import qualified SockeyeASTParser as ParseAST
+import qualified SockeyeAST as AST
+
+data Context = Context
+    { spec       :: AST.SockeyeSpec
+    , moduleName :: !String
+    , vars       :: Set String
+    , instModule :: String
+    }
+
+data FailedCheckType
+    = DuplicateModule String
+    | DuplicateParameter String
+    | DuplicateVariable String
+    | NoSuchModule String
+    | NoSuchParameter String
+    | NoSuchVariable String
+    | ParamTypeMismatch String AST.ModuleParamType AST.ModuleParamType
+    | WrongNumberOfArgs String Int Int
+    | ArgTypeMismatch String String AST.ModuleParamType AST.ModuleParamType
+
+instance Show FailedCheckType where
+    show (DuplicateModule name)          = concat ["Multiple definitions for module '", name, "'"]
+    show (DuplicateParameter name)       = concat ["Multiple parameters named '", name, "'"]
+    show (DuplicateVariable name)        = concat ["Multiple definitions for variable '", name, "'"]
+    show (NoSuchModule name)             = concat ["No definition for module '", name, "'"]
+    show (NoSuchParameter name)          = concat ["Parameter '", name, "' not in scope"]
+    show (NoSuchVariable name)           = concat ["Variable '", name, "' not in scope"]
+    show (WrongNumberOfArgs name takes given) =
+        let arg = if takes == 1
+            then "argument"
+            else "arguments"
+        in concat ["Module '", name, "' takes ", show takes, " ", arg, ", given ", show given]
+    show (ParamTypeMismatch name expected actual) =
+        concat ["Expected type '", show expected, "' but '", name, "' has type '", show actual, "'"]
+    show (ArgTypeMismatch modName name expected actual) =
+        concat ["Type mismatch for argument '", name, "' for module '", modName, "': Expected '", show expected, "', given '", show actual, "'"]
+
+data FailedCheck = FailedCheck
+    { failure  :: FailedCheckType
+    , inModule :: !String
+    }
+
+newtype CheckFailure = CheckFailure
+    { failedChecks :: [FailedCheck] }
+
+instance Show CheckFailure where
+    show (CheckFailure fs) = 
+        let
+            modules = nub $ map inModule fs
+        in unlines $ concat (map showFailsForModule modules)
+        where
+            showFailsForModule name =
+                let
+                    title = "\nIn module '" ++ name ++ "':"
+                    fails = filter (\f -> name == inModule f) fs
+                in if name == "@root"
+                    then "":showFails 0 fails
+                    else title:showFails 1 fails
+            showFails indentLevel fs =
+                let
+                    indent = replicate (indentLevel * 4) ' '
+                in map ((indent ++) . showFail) fs
+            showFail f = (show $ failure f)
+
+checkFailure :: Context -> [FailedCheckType] -> CheckFailure
+checkFailure context fs = CheckFailure $ map failCheck fs
+    where
+        failCheck f = FailedCheck
+            { failure  = f
+            , inModule = moduleName context
+            }
+
+checkSockeye :: ParseAST.SockeyeSpec -> Either CheckFailure AST.SockeyeSpec
+checkSockeye ast = do
+    let
+        emptySpec = AST.SockeyeSpec Map.empty
+        initContext = Context
+            { spec       = emptySpec
+            , moduleName = ""
+            , vars       = Set.empty
+            , instModule = ""
+            }
+    symbolTable <- buildSymbolTable initContext ast
+    let
+        context = initContext
+            { spec = symbolTable }
+    check context ast
+
+--
+-- Build Symbol table
+--
+class SymbolSource a b where
+    buildSymbolTable :: Context -> a -> Either CheckFailure b
+
+instance SymbolSource ParseAST.SockeyeSpec AST.SockeyeSpec where
+    buildSymbolTable context ast = do
+        let
+            modules = (rootModule ast):(ParseAST.modules ast)
+            names = map ParseAST.name modules
+        checkDuplicates context names DuplicateModule
+        symbolTables <- buildSymbolTable context modules
+        let
+            moduleMap = Map.fromList $ zip names symbolTables
+        return AST.SockeyeSpec
+                { AST.modules = moduleMap }
+
+instance SymbolSource ParseAST.Module AST.Module where
+    buildSymbolTable context ast = do
+        let
+            name = ParseAST.name ast
+            paramNames = map ParseAST.paramName (ParseAST.parameters ast)
+            paramTypes = map ParseAST.paramType (ParseAST.parameters ast)
+            moduleContext = context
+                { moduleName = name}
+        checkDuplicates moduleContext paramNames DuplicateParameter
+        let
+            paramTypeMap = Map.fromList $ zip paramNames paramTypes
+        return AST.Module
+            { AST.paramNames   = paramNames
+            , AST.paramTypeMap = paramTypeMap
+            , AST.inputPorts   = []
+            , AST.outputPorts  = []
+            , AST.nodeDecls    = []
+            , AST.moduleInsts  = []
+            }
+
+instance SymbolSource a b => SymbolSource [a] [b] where
+    buildSymbolTable context as = forAll (buildSymbolTable context) as
+
+--
+-- Check module bodies
+--
+class Checkable a b where
+    check :: Context -> a -> Either CheckFailure b
+
+instance Checkable ParseAST.SockeyeSpec AST.SockeyeSpec where
+    check context ast = do
+        let
+            modules = (rootModule ast):(ParseAST.modules ast)
+            names = map ParseAST.name modules
+        checked <- check context modules
+        let
+            sockeyeSpec = spec context
+            checkedMap = Map.fromList $ zip names checked
+        return sockeyeSpec
+            { AST.modules = checkedMap }
+
+instance Checkable ParseAST.Module AST.Module where
+    check context ast = do
+        let
+            name = ParseAST.name ast
+            bodyContext = context
+                { moduleName = name}
+            body = ParseAST.moduleBody ast
+            portDefs = ParseAST.ports body
+            netSpecs = ParseAST.moduleNet body
+        inputPorts  <- check bodyContext $ filter isInPort  portDefs
+        outputPorts <- check bodyContext $ filter isOutPort portDefs
+        checkedNetSpecs <- check bodyContext netSpecs
+        let
+            checkedNodeDecls = lefts checkedNetSpecs
+            checkedModuleInsts = rights checkedNetSpecs
+            mod = getCurrentModule bodyContext
+        return mod
+            { AST.inputPorts  = inputPorts
+            , AST.outputPorts = outputPorts
+            , AST.nodeDecls   = checkedNodeDecls
+            , AST.moduleInsts = checkedModuleInsts
+            }
+        where
+            isInPort (ParseAST.InputPortDef _ _) = True
+            isInPort (ParseAST.MultiPortDef for) = isInPort $ ParseAST.body for
+            isInPort _ = False
+            isOutPort = not . isInPort
+
+instance Checkable ParseAST.PortDef AST.Port where
+    check context (ParseAST.InputPortDef portId portWidth) = do
+        checkedId <- check context portId
+        return $ AST.InputPort checkedId portWidth
+    check context (ParseAST.OutputPortDef portId portWidth) = do
+        checkedId <- check context portId
+        return $ AST.OutputPort checkedId portWidth
+    check context (ParseAST.MultiPortDef for) = do
+        checkedFor <- check context for
+        return $ AST.MultiPort checkedFor
+
+instance Checkable ParseAST.NetSpec (Either AST.NodeDecl AST.ModuleInst) where
+    check context (ParseAST.NodeDeclSpec decl) = do
+        checkedDecl <- check context decl
+        return $ Left checkedDecl
+    check context (ParseAST.ModuleInstSpec inst) = do
+        checkedInst <- check context inst
+        return $ Right checkedInst
+
+instance Checkable ParseAST.ModuleInst AST.ModuleInst where
+    check context (ParseAST.MultiModuleInst for) = do
+        checkedFor <- check context for
+        return $ AST.MultiModuleInst checkedFor
+    check context ast = do
+        let
+            namespace = ParseAST.namespace ast
+            name = ParseAST.moduleName ast
+            arguments = ParseAST.arguments ast
+            portMaps = ParseAST.portMappings ast
+        mod <- getModule context name
+        let
+            paramNames = AST.paramNames mod
+            instContext = context
+                { instModule = name }
+        checkedArgs <- checkArgs instContext arguments
+        checkedNamespace <- check instContext namespace
+        inPortMap  <- check instContext $ filter isInMap  portMaps
+        outPortMap <- check instContext $ filter isOutMap portMaps
+        let
+            argMap = Map.fromList $ zip paramNames checkedArgs
+        return AST.ModuleInst
+            { AST.namespace  = checkedNamespace
+            , AST.moduleName = name
+            , AST.arguments  = argMap
+            , AST.inPortMap  = inPortMap
+            , AST.outPortMap = outPortMap
+            }
+        where
+            isInMap (ParseAST.InputPortMap {}) = True
+            isInMap (ParseAST.MultiPortMap for) = isInMap $ ParseAST.body for
+            isInMap _ = False
+            isOutMap = not . isInMap
+            checkArgs context args = do
+                mod <- getInstantiatedModule context
+                let
+                    typeMap = AST.paramTypeMap mod
+                    paramNames = AST.paramNames mod
+                    paramTypes = map (typeMap Map.!) paramNames
+                    params = zip paramNames paramTypes
+                checkArgCount paramNames args
+                forAll id $ zipWith checkArgType params args
+                where
+                    checkArgCount params args = do
+                        let
+                            paramc = length params
+                            argc = length args
+                        if argc == paramc
+                            then return ()
+                            else Left $ checkFailure context [WrongNumberOfArgs (instModule context) paramc argc]
+                    checkArgType (name, expected) arg = do
+                        case arg of
+                            ParseAST.AddressArg value -> do
+                                if expected == AST.AddressParam
+                                    then return $ AST.AddressArg value
+                                    else Left $ mismatch AST.AddressParam
+                            ParseAST.NaturalArg value -> do
+                                if expected == AST.NaturalParam
+                                    then return $ AST.NaturalArg value
+                                    else Left $ mismatch AST.NaturalParam
+                            ParseAST.ParamArg pName -> do
+                                checkParamType context pName expected
+                                return $ AST.ParamArg pName
+                        where
+                            mismatch t = checkFailure context [ArgTypeMismatch (instModule context) name expected t]
+
+instance Checkable ParseAST.PortMap AST.PortMap where
+    check context (ParseAST.MultiPortMap for) = do
+        checkedFor <- check context for
+        return $ AST.MultiPortMap checkedFor
+    check context portMap = do
+        let
+            mappedId = ParseAST.mappedId portMap
+            mappedPort = ParseAST.mappedPort portMap
+        (checkedId, checkedPort) <- check context (mappedId, mappedPort)
+        return $ AST.PortMap
+            { AST.mappedId   = checkedId
+            , AST.mappedPort = checkedPort
+            }
+
+instance Checkable ParseAST.NodeDecl AST.NodeDecl where
+    check context (ParseAST.MultiNodeDecl for) = do
+        checkedFor <- check context for
+        return $ AST.MultiNodeDecl checkedFor
+    check context ast = do
+        let
+            nodeId = ParseAST.nodeId ast
+            nodeSpec = ParseAST.nodeSpec ast
+        checkedId <- check context nodeId
+        checkedSpec <- check context nodeSpec
+        return AST.NodeDecl
+            { AST.nodeId   = checkedId
+            , AST.nodeSpec = checkedSpec
+            }
+
+instance Checkable ParseAST.Identifier AST.Identifier where
+    check _ (ParseAST.SimpleIdent name) = return $ AST.SimpleIdent name
+    check context ast = do
+        let
+            prefix = ParseAST.prefix ast
+            varName = ParseAST.varName ast
+            suffix = ParseAST.suffix ast
+        checkVarInScope context varName
+        checkedSuffix <- case suffix of
+            Nothing    -> return Nothing
+            Just ident -> do
+                checkedIdent <- check context ident
+                return $ Just checkedIdent
+        return AST.TemplateIdent
+            { AST.prefix  = prefix
+            , AST.varName = varName
+            , AST.suffix  = checkedSuffix
+            }
+
+instance Checkable ParseAST.NodeSpec AST.NodeSpec where
+    check context ast = do
+        let 
+            nodeType = ParseAST.nodeType ast
+            accept = ParseAST.accept ast
+            translate = ParseAST.translate ast
+            overlay = ParseAST.overlay ast
+            reserved = ParseAST.reserved ast
+        checkedAccept <- check context accept
+        checkedTranslate <- check context translate
+        checkedReserved <- check context reserved
+        checkedOverlay <- case overlay of
+            Nothing    -> return Nothing
+            Just ident -> do
+                checkedIdent <- check context ident
+                return $ Just checkedIdent
+        return AST.NodeSpec
+            { AST.nodeType  = nodeType
+            , AST.accept    = checkedAccept
+            , AST.translate = checkedTranslate
+            , AST.reserved  = checkedReserved
+            , AST.overlay   = checkedOverlay
+            }
+
+instance Checkable ParseAST.BlockSpec AST.BlockSpec where
+    check context (ParseAST.SingletonBlock address) = do
+        checkedAddress <- check context address
+        return AST.SingletonBlock
+            { AST.base = checkedAddress }
+    check context (ParseAST.RangeBlock base limit) = do
+        (checkedBase, checkedLimit) <- check context (base, limit)
+        return AST.RangeBlock
+            { AST.base  = checkedBase
+            , AST.limit = checkedLimit
+            }
+    check context (ParseAST.LengthBlock base bits) = do
+        checkedBase <- check context base
+        return AST.LengthBlock
+            { AST.base = checkedBase
+            , AST.bits = bits
+            }
+
+instance Checkable ParseAST.MapSpec AST.MapSpec where
+    check context ast = do
+        let
+            block = ParseAST.block ast
+            destNode = ParseAST.destNode ast
+            destBase = ParseAST.destBase ast
+        checkedBlock <- check context block
+        checkedDestNode <- check context destNode
+        checkedDestBase <- case destBase of
+            Nothing      -> return Nothing
+            Just address -> do
+                checkedAddress <- check context address
+                return $ Just checkedAddress
+        return AST.MapSpec
+            { AST.block    = checkedBlock
+            , AST.destNode = checkedDestNode
+            , AST.destBase = checkedDestBase
+            }
+
+instance Checkable ParseAST.OverlaySpec AST.OverlaySpec where
+    check context (ParseAST.OverlaySpec over width) = do
+        checkedOver <- check context over
+        return $ AST.OverlaySpec checkedOver width
+
+instance Checkable ParseAST.Address AST.Address where
+    check _ (ParseAST.LiteralAddress value) = do
+        return $ AST.LiteralAddress value
+    check context (ParseAST.ParamAddress name) = do
+        checkParamType context name AST.AddressParam
+        return $ AST.ParamAddress name
+
+instance Checkable a b => Checkable (ParseAST.For a) (AST.For b) where
+    check context ast = do
+        let
+            varRanges = ParseAST.varRanges ast
+            varNames = map ParseAST.var varRanges
+            body = ParseAST.body ast
+        checkDuplicates context varNames DuplicateVariable
+        ranges <- check context varRanges
+        let
+            currentVars = vars context
+            bodyVars = currentVars `Set.union` (Set.fromList varNames)
+            bodyContext = context
+                { vars = bodyVars }
+        checkedBody <- check bodyContext body
+        let
+            checkedVarRanges = Map.fromList $ zip varNames ranges
+        return AST.For
+                { AST.varRanges = checkedVarRanges
+                , AST.body      = checkedBody
+                }
+
+instance Checkable ParseAST.ForVarRange AST.ForRange where
+    check context ast = do
+        let 
+            start = ParseAST.start ast
+            end = ParseAST.end ast
+        (checkedStart, checkedEnd) <- check context (start, end)
+        return AST.ForRange
+            { AST.start = checkedStart
+            , AST.end   = checkedEnd
+            }
+
+instance Checkable ParseAST.ForLimit AST.ForLimit where
+    check _ (ParseAST.LiteralLimit value) = do
+        return $ AST.LiteralLimit value
+    check context (ParseAST.ParamLimit name) = do
+        checkParamType context name AST.NaturalParam
+        return $ AST.ParamLimit name
+
+instance Checkable a b => Checkable [a] [b] where
+    check context as = forAll (check context) as
+
+instance (Checkable a c, Checkable b d) => Checkable (a, b) (c, d) where
+    check context (a, b) =
+        let
+            eitherC = check context a
+            eitherD = check context b
+        in case (eitherC, eitherD) of
+            (Right c, Right d) -> return (c, d)
+            (Left e1, Left e2) -> Left $ CheckFailure (concat $ map failedChecks [e1, e2])
+            (Left e1, _)       -> Left $ e1
+            (_      , Left e2) -> Left $ e2
+--
+-- Helpers
+--
+rootModule :: ParseAST.SockeyeSpec -> ParseAST.Module
+rootModule spec =
+    let
+        body = ParseAST.ModuleBody
+            { ParseAST.ports = []
+            , ParseAST.moduleNet = ParseAST.net spec
+            }
+    in ParseAST.Module
+        { ParseAST.name       = "@root"
+        , ParseAST.parameters = []
+        , ParseAST.moduleBody = body
+        }
+
+getModule :: Context -> String -> Either CheckFailure AST.Module
+getModule context name = do
+    let
+        modMap = AST.modules $ spec context
+    case Map.lookup name modMap of
+        Nothing -> Left $ checkFailure context [NoSuchModule name]
+        Just m  -> return m
+
+getCurrentModule :: Context -> AST.Module
+getCurrentModule context =
+    let
+        modMap = AST.modules $ spec context
+    in modMap Map.! (moduleName context)
+
+getInstantiatedModule :: Context -> Either CheckFailure AST.Module
+getInstantiatedModule context =
+    let
+        modName = instModule context
+    in getModule context modName
+
+getParameterType :: Context -> String -> Either CheckFailure AST.ModuleParamType
+getParameterType context name = do
+    let
+        mod = getCurrentModule context
+        paramMap = AST.paramTypeMap mod
+    case Map.lookup name paramMap of
+        Nothing -> Left $ checkFailure context [NoSuchParameter name]
+        Just t  -> return t
+
+forAll :: (a -> Either CheckFailure b) -> [a] -> Either CheckFailure [b]
+forAll f as = do
+    let
+        bs = map f as
+        es = concat $ map failedChecks (lefts bs)
+    case es of
+        [] -> return $ rights bs
+        _  -> Left $ CheckFailure es
+
+checkDuplicates :: Context -> [String] -> (String -> FailedCheckType) -> Either CheckFailure ()
+checkDuplicates context names failure = do
+    let
+        duplicates = duplicateNames names
+    case duplicates of
+        [] -> return ()
+        _  -> Left $ checkFailure context (map failure duplicates)
+    where
+        duplicateNames [] = []
+        duplicateNames (x:xs)
+            | x `elem` xs = nub $ [x] ++ duplicateNames xs
+            | otherwise = duplicateNames xs
+
+checkVarInScope :: Context -> String -> Either CheckFailure ()
+checkVarInScope context name = do
+    if name `Set.member` (vars context)
+        then return ()
+        else Left $ checkFailure context [NoSuchVariable name]
+
+
+checkParamType :: Context -> String -> AST.ModuleParamType -> Either CheckFailure ()
+checkParamType context name expected = do
+    actual <- getParameterType context name
+    if actual == expected
+        then return ()
+        else Left $ mismatch actual
+    where
+        mismatch t = checkFailure context [ParamTypeMismatch name expected t]
diff --git a/tools/sockeye/SockeyeNetBuilder.hs b/tools/sockeye/SockeyeNetBuilder.hs
new file mode 100644 (file)
index 0000000..dee7e86
--- /dev/null
@@ -0,0 +1,575 @@
+{-
+    SockeyeNetBuilder.hs: Decoding net builder for Sockeye
+
+    Part of Sockeye
+
+    Copyright (c) 2017, ETH Zurich.
+
+    All rights reserved.
+
+    This file is distributed under the terms in the attached LICENSE file.
+    If you do not find this file, copies can be found by writing to:
+    ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+    Attn: Systems Group.
+-}
+
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+
+module SockeyeNetBuilder
+( sockeyeBuildNet ) where
+
+import Control.Monad.State
+
+import Data.Either
+import Data.List (nub, intercalate, sort)
+import Data.Map (Map)
+import qualified Data.Map as Map
+import Data.Maybe (fromMaybe)
+import Data.Set (Set)
+import qualified Data.Set as Set
+
+import qualified SockeyeAST as AST
+import qualified SockeyeASTDecodingNet as NetAST
+
+type NetNodeDecl = (NetAST.NodeId, NetAST.NodeSpec)
+type NetList = [NetNodeDecl]
+type PortMap = [(String, NetAST.NodeId)]
+
+data FailedCheck
+    = ModuleInstLoop [String]
+    | DuplicateInPort !String !String
+    | DuplicateInMap !String !String
+    | UndefinedInPort !String !String
+    | DuplicateOutPort !String !String
+    | DuplicateOutMap !String !String
+    | UndefinedOutPort !String !String
+    | DuplicateIdentifer !String
+    | UndefinedReference !String
+
+instance Show FailedCheck where
+    show (ModuleInstLoop loop) = concat ["Module instantiation loop:'", intercalate "' -> '" loop, "'"]
+    show (DuplicateInPort  modName port) = concat ["Multiple declarations of input port '", port, "' in '", modName, "'"]
+    show (DuplicateInMap   ns      port) = concat ["Multiple mappings for input port '", port, "' in '", ns, "'"]
+    show (UndefinedInPort  modName port) = concat ["'", port, "' is not an input port in '", modName, "'"]
+    show (DuplicateOutPort modName port) = concat ["Multiple declarations of output port '", port, "' in '", modName, "'"]
+    show (DuplicateOutMap   ns      port) = concat ["Multiple mappings for output port '", port, "' in '", ns, "'"]
+    show (UndefinedOutPort modName port) = concat ["'", port, "' is not an output port in '", modName, "'"]
+    show (DuplicateIdentifer ident)   = concat ["Multiple declarations of node '", show ident, "'"]
+    show (UndefinedReference ident)   = concat ["Reference to undefined node '", show ident, "'"]
+
+newtype CheckFailure = CheckFailure
+    { failures :: [FailedCheck] }
+
+instance Show CheckFailure where
+    show (CheckFailure fs) = unlines $ "":(map show fs)
+
+data Context = Context
+    { spec         :: AST.SockeyeSpec
+    , modulePath   :: [String]
+    , curNamespace :: NetAST.Namespace
+    , paramValues  :: Map String Integer
+    , varValues    :: Map String Integer
+    , inPortMaps   :: Map String NetAST.NodeId
+    , outPortMaps  :: Map String NetAST.NodeId
+    , mappedBlocks :: [NetAST.BlockSpec]
+    }
+
+sockeyeBuildNet :: AST.SockeyeSpec -> Either CheckFailure NetAST.NetSpec
+sockeyeBuildNet ast = do
+    let
+        context = Context
+            { spec         = AST.SockeyeSpec Map.empty
+            , modulePath   = []
+            , curNamespace = NetAST.Namespace []
+            , paramValues  = Map.empty
+            , varValues    = Map.empty
+            , inPortMaps   = Map.empty
+            , outPortMaps  = Map.empty
+            , mappedBlocks = []
+            }        
+    net <- transform context ast
+    check Set.empty net
+    return net
+--            
+-- Build net
+--
+class NetTransformable a b where
+    transform :: Context -> a -> Either CheckFailure b
+
+instance NetTransformable AST.SockeyeSpec NetAST.NetSpec where
+    transform context ast = do
+        let
+            rootInst = AST.ModuleInst
+                { AST.namespace  = AST.SimpleIdent ""
+                , AST.moduleName = "@root"
+                , AST.arguments  = Map.empty
+                , AST.inPortMap  = []
+                , AST.outPortMap = []
+                }
+            specContext = context
+                { spec = ast }
+        netList <- transform specContext rootInst
+        let
+            nodeIds = map fst netList
+        checkDuplicates nodeIds DuplicateIdentifer
+        let
+            nodeMap = Map.fromList netList
+        return $ NetAST.NetSpec nodeMap
+
+instance NetTransformable AST.Module NetList where
+    transform context ast = do
+        let
+            inPorts = AST.inputPorts ast
+            outPorts = AST.outputPorts ast
+            nodeDecls = AST.nodeDecls ast
+            moduleInsts = AST.moduleInsts ast
+        inDecls <- do
+            net <- transform context inPorts
+            return $ concat (net :: [NetList])
+        outDecls <- do
+            net <- transform context outPorts
+            return $ concat (net :: [NetList])
+        -- TODO check duplicate ports
+        -- TODO check mappings to non existing port
+        netDecls <- transform context nodeDecls
+        netInsts <- transform context moduleInsts
+        return $ concat (inDecls:outDecls:netDecls ++ netInsts)            
+
+instance NetTransformable AST.Port NetList where
+    transform context (AST.MultiPort for) = do
+        netPorts <- transform context for
+        return $ concat (netPorts :: [NetList])
+    transform context (AST.InputPort portId portWidth) = do
+        netPortId <- transform context portId
+        let
+            portMap = inPortMaps context
+            name = NetAST.name netPortId
+            mappedId = Map.lookup name portMap
+        case mappedId of
+            Nothing    -> return []
+            Just ident -> do
+                let
+                    node = portNode netPortId portWidth
+                return [(ident, node)]
+    transform context (AST.OutputPort portId portWidth) = do
+        netPortId <- transform context portId
+        let
+            portMap = outPortMaps context
+            name = NetAST.name netPortId
+            mappedId = Map.lookup name portMap
+        case mappedId of
+            Nothing    -> return [(netPortId, portNodeTemplate)]
+            Just ident -> do
+                let
+                    node = portNode ident portWidth
+                return [(netPortId, node)]
+
+portNode :: NetAST.NodeId -> Integer -> NetAST.NodeSpec
+portNode destNode width =
+    let
+        base = NetAST.Address 0
+        limit = NetAST.Address $ 2^width - 1
+        srcBlock = NetAST.BlockSpec
+            { NetAST.base  = base
+            , NetAST.limit = limit
+            }
+        map = NetAST.MapSpec
+                { NetAST.srcBlock = srcBlock
+                , NetAST.destNode = destNode
+                , NetAST.destBase = base
+                }
+    in portNodeTemplate { NetAST.translate = [map] }
+
+portNodeTemplate :: NetAST.NodeSpec
+portNodeTemplate = NetAST.NodeSpec
+    { NetAST.nodeType  = NetAST.Other
+    , NetAST.accept    = []
+    , NetAST.translate = []
+    }    
+
+instance NetTransformable AST.ModuleInst NetList where
+    transform context (AST.MultiModuleInst for) = do
+        net <- transform context for
+        return $ concat (net :: [NetList])
+    transform context ast = do
+        let
+            namespace = AST.namespace ast
+            name = AST.moduleName ast
+            args = AST.arguments ast
+            inPortMap = AST.inPortMap ast
+            outPortMap = AST.outPortMap ast
+            mod = getModule context name
+        checkSelfInst name
+        netNamespace <- transform context namespace
+        netArgs <- transform context args
+        netInMap <- transform context inPortMap
+        netOutMap <- transform context outPortMap
+        let
+            inMaps = concat (netInMap :: [PortMap])
+            outMaps = concat (netOutMap :: [PortMap])
+        checkDuplicates (map fst inMaps) (DuplicateInMap $ show netNamespace) 
+        checkDuplicates (map fst outMaps) (DuplicateOutMap $ show netNamespace)
+        let
+            modContext = moduleContext name netNamespace netArgs inMaps outMaps
+        transform modContext mod
+            where
+                moduleContext name namespace args inMaps outMaps =
+                    let
+                        path = modulePath context
+                        base = NetAST.ns $ NetAST.namespace namespace
+                        newNs = case NetAST.name namespace of
+                            "" -> NetAST.Namespace base
+                            n  -> NetAST.Namespace $ n:base
+                    in context
+                        { modulePath   = name:path
+                        , curNamespace = newNs
+                        , paramValues  = args
+                        , varValues    = Map.empty
+                        , inPortMaps   = Map.fromList inMaps
+                        , outPortMaps  = Map.fromList outMaps
+                        }
+                checkSelfInst name = do
+                    let
+                        path = modulePath context
+                    case loop path of
+                        [] -> return ()
+                        l  -> Left $ CheckFailure [ModuleInstLoop (reverse $ name:l)]
+                        where
+                            loop [] = []
+                            loop path@(p:ps)
+                                | name `elem` path = p:(loop ps)
+                                | otherwise = []
+
+
+instance NetTransformable AST.PortMap PortMap where
+    transform context (AST.MultiPortMap for) = do
+        ts <- transform context for
+        return $ concat (ts :: [PortMap])
+    transform context ast = do
+        let
+            mappedId = AST.mappedId ast
+            mappedPort = AST.mappedPort ast
+        netMappedId <- transform context mappedId
+        netMappedPort <- transform context mappedPort
+        return [(NetAST.name netMappedPort, netMappedId)]
+
+instance NetTransformable AST.ModuleArg Integer where
+    transform _ (AST.AddressArg value) = return value
+    transform _ (AST.NaturalArg value) = return value
+    transform context (AST.ParamArg name) = return $ getParamValue context name
+
+instance NetTransformable AST.Identifier NetAST.NodeId where
+    transform context ast = do
+        let
+            namespace = curNamespace context
+            name = identName ast
+        return NetAST.NodeId
+            { NetAST.namespace = namespace
+            , NetAST.name      = name
+            }
+            where
+                identName (AST.SimpleIdent name) = name
+                identName ident =
+                    let
+                        prefix = AST.prefix ident
+                        varName = AST.varName ident
+                        suffix = AST.suffix ident
+                        varValue = show $ getVarValue context varName
+                        suffixName = case suffix of
+                            Nothing -> ""
+                            Just s  -> identName s
+                    in prefix ++ varValue ++ suffixName
+
+instance NetTransformable AST.NodeDecl NetList where
+    transform context (AST.MultiNodeDecl for) = do
+        ts <- transform context for
+        return $ concat (ts :: [NetList])
+    transform context ast = do
+        let
+            ident = AST.nodeId ast
+            nodeSpec = AST.nodeSpec ast
+        nodeId <- transform context ident
+        netNodeSpec <- transform context nodeSpec
+        return [(nodeId, netNodeSpec)]
+
+instance NetTransformable AST.NodeSpec NetAST.NodeSpec where
+    transform context ast = do
+        let
+            nodeType = AST.nodeType ast
+            accept = AST.accept ast
+            translate = AST.translate ast
+            reserved = AST.reserved ast
+            overlay = AST.overlay ast
+        netNodeType <- maybe (return NetAST.Other) (transform context) nodeType
+        netAccept <- transform context accept
+        netTranslate <- transform context translate
+        netReserved <- transform context reserved
+        let
+            mapBlocks = map NetAST.srcBlock netTranslate
+            nodeContext = context
+                { mappedBlocks = netAccept ++ mapBlocks ++ netReserved }
+        netOverlay <- case overlay of
+                Nothing -> return []
+                Just o  -> transform nodeContext o
+        return NetAST.NodeSpec
+            { NetAST.nodeType  = netNodeType
+            , NetAST.accept    = netAccept
+            , NetAST.translate = netTranslate ++ netOverlay
+            }
+
+instance NetTransformable AST.NodeType NetAST.NodeType where
+    transform _ AST.Memory = return NetAST.Memory
+    transform _ AST.Device = return NetAST.Device
+
+instance NetTransformable AST.BlockSpec NetAST.BlockSpec where
+    transform context (AST.SingletonBlock address) = do
+        netAddress <- transform context address
+        return NetAST.BlockSpec
+            { NetAST.base  = netAddress
+            , NetAST.limit = netAddress
+            }
+    transform context (AST.RangeBlock base limit) = do
+        netBase <- transform context base
+        netLimit <- transform context limit
+        return NetAST.BlockSpec
+            { NetAST.base  = netBase
+            , NetAST.limit = netLimit
+            }
+    transform context (AST.LengthBlock base bits) = do
+        netBase <- transform context base
+        let
+            baseAddress = NetAST.address netBase
+            limit = baseAddress + 2^bits - 1
+            netLimit = NetAST.Address limit
+        return NetAST.BlockSpec
+            { NetAST.base  = netBase
+            , NetAST.limit = netLimit
+            }
+
+instance NetTransformable AST.MapSpec NetAST.MapSpec where
+    transform context ast = do
+        let
+            block = AST.block ast
+            destNode = AST.destNode ast
+            destBase = fromMaybe (AST.LiteralAddress 0) (AST.destBase ast)
+        netBlock <- transform context block
+        netDestNode <- transform context destNode
+        netDestBase <- transform context destBase
+        return NetAST.MapSpec
+            { NetAST.srcBlock = netBlock
+            , NetAST.destNode = netDestNode
+            , NetAST.destBase = netDestBase
+            }
+
+instance NetTransformable AST.OverlaySpec [NetAST.MapSpec] where
+    transform context ast = do
+        let
+            over = AST.over ast
+            width = AST.width ast
+            blocks = mappedBlocks context
+        netOver <- transform context over
+        let
+            maps = overlayMaps netOver width blocks
+        return maps
+
+overlayMaps :: NetAST.NodeId -> Integer ->[NetAST.BlockSpec] -> [NetAST.MapSpec]
+overlayMaps destId width blocks =
+    let
+        blockPoints = concat $ map toScanPoints blocks
+        maxAddress = 2^width
+        overStop  = BlockStart $ maxAddress
+        scanPoints = filter ((maxAddress >=) . address) $ sort (overStop:blockPoints)
+        startState = ScanLineState
+            { insideBlocks    = 0
+            , startAddress    = 0
+            }
+    in evalState (scanLine scanPoints []) startState
+    where
+        toScanPoints (NetAST.BlockSpec base limit) =
+                [ BlockStart $ NetAST.address base
+                , BlockEnd   $ NetAST.address limit
+                ]
+        scanLine [] ms = return ms
+        scanLine (p:ps) ms = do
+            maps <- pointAction p ms
+            scanLine ps maps
+        pointAction (BlockStart a) ms = do
+            s <- get       
+            let
+                i = insideBlocks s
+                base = startAddress s
+                limit = a - 1
+            maps <- if (i == 0) && (base <= limit)
+                then
+                    let
+                        baseAddress = NetAST.Address $ startAddress s
+                        limitAddress = NetAST.Address $ a - 1
+                        srcBlock = NetAST.BlockSpec baseAddress limitAddress
+                        m = NetAST.MapSpec srcBlock destId baseAddress
+                    in return $ m:ms
+                else return ms
+            modify (\s -> s { insideBlocks = i + 1})
+            return maps
+        pointAction (BlockEnd a) ms = do
+            s <- get
+            let
+                i = insideBlocks s
+            put $ ScanLineState (i - 1) (a + 1)
+            return ms
+
+data StoppingPoint
+    = BlockStart { address :: !Integer }
+    | BlockEnd   { address :: !Integer }
+    deriving (Eq, Show)
+
+instance Ord StoppingPoint where
+    (<=) (BlockStart a1) (BlockEnd   a2)
+        | a1 == a2 = True
+        | otherwise = a1 <= a2
+    (<=) (BlockEnd   a1) (BlockStart a2)
+        | a1 == a2 = False
+        | otherwise = a1 <= a2
+    (<=) sp1 sp2 = (address sp1) <= (address sp2)
+
+data ScanLineState
+    = ScanLineState
+        { insideBlocks :: !Integer
+        , startAddress :: !Integer
+        } deriving (Show)
+
+instance NetTransformable AST.Address NetAST.Address where
+    transform _ (AST.LiteralAddress value) = do
+        return $ NetAST.Address value
+    transform context (AST.ParamAddress name) = do
+        let
+            value = getParamValue context name
+        return $ NetAST.Address value
+
+instance NetTransformable a b => NetTransformable (AST.For a) [b] where
+    transform context ast = do
+        let
+            body = AST.body ast
+            varRanges = AST.varRanges ast
+        concreteRanges <- transform context varRanges
+        let
+            valueList = Map.foldWithKey iterations [] concreteRanges
+            iterContexts = map iterationContext valueList
+            ts = map (\c -> transform c body) iterContexts
+            fs = lefts ts
+            bs = rights ts
+        case fs of
+            [] -> return $ bs
+            _  -> Left $ CheckFailure (concat $ map failures fs)
+        where
+            iterations k vs [] = [Map.fromList [(k,v)] | v <- vs]
+            iterations k vs ms = concat $ map (f ms k) vs
+                where
+                    f ms k v = map (Map.insert k v) ms
+            iterationContext varMap =
+                let
+                    values = varValues context
+                in context
+                    { varValues = values `Map.union` varMap }
+
+instance NetTransformable AST.ForRange [Integer] where
+    transform context ast = do
+        let
+            start = AST.start ast
+            end = AST.end ast
+        startVal <- transform context start
+        endVal <- transform context end
+        return [startVal..endVal]
+
+instance NetTransformable AST.ForLimit Integer where
+    transform _ (AST.LiteralLimit value) = return value
+    transform context (AST.ParamLimit name) = return $ getParamValue context name
+
+instance NetTransformable a b => NetTransformable [a] [b] where
+    transform context ast = do
+        let
+            ts = map (transform context) ast
+            fs = lefts ts
+            bs = rights ts
+        case fs of
+            [] -> return bs
+            _  -> Left $ CheckFailure (concat $ map failures fs)
+
+instance (Ord k, NetTransformable a b) => NetTransformable (Map k a) (Map k b) where
+    transform context ast = do
+        let
+            ks = Map.keys ast
+            es = Map.elems ast
+        ts <- transform context es
+        return $ Map.fromList (zip ks ts)
+
+--
+-- Checks
+--
+class NetCheckable a where
+    check :: Set NetAST.NodeId -> a -> Either CheckFailure ()
+
+instance NetCheckable NetAST.NetSpec where
+    check _ (NetAST.NetSpec net) = do
+        let
+            specContext = Map.keysSet net
+        check specContext $ Map.elems net
+
+instance NetCheckable NetAST.NodeSpec where
+    check context net = do
+        let
+            translate = NetAST.translate net
+        check context translate
+
+instance NetCheckable NetAST.MapSpec where
+    check context net = do
+        let
+           destNode = NetAST.destNode net
+        check context destNode
+
+instance NetCheckable NetAST.NodeId where
+    check context net = do
+        if net `Set.member` context
+            then return ()
+            else Left $ CheckFailure [UndefinedReference $ show net]
+
+instance NetCheckable a => NetCheckable [a] where
+    check context net = do
+        let
+            checked = map (check context) net
+            fs = lefts $ checked
+        case fs of
+            [] -> return ()
+            _  -> Left $ CheckFailure (concat $ map failures fs)
+
+getModule :: Context -> String -> AST.Module
+getModule context name =
+    let
+        modules = AST.modules $ spec context
+    in modules Map.! name
+
+getParamValue :: Context -> String -> Integer
+getParamValue context name =
+    let
+        params = paramValues context
+    in params Map.! name
+
+getVarValue :: Context -> String -> Integer
+getVarValue context name =
+    let
+        vars = varValues context
+    in vars Map.! name
+
+checkDuplicates :: (Eq a, Show a) => [a] -> (String -> FailedCheck) -> Either CheckFailure ()
+checkDuplicates nodeIds fail = do
+    let
+        duplicates = duplicateNames nodeIds
+    case duplicates of
+        [] -> return ()
+        _  -> Left $ CheckFailure (map (fail . show) duplicates)
+    where
+        duplicateNames [] = []
+        duplicateNames (x:xs)
+            | x `elem` xs = nub $ [x] ++ duplicateNames xs
+            | otherwise = duplicateNames xs
diff --git a/tools/sockeye/SockeyeParser.hs b/tools/sockeye/SockeyeParser.hs
new file mode 100644 (file)
index 0000000..c3f50ca
--- /dev/null
@@ -0,0 +1,421 @@
+{-
+  SockeyeParser.hs: Parser for Sockeye
+
+  Part of Sockeye
+
+  Copyright (c) 2017, ETH Zurich.
+
+  All rights reserved.
+
+  This file is distributed under the terms in the attached LICENSE file.
+  If you do not find this file, copies can be found by writing to:
+  ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+  Attn: Systems Group.
+-}
+
+module SockeyeParser
+( parseSockeye ) where
+
+import Text.Parsec
+import qualified Text.Parsec.Token as P
+import Text.Parsec.Language (javaStyle)
+
+import qualified SockeyeASTParser as AST
+
+{- Parser main function -}
+parseSockeye :: String -> String -> Either ParseError AST.SockeyeSpec
+parseSockeye = parse sockeyeFile
+
+{- Sockeye parsing -}
+sockeyeFile = do
+    whiteSpace
+    spec <- sockeyeSpec
+    eof
+    return spec
+
+sockeyeSpec = do
+    imports <- many imports
+    modules <- many sockeyeModule
+    net <- many netSpecs
+    return AST.SockeyeSpec
+        { AST.imports = imports
+        , AST.modules = modules
+        , AST.net     = concat net
+        }
+
+imports = do
+    reserved "import"
+    path <- try importPath <?> "import path"
+    return $ AST.Import path
+
+
+sockeyeModule = do
+    reserved "module"
+    name <- moduleName
+    params <- option [] $ parens (commaSep moduleParam)
+    body <- braces moduleBody
+    return AST.Module
+        { AST.name       = name
+        , AST.parameters = params
+        , AST.moduleBody = body
+        }
+
+moduleParam = do
+    paramType <- choice [intType, addrType] <?> "parameter type"
+    paramName <- parameterName
+    return AST.ModuleParam
+        { AST.paramName = paramName
+        , AST.paramType = paramType 
+        }
+    where
+        intType = do
+            symbol "nat"
+            return AST.NaturalParam
+        addrType = do
+            symbol "addr" 
+            return AST.AddressParam
+
+moduleBody = do
+    ports <- many portDefs
+    net <- many netSpecs
+    return AST.ModuleBody
+        { AST.ports     = concat ports
+        , AST.moduleNet = concat net
+        }
+
+portDefs = choice [inputPorts, outputPorts]
+    where
+        inputPorts = do
+            reserved "input"
+            commaSep1 inDef
+        inDef = do
+            (forFn, portId) <- identifierFor
+            symbol "/"
+            portWidth <- decimal <?> "number of bits"
+            let
+                portDef = AST.InputPortDef portId portWidth
+            case forFn of
+                Nothing -> return portDef
+                Just f  -> return $ AST.MultiPortDef (f portDef)
+        outputPorts = do
+            reserved "output"
+            commaSep1 outDef
+        outDef = do
+            (forFn, portId) <- identifierFor
+            symbol "/"
+            portWidth <- decimal <?> "number of bits"
+            let
+                portDef = AST.OutputPortDef portId portWidth
+            case forFn of
+                Nothing -> return portDef
+                Just f  -> return $ AST.MultiPortDef (f portDef)
+
+netSpecs = choice [ inst <?> "module instantiation"
+                 , decl <?> "node declaration"
+                 ]
+    where
+        inst = do
+            moduleInst <- moduleInst
+            return $ [AST.ModuleInstSpec moduleInst]
+        decl = do
+            nodeDecls <- nodeDecls
+            return $ [AST.NodeDeclSpec decl | decl <- nodeDecls]
+
+moduleInst = do
+    (name, args) <- try $ do
+        name <- moduleName
+        args <- option [] $ parens (commaSep moduleArg)
+        symbol "as"
+        return (name, args)
+    (forFn, namespace) <- identifierFor
+    portMappings <- option [] $ symbol "with" *> many1 portMapping
+    return $ let
+        moduleInst = AST.ModuleInst
+            { AST.moduleName = name
+            , AST.namespace  = namespace
+            , AST.arguments  = args 
+            , AST.portMappings = portMappings
+            }
+        in case forFn of
+            Nothing -> moduleInst
+            Just f  -> AST.MultiModuleInst $ f moduleInst
+
+moduleArg = choice [addressArg, numberArg, paramArg]
+    where
+        addressArg = do
+            addr <- addressLiteral
+            return $ AST.AddressArg addr
+        numberArg = do
+            num <- numberLiteral
+            return $ AST.NaturalArg num
+        paramArg = do
+            name <- parameterName
+            return $ AST.ParamArg name
+
+portMapping = choice [inputMapping, outputMapping]
+    where
+        inputMapping = do
+            (forFn, mappedId) <- try $ identifierFor <* symbol ">"
+            portId <- identifier
+            return $ let
+                portMap = AST.InputPortMap
+                    { AST.mappedId   = mappedId
+                    , AST.mappedPort = portId
+                    }
+                in case forFn of
+                    Nothing -> portMap
+                    Just f  -> AST.MultiPortMap $ f portMap
+        outputMapping = do
+            (forFn, mappedId) <- try $ identifierFor <* symbol "<"
+            portId <- identifier
+            return $ let
+                portMap = AST.OutputPortMap
+                    { AST.mappedId   = mappedId
+                    , AST.mappedPort = portId
+                    }
+                in case forFn of
+                    Nothing -> portMap
+                    Just f  -> AST.MultiPortMap $ f portMap
+
+nodeDecls = do
+    nodeIds <- choice [try single, try multiple]
+    nodeSpec <- nodeSpec
+    return $ map (toNodeDecl nodeSpec) nodeIds
+    where
+        single = do
+            nodeId <- identifier
+            reserved "is"
+            return [(Nothing, nodeId)]
+        multiple = do
+            nodeIds <- commaSep1 identifierFor
+            reserved "are"
+            return nodeIds
+        toNodeDecl nodeSpec (forFn, ident) = let
+            nodeDecl = AST.NodeDecl
+                { AST.nodeId = ident
+                , AST.nodeSpec = nodeSpec
+                }
+            in case forFn of
+                Nothing -> nodeDecl
+                Just f  -> AST.MultiNodeDecl $ f nodeDecl
+
+identifier = do
+    (_, ident) <- identifierHelper False
+    return ident
+
+nodeSpec = do
+    nodeType <- optionMaybe $ try nodeType
+    accept <- option [] accept 
+    translate <- option [] tranlsate
+    reserve <- option [] reserve
+    overlay <- optionMaybe overlay
+    return AST.NodeSpec 
+        { AST.nodeType  = nodeType
+        , AST.accept    = accept
+        , AST.translate = translate
+        , AST.reserved  = reserve
+        , AST.overlay   = overlay
+        }
+    where
+        accept = do
+            try $ reserved "accept"
+            brackets $ many blockSpec
+        tranlsate = do
+            try $ reserved "map"
+            specs <- brackets $ many mapSpecs
+            return $ concat specs
+        reserve = do
+            try $ reserved "reserved"
+            brackets $ many blockSpec
+
+nodeType = choice [memory, device]
+    where memory = do
+            symbol "memory"
+            return AST.Memory
+          device = do
+            symbol "device"
+            return AST.Device
+
+blockSpec = choice [range, length, singleton]
+    where
+        singleton = do
+            address <- address
+            return $ AST.SingletonBlock address
+        range = do
+            base <- try $ address <* symbol "-"
+            limit <- address
+            return $ AST.RangeBlock base limit
+        length = do
+            base <- try $ address <* symbol "/"
+            bits <- decimal <?> "number of bits"
+            return $ AST.LengthBlock base bits
+
+address = choice [address, param]
+    where
+        address = do
+            addr <- addressLiteral
+            return $ AST.LiteralAddress addr
+        param = do
+            name <- parameterName
+            return $ AST.ParamAddress name
+
+mapSpecs = do
+    block <- blockSpec
+    reserved "to"
+    dests <- commaSep1 $ mapDest
+    return $ map (toMapSpec block) dests
+    where
+        mapDest = do
+            destNode <- identifier
+            destBase <- optionMaybe $ reserved "at" *> address
+            return (destNode, destBase)
+        toMapSpec block (destNode, destBase) = AST.MapSpec
+            { AST.block    = block
+            , AST.destNode = destNode
+            , AST.destBase = destBase
+            }
+
+overlay = do
+    reserved "over"
+    over <- identifier
+    symbol "/"
+    width <- decimal <?> "number of bits"
+    return AST.OverlaySpec
+        { AST.over  = over
+        , AST.width = width
+        }
+
+identifierFor = identifierHelper True
+
+forVarRange optVarName
+    | optVarName = do 
+        var <- option "#" (try $ variableName <* reserved "in")
+        range var
+    | otherwise = do
+        var <- variableName
+        reserved "in"
+        range var
+    where
+        range var = brackets (do
+            start <- index
+            symbol ".."
+            end <- index
+            return AST.ForVarRange
+                { AST.var   = var
+                , AST.start = start
+                , AST.end   = end
+                }
+            )
+            <?> "range ([a..b])"
+        index = choice [numberIndex, paramIndex]
+        numberIndex = do
+            num <- numberLiteral
+            return $ AST.LiteralLimit num
+        paramIndex = do
+            name <- parameterName
+            return $ AST.ParamLimit name
+
+{- Helper functions -}
+lexer = P.makeTokenParser (
+    javaStyle  {
+        {- list of reserved Names -}
+        P.reservedNames = keywords,
+
+        {- valid identifiers -}
+        P.identStart = letter,
+        P.identLetter = identLetter,
+
+        {- comment start and end -}
+        P.commentStart = "/*",
+        P.commentEnd = "*/",
+        P.commentLine = "//",
+        P.nestedComments = False
+    })
+
+whiteSpace    = P.whiteSpace lexer
+reserved      = P.reserved lexer
+parens        = P.parens lexer
+brackets      = P.brackets lexer
+braces        = P.braces lexer
+symbol        = P.symbol lexer
+commaSep      = P.commaSep lexer
+commaSep1     = P.commaSep1 lexer
+identString    = P.identifier lexer
+hexadecimal   = symbol "0" *> P.hexadecimal lexer <* whiteSpace
+decimal       = P.decimal lexer <* whiteSpace
+
+keywords = ["import", "module",
+            "input", "output",
+            "in",
+            "as", "with",
+            "is", "are",
+            "accept", "map",
+            "reserved", "over",
+            "to", "at"]   
+
+identStart     = letter
+identLetter    = alphaNum <|> char '_' <|> char '-'
+
+importPath     = many (identLetter <|> char '/' <|> char '.') <* whiteSpace
+moduleName     = identString <?> "module name"
+parameterName  = identString <?> "parameter name"
+variableName   = identString <?> "variable name"
+identifierName = try ident <?> "identifier"
+    where
+        ident = do
+            start <- identStart
+            rest <- many identLetter
+            let ident = start:rest
+            if ident `elem` keywords
+                then unexpected $ "reserved word \"" ++ ident ++ "\""
+                else return ident
+
+numberLiteral  = try decimal <?> "number literal"
+addressLiteral = try hexadecimal <?> "address literal (hex)"
+
+identifierHelper inlineFor = do
+    (varRanges, Just ident) <- choice [template identifierName, simple identifierName] <* whiteSpace
+    let
+        forFn = case varRanges of
+         [] -> Nothing
+         _  -> Just $ \body -> AST.For
+                { AST.varRanges = varRanges
+                , AST.body      = body
+                }
+    return (forFn, ident)
+    where
+        simple ident = do
+            name <- ident
+            return $ ([], Just $ AST.SimpleIdent name)
+        template ident = do
+            prefix <- try $ ident <* symbol "{"
+            (ranges, varName, suffix) <- if inlineFor 
+                then choice [forTemplate, varTemplate]
+                else varTemplate
+            let
+                ident = Just AST.TemplateIdent
+                    { AST.prefix = prefix
+                    , AST.varName = varName
+                    , AST.suffix = suffix
+                    }
+            return (ranges, ident)
+        varTemplate = do
+            varName <- variableName
+            char '}'
+            (ranges, suffix) <- templateSuffix
+            return (ranges, varName, suffix)
+        forTemplate = do
+            optVarRange <- forVarRange True
+            char '}'
+            (subRanges, suffix) <- templateSuffix
+            return $ let
+                varName = mapOptVarName subRanges (AST.var optVarRange)
+                varRange = optVarRange { AST.var = varName }
+                ranges = varRange:subRanges
+                in (ranges, varName, suffix)
+        templateSuffix = option ([], Nothing) $ choice
+            [ template $ many identLetter
+            , simple $ many1 identLetter
+            ]
+        mapOptVarName prev "#" = "#" ++ (show $ (length prev) + 1)
+        mapOptVarName _ name = name
index 3a768ac..c188504 100644 (file)
@@ -12,6 +12,7 @@
 
 let ramfs_files = find inDir "programs" ".pl" ++
                   find inDir ("programs" </> "platforms") ".pl"
+    sockeyeFiles = [ "omap44xx" ]
     ramdisk = "/skb_ramfs.cpio.gz"
     args arch = application {
                         target = "skb",
@@ -37,5 +38,6 @@ in
     Rule ( [ Str "bash",
              In SrcTree "src" "skripts/mkcpio",
              NoDep SrcTree "src" "", Out "root" ramdisk]
-             ++ [ In SrcTree "src" f | f <- ramfs_files ] )
+             ++ [ In SrcTree "src" f | f <- ramfs_files ]
+             ++ [ In BuildTree "" (sockeyeFactFilePath f) | f <- sockeyeFiles ] )
   ]
diff --git a/usr/skb/programs/decodingNet.pl b/usr/skb/programs/decodingNet.pl
new file mode 100644 (file)
index 0000000..3862075
--- /dev/null
@@ -0,0 +1,94 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copyright (c) 2017, ETH Zurich.
+% All rights reserved.
+%
+% This file is distributed under the terms in the attached LICENSE file.
+% If you do not find this file, copies can be found by writing to:
+% ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich.
+% Attn: Systems Group.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+:- module(decodingNet).
+:- export net/2.
+:- export loadnet/1.
+:- export resolve/2.
+:- export toRegion/2.
+
+:- lib(ic).
+
+:- dynamic net/2.
+
+%% Load a precompiled decoding net
+loadnet(File) :- [File].
+
+%% Address range in block
+blockRange(block(Base,Limit),Range) :-
+    Range = Base..Limit.
+
+%% Address ranges in block list
+blockListRanges(Blocks,Ranges) :-
+    (
+        foreach(Block,Blocks),
+        fromto([],Prev,Next,Ranges)
+    do
+        blockRange(Block,Range),
+        Next = [Range|Prev]
+    ).
+    
+%% Extract block ranges from map list
+mapListRanges(Maps,Ranges) :-
+    (
+        foreach(map(Block,_,_),Maps),
+        fromto([],Prev,Next,Blocks)
+    do
+        Next = [Block|Prev]
+    ),
+    blockListRanges(Blocks,Ranges).
+
+mapsToName(map(SrcBlock,Dest,DestBase),Addr,Name) :-
+    name(Dest,DestAddr) = Name,
+    blockRange(SrcBlock,Range),
+    Addr :: Range,
+    block(SrcBase,_) = SrcBlock,
+    DestAddr #= Addr - SrcBase + DestBase.
+
+listMapsToName([M|Maps],Addr,Name) :-
+    mapsToName(M,Addr,Name);
+    listMapsToName(Maps,Addr,Name).    
+
+translateMap(node(_,_,Translate),Addr,Name) :-
+    listMapsToName(Translate,Addr,Name).
+
+translate(Node,Addr,Name) :-
+    translateMap(Node,Addr,Name).
+
+accept(node(_,Accept,_),Addr) :-
+    blockListRanges(Accept,Ranges),
+    Addr :: Ranges.
+
+acceptedName(name(NodeId,Addr)) :-
+    net(NodeId,Node),
+    accept(Node,Addr).
+
+decodeStep(name(NodeId,Addr),Name) :-
+    net(NodeId,Node),
+    translate(Node,Addr,Name).
+
+decodesTo(SrcName,DestName) :-
+    decodeStep(SrcName,Name),
+    (   DestName = Name
+    ;   decodesTo(Name,DestName)
+    ).
+
+resolve(SrcName,DestName) :-
+    (   DestName = SrcName
+    ;   decodesTo(SrcName,DestName)
+    ),
+    acceptedName(DestName).
+
+toRegion(Name,Region) :-
+    name(Id,Addr) = Name,
+    get_min(Addr,Min),get_max(Addr,Max),
+    Size is Max - Min + 1,
+    Region = (Id, Min, Size).
+  
\ No newline at end of file
diff --git a/usr/skb/programs/decodingNetQueries.pl b/usr/skb/programs/decodingNetQueries.pl
new file mode 100644 (file)
index 0000000..db892f4
--- /dev/null
@@ -0,0 +1,82 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copyright (c) 2017, ETH Zurich.
+% All rights reserved.
+%
+% This file is distributed under the terms in the attached LICENSE file.
+% If you do not find this file, copies can be found by writing to:
+% ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich.
+% Attn: Systems Group.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+:- module(decodingNetQueries).
+:- export findTargetRegion/2.
+:- export findOriginRegion/2.
+:- export findDeviceRegion/3.
+:- export findMemoryRegion/3.
+:- export findSharedMemoryRegion/3.
+:- export findDeviceId/3.
+:- export findInterruptLine/3.
+
+:- use_module(decodingNet).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%
+%% Helper predicates %%
+%%%%%%%%%%%%%%%%%%%%%%%
+resolveToRegion(SrcName,DestName,SrcRegion,DestRegion) :-
+    resolve(SrcName,DestName),
+    toRegion(SrcName,SrcRegion),
+    toRegion(DestName,DestRegion).
+
+
+%%%%%%%%%%%%%
+%% Queries %%
+%%%%%%%%%%%%%
+findTargetRegion(NodeId,Result) :-
+    SrcName = name(NodeId,_),
+    resolveToRegion(SrcName,_,SrcRegion,DestRegion),
+    Result = (SrcRegion,DestRegion).
+
+findOriginRegion(NodeId,Result) :-
+    DestName = name(NodeId,_),
+    resolveToRegion(_,DestName,SrcRegion,DestRegion),
+    Result = (SrcRegion,DestRegion).
+
+%% Address space queries
+findDeviceRegion(NodeId,DeviceId,Result) :-
+    SrcName = name(NodeId,_),
+    DestName = name(DeviceId,_),
+    net(DeviceId,node(device,_,_)),
+    resolveToRegion(SrcName,DestName,SrcRegion,DestRegion),
+    Result = (SrcRegion,DestRegion).
+
+findMemoryRegion(NodeId,MemoryId,Result) :-
+    SrcName = name(NodeId,_),
+    DestName = name(MemoryId,_),
+    net(MemoryId,node(memory,_,_)),
+    resolveToRegion(SrcName,DestName,SrcRegion,DestRegion),
+    Result = (SrcRegion,DestRegion).
+
+findSharedMemoryRegion(NodeId,DeviceId,Result) :-
+    NodeName = name(NodeId,_),
+    DeviceName = name(DeviceId,_),
+    SharedName = name(SharedId,_),
+    net(SharedId,node(memory,_,_)),
+    resolve(NodeName,SharedName),
+    resolve(DeviceName,SharedName),
+    toRegion(NodeName,NodeRegion),
+    toRegion(SharedName,SharedRegion),
+    toRegion(DeviceName,DeviceRegion),
+    Result = (NodeRegion,DeviceRegion,SharedRegion).
+
+findDeviceId(NodeId,Addr,Result) :-
+    SrcName = name(NodeId,Addr),
+    resolve(SrcName,name(DeviceId,_)),
+    Result = DeviceId.
+
+%% Interrupt queries
+findInterruptLine(NodeId,DeviceId,Result) :-
+    SrcName = name(DeviceId,_),
+    DestName = name(NodeId,_),
+    resolveToRegion(SrcName,DestName,SrcRegion,DestRegion),
+    Result = (SrcRegion,DestRegion).
\ No newline at end of file
diff --git a/usr/skb/programs/decodingNetSKB.pl b/usr/skb/programs/decodingNetSKB.pl
new file mode 100644 (file)
index 0000000..c6a2f53
--- /dev/null
@@ -0,0 +1,84 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copyright (c) 2017, ETH Zurich.
+% All rights reserved.
+%
+% This file is distributed under the terms in the attached LICENSE file.
+% If you do not find this file, copies can be found by writing to:
+% ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich.
+% Attn: Systems Group.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+:- use_module(decodingNet).
+:- use_module(decodingNetQueries).
+:- local loadnet/1.
+
+%%%%%%%%%%%%%%
+%% Printing %%
+%%%%%%%%%%%%%%
+printNodeid(nodeId(Name, Namespace)) :-
+    reverse([Name|Namespace], IdList),
+    join_string(IdList,".",String),
+    write(String).
+
+printRegion((Id,Addr,Size)) :-
+    End is Addr + Size - 1,
+    printNodeid(Id),
+    printf(" [0x%16R..0x%16R]",
+        [ Addr,End ]
+    ).
+
+printSrcDestRegions((SrcRegion,DestRegion)) :-
+    printRegion(SrcRegion),
+    write(" -> "),
+    printRegion(DestRegion),
+    writeln("").
+
+printSharedRegions((Region1,Region2,SharedRegion)) :-
+    printRegion(Region1),
+    write(" -> "),
+    printRegion(SharedRegion),
+    write(" <- "),
+    printRegion(Region2),
+    writeln("").
+
+
+%%%%%%%%%%%%%%%%%%%%%%%
+%% Helper predicates %%
+%%%%%%%%%%%%%%%%%%%%%%%
+loadnet(Name) :- 
+    concat_string(["sockeyefacts/",Name],File),
+    decodingNet:loadnet(File).
+
+all(Pred) :- findall(_,Pred,_).
+
+
+%%%%%%%%%%%%%
+%% Queries %%
+%%%%%%%%%%%%%
+findTargetRegion(NodeId) :-
+    findTargetRegion(NodeId,Result),
+    printSrcDestRegions(Result).
+
+findOriginRegion(NodeId) :-
+    findOriginRegion(NodeId,Result),
+    printSrcDestRegions(Result).
+
+findDeviceRegion(NodeId,DeviceId) :-
+    findDeviceRegion(NodeId,DeviceId,Result),
+    printSrcDestRegions(Result).
+
+findMemoryRegion(NodeId,MemoryId) :-
+    findMemoryRegion(NodeId,MemoryId,Result),
+    printSrcDestRegions(Result).
+
+findSharedMemoryRegion(NodeId,DeviceId) :-
+    findSharedMemoryRegion(NodeId,DeviceId,Result),
+    printSharedRegions(Result).
+
+findDeviceId(NodeId,Addr) :-
+    findDeviceId(NodeId,Addr,Result),
+    writeln(Result).
+
+findInterruptLine(NodeId,DeviceId) :-
+    findInterruptLine(NodeId,DeviceId,Result),
+    printSrcDestRegions(Result).
\ No newline at end of file