From 68dfe53b5995913363ac3fa0240e789e6774cf8a Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Sun, 13 Dec 2009 21:00:16 +0100 Subject: [PATCH] Add rest of my presentation --- Makefile | 5 +- christiaan/introduction.lhs | 9 +- christiaan/recursion.lhs | 63 ++++++++++++ christiaan/reductioncircuit.lhs | 106 +++++++++++++++++++++ christiaan/structure.lhs | 164 ++++++++++++++++++++++++++++++++ treeadder.pdf | Bin 0 -> 10052 bytes 6 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 christiaan/recursion.lhs create mode 100644 christiaan/reductioncircuit.lhs create mode 100644 christiaan/structure.lhs create mode 100644 treeadder.pdf diff --git a/Makefile b/Makefile index b4b9a3f..ddaa3fc 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,10 @@ LHSRCS = \ matthijs/introduction.lhs \ christiaan/introduction.lhs \ christiaan/fir.lhs \ - christiaan/dotproduct.lhs + christiaan/dotproduct.lhs \ + christiaan/structure.lhs \ + christiaan/reductioncircuit.lhs \ + christiaan/recursion.lhs LHFORMATS = \ talk.fmt diff --git a/christiaan/introduction.lhs b/christiaan/introduction.lhs index e88a32b..bb142fa 100644 --- a/christiaan/introduction.lhs +++ b/christiaan/introduction.lhs @@ -4,6 +4,13 @@ \author{Christiaan Baaij} \date{December 14, 2009} +\section{Presentation Christiaan} \frame{\titlepage \setcounter{framenumber}{1}} -\input{christiaan/fir} \ No newline at end of file +\input{christiaan/fir} +\input{christiaan/structure} +\input{christiaan/reductioncircuit} +\input{christiaan/recursion} + +\section{Questions} +\frame{\vspace{2cm}\centerline{\Huge{Questions?}}} \ No newline at end of file diff --git a/christiaan/recursion.lhs b/christiaan/recursion.lhs new file mode 100644 index 0000000..c388355 --- /dev/null +++ b/christiaan/recursion.lhs @@ -0,0 +1,63 @@ +\section{Recursion} +%include talk.fmt +\frame{ +\frametitle{Future Work: Recursion} +\begin{itemize} + \item The most pressing future work is to support recursive functions. + \item Partially explored solution: static loop unrolling + \item Unexplored solution: Haskell language extensions, new source language +\end{itemize} +} + +\subsection{Static loop unrolling} +\frame{ +\frametitle{Static loop unrolling} +\begin{itemize} + \item Unroll, and simplify recursive definitions at compile time. + \item Explored solution: Unrolling number-guided recursive functions using Template Haskell +\end{itemize} +} + +\frame{ +\frametitle{Template Haskell} +\begin{itemize} + \item Template Haskell allows for compile-time inspection, construction, and manipulation of Haskell code. + \item All these functions are expressible in normal Haskell +\end{itemize} +} + +\frame{ +\frametitle{Tree Adder} +\begin{verbatim} +$(do + [typ, _] <- [d|{ +treeSum :: Vector D8 (SizedWord D8) -> SizedWord D8; +treeSum xs = undefined + }|] + [func] <- [d|{ +treeSum i xs | i < 1 = head xs + | otherwise = let (a,b) = split xs + in (treeSum (i-1) a) + + (treeSum (i-1) b) + }|] + let func' = unroll Nothing 0 (IntegerL 3) funct + return [typ,func'] +) +\end{verbatim} +} + +\begin{frame} + \frametitle{Unrolled tree adder} + \begin{figure} + \includegraphics[height=5cm]{treeadder} + \end{figure} +\end{frame} + +\subsection{Input Language} +\frame{ +\frametitle{Input Language} +\begin{itemize} + \item New source language: One of the problems is that Haskell does not properly support dependent types. Investigate languages with dependent type systems. + \item Haskell extentions: Invariant descriptions at the type-level. +\end{itemize} +} \ No newline at end of file diff --git a/christiaan/reductioncircuit.lhs b/christiaan/reductioncircuit.lhs new file mode 100644 index 0000000..a4f55f6 --- /dev/null +++ b/christiaan/reductioncircuit.lhs @@ -0,0 +1,106 @@ +\section{Restrictions} +%include talk.fmt +\frame{ +\frametitle{Too Restrictive?} +\begin{itemize} + \item Is CλasH too restrictive given the fact that a designer can currently not define his own vector transformations, or recursive functions for that matter? +\end{itemize} +} + +\frame{ +\frametitle{Too Restrictive?} +\begin{itemize} + \item There is certainly room to increase expressivity. But we can already describe non-trivial design in CλasH. + \item Example: Reduction circuit +\end{itemize} +} + +\section{Reduction circuit} + +\frame{ +\frametitle{Reduction Circuit} +\begin{columns}[l] +\column{0.5\textwidth} +\begin{figure} +\includegraphics[height=6.5cm]{reducer} +\end{figure} +\column{0.5\textwidth} +\begin{itemize} + \item Reduction circuit sums the floating-point values of each row in a matrix. + \item Non-trivial due to pipe-lined floating-point adder. + \item Largest restrictions are the fixed-size vectors. +\end{itemize} +\end{columns} +} + +\begin{frame} + \begin{figure} + \includegraphics[height=9cm]{reducerschematic} + \end{figure} +\end{frame} + + +\begin{frame} +\frametitle{FIFO Buffer} +\begin{itemize} + \item Wish: +\begin{verbatim} +fifo :: (State mem) (input, shift) = + (State mem', out1, out2) + where + out1 | length mem == 0 = NotValid + | otherwise = head mem + out2 | length mem < 2 = NotValid + | otherwise = head (tail mem) + mem' = drop shift mem ++ [input] +\end{verbatim} +\end{itemize} +\end{frame} + +\begin{frame} +\frametitle{FIFO Buffer} +\begin{itemize} + \item Reality: +\begin{verbatim} +fifo :: (State (Fifo {..})) (inp, shift) = + ( State (Fifo { mem = mem' + , ptr = ptr' + }) + , out1, out2 + ) + where + ptr' = ptr - shift + 1 + mem'' = replace mem ptr (Valid inp) + mem' | shift == 0 = mem'' + | shift == 1 = (tail mem'') <+ NotValid + | otherwise = ((tail (tail mem'') + <+ NotValid) <+ NotValid) + out1 = head mem + out2 = head (tail mem) +\end{verbatim} +\end{itemize} +\end{frame} + +\frame{ +\frametitle{FIFO Buffer} +\begin{itemize} + \item Wish: Dynamically sized vectors + \item Reality: Statically sized vectors +\end{itemize} +} + +\frame{ +\frametitle{Dynamically Sized Vectors} +\begin{itemize} + \item Map all vectors to RAMs: + \begin{itemize} + \item Store length separately, extra logic + \item What happens if size exceeds size of 1 blockRAM? + \end{itemize} + \item Translate to (shift/circular) Buffers + \begin{itemize} + \item Requires analysis of data-access + \item How do we determine maximum size? + \end{itemize} +\end{itemize} +} \ No newline at end of file diff --git a/christiaan/structure.lhs b/christiaan/structure.lhs new file mode 100644 index 0000000..2c81397 --- /dev/null +++ b/christiaan/structure.lhs @@ -0,0 +1,164 @@ +\section{Structure} +%include talk.fmt +\frame{ +\frametitle{Structure} +\begin{verbatim} +fir (State pxs) x = (pxs**hs, State (pxs<++x)) + where hs = $(vectorTH [2::Int16,3,-2,4]) +\end{verbatim} +\begin{itemize} + \item How did we know how big the circuit would have to be? e.g. How many multipliers? + \item The size of the circuit is determined by the size of the vectors! +\end{itemize} +} + +\frame{ +\frametitle{Structure} +\begin{itemize} + \item The size of the vectors determines the size of the circuit. + \item How do we know the size of the vectors? + \begin{itemize} + \item We infer the size + \item We specify the size + \end{itemize} +\end{itemize} +} + +\subsection{Size Inference} +\frame{ +\frametitle{Infer Size} +\begin{itemize} + \item Determine the size by counting the elements inside, at compile-time. + \item Base size of new vectors based on size of other vectors of which you already know the size. + \item Requires a lot of bookkeeping. +\end{itemize} +} + +\frame{ +\frametitle{Infer Size} +\begin{itemize} + \item Might not be possible in the general case? + \item What is the size of the combinatorial circuit seen below? Infinite? Zero? +\end{itemize} +\begin{verbatim} + xs ** hs = foldl (+) 0 (zipWith (*) xs hs) +\end{verbatim} +} + +\subsection{Size Specification} +\frame{ +\frametitle{Specify Size} +\begin{itemize} + \item Have the designer specify the size of a vector. + \item Two ways to specify + \begin{itemize} + \item As part of each specific instance / term + \item As part of the type + \end{itemize} +\end{itemize} +} + +\frame{ +\frametitle{Some basic concepts} +\begin{itemize} + \item Programming languages express computations + \item Computations manipulate values + \item Types = Set of values + \item Computations can be assigned types to indicate what kind of values to produce or manipulate +\end{itemize} +} + +\frame{ +\frametitle{Specify Size (term-level)} +\begin{itemize} + \item Size specification at the instance / term level suffers from the same problems as size inference: + \begin{itemize} + \item Extensive bookkeeping + \item Compile Time-Evaluation + \item Generality of the solution + \end{itemize} +\end{itemize} +} + +\frame{ +\frametitle{Specify Size (type-level)} +\begin{itemize} + \item The size of the vector becomes part of the type: + \begin{itemize} + \item Unconstrained Vectors: + \begin{verbatim} +Nat n => Vector n a + \end{verbatim} + \item Constrained Vectors: + \begin{verbatim} +Vector 4 a + \end{verbatim} + \end{itemize} +\end{itemize} +} + +\frame{ +\frametitle{Specify Size (type-level)} +\begin{itemize} + \item Not only do we want to indicate the size of vectors + \item We also want to manipulate or query the size of a vector +\end{itemize} +} + +\frame{ +\frametitle{Size Query} +\begin{itemize} + \item Sometimes we want to know something about the size of the vector + \item Get the first element of the vector + \begin{verbatim} +first :: Positive n => Vector n a -> a + \end{verbatim} + \item Only works for vectors that are not empty +\end{itemize} +} + +\frame{ +\frametitle{Size Manipulation} +\begin{itemize} + \item Sometimes we want to relate the size of one or more vectors to the size of one or more other vectors + \item Combine 2 vectors into 1 large vector + \begin{verbatim} +combine :: Vector n1 a -> Vector n2 a -> + Vector (n1 + n2) a + \end{verbatim} +\end{itemize} +} + +\frame{ +\frametitle{Type-level numbers} +\begin{itemize} + \item Number literals, e.g. 1, 4 , 17, etc. are not allowed in the type signature. + \item We must resort to so-called type-level numbers + \item When dealing with type-level number,s each instance is a type in it’s own right! e.g. the type-level equivalent of 3 is D3. +\end{itemize} +} + +\frame{ +\frametitle{Type-level problems} +\begin{itemize} + \item Type systems demand proofs! Otherwise they are of no use to us! + \item When dealing with type-level numbers we suddenly have to proof invariants that we normally take for granted. + \item For example, commutativity of addition:\\ a + b = b + a +\end{itemize} +} + +\frame{ +\frametitle{Consequences} +\begin{itemize} + \item Currently such proofs have to specified as part of the programs, and in a very cumbersome way! + \item We chose not to expose this need for proofs to the developer. + \item Result: a (limited) set of vector transformations is exposed to a developer. +\end{itemize} +} + +\frame{ +\frametitle{Consequences} +\begin{itemize} + \item The largest consequence of not allowing any type of vector transforming functions is that a developer can no longer specify recursive functions! +\end{itemize} +} \ No newline at end of file diff --git a/treeadder.pdf b/treeadder.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f547b57bb31085b991ccd13d16906c30d10c77e7 GIT binary patch literal 10052 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