Useful features from the functional perspective, like polymorphism and
higher-order functions and expressions also prove suitable to describe
hardware and our implementation shows that they can be translated to
-\VHDL as well.
+\VHDL\ as well.
A prototype compiler was created in this research. For this prototype the
Haskell language was chosen as the input language, instead of creating a new
University of Twente soon, hopefully this will provide a better insight
in how the system performs.
-The prototype compiler has a clear design. Its frontend is taken from the \GHC
+The prototype compiler has a clear design. Its frontend is taken from the \GHC\
compiler and desugares Haskell into a small, but functional and typed
language, called \emph{Core}. Cλash adds a transformation system that reduces
this small language to a normal form and a simple backend that performs a
\stopalignment
\blank[medium]
- Template Haskell is an extension to the \GHC compiler that allows
+ Template Haskell is an extension to the \GHC\ compiler that allows
a program to mark some parts to be evaluated \emph{at compile
time}. These \emph{templates} can then access the abstract syntax
tree (\small{AST}) of the program that is being compiled and
with an \small{EDSL} approach, it can get confusing when to use
\small{TH} and when not to.
\item Function hierarchies cannot be observed in an \small{EDSL}.
- For example, Lava generates a single flat \VHDL architecture,
+ For example, Lava generates a single flat \VHDL\ architecture,
which has no structure whatsoever. Even though this is strictly
correct, it offers no support to the synthesis software about
which parts of the system can best be placed together and makes
\subsection{Arrows}
Another abstraction mechanism offered by Haskell are arrows. Arrows are
-a generalisation of monads \cite[hughes98], for which \GHC also supports
+a generalisation of monads \cite[hughes98], for which \GHC\ also supports
some syntax sugar \cite[paterson01]. Their use for hiding away state
boilerplate is not directly evident, but since arrows are a complex
concept further investigation is appropriate.
The main cost of this approach will probably be extra complexity in the
compiler: The paths (state) data can take become very non-trivial, and it
is probably hard to properly analyze these paths and produce the
-intended \VHDL description.
+intended \VHDL\ description.
\section{Multiple cycle descriptions}
In the current Cλash prototype, every description is a single-cycle
probably a non-trivial problem, though.
\section{Don't care values}
- A powerful value in \VHDL is the \emph{don't care} value, given as
+ A powerful value in \VHDL\ is the \emph{don't care} value, given as
\type{'-'}. This value tells the compiler that you do not really care about
which value is assigned to a signal, allowing the compiler to make some
optimizations. Since choice in hardware is often implemented using
This would also require some kind of \quote{Don't careable} type class
that allows each type to specify what its don't care value is. The
compiler must then recognize this constant and replace it with don't care
- values in the final \VHDL code.
+ values in the final \VHDL\ code.
This is of course a very intrusive solution. Every type must become member
of this type class, and there is now some member in every type that is a
mapped to a signal, which is used as the result of the application.
Since every top level function generates its own component, the
- hierarchy of of function calls is reflected in the final \VHDL output
- as well, creating a hierarchical \VHDL description of the hardware.
- This separation in different components makes the resulting \VHDL
+ hierarchy of of function calls is reflected in the final \VHDL\ output
+ as well, creating a hierarchical \VHDL\ description of the hardware.
+ This separation in different components makes the resulting \VHDL\
output easier to read and debug.
\in{Example}[ex:And3] shows a simple program using only function
the comparator and directly feed 'in' into the multiplexer (or even use an
inverter instead of a multiplexer). However, we will try to make a
general translation, which works for all possible \hs{case} expressions.
- Optimizations such as these are left for the \VHDL synthesizer, which
+ Optimizations such as these are left for the \VHDL\ synthesizer, which
handles them very well.
\todo{Be more explicit about >2 alternatives}
\subsection{User-defined types}
There are three ways to define new types in Haskell: Algebraic
datatypes with the \hs{data} keyword, type synonyms with the \hs{type}
- keyword and type renamings with the \hs{newtype} keyword. \GHC
+ keyword and type renamings 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. These will be left outside the scope of this research.
Only an algebraic datatype declaration actually introduces a
- completely new type, for which we provide the \VHDL translation
+ completely new type, for which we provide the \VHDL\ translation
below. Type synonyms and renamings only define new names for
existing types (where synonyms are completely interchangeable and
renamings need explicit conversion). Therefore, these do not need
- any particular \VHDL translation, a synonym or renamed type will
+ any particular \VHDL\ translation, a synonym or renamed type will
just use the same representation as the original type. The
distinction between a renaming and a synonym does no longer matter
in hardware and can be disregarded in the generated \VHDL.
to this type. The collection for a product type is the Cartesian
product of the collections for the types of its fields.
- These types are translated to \VHDL record types, with one field for
+ These types are translated to \VHDL\ record types, with one field for
every field in the constructor. This translation applies to all single
constructor algebraic datatypes, including those with just one
field (which are technically not a product, but generate a VHDL
Note that Haskell's \hs{Bool} type is also defined as an
enumeration type, but we have a fixed translation for that.
- These types are translated to \VHDL enumerations, with one value for
+ These types are translated to \VHDL\ enumerations, with one value for
each constructor. This allows references to these constructors to be
translated to the corresponding enumeration value.
\stopdesc
union of the the collections for each of the constructors.
Sum types are currently not supported by the prototype, since there is
- no obvious \VHDL alternative. They can easily be emulated, however, as
+ no obvious \VHDL\ alternative. They can easily be emulated, however, as
we will see from an example:
\starthaskell
last one if \hs{B}), all the other ones have no useful value.
An obvious problem with this naive approach is the space usage: The
- example above generates a fairly big \VHDL type. Since we can be
+ example above generates a fairly big \VHDL\ type. Since we can be
sure that the two \hs{Word}s in the \hs{Sum} type will never be valid
at the same time, this is a waste of space.
If the naive approach for sum types described above would be used,
a record would be created where the first field is an enumeration
to distinguish \hs{Empty} from \hs{Cons}. Furthermore, two more
- fields would be added: One with the (\VHDL equivalent of) type
+ fields would be added: One with the (\VHDL\ equivalent of) type
\hs{t} (assuming this type is actually known at compile time, this
should not be a problem) and a second one with type \hs{List t}.
The latter one is of course a problem: This is exactly the type
that was to be translated in the first place.
- The resulting \VHDL type will thus become infinitely deep. In
+ The resulting \VHDL\ type will thus become infinitely deep. In
other words, there is no way to statically determine how long
(deep) the list will be (it could even be infinite).
Fortunately, we can again use the principle of specialization: Since every
function application generates a separate piece of hardware, we can know
the types of all arguments exactly. Provided that existential typing
- (which is a \GHC extension) is not used typing, all of the
+ (which is a \GHC\ extension) is not used typing, all of the
polymorphic types in a function must depend on the types of the
arguments (In other words, the only way to introduce a type variable
is in a lambda abstraction).
result is stateful. This means that the annotation lives
\quote{outside} of the function, it is completely invisible when
looking at the function body.
- \item Use some kind of annotation on the type level, \ie give stateful
+ \item Use some kind of annotation on the type level, \ie\ give stateful
arguments and stateful (parts of) results a different type. This has the
potential to make this annotation visible inside the function as well,
such that when looking at a value inside the function body you can
(evaluation of constant comparisons), to ensure non-termination.
Supporting general recursion will probably require strict conditions
on the input descriptions. Even then, it will be hard (if not
- impossible) to really guarantee termination, since the user (or \GHC
+ impossible) to really guarantee termination, since the user (or \GHC\
desugarer) might use some obscure notation that results in a corner
case of the simplifier that is not caught and thus non-termination.
In addition to looking at designing a hardware description language, we
will also implement a prototype to test ideas. This prototype will
translate hardware descriptions written in the Haskell functional language
- to simple (netlist-like) hardware descriptions in the \VHDL language. The
+ to simple (netlist-like) hardware descriptions in the \VHDL\ language. The
reasons for choosing these languages are detailed in section
\in{}[sec:prototype:input] and \in{}[sec:prototype:output] respectively.
There are two things missing: Cast expressions are sometimes
allowed by the prototype, but not specified here and the below
- definition allows uses of state that cannot be translated to \VHDL
+ definition allows uses of state that cannot be translated to \VHDL\
properly. These two problems are discussed in
\in{section}[sec:normalization:castproblems] and
\in{section}[sec:normalization:stateproblems] respectively.
Most function applications bound by the let expression define a
component instantiation, where the input and output ports are
mapped to local signals or arguments. Some of the others use a
- built-in construction (\eg the \lam{case} expression) or call a
- built-in function (\eg \lam{+} or \lam{map}). For these, a
+ built-in construction (\eg\ the \lam{case} expression) or call a
+ built-in function (\eg\ \lam{+} or \lam{map}). For these, a
hardcoded \small{VHDL} translation is available.
\section[sec:normalization:transformation]{Transformation notation}
against (subexpressions of) the expression to be transformed. We call this a
pattern, because it can contain \emph{placeholders} (variables), which match
any expression or binder. Any such placeholder is said to be \emph{bound} to
- the expression it matches. It is convention to use an uppercase letter (\eg
+ the expression it matches. It is convention to use an uppercase letter (\eg\
\lam{M} or \lam{E}) to refer to any expression (including a simple variable
- reference) and lowercase letters (\eg \lam{v} or \lam{b}) to refer to
+ reference) and lowercase letters (\eg\ \lam{v} or \lam{b}) to refer to
(references to) binders.
For example, the pattern \lam{a + B} will match the expression
lambda abstractions, let expressions and pattern matches of case
alternatives). This is a slightly different notion of global versus
local than what \small{GHC} uses internally, but for our purposes
- the distinction \GHC makes is not useful.
+ the distinction \GHC\ makes is not useful.
\defref{global variable} \defref{local variable}
A \emph{hardware representable} (or just \emph{representable}) type or value
desugarer or simplifier emits some bindings that cannot be
normalized (e.g., calls to a
\hs{Control.Exception.Base.patError}) but are not used anywhere
- either. To prevent the \VHDL generation from breaking on these
+ either. To prevent the \VHDL\ generation from breaking on these
artifacts, this transformation removes them.
\todo{Do not use old-style numerals in transformations}
\subsubsection[sec:normalization:simplelet]{Simple let binding removal}
This transformation inlines simple let bindings, that bind some
- binder to some other binder instead of a more complex expression (\ie
+ binder to some other binder instead of a more complex expression (\ie\
a = b).
This transformation is not needed to get an expression into intended
\in{Section}[section:prototype:polymorphism].
Without this transformation, there would be a \lam{(+)} entity
- in the \VHDL which would just add its inputs. This generates a
+ in the \VHDL\ which would just add its inputs. This generates a
lot of overhead in the \VHDL, which is particularly annoying
when browsing the generated RTL schematic (especially since most
non-alphanumerics, like all characters in \lam{(+)}, are not
- allowed in \VHDL architecture names\footnote{Technically, it is
+ allowed in \VHDL\ architecture names\footnote{Technically, it is
allowed to use non-alphanumerics when using extended
identifiers, but it seems that none of the tooling likes
extended identifiers in filenames, so it effectively does not
This transformation ensures that all representable arguments will become
references to local variables. This ensures they will become references
to local signals in the resulting \small{VHDL}, which is required due to
- limitations in the component instantiation code in \VHDL (one can only
+ limitations in the component instantiation code in \VHDL\ (one can only
assign a signal or constant to an input port). By ensuring that all
arguments are always simple variable references, we always have a signal
available to map to the input ports.
function without arguments, but also an argumentless dataconstructors
like \lam{True}) are also simplified. Only local variables generate
signals in the resulting architecture. Even though argumentless
- dataconstructors generate constants in generated \VHDL code and could be
+ dataconstructors generate constants in generated \VHDL\ code and could be
mapped to an input port directly, they are still simplified to make the
normal form more regular.
will become one of: \refdef{intended normal form definition}
\startitemize
\item An extractor case with a single alternative that picks a field
- from a datatype, \eg \lam{case x of (a, b) -> a}.
+ from a datatype, \eg\ \lam{case x of (a, b) -> a}.
\item A selector case with multiple alternatives and only wild binders, that
makes a choice between expressions based on the constructor of another
- expression, \eg \lam{case x of Low -> a; High -> b}.
+ expression, \eg\ \lam{case x of Low -> a; High -> b}.
\stopitemize
For an arbitrary case, that has \lam{n} alternatives, with
There is one case where polymorphism cannot be completely
removed: Built-in functions are still allowed to be polymorphic
(Since we have no function body that we could properly
- specialize). However, the code that generates \VHDL for built-in
+ specialize). However, the code that generates \VHDL\ for built-in
functions knows how to handle this, so this is not a problem.
\subsubsection[sec:normalization:defunctionalization]{Defunctionalization}
\stoplambda
This example shows a number of higher-order values that we cannot
- translate to \VHDL directly. The \lam{double} binder bound in the let
+ translate to \VHDL\ directly. The \lam{double} binder bound in the let
expression has a function type, as well as both of the alternatives of
the case expression. The first alternative is a partial application of
the \lam{map} built-in function, whereas the second alternative is a
Haskell's \hs{Num} type class, which offers a \hs{fromInteger} method
that converts any \hs{Integer} to the Cλash datatypes.
- When \GHC sees integer literals, it will automatically insert calls to
+ When \GHC\ sees integer literals, it will automatically insert calls to
the \hs{fromInteger} method in the resulting Core expression. For
example, the following expression in Haskell creates a 32 bit unsigned
word with the value 1. The explicit type signature is needed, since
- there is no context for \GHC to determine the type from otherwise.
+ there is no context for \GHC\ to determine the type from otherwise.
\starthaskell
1 :: SizedWord D32
normal form definition} offers enough freedom to describe all
valid stateful descriptions, but is not limiting enough. It is
possible to write descriptions which are in intended normal
- form, but cannot be translated into \VHDL in a meaningful way
+ form, but cannot be translated into \VHDL\ in a meaningful way
(\eg, a function that swaps two substates in its result, or a
function that changes a substate itself instead of passing it to
a subfunction).
Without going into detail about the exact problems (of which
there are probably more than have shown up so far), it seems
unlikely that these problems can be solved entirely by just
- improving the \VHDL state generation in the final stage. The
+ improving the \VHDL\ state generation in the final stage. The
normalization stage seems the best place to apply the rewriting
needed to support more complex stateful descriptions. This does
of course mean that the intended normal form definition must be
sufficient for our goals (but it is a good start).
It should be possible to have a single formal definition of
- meaning for Core for both normal Core compilation by \GHC and for
+ meaning for Core for both normal Core compilation by \GHC\ and for
our compilation to \VHDL. The main difference seems to be that in
hardware every expression is always evaluated, while in software
it is only evaluated if needed, but it should be possible to
This approach is especially useful for proving completeness of our
system, since if expressions exist to which none of the
- transformations apply (\ie if the system is not yet complete), it
+ transformations apply (\ie\ if the system is not yet complete), it
is immediately clear which expressions these are and adding
(or modifying) transformations to fix this should be relatively
easy.
\small{EDIF} standard. \cite[li89]
This means that when working with \small{EDIF}, our prototype would become
- technology dependent (\eg only work with \small{FPGA}s of a specific
+ technology dependent (\eg\ only work with \small{FPGA}s of a specific
vendor, or even only with specific chips). This limits the applicability
of our prototype. Also, the tools we would like to use for verifying,
simulating and draw pretty pictures of our output (like Precision, or
QuestaSim) are designed for \small{VHDL} or Verilog input.
For these reasons, we will not use \small{EDIF}, but \small{VHDL} as our
- output language. We choose \VHDL over Verilog simply because we are
+ output language. We choose \VHDL\ over Verilog simply because we are
familiar with \small{VHDL} already. The differences between \small{VHDL}
and Verilog are on the higher level, while we will be using \small{VHDL}
mainly to write low level, netlist-like descriptions anyway.
In this thesis the words \emph{translation}, \emph{compilation} and
sometimes \emph{synthesis} will be used interchangedly to refer to the
process of translating the hardware description from the Haskell
- language to the \VHDL language.
+ language to the \VHDL\ language.
Similarly, the prototype created is referred to as both the
\emph{translator} as well as the \emph{compiler}.
- The final part of this process is usually referred to as \emph{\VHDL
+ The final part of this process is usually referred to as \emph{\VHDL\
generation}.
\stopframedtext
}
simple, structural descriptions, without any complex behavioural
descriptions like arbitrary sequential statements (which might not
be supported by all tools). This ensures that any tool that works
- with \VHDL will understand our output (most tools do not support
+ with \VHDL\ will understand our output (most tools do not support
synthesis of more complex \VHDL). This also leaves open the option
to switch to \small{EDIF} in the future, with minimal changes to the
prototype.
The main topic of this thesis is therefore the path from the Haskell
hardware descriptions to \small{FPGA} synthesis, focusing of course on the
- \VHDL generation. Since the \VHDL generation process preserves the meaning
+ \VHDL\ generation. Since the \VHDL\ generation process preserves the meaning
of the Haskell description exactly, any simulation done in Haskell
\emph{should} produce identical results as the synthesized hardware.
though the simplified Core version is an equivalent, but simpler
definition, some problems were encountered with it in practice. The
simplifier restructures some (stateful) functions in a way the normalizer
- and the \VHDL generation cannot handle, leading to uncompilable programs
+ and the \VHDL\ generation cannot handle, leading to uncompilable programs
(whereas the non-simplified version more closely resembles the original
program, allowing the original to be written in a way that can be
handled). This problem is further discussed in
\defref{entry function}Translation of a hardware description always
starts at a single function, which is referred to as the \emph{entry
- function}. \VHDL is generated for this function first, followed by
+ function}. \VHDL\ is generated for this function first, followed by
any functions used by the entry functions (recursively).
\section[sec:prototype:core]{The Core language}
evaluates to this bit.
If none of the alternatives match, the \lam{DEFAULT} alternative
- is chosen. A case expression must always be exhaustive, \ie it
+ is chosen. A case expression must always be exhaustive, \ie\ it
must cover all possible constructors that the scrutinee can have
(if all of them are covered explicitly, the \lam{DEFAULT}
alternative can be left out).
f (case a of arg DEFAULT -> arg)
\stoplambda
- According to the \GHC documentation, this is the only use for the extra
+ According to the \GHC\ documentation, this is the only use for the extra
binder to which the scrutinee is bound. When not using strictness
annotations (which is rather pointless in hardware descriptions),
\small{GHC} seems to never generate any code making use of this binder.
- In fact, \GHC has never been observed to generate code using this
+ In fact, \GHC\ has never been observed to generate code using this
binder, even when strictness was involved. Nonetheless, the prototype
handles this binder as expected.
equivalent type. Note that this is not meant to do any actual work, like
conversion of data from one format to another, or force a complete type
change. Instead, it is meant to change between different representations
- of the same type, \eg switch between types that are provably equal (but
+ of the same type, \eg\ switch between types that are provably equal (but
look different).
In our hardware descriptions, we typically see casts to change between a
In Core, every expression is typed. The translation to Core happens
after the typechecker, so types in Core are always correct as well
(though you could of course construct invalidly typed expressions
- through the \GHC API).
+ through the \GHC\ API).
Any type in core is one of the following:
Without going into the implementation details, a dictionary can be
seen as a lookup table all the methods for a given (single) type class
instance. This means that all the dictionaries for the same type class
- look the same (\eg contain methods with the same names). However,
+ look the same (\eg\ contain methods with the same names). However,
dictionaries for different instances of the same class contain
different methods, of course.
Word} and \hs{Word} types by pattern matching and by using the explicit
the \hs{State constructor}.
- This explicit conversion makes the \VHDL generation easier: Whenever we
+ This explicit conversion makes the \VHDL\ generation easier: Whenever we
remove (unpack) the \hs{State} type, this means we are accessing the
current state (\eg, accessing the register output). Whenever we are a
adding (packing) the \hs{State} type, we are producing a new value for
\subsubsection{Different input and output types}
An alternative could be to use different types for input and output
- state (\ie current and updated state). The accumulator example would
+ state (\ie\ current and updated state). The accumulator example would
then become something like:
\starthaskell
Now its clear how to put state annotations in the Haskell source,
there is the question of how to implement this state translation. As
we have seen in \in{section}[sec:prototype:design], the translation to
- \VHDL happens as a simple, final step in the compilation process.
+ \VHDL\ happens as a simple, final step in the compilation process.
This step works on a core expression in normal form. The specifics
of normal form will be explained in
\in{chapter}[chap:normalization], but the examples given should be
Before describing how to translate state from normal form to
\VHDL, we will first see how state handling looks in normal form.
What limitations are there on their use to guarantee that proper
- \VHDL can be generated?
+ \VHDL\ can be generated?
We will try to formulate a number of rules about what operations are
allowed with state variables. These rules apply to the normalized Core
The prototype currently does not check much of the above
conditions. This means that if the conditions are violated,
sometimes a compile error is generated, but in other cases output
- can be generated that is not valid \VHDL or at the very least does
+ can be generated that is not valid \VHDL\ or at the very least does
not correspond to the input.
\subsection{Translating to \VHDL}
- As noted above, the basic approach when generating \VHDL for stateful
+ As noted above, the basic approach when generating \VHDL\ for stateful
functions is to generate a single register for every stateful function.
We look around the normal form to find the let binding that removes the
\lam{State} newtype (using a cast). We also find the let binding that
This approach seems simple enough, but will this also work for more
complex stateful functions involving substates? Observe that any
- component of a function's state that is a substate, \ie passed on as
+ component of a function's state that is a substate, \ie\ passed on as
the state of another function, should have no influence on the
hardware generated for the calling function. Any state-specific
\small{VHDL} for this component can be generated entirely within the
called function. So, we can completely ignore substates when
- generating \VHDL for a function.
+ generating \VHDL\ for a function.
From this observation it might seem logical to remove the
substates from a function's states altogether and leave only the
to \lam{s'}. However, \lam{s'} is build up from both \lam{accs'} and
\lam{count'}, while only \lam{count'} should end up in the register.
\lam{accs'} is a substate for the \lam{acc} function, for which a
- register will be created when generating \VHDL for the \lam{acc}
+ register will be created when generating \VHDL\ for the \lam{acc}
function.
Fortunately, the \lam{accs'} variable (and any other substate) has a
property that we can easily check: It has a \lam{State} type
- annotation. This means that whenever \VHDL is generated for a tuple
+ annotation. This means that whenever \VHDL\ is generated for a tuple
(or other algebraic type), we can simply leave out all elements that
have a \lam{State} type. This will leave just the parts of the state
that do not have a \lam{State} type themselves, like \lam{count'},
When applying these rules to the description in
\in{example}[ex:AvgStateNormal], we be left with the description
in \in{example}[ex:AvgStateRemoved]. All the parts that do not
- generate any \VHDL directly are crossed out, leaving just the
+ generate any \VHDL\ directly are crossed out, leaving just the
actual flow of values in the final hardware.
\startlambda
removed, leaving us just with the state of \lam{avg} itself.
As an illustration of the result of this function,
- \in{example}[ex:AccStateVHDL] and \in{example}[ex:AvgStateVHDL] show the the \VHDL that is
+ \in{example}[ex:AccStateVHDL] and \in{example}[ex:AvgStateVHDL] show the the \VHDL\ that is
generated from the examples is this section.
\startbuffer[AvgStateVHDL]
end architecture structural;
\stopbuffer
- \placeexample[][ex:AccStateVHDL]{\VHDL generated for acc from \in{example}[ex:AvgState]}
+ \placeexample[][ex:AccStateVHDL]{\VHDL\ generated for acc from \in{example}[ex:AvgState]}
{\typebuffer[AccStateVHDL]}
- \placeexample[][ex:AvgStateVHDL]{\VHDL generated for avg from \in{example}[ex:AvgState]}
+ \placeexample[][ex:AvgStateVHDL]{\VHDL\ generated for avg from \in{example}[ex:AvgState]}
{\typebuffer[AvgStateVHDL]}
% \subsection{Initial state}
% How to specify the initial state? Cannot be done inside a hardware
% This file defines some useful shortcut commands
%
-\def\autoinsertnextspace{}
-
% A shortcut for italicized e.g. and i.e.
-\define[0]\eg{{\em e.g.}\autoinsertnextspace}
-\define[0]\ie{{\em i.e.}\autoinsertnextspace}
+\define[0]\eg{{\em e.g.}}
+\define[0]\ie{{\em i.e.}}
% Define a new reference to a definition of the term. The text of the
\define[1]\refdef{\inothermargin{\goto{\ref[t][def:#1] p.\ref[p][def:#1]}[def:#1]}}
% Shortcuts to write in smallcaps
-\def\VHDL{\small{VHDL}\autoinsertnextspace}
-\def\GHC{\small{GHC}\autoinsertnextspace}
+\def\VHDL{\small{VHDL}}
+\def\GHC{\small{GHC}}
% TODO: Use this instead of $ to fool syntax highlighting
\def\${\char36}