+++ /dev/null
-Language Design
-===============
-A central question is, what do we want our language to look like? Deciding to
-use haskell would be a first step, but that still leaves a lot of
-possibilities. However, why would we want to use Haskell?
-
- * Lots of existing support: Language specification, compilers, libraries,
- userbase. All of this reduces the workload to implement something.
- * All of Haskell is usable in simulation / testing: When not compiling to
- VHDL, but when doing functional tests, we can use all of Haskell's syntax,
- libraries, functions, etc. even when we don't support all of it in our
- compiler.
- * Haskell is probably expressive enough to be able to express a lot of
- different things and different approaches. By defining new (algebraic)
- types and operators, we can extend this even further. Finally, we could
- even use Template Haskell to do almost anything (The ForSyDe project uses
- Template Haskell extensively).
-
-Typing
-------
-What kind of types will we be using in our programs? The base type should be
-some kind of bit type, but there are two main options for these:
-
- * Use a single bit as a type. Calculations on these types represent the
- calculations in a single time slice (ie, during one clock cycle). Any
- state in the calculation is explicit, since the input state must be a
- function argument and the output state part of the function's value.
-
- Through the state values, these functions are closely tied to the clock
- domain in use (or whatever other model is used for the time domain). Ie,
- having different clock domains is non-trivial and will require
- modification to the function.
-
- Composition can be done by simply connection functions together. This does
- require that the "state" of a function contains the states of each of the
- function it calls. These are extracted from its state argument and passed
- on to the callees, while the states returned are again inserted into the
- resulting state of the outer function.
-
- This approach is the closest to normal functional programming and shows
- state very explicitly.
-
- * Use a stream of bits as a type. Each value models a continuous (infinite)
- stream of bits. Functions have streams as arguments and value and state
- could probably be implicit in the calculation or could be made explicit
- using delay elements (this is what Lava does).
-
- The primitive operations all operate on streams, which seems the
- fundamental difference between this and the previous approach.
-
- This approach shows structure more explicitly when delay elements are
- used, since the registers end up exactly there.
-
-It is probably possible to mix these approaches. In particular, the first
-approache eventually needs to do some I/O, which can be modeled as recursion
-over an infinite list of inputs resulting in an infinite list of outputs. This
-can be done at the top level always, but it is perhaps possible to move this
-recursion a bit downward and do composition based on stream functions instead
-of "single clock" functions. One problem that comes to mind is that one needs
-to guarantee that a function does not look into the future (ie, uses multiple
-input elements to generate one output element) and the state becomes a lot
-less explicit. This needs more thought.
-
-Implementation
-==============
-Assume we will want to translate a (subset of) haskell into something else.
-We will need to do parsing, typechecking, interpretation, etc. A few options
-for this are available:
-
- * Doing everything manually, possibly using a parser generator.
- Lot's of work. Requires us to write down the haskell grammar, create a
- parser, do all kinds of funky type checking -> Too much work.
- * Use the Language.Haskell library and write something in haskell. This
- library contains a Lexer, Parser and AST, but still does not do any type
- checking, desugaring and simplification. Still lots of work.
- * Hack into an existing compiler. By writing a backend for an existing
- compiler, we can save most of the haskell-specific work. This requires a
- compiler that is modular enough to have its backend replaced by another
- implementation. Also, the border between backend and frontend must be
- suited for the work we would like to do. This approach would use the
- original compiler's driver for the most part
- * Use components from an existing compiler. By reusing selected components
- and creating an own driver that uses these components, we can work with
- the haskell source without doing all the work ourselves. This requires a
- compiler that is very modular, so we can decide exactly which parts we
- would like to use and which we don't need.
-
-After some looking around it seems GHC provides a consistent and (as of
-version 6.10) documented API into its internals This allows us to write
-
- core <- compileToCoreSimplified "adder.hs"
-
-to compile the file `adder.hs` into a version in GHC's simplified CoreSyn
-representation. This is essentially an AST with type annotations, all
-syntactic sugar removed, redundant expressions simplified, etc. This seems to
-be a very useful form to work with. However, GHC provides other functions to
-access other parts of the compiler, so if we would like to access the source
-at another stage, or do some custom procesing in between, this is also
-possible (albeit a bit more complex than this).
-
-Problems
---------
-Some problems encountered or expected when trying to do some initial
-translator hackup:
-
- * Signal naming. In the generated VHDL the signals and ports need names.
- These can of course be generated, but if we want to do some actual
- debugging, we want useful signal names. For input ports generated from
- function arguments, the binder name could perhaps be used, but that is not
- always possible when patterns are more complex.
-
- For output ports, a name could be deduced when the output value is always
- computed in a where or let clause. However the simplification phase
- removes these clauses where possible, so this information is lost.
-
- Perhaps some way of explicitely labeling ports could be used.
- * Type classes and universal qualification types are a powerful way of
- making functions generic, which greatly increases their reusability.
- However, this extra genericity makes the resulting Core representation
- more complex. Since the actual types used are modeled as extra function
- arguments, this shouldn't be too hard, but this is something that probably
- needs implementation right away (because a lot of builtin haskell
- constructs, such as tuples, use it).
-
-<!-- vim: set sw=2 sts=2 ts=8: -->