Add the latest version of the flat functions document.
authorMatthijs Kooijman <m.kooijman@student.utwente.nl>
Wed, 20 May 2009 09:48:03 +0000 (11:48 +0200)
committerMatthijs Kooijman <m.kooijman@student.utwente.nl>
Wed, 20 May 2009 09:48:03 +0000 (11:48 +0200)
This document is unfinished and will probably be deprecated in the future,
but is still added to preserve history.

FlatFunctions.lout [new file with mode: 0644]

diff --git a/FlatFunctions.lout b/FlatFunctions.lout
new file mode 100644 (file)
index 0000000..36eb137
--- /dev/null
@@ -0,0 +1,927 @@
+@SysInclude { report }
+@SysInclude { tbl }
+@SysInclude { haskell }
+def @SectionLink right sec {sec @CrossLink {section @NumberOf sec}}
+
+@Report
+  @InitialSpace {tex} # Treat multiple spaces as one
+  @Title {From Haskell to VHDL}
+  @Author {Matthijs Kooijman}
+  @Institution {University of Twente}
+  @DateLine {Yes}
+  @CoverSheet {No}
+#  @OptimizePages {Yes}
+//
+@Section
+  @Title {Introduction}
+@Begin
+  @LP The aim of this project is to design a structural hardware
+  description language, embedded in the functional language Haskell.
+  This means that a program written in (a subset of) Haskell will be
+  translated into hardware, using a VHDL description. The original
+  Haskell program is a structural description, meaning that the
+  programmer explicitly specifies hardware and area vs time trade-offs
+  are already made explicit in the description and the translator is not
+  required to do any scheduling.
+
+  @LP The compilation process is divided roughly into four steps:
+
+  @LeftList
+    @ParagraphItem { Parsing, typechecking and simplifying the Haskell
+    source(s).  By using the API that GHC makes available, this step is
+    fairly easy. We can feed a Haskell source file into GHC, which then
+    performs all the neccesary steps to create a @I Core module, which
+    is a simplified representation of the Haskell source file.}
+
+    @ParagraphItem { Flattening the function that is the top of the design, and
+    (recursively) any functions it requires. Flattening is the process
+    of removing nesting from expressions in the functions and making the
+    routes values take through an expression more explicit. This results
+    in a flat list of flat functions.}
+
+    @ParagraphItem { Processing the flattened functions. This step does
+    transformations such as deciding which function arguments will be
+    used as state values, decide names for signals, etc.}
+
+    @ParagraphItem { Translate the flat functions generated so far into VHDL.
+    This is a fairly direct translation, all information should be
+    present by now.}
+  @EndList
+
+  @LP In this document we will focus on the second step.  The first step
+  is completely handled by GHC and results in a Core module. The
+  representation GHC uses for the Core language is the subject of
+  @SectionLink {Core}. The second step translates
+  a Core module to a set of flat functions. The representation of a flat
+  function is the subject of @SectionLink {FlatFunctions}. The fourth
+  step is also partly discussed in this section. Finally, the actual
+  flattening that happens in the second step is the subject of
+  @SectionLink {Flattening}. The third step remains undiscussed for now.
+@End @Section
+
+@Section
+  @Title { The Core language }
+  @Tag {Core}
+@Begin
+  @LP GHC uses an internal representation for Haskell programs called @I
+  {Core} . Core is essentially a small programming language, but we
+  focus on the representation GHC uses. Inside GHC a Core program is
+  stored using a number of custom data types, which we will describe
+  here.
+
+  @LP The descriptions given here are therefore very similar to Haskell
+  source, and can usually be interpreted as such. To simplify this
+  discussion, some details that are irrelevant from our point of view
+  are left out, but each of these simplifications is noted in the text.
+
+  @LP There are two main aspects of Core: Its typing system and its
+  bindings and expression structure.
+
+  @LP So far, I've focussed on the expression signature without looking closely at
+  the typing structure, except where needed. Thus, I will describe the
+  expression structure a bit here and provide examples to show the relation with
+  Haskell source programs.
+
+@BeginSubSections
+@SubSection
+  @Title { Core bindings }
+@Begin
+@LP A central role in the core language is played by the @I binding. A binding binds
+one or more expressions to one or more identifiers (@I binders). A core program is
+essentially a set of bindings, each of which bind to an identifier on global
+scope (i.e., you get one binding for each function that is defined).
+
+The @I CoreBind type is defined as follows:
+
+@ID @Haskell {
+  NonRec CoreBndr CoreExpr
+  | Rec [(CoreBndr, CoreExpr)]
+}
+
+@LP The @I NonRec constructor is the simplest: It binds a single expression to a
+single binder. The @I Rec constructors takes a list of binder, expression
+pairs, and binds each expression to the corresponding binder. These bindings
+happen on the same scope level, meaning that each expression can use any of
+the (other) bindings, creating mutually recursive references.
+
+@LP When a program is initially compiled to Core, it consists of a single @I Rec
+binding, containing all the bindings in the original haskell source. These
+bindings are allowed to reference each other, possibly recursively, but might
+not. One of the Core simplification passes splits out this large @I Rec
+constructor into as much small @I Recs and @I NonRecs as possible.
+
+@LP The @I CoreBnder type is used in @I Let expressions as well, see below.
+@End @SubSection
+
+@SubSection
+  @Title { Core expressions }
+@Begin
+@LP The main expression type is @I CoreExpr, @FootNote {In reality, @I CoreExpr
+is an alias for @I {Expr CoreBndr}, but different types of binders are only
+used by GHC internally.} which has the following
+constructors @FootNote{The @I Note constructor was omitted, since it only
+serves as annotation and does not influence semantics of the expression.}.
+
+@DP
+@Tbl
+  aformat { @Cell @I A | @Cell B }
+{
+  @Rowa 
+    A {Var Id} 
+    B {A variable reference}
+  @Rowa
+    A {Lit Literal}
+    B {A literal value}
+  @Rowa
+    A {App CoreExpr CoreExpr}
+    B {An application. The first expression is the function or data
+       constructor to apply, the second expression is the argument to apply
+       the function to.  Function application always applies a single
+       argument, for functions with multiple arguments application is applied
+       recursively.}
+  @Rowa
+    A {Lam CoreBndr CoreExpr}
+    B {A lambda expression. When this expression is applied to some argument,
+       the argument is bound to the binder given and the result is the
+       given expression. Or, slightly more formal, the result is the given
+       expression with all @I Var expressions corresponding to the binder
+       replaced with the argument the entire lambda is applied to.}
+  @Rowa
+    A {Let CoreBind CoreExpr}
+    B {
+      A let expression. The given bind is one or more binder, expression
+      pairs. Each expression is evaluated and bound to the corresponding
+      binder.  The result is of the entire let expression is then the given
+      expression.
+
+      @DP Or, slightly more formal, evaluates all expressions inside the given bind and
+      returns the given expression with all @I Var expressions corresponding to
+      the binders in the given bind replaced by their respective evaluated
+      expressions.
+    }
+  @Rowa
+    A {
+      Case CoreExpr [CoreAlt]
+      @FootNote {In reality, there are also another Type and CoreBndr
+      arguments. However,  the Type argument only contains the type of the
+      entire expression, and thus is redundant and not useful for our purpose.
+      The CoreBndr is a binder to which the scrutinee is bound, but seems
+      this is only used for forcing evaluation of a term. Therefore, these two
+      are left out in this discussion.}
+    }
+    B {
+      A case expression, which can be used to do conditional evaluation and
+      data type ``unpacking''. The given expression (``scrutinee'') is
+      evaluated, bound to the given binder and depending on its value on of
+      the CoreAlts is chosen whose expression is returned.
+      
+      @DP A @I CoreAlt is a three tuple describing the alternative:
+
+      @IndentedDisplay @I {(AltCon, [CoreBndr], CoreExpr)}
+
+      @DP Here, the @I AltCon is an alternative constructor which can matched
+      to the scrutinee. An alternative constructor can be one of the default
+      alternative (which matches any value not matched by other alternative
+      constructors in the list), a literal (which matches if the scrutinee
+      evaluates to a literal or a data constructor, which matches if the value
+      is constructed using that specific data constructor.
+
+      @DP In the last case, when a data constructor is used for the
+      alternative, the arguments to the data constructor are extracted from
+      the scrutinee and bound to the corresponding binders (from the second
+      element of the @I CoreAlt tuple).
+
+      @DP The last element from the tuple is the expression to return, with
+      the extra bindings in effect.
+    }
+  @Rowa
+    A {
+      Cast CoreExpr Type
+    }
+    B {
+      Cast the given expression to the given type. This plays an import role
+      when working with @F newtype declarations and type classes. The exact
+      workings of this expression are a bit shady, but for now we can get away
+      with ignore it.
+    }
+  @Rowa
+    A {
+      Type Type
+    }
+    B {
+      This expression turns a type into an expression, so it can be applied to
+      functions to implement polymorphic functions and type classes. It cannot
+      be used anywhere else.
+
+      Again, we can can get away with ignore this expression for now.
+    }
+}
+@DP
+@BeginSubSubSections
+  @SubSubSection
+    @Title {Examples}
+    @Tag {CoreExamples}
+  @Begin
+
+    @LP To get a clearer example of how Haskell programs translate to the Core
+    language, a number of programs are given in both Haskell syntax and the
+    equivalent core representation. These are all simple examples, focused on
+    showing a particular aspect of the Core language.
+    
+    @LP In these examples, we will use the following data type. Since most of the
+    primitive datatypes and operators are involved in some kind of
+    polymorphism (Even the + operator is tricky), those are less useful for
+    simple examples. Using the following @I Bit datatype will also make these
+    examples more appropriate for our goals.
+
+    @ID @Haskell {
+      data Bit = High | Low
+    }
+
+    @Display @Heading {Fixed value}
+      @LP This is a trivial example which shows a simple data constructor without
+      arguments bound to the binders ``high'' and ``low''. Note that in
+      reality, the binder and @I Id values in @I Var nodes include some extra
+      info about the module it is defined in and what kind of identifier it
+      is, but that is left out here for simplicity.
+      
+      @CNP @ID @Example
+        @Title {Haskell code}
+      {
+        @LP @Haskell {
+high = High
+low = Low}}
+
+      @LP This haskell source results in the following list of @I
+      CoreBndrs.
+       
+      @CNP @ID @Example
+        @Title {Core Structure}
+      {
+      @LP @Haskell {
+[ NonRec ``high'' (Var High)
+, NonRec ``low'; (Var Low)]}}
+
+      @LP In subsequent examples I will leave out the @I NonRec constructor and
+      binder name and just show the resulting @I CoreExpr.
+
+    @Display @Heading {Function arguments}
+      This example shows a simple function that simply returns its argument.
+
+      @CNP @ID @Example
+        @Title {Haskell code}
+      {
+        @LP @Haskell {
+wire :: Bit -> Bit
+wire a = a}}
+
+      @CNP @ID @Example
+        @Title {Core Structure}
+      {
+        @LP @Haskell {
+Lam a (Var a)}}
+
+    @Display @Heading { Pattern matching }
+      This example shows a function with a single argument which uses
+      pattern matching, which results in a simple case statement.
+
+    @CNP @ID @Example
+        @Title {Haskell Code}
+      {
+        @LP @Haskell {
+inv :: Bit -> Bit
+inv High = Low
+inv Low = High}}
+
+    @ID @Example
+        @Title {Core Structure}
+      {
+        @LP @Haskell {
+Lam ds (Case 
+       (Var ds) 
+       [
+               (High, [], (Var Low)), 
+               (Low, [], (Var High))
+       ]
+)}}
+
+  @LP Note that in the tuples describing the alternatives, the first element
+  is a data constructor directly, while the third argument is an expression
+  referring to a dataconstructor (henc the Var constructor).
+
+  @Display @Heading {Function application}
+    This example shows a function that applies other functions (with one and
+    two arguments) to its own arguments to do its work. It also illustrates
+    functions accepting multiple arguments.
+
+    @LP For this example we assume there is a function @I nand available to
+    returns the negated and of its two arguments.
+
+  @CNP @ID @Example
+    @Title {Haskell code}
+  {
+    @LP @Haskell {
+or :: Bit -> Bit -> Bit
+or a b = inv (nand a b)}}
+
+  @CNP @ID @Example
+    @Title {Core structure}
+  {
+    @LP @Haskell {
+Lam a (Lam b (App
+       (Var inv)
+       (App
+               (App
+                       (Var nand)
+                       (Var a))
+               (Var b)
+       )
+))}}
+
+  @Display @Heading {Tuples}
+    This example shows a function that accepts a tuple of two values and
+    returns a tuple of two values again.
+
+    @LP This example assumes the availability of two functions @I and and 
+    @I xor, with obvious meaning.
+
+  @CNP @ID @Example
+    @Title {Haskell code}
+  {
+    @LP @Haskell {
+-- Accepts two values and returns the sum and carry out respectively.
+half_adder :: (Bit, Bit) -> (Bit, Bit)
+half_adder (a, b) =
+  (and a b, xor a b)}}
+
+  @LP Since the core structure corresponding to this (still pretty trivial)
+  function will be quite complex already, we will first show the desugared and
+  simplified version of the function, to which the core structure directly
+  corresponds.
+
+  @CNP @ID @Example
+    @Title {Simplified haskell code}
+  {
+    @LP @Haskell {
+    half_adder = \ds ->
+      Case ds of
+        (a, b) ->
+          (,) (and a b) (xor a b)
+}}
+  @CNP @ID @Example
+    @Title {Core structure}
+  {
+    @LP @Haskell
+    {
+Lam ds (Case (Var ds)
+       [(
+               (,),
+               [a, b],
+               (App
+                       (App
+                               (Var (,))
+                               (App
+                                       (App
+                                               (Var and)
+                                               (Var a)
+                                       )
+                                       (Var b)
+                               )
+                       )
+                       (App
+                               (App
+                                       (Var xor)
+                                       (Var a)
+                               )
+                               (Var b)
+                       )
+               )
+       )]
+)}}
+
+
+  @LP Note the (,) in this example, which is the data constructor for a
+  two-tuple. It can be passed two values and will construct a tuple from
+  them. @FootNote {In reality, this dataconstructor takes @I four arguments,
+  namely the types of each of the elements and then the elements themselves.
+  This is because the two-tuple type really takes type arguments, which are
+  made explicit on every call to its data constructors.}
+
+  @Display @Heading {Let expressions}
+    This example shows a function that uses a let expression to use a value
+    twice.
+
+  @CNP @ID @Example
+    @Title {Haskell code}
+  {
+    @LP @Haskell {
+f :: Bit -> (Bit, Bit)
+f a = 
+  (x, and a x)
+  where
+    x = xor a a}}
+
+  @CNP @ID @Example
+    @Title {Simplified haskell code}
+  {
+    @LP @Haskell {
+    f = \a ->
+      let x = xor a a in
+      (,) x (and a x)
+}}
+  @CNP @ID @Example
+    @Title {Core structure}
+  {
+    @LP @Haskell
+    {
+Lam a (Let
+       [(NonRec
+               x 
+               (App
+                       (App
+                               (Var xor)
+                               (Var a)
+                       )
+                       (Var a)
+               )
+       )]
+       (App
+               (App
+                       (Var (,))
+                       (Var x)
+               )
+               (App
+                       (App
+                               (Var and)
+                               (Var a)
+                       )
+                       (Var x)
+               )
+       )
+)}}
+
+  @Display @Heading {Pattern matching}
+    This example shows a multiplexer, i.e., a function that selects one
+    of two inputs, based on a third input. This illustrates how pattern
+    matching is translated into core and can be used to create
+    conditional signal connections.
+
+  @CNP @ID @Example
+    @Title {Haskell code}
+  {
+    @LP @Haskell
+    {
+mux2 :: Bit -> (Bit, Bit) -> Bit
+mux2 Low (a, b) = a
+mux2 High (a, b) = b}}
+
+  @CNP @ID @Example
+    @Title {Simplified haskell code}
+  {
+    @LP @Haskell {
+    mux2 = \ds ds1 -> case ds of
+      Low -> case ds1 of (a, b) -> a
+      High -> case ds1 of (a, b) -> b}}
+
+  @CNP @ID @Example
+    @Title {Core structure}
+  {
+    @LP @Haskell
+    {
+Lam ds (Lam ds1 (Case (Var ds)
+       [(
+               Low,
+               [],
+               (Case (Var ds1)
+                       [(
+                               (,)
+                               [a, b],
+                               (Var a)
+                       )]
+               )
+       ),(
+               High,
+               [],
+               (Case (Var ds1)
+                       [(
+                               (,)
+                               [a, b],
+                               (Var b)
+                       )]
+               )
+       )]
+))}}
+  @End @SubSubSection
+@EndSubSubSections
+@End @SubSection
+@EndSubSections
+@End @Section
+
+@Section
+  @Title {Flat Functions}
+  @Tag {FlatFunctions}
+@Begin
+  @LP As an intermediate between Core and VHDL, we use "flat" functions (the name
+  is open for suggestions). A flat function is a simplified version of the
+  function, which defines a number of signals (corresponding to single haskell
+  values) which can be used in a number of places and are defined to a single
+  value. A single value in this case means something that will probably result
+  in a single VHDL signal or port, so a 2-tuple results in two signals, for
+  example.
+
+  @LP The function is flat, because there are no directly nested expressions. A
+  function application can only use signals, not nested applications or other
+  expressions. These signals can of course be defined as the result of an
+  expression or function application, so the original expressions can still be
+  expressed.
+
+  @LP A flat function is defined as a single @I FlatFunction constructor with
+  the following fields @FootNote {The implementation additionally has a @I
+  sigs fields listing all the signals, but since that list is directly
+  deducable from the @I args and @I defs fields, it is left out here}:
+
+  @DP
+  @Tbl
+    aformat { @Cell @I A | @Cell B }
+  {
+    @Rowa 
+      A {args :: [SignalMap]}
+      B {A list that maps each argument to this function to a (number of)
+         signal(s). In other words, this field specifies to which signals the
+         function arguments should be assigned when this function is called.}
+    @Rowa 
+      A {res :: SignalMap}
+      B {A map that maps the return value to a (number of) signal(s).
+         signal(s). In other words, this field specifies which signals contain
+         the function result when this function is called.}
+    @Rowa 
+      A {defs :: [SignalDef]}
+      B {Definitions for each of the signals in the function. Each @I SignalDef
+      defines one ore more signals, and each signal should be defined exactly
+      once. Note that the signals in @I args don't have a @I SignalDef entry.}
+  }
+
+  @LP The type @I Signal plays a central role in a flat function. It
+  identifies a signal. It's exact representation is not that important (the
+  current implementation uses an Int), as long as it can be compared and
+  unique new @I Signals can be generated.
+
+  @LP The @I SignalMap type has the following two constructors:
+  
+  @ID @Haskell {
+Single Signal
+| Tuple [SignalMap]
+  }
+  
+  @LP This means we can support any type that can be translated to a signal
+  directly (currently only @I Bit and @I Bool) and tuples containing those
+  types. A signal map allows us to decompose a Haskell value into individual
+  pieces that can be used in the resulting VHDL.
+
+  @LP The @I SignalDef type is slightly more complex. For one or more signals,
+  it specifies how they are defined. In the resulting hardware, these can be
+  mapped to simple signal assignments or port mappings on component
+  instantiations. The type has the following constructors:
+
+  @DP @Tbl
+    aformat { @Cell @I A | @Cell B }
+  {
+    @Rowa 
+      A {lines @Break {
+FApp 
+       func :: HsFunction @FootNote {In the current implementation, this
+    value can also be a representation of a higher order function.
+    However, since this is not functional yet, it is left out of this
+    discussion.}
+       args :: [SignalMap]
+       res :: SignalMap
+      }}
+      B {A function application. The function that is called is identified by
+         the given @I HsFunction, and passed the values in the given
+         @I SignalMaps as arguments. The result of the function will be
+         assigned to the @I SignalMap in @I res.}
+    @Rowa 
+      A {lines @Break {
+CondDef 
+       cond :: Signal
+       true :: Signal
+       false :: Signal
+       res :: Signal
+      }}
+      B {A conditional signal definition. If the signal pointed to by @I cond
+      is True, @I true is assigned to @I res, else @I false is assigned to
+      @I res. The @I cond signal must thus be of type @I Bool.
+
+      This keeps conditional assignment very simple, all complexity in the
+      conditions will be put into @I SignalExpr in @I UncondDef. }
+    @Rowa 
+      A {lines @Break {
+UncondDef 
+       src :: SignalExpr
+       dst :: Signal}}
+      B {Unconditional signal definition. In the most basic form (assigning a
+      simple signal to another signal) this is not often useful (only in
+      specific cases where two signals cannot be merged, when assigning an
+      output port to an input port for example).
+
+      The more interesting use for unconditional definition is when the 
+      @I SignalExpr is more complicated and allows for more complexity. }
+  } 
+
+  @LD @Heading {Identifying functions}
+    @LP To identify a function to call we use the @I HsFunction type. This
+    type is used for two purposes. First, it contains the name of the
+    function to call, so the corresponding @I CoreBndr and @I CoreExpr
+    can be found in the current module. Secondly, an @I HsFunction
+    contains information on the use of each argument and the return
+    value. In particular, it stores for each (part of an) argument or
+    return value if it should become an input or output Port, or a state
+    internal to the called function.
+
+    @LP The @I HsFunction type looks as follows:
+    
+    @ID @Haskell {
+HsFunction {
+       func :: String,
+       args :: [UseMap],
+       res :: UseMap
+}}
+    @LP Here, the UseMap type is defined similar to the @I SignalMap
+    type @FootNote{In reality, both @I SignalMap and @I UseMap are
+    generalized into a type @I HsValueMap which takes an element type as
+    a type parameter}:
+
+    @ID @Haskell {
+Single Use
+| Tuple [Use]}
+
+    @LP The @I Use type is defined as follows. The @I StateId argument
+    to the @I State constructor is a unique identifier for the state
+    variable, which can be used to match input and output state
+    variables together. This state id should be unique within either
+    arguments or the return value, but should be matched between them
+    (@I i.e., there should be exactly one @I State use with id 0 in the
+    arguments, and exactly once in the return value) @FootNote{In the
+    current implementation, there is third constructor in the @I Use
+    type for arguments that get higher order functions passed in. Since
+    this is not functional yet, this is left out of this discussion}.
+    
+    @ID @Haskell {
+Port
+| State StateId}
+
+  @LP The last type used in this description is @I SignalExpr. It allows for certain
+  expressions in the resulting VHDL, currently only comparison. The type has
+  the following constructors:
+
+  @DP @Tbl
+    aformat { @Cell @I A | @Cell B }
+  {
+    @Rowa 
+      A {
+        Sig Signal
+      }
+      B {
+        A simple signal reference.
+      }
+    @Rowa
+      A {
+        Literal String
+      }
+      B {
+        A literal value. The given string is the resulting VHDL value. Perhaps
+        this should better be something less VHDL-specific, but this works for
+        now.
+      }
+    @Rowa
+      A {
+        Eq Signal Signal
+      }
+      B {
+        Equality comparison. This is the only comparison supported for now and
+        results in a @I Bool signal that can be used in a @I CondDef.
+      }
+  }
+
+  @BeginSubSections
+       @SubSection
+         @Title {Examples}
+       @Begin
+      @LP To ease the understanding of this datastructure, we will show
+      the flattened equivalents of some of the examples given in
+      @SectionLink {CoreExamples}. When reading these examples, don't
+      forget that the signal id's themselves are interchangeable, as
+      long as they remain unique and still link the right expressions
+      together (@I i.e., the actual numbers are not relevant).
+      @Display @Heading {Fixed value}
+        
+        @CNP @ID @Example
+          @Title {Haskell code}
+        {
+          @LP @Haskell {high = High}}
+      
+        @LP This Haskell source results in the following @I FlatFunction.
+
+        @CNP @ID @Example
+          @Title {Flat function}
+        {
+        @LP @Haskell {
+FlatFunction {
+       sigs = [0],
+       args = [],
+       res = (Single 0),
+       defs = [UncondDef (Lit "'1'") 0]
+}}}
+            
+      @Display @Heading {Function application}
+
+        @CNP @ID @Example
+          @Title {Haskell code}
+        {
+          @LP @Haskell {
+or :: Bit -> Bit -> Bit
+or a b = inv (nand a b)}}
+
+        @CNP @ID @Example
+          @Title {Flat function}
+        {
+        @LP @Haskell {
+FlatFunction {
+       sigs = [0, 1, 2, 3],
+       args = [Single 0, Single 1],
+       res = (Single 3),
+       defs = [
+      (FApp   
+        (HsFunction "nand" [Single Port, Single Port] (Single Port))
+        [Single 0, Single 1]
+        (Single 2)
+      ),
+      (FApp
+        (HsFunction "inv" [Single Port] (Single Port))
+        [Single 2]
+        (Single 3)
+      )
+    ]
+}}}
+
+      @Display @Heading {Pattern matching}
+        @CNP @ID @Example
+          @Title {Haskell code}
+        {
+          @LP @Haskell
+          {
+mux2 :: Bit -> (Bit, Bit) -> Bit
+mux2 Low (a, b) = a
+mux2 High (a, b) = b}}
+
+        @CNP @ID @Example
+          @Title {Flat function}
+        {
+        @LP @Haskell {
+FlatFunction {
+       sigs = [0, 1, 2, 3, 4, 5],
+       args = [Single 0, Tuple [Single 3, Single 4]],
+       res = (Single 5),
+       defs = [
+               (UncondDef (Lit "'1'") 1),
+               (UncondDef (Eq 0 1) 2),
+               (CondDef 2 4 3 5)
+       ]
+}}}
+       @End @SubSection
+  @EndSubSections
+
+@End @Section
+
+@Section
+  @Title {Flattening of functions}
+  @Tag {Flattening}
+@Begin
+  @LP The most interesting part of all this is of course the translation of our
+  Haskell functions (in Core format) to flattened functions. From there, the
+  translation of VHDL is relatively easy.
+
+  @LP This section details the "flattening" of a function. To this end, we define
+  a function @I flattenFunction which translates a (nonrecursive) binding to a
+  flat function.
+
+  @LP The syntax used for these functions is not quite Haskell. It is similar,
+  but some functions can have side effects or don't return any value. They
+  are probably best read as if the lines are sequentially executed (though
+  pattern matching does happen as is normal in Haskell). This notation is
+  probably closest to the monadic "do" notation in Haskell, but with the
+  special syntax for that ("do", "<-" and "return") implied.
+
+  @LP @Haskell {
+flattenFunction (NonRec b expr) =
+       (args, res) = flattenExpr expr
+       defs = getDefs
+       FlatFunction args res defs
+  }
+
+  @LP This is a rather simple function, but it does need some explaination. First
+  of all, the flattenExpr function has some hidden state (In the
+  implementation, this is state is made explicit using a @I State @I Monad).
+  To understand the above function, it is sufficient to know that the @I
+  getDefs function simply returns all the definitions that were added in @I
+  flattenExpr using the @I addDef function.
+
+  @LP Similary, in the below function definitions, the @I insertBind function
+  inserts a signal bind (that binds a haskell identifier to a signal in the
+  flat function) into the current table of binds. This binds remains in the
+  table for any other functions called by the caller of @I insertBind, but is
+  removed again when that caller "returns". The @I lookupBind function looks
+  up such a bind in this table.
+
+  @LP Now, the actual work is done by the @I flattenExpr function, which processes
+  an arbitrary expressions and returns a tuple with argument @I SignalMaps and
+  a result @I SignalMap. The argument @I SignalMaps map each argument that
+  should be passed to the expression (when it has a function type, this is an
+  empty list for non-function types). The signals these maps map to are the
+  signals to which the arguments are assumed to have been assigned. In the
+  final @I FlatFunction, these maps are used to tell to which signals the
+  input ports should be bound.
+
+  @LP The result @I SignalMap is the inverse of the argument @I SIgnalMaps. It
+  contains the signals that the results of the expression are bound to.
+
+  @Display @Heading {Lambda expressions}
+  @LP @Haskell {
+flattenExpr (Lam b expr) =
+       arg = genSignals b
+       insertBind (b <= arg)
+       (args, res) = flattenExpr expr
+       (arg:args, res)
+  }
+
+  @Display @Heading {Variable references}
+  @LP @Haskell {
+flattenExpr (Var id) =
+       case id of
+               ``localid'' -> 
+                       ([], lookupBind id)
+               () -> 
+                       ([], Tuple [])
+               ``datacon'' -> 
+                               res = genSignals id
+                               lit = Lit (dataconToLit id)
+                               addDef UncondDef {src = lit, dst = s}
+
+                               ([], res)
+dataconToLit datacon =
+       case datacon of
+               Low -> "'0'"
+               High -> "'1'"
+               True -> "true"
+               False -> "false"
+  }
+
+  @LP Here, @I genSignals generates a map of new (unique) signals. The structure
+  on the map is based on the (Haskell) type of whatever is passed to it, such
+  as the value bound to the identifier in this case.
+
+  @LP The @I ``datacon'' and @I ``localid'' patterns should be read as matching
+  when the id matching against refers to a local identifier (local to the
+  function or expression containing it) or a dataconstructor (such as @I True,
+  @I False, @I High or @I (,)).
+
+
+  @Display @Heading {Let expressions}
+  @LP @Haskell {
+flattenExpr (Let (NonRec b bexpr) expr) =
+       (b_args, b_res) = flattenExpr bexpr
+       insertBind (b <= b_res)
+       flattenExpr expr
+  }
+
+  @Display @Heading {Case expressions}
+  @LP @Haskell {
+flattenExpr (Case scrut alts) =
+       (args, res) = flattenExpr scrut
+       flattenAlts res alts
+
+flattenAlt scrut alt =
+       TODO
+       
+flattenAlts scrut [alt] =
+       flattenAlt scrut alt
+
+flattenAlts scrut (alt:alts)
+       (true_args, true_res) = flattenAlt scrut alt
+       (false_args, false_res) = flattenAlts scrut alts
+       (altcon, bind_vars, expr) = alt
+       lit = Lit (dataconToLit)
+
+       TODO
+  }
+
+  @Display @Heading {Function applications}
+  @LP @Haskell {
+flattenExpr (App f arg) =
+       TODO
+  }
+
+
+@End @Section
+
+# vim: set sts=2 sw=2 expandtab: