X-Git-Url: https://git.stderr.nl/gitweb?p=matthijs%2Fmaster-project%2Fdsd-paper.git;a=blobdiff_plain;f=c%CE%BBash.lhs;h=886376648304d8550742b94de4148a53399dcbcd;hp=438cce4290f1004a5f12713d2dcb243f7f5602d3;hb=d8b9a02732239603a440bf060bdbe6db0522b981;hpb=5f94742c1854c1d5f47d4e89f8d96bc74d1b20c9 diff --git "a/c\316\273ash.lhs" "b/c\316\273ash.lhs" index 438cce4..8863766 100644 --- "a/c\316\273ash.lhs" +++ "b/c\316\273ash.lhs" @@ -342,9 +342,11 @@ % Macro for certain acronyms in small caps. Doesn't work with the % default font, though (it contains no smallcaps it seems). \def\acro#1{{\small{#1}}} +\def\acrotiny#1{{\scriptsize{#1}}} \def\VHDL{\acro{VHDL}} \def\GHC{\acro{GHC}} \def\CLaSH{{\small{C}}$\lambda$a{\small{SH}}} +\def\CLaSHtiny{{\scriptsize{C}}$\lambda$a{\scriptsize{SH}}} % Macro for pretty printing haskell snippets. Just monospaced for now, perhaps % we'll get something more complex later on. @@ -392,8 +394,9 @@ % author names and affiliations % use a multiple column layout for up to three different % affiliations -\author{\IEEEauthorblockN{Christiaan P.R. Baaij, Matthijs Kooijman, Jan Kuper, Marco E.T. Gerards, Bert Molenkamp, Sabih H. Gerez} -\IEEEauthorblockA{University of Twente, Department of EEMCS\\ +\author{\IEEEauthorblockN{Christiaan P.R. Baaij, Matthijs Kooijman, Jan Kuper, Marco E.T. Gerards}%, Bert Molenkamp, Sabih H. Gerez} +\IEEEauthorblockA{%Computer Architecture for Embedded Systems (CAES)\\ +Department of EEMCS, University of Twente\\ P.O. Box 217, 7500 AE, Enschede, The Netherlands\\ c.p.r.baaij@@utwente.nl, matthijs@@stdin.nl, j.kuper@@utwente.nl}} % \and @@ -479,7 +482,7 @@ traditional hardware description languages. \section{Introduction} -Hardware description languages has allowed the productivity of hardware +Hardware description languages have allowed the productivity of hardware engineers to keep pace with the development of chip technology. Standard Hardware description languages, like \VHDL~\cite{VHDL2008} and Verilog~\cite{Verilog}, allowed an engineer to describe circuits using a @@ -504,7 +507,7 @@ means that a developer is given a library of Haskell~\cite{Haskell} functions and types that together form the language primitives of the domain specific language. As a result of how the signals are modeled and abstracted, the functions used to describe a circuit also build a large domain-specific -datatype (hidden from the designer) which can be further processed by an +datatype (hidden from the designer) which can then be processed further by an embedded compiler. This compiler actually runs in the same environment as the description; as a result compile-time and run-time become hard to define, as the embedded compiler is usually compiled by the same Haskell compiler as the @@ -516,7 +519,7 @@ itself for the purpose of describing hardware. By taking this approach, we can capture certain language constructs, such as Haskell's choice elements (if-constructs, case-constructs, pattern matching, etc.), which are not available in the functional hardware description languages that are embedded -in Haskell as a domain specific languages. As far as the authors know, such +in Haskell as a domain specific language. As far as the authors know, such extensive support for choice-elements is new in the domain of functional hardware description languages. As the hardware descriptions are plain Haskell functions, these descriptions can be compiled for simulation using an @@ -525,18 +528,29 @@ optimizing Haskell compiler such as the Glasgow Haskell Compiler (\GHC)~\cite{gh Where descriptions in a conventional hardware description language have an explicit clock for the purpose state and synchronicity, the clock is implied in this research. A developer describes the behavior of the hardware between -clock cycles, as such, only synchronous systems can be described. Many -functional hardware description model signals as a stream of all values over -time; state is then modeled as a delay on this stream of values. The approach -taken in this research is to make the current state of a circuit part of the -input of the function and the updated state part of the output. +clock cycles. Many functional hardware description model signals as a stream +of all values over time; state is then modeled as a delay on this stream of +values. The approach taken in this research is to make the current state of a +circuit part of the input of the function and the updated state part of the +output. The current abstraction of state and time limits the descriptions to +synchronous hardware, there however is room within the language to eventually +add a different abstraction mechanism that will allow for the modeling of +asynchronous systems. Like the standard hardware description languages, descriptions made in a functional hardware description language must eventually be converted into a -netlist. This research also features a prototype translator called \CLaSH\ -(pronounced: clash), which converts the Haskell code to equivalently behaving -synthesizable \VHDL\ code, ready to be converted to an actual netlist format -by an (optimizing) \VHDL\ synthesis tool. +netlist. This research also features a prototype translator, which has the +same name as the language: \CLaSH\footnote{\CLaSHtiny: \acrotiny{CAES} +Language for Synchronous Hardware} (pronounced: clash). This compiler converts +the Haskell code to equivalently behaving synthesizable \VHDL\ code, ready to +be converted to an actual netlist format by an (optimizing) \VHDL\ synthesis +tool. + +Besides trivial circuits such as variants of both the FIR filter and the +simple CPU shown in \Cref{sec:usecases}, the \CLaSH\ compiler has also been +shown to work for non-trivial descriptions. \CLaSH\ has been able to +successfully translate the functional description of a streaming reduction +circuit~\cite{reductioncircuit} for floating point numbers. \section{Hardware description in Haskell} @@ -551,18 +565,19 @@ by an (optimizing) \VHDL\ synthesis tool. and \item function applications are translated to component instantiations. \end{inparaenum} - The output port can have a complex type (such as a tuple), so having just - a single output port does not pose any limitation. The arguments of a - function applications are assigned to a signal, which are then mapped to + The output port can have a structured type (such as a tuple), so having + just a single output port does not pose any limitation. The arguments of a + function application are assigned to signals, which are then mapped to the corresponding input ports of the component. The output port of the function is also mapped to a signal, which is used as the result of the application itself. Since every top level function generates its own component, the hierarchy of function calls is reflected in the final netlist,% aswell, - creating a hierarchical description of the hardware. This separation in - different components makes the resulting \VHDL\ output easier to read and - debug. + creating a hierarchical description of the hardware. The separation in + different components makes it easier for a developer to understand and + possibly hand-optimize the resulting \VHDL\ output of the \CLaSH\ + compiler. As an example we can see the netlist of the |mac| function in \Cref{img:mac-comb}; the |mac| function applies both the |mul| and |add| @@ -578,7 +593,7 @@ by an (optimizing) \VHDL\ synthesis tool. \label{img:mac-comb} \end{figure} - The result of using a complex input type can be seen in + The result of using a structural input type can be seen in \cref{img:mac-comb-nocurry} where the |mac| function now uses a single input tuple for the |a|, |b|, and |c| arguments: @@ -595,7 +610,7 @@ by an (optimizing) \VHDL\ synthesis tool. \subsection{Choice} In Haskell, choice can be achieved by a large set of language constructs, consisting of: \hs{case} constructs, \hs{if-then-else} constructs, - pattern matching, and guards. The easiest of these are the \hs{case} + pattern matching, and guards. The most general of these are the \hs{case} constructs (\hs{if} expressions can be very directly translated to \hs{case} expressions). A \hs{case} construct is translated to a multiplexer, where the control value is linked to the selection port and @@ -605,17 +620,27 @@ by an (optimizing) \VHDL\ synthesis tool. % assignment in \VHDL, where the conditions use equality comparisons % against the constructors in the \hs{case} expressions. We can see two versions of a contrived example below, the first - using a \hs{case} construct and the other using a \hs{if-then-else} - constructs, in the code below. + using a \hs{case} construct and the other using an \hs{if-then-else} + construct, in the code below. The examples sums two values when they are + equal or non-equal (depending on the given predicate, the \hs{pred} + variable) and returns 0 otherwise. The \hs{pred} variable has the + following, user-defined, enumeration datatype: \begin{code} + data Pred = Equiv | NotEquiv + \end{code} + + The naive netlist corresponding to both versions of the example is + depicted in \Cref{img:choice}. + + \begin{code} sumif pred a b = case pred of - Eq -> case a == b of - True -> a + b - False -> 0 - Neq -> case a != b of - True -> a + b - False -> 0 + Equiv -> case a == b of + True -> a + b + False -> 0 + NotEquiv -> case a != b of + True -> a + b + False -> 0 \end{code} \begin{code} @@ -631,28 +656,30 @@ by an (optimizing) \VHDL\ synthesis tool. \caption{Choice - sumif} \label{img:choice} \end{figure} - - The example sums two values when they are equal or non-equal (depending on - the predicate given) and returns 0 otherwise. Both versions of the example - roughly correspond to the same netlist, which is depicted in - \Cref{img:choice}. - A slightly more complex (but very powerful) form of choice is pattern + A user-friendly and also very powerful form of choice is pattern matching. A function can be defined in multiple clauses, where each clause - specifies a pattern. When the arguments match the pattern, the + corresponds to a pattern. When an argument matches a pattern, the corresponding clause will be used. Expressions can also contain guards, - where the expression is only executed if the guard evaluates to true. Like + where the expression is only executed if the guard evaluates to true, and + continues with the next clause if the guard evaluates to false. Like \hs{if-then-else} constructs, pattern matching and guards have a (straightforward) translation to \hs{case} constructs and can as such be mapped to multiplexers. A third version of the earlier example, using both - pattern matching and guards, can be seen below. The version using pattern - matching and guards also has roughly the same netlist representation - (\Cref{img:choice}) as the earlier two versions of the example. + pattern matching and guards, can be seen below. The guard is the + expression that follows the vertical bar (\hs{|}) and precedes the + assignment operator (\hs{=}). The \hs{otherwise} guards always evaluate to + \hs{true}. + + The version using pattern matching and guards corresponds to the same + naive netlist representation (\Cref{img:choice}) as the earlier two + versions of the example. \begin{code} - sumif Eq a b | a == b = a + b - sumif Neq a b | a != b = a + b - sumif _ _ _ = 0 + sumif Eq a b | a == b = a + b + | otherwise = 0 + sumif Neq a b | a != b = a + b + | otherwise = 0 \end{code} % \begin{figure} @@ -664,8 +691,8 @@ by an (optimizing) \VHDL\ synthesis tool. \subsection{Types} Haskell is a statically-typed language, meaning that the type of a variable or function is determined at compile-time. Not all of Haskell's - typing constructs have a clear translation to hardware, as such this - section will only deal with the types that do have a clear correspondence + typing constructs have a clear translation to hardware, this section will + therefor only deal with the types that do have a clear correspondence to hardware. The translatable types are divided into two categories: \emph{built-in} types and \emph{user-defined} types. Built-in types are those types for which a direct translation is defined within the \CLaSH\ @@ -690,16 +717,16 @@ by an (optimizing) \VHDL\ synthesis tool. % using translation rules that are discussed later on. \subsubsection{Built-in types} - The following types have direct translation defined within the \CLaSH\ + The following types have direct translations defined within the \CLaSH\ compiler: \begin{xlist} \item[\bf{Bit}] - This is the most basic type available. It can have two values: - \hs{Low} and \hs{High}. + the most basic type available. It can have two values: + \hs{Low} or \hs{High}. % It is mapped directly onto the \texttt{std\_logic} \VHDL\ type. \item[\bf{Bool}] - This is a basic logic type. It can have two values: \hs{True} - and \hs{False}. + this is a basic logic type. It can have two values: \hs{True} + or \hs{False}. % It is translated to \texttt{std\_logic} exactly like the \hs{Bit} % type (where a value of \hs{True} corresponds to a value of % \hs{High}). @@ -707,7 +734,7 @@ by an (optimizing) \VHDL\ synthesis tool. \hs{if-then-else} construct, which requires a \hs{Bool} value for the condition. \item[\bf{SizedWord}, \bf{SizedInt}] - These are types to represent integers. A \hs{SizedWord} is unsigned, + these are types to represent integers. A \hs{SizedWord} is unsigned, while a \hs{SizedInt} is signed. Both are parametrizable in their size. % , so you can define an unsigned word of 32 bits wide as follows: @@ -723,7 +750,7 @@ by an (optimizing) \VHDL\ synthesis tool. % types are translated to the \VHDL\ \texttt{unsigned} and % \texttt{signed} respectively. \item[\bf{Vector}] - This is a vector type that can contain elements of any other type and + this is a vector type that can contain elements of any other type and has a fixed length. The \hs{Vector} type constructor takes two type arguments: the length of the vector and the type of the elements contained in it. The short-hand notation used for the vector type in @@ -743,7 +770,7 @@ by an (optimizing) \VHDL\ synthesis tool. % \hs{RegisterState} type is a vector of 8 32-bit words. A fixed size % vector is translated to a \VHDL\ array type. \item[\bf{Index}] - This is another type to describe integers, but unlike the previous + this is another type to describe integers, but unlike the previous two it has no specific bit-width, but an upper bound. This means that its range is not limited to powers of two, but can be any number. An \hs{Index} only has an upper bound, its lower bound is @@ -770,14 +797,14 @@ by an (optimizing) \VHDL\ synthesis tool. data-types with the \hs{data} keyword, type synonyms with the \hs{type} keyword and datatype renaming constructs with the \hs{newtype} keyword. \GHC\ offers a few more advanced ways to introduce types (type families, - existential typing, {\small{GADT}}s, etc.) which are not standard Haskell. + existential typing, {\acro{GADT}}s, etc.) which are not standard Haskell. As it is currently unclear how these advanced type constructs correspond - with hardware, they are for now unsupported by the \CLaSH\ compiler + to hardware, they are for now unsupported by the \CLaSH\ compiler. Only an algebraic datatype declaration actually introduces a - completely new type. Type synonyms and renaming constructs only define new + completely new type. Type synonyms and type renaming only define new names for existing types, where synonyms are completely interchangeable - and renaming constructs need explicit conversions. Therefore, these do not + and type renaming requires explicit conversions. Therefore, these do not need any particular translation, a synonym or renamed type will just use the same representation as the original type. For algebraic types, we can make the following distinctions: @@ -810,8 +837,8 @@ by an (optimizing) \VHDL\ synthesis tool. % value. \item[\bf{Multiple constructors with fields}] Algebraic datatypes with multiple constructors, where at least - one of these constructors has one or more fields are not - currently supported. + one of these constructors has one or more fields are currently not + supported. \end{xlist} \subsection{Polymorphism} @@ -1008,14 +1035,40 @@ by an (optimizing) \VHDL\ synthesis tool. value in the input list corresponds to exactly one cycle of the (implicit) clock. The result of the simulation is a list of outputs for every clock cycle. As both the \hs{run} function and the hardware description are - plain hardware, the complete simulation can be compiled by an optimizing + plain Haskell, the complete simulation can be compiled by an optimizing Haskell compiler. \section{\CLaSH\ prototype} -foo\par bar +The \CLaSH\ language as presented above can be translated to \VHDL\ using +the prototype \CLaSH\ compiler. This compiler allows experimentation with +the \CLaSH\ language and allows for running \CLaSH\ designs on actual FPGA +hardware. + +\begin{figure} +\centerline{\includegraphics{compilerpipeline.svg}} +\caption{\CLaSHtiny\ compiler pipeline} +\label{img:compilerpipeline} +\end{figure} + +The prototype heavily uses \GHC, the Glasgow Haskell Compiler. +\Cref{img:compilerpipeline} shows the \CLaSH\ compiler pipeline. As you can +see, the front-end is completely reused from \GHC, which allows the \CLaSH\ +prototype to support most of the Haskell Language. The \GHC\ front-end +produces the program in the \emph{Core} format, which is a very small, +functional, typed language which is relatively easy to process. + +The second step in the compilation process is \emph{normalization}. This +step runs a number of \emph{meaning preserving} transformations on the +Core program, to bring it into a \emph{normal form}. This normal form +has a number of restrictions that make the program similar to hardware. +In particular, a program in normal form no longer has any polymorphism +or higher order functions. + +The final step is a simple translation to \VHDL. \section{Use cases} +\label{sec:usecases} As an example of a common hardware design where the use of higher-order functions leads to a very natural description is a FIR filter, which is basically the dot-product of two vectors: @@ -1089,7 +1142,7 @@ is depicted in \Cref{img:4tapfir}. \begin{figure} \centerline{\includegraphics{4tapfir.svg}} -\caption{4-taps FIR Filter} +\caption{4-taps \acrotiny{FIR} Filter} \label{img:4tapfir} \end{figure} @@ -1124,9 +1177,11 @@ semantic preserving transformations. A designer can model systems using heterogeneous models of computation, which include continuous time, synchronous and untimed models of computation. Using so-called domain interfaces a designer can simulate electronic systems which have both analog -as digital parts. ForSyDe has several simulation and synthesis backends, -though synthesis is restricted to the synchronous subset of the ForSyDe -language. Unlike \CLaSH\ there is no support for the automated synthesis of description that contain polymorphism or higher-order functions. +as digital parts. ForSyDe has several backends including simulation and +automated synthesis, though automated synthesis is restricted to the +synchronous model of computation within ForSyDe. Unlike \CLaSH\ there is no +support for the automated synthesis of descriptions that contain polymorphism +or higher-order functions. Lava~\cite{Lava} is a hardware description language that focuses on the structural representation of hardware. Besides support for simulation and @@ -1135,7 +1190,7 @@ tools for formal verification. Lava descriptions are actually circuit generators when viewed from a synthesis viewpoint, in that the language elements of Haskell, such as choice, can be used to guide the circuit generation. If a developer wants to insert a choice element inside an actual -circuit he will have to specify this explicitly as a component. +circuit he will have to explicitly instantiate a multiplexer-like component. In this respect \CLaSH\ differs from Lava, in that all the choice elements, such as case-statements and pattern matching, are synthesized to choice @@ -1145,11 +1200,9 @@ mentioned in this section. The merits of polymorphic typing, combined with higher-order functions, are now also recognized in the `main-stream' hardware description languages, -exemplified by the new \VHDL-2008 standard~\cite{VHDL2008}. \VHDL-2008 has -support to specify types as generics, thus allowing a developer to describe +exemplified by the new \VHDL-2008 standard~\cite{VHDL2008}. \VHDL-2008 support for generics has been extended to types, allowing a developer to describe polymorphic components. Note that those types still require an explicit -generic map, whereas type-inference and type-specialization are implicit in -\CLaSH. +generic map, whereas types can be automatically inferred in \CLaSH. % Wired~\cite{Wired},, T-Ruby~\cite{T-Ruby}, Hydra~\cite{Hydra}. % @@ -1277,7 +1330,7 @@ The authors would like to thank... % http://www.michaelshell.org/tex/ieeetran/bibtex/ \bibliographystyle{IEEEtran} % argument is your BibTeX string definitions and bibliography database(s) -\bibliography{IEEEabrv,clash.bib} +\bibliography{clash} % % manually copy in the resultant .bbl file % set second argument of \begin to the number of references