From f020910d25275d30922e6aac94935244142dcd30 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Fri, 26 Sep 2025 14:04:14 +0200 Subject: [PATCH 1/2] Remove content from Clash.Tutorial module The actual tutorial has been moved to: https://docs.clash-lang.org/tutorial/ Parts that belong to the Clash compiler user guide have been moved to: https://docs.clash-lang.org/compiler-user-guide/ --- .../2025-09-26T14_06_42+02_00_move_tutorial | 5 + clash-prelude/clash-prelude.cabal | 7 +- .../src/Clash/Explicit/Synchronizer.hs | 1 - clash-prelude/src/Clash/Prelude.hs | 5 +- clash-prelude/src/Clash/Prelude/Safe.hs | 5 +- clash-prelude/src/Clash/Tutorial.hs | 2492 +---------------- 6 files changed, 21 insertions(+), 2494 deletions(-) create mode 100644 changelog/2025-09-26T14_06_42+02_00_move_tutorial diff --git a/changelog/2025-09-26T14_06_42+02_00_move_tutorial b/changelog/2025-09-26T14_06_42+02_00_move_tutorial new file mode 100644 index 0000000000..37ad3bf128 --- /dev/null +++ b/changelog/2025-09-26T14_06_42+02_00_move_tutorial @@ -0,0 +1,5 @@ +CHANGED: The content from the `Clash.Tutorial` module has been split and moved to two new locations. +1. The actual tutorial parts has been moved to: https://docs.clash-lang.org/tutorial/ +2. Parts that fit better in the clash compiler user guide have been moved to: https://docs.clash-lang.org/compiler-user-guide/ + +Moving the documentation to these locations makes it easier to update their content as it is no longer needed to release a new version of the `clash-prelude` package for the publication of this content. diff --git a/clash-prelude/clash-prelude.cabal b/clash-prelude/clash-prelude.cabal index 8f050f62b2..ea96d94075 100644 --- a/clash-prelude/clash-prelude.cabal +++ b/clash-prelude/clash-prelude.cabal @@ -39,9 +39,10 @@ Description: "Clash.Prelude" and "Clash.Explicit.Prelude" at the same time as they have overlapping definitions. . - A preliminary version of a tutorial can be found in "Clash.Tutorial", for a - general overview of the library you should however check out "Clash.Prelude". - Some circuit examples can be found in "Clash.Examples". + A preliminary version of a tutorial can be found at + , for a general overview of the library + you should however check out "Clash.Prelude". Some circuit examples can be + found in "Clash.Examples". Homepage: https://clash-lang.org/ bug-reports: https://github.com/clash-lang/clash-compiler/issues License: BSD-2-Clause diff --git a/clash-prelude/src/Clash/Explicit/Synchronizer.hs b/clash-prelude/src/Clash/Explicit/Synchronizer.hs index f5987ed1a3..533a4f2a13 100644 --- a/clash-prelude/src/Clash/Explicit/Synchronizer.hs +++ b/clash-prelude/src/Clash/Explicit/Synchronizer.hs @@ -193,7 +193,6 @@ isFull addrSize@SNat ptr s_ptr = in ptr == (complement (slice addrSize a1 s_ptr) ++# slice a2 d0 s_ptr) -- | Synchronizer implemented as a FIFO around a synchronous RAM. Based on the --- design described in "Clash.Tutorial#multiclock", which is itself based on the -- design described in . -- However, this FIFO uses a synchronous dual-ported RAM which, unlike those -- designs using RAM with an asynchronous read port, is nearly guaranteed to diff --git a/clash-prelude/src/Clash/Prelude.hs b/clash-prelude/src/Clash/Prelude.hs index dd61b4ad12..1032d3187c 100644 --- a/clash-prelude/src/Clash/Prelude.hs +++ b/clash-prelude/src/Clash/Prelude.hs @@ -29,8 +29,9 @@ have overlapping definitions. For now, "Clash.Prelude" is also the best starting point for exploring the - library. A preliminary version of a tutorial can be found in "Clash.Tutorial". - Some circuit examples can be found in "Clash.Examples". + library. A preliminary version of a tutorial can be found at + https://docs.clash-lang.org/tutorial. Some circuit examples can be found in + "Clash.Examples". -} {-# LANGUAGE CPP #-} diff --git a/clash-prelude/src/Clash/Prelude/Safe.hs b/clash-prelude/src/Clash/Prelude/Safe.hs index 8d2cf73b0b..954e8af640 100644 --- a/clash-prelude/src/Clash/Prelude/Safe.hs +++ b/clash-prelude/src/Clash/Prelude/Safe.hs @@ -26,8 +26,9 @@ explicitly clocked circuits in a multi-clock setting For now, "Clash.Prelude" is also the best starting point for exploring the - library. A preliminary version of a tutorial can be found in "Clash.Tutorial". - Some circuit examples can be found in "Clash.Examples". + library. A preliminary version of a tutorial can be found at + https://docs.clash-lang.org/tutorial. Some circuit examples can be found in + "Clash.Examples". -} {-# LANGUAGE CPP #-} diff --git a/clash-prelude/src/Clash/Tutorial.hs b/clash-prelude/src/Clash/Tutorial.hs index ed9da61acb..ca51656e50 100644 --- a/clash-prelude/src/Clash/Tutorial.hs +++ b/clash-prelude/src/Clash/Tutorial.hs @@ -10,2496 +10,16 @@ Licence : Creative Commons 4.0 (CC BY 4.0) (https://creativecommons.org/licens Maintainer: QBayLogic B.V. -} -{-# LANGUAGE NoImplicitPrelude #-} - -{-# OPTIONS_GHC -fno-warn-unused-imports #-} - module Clash.Tutorial ( - -- * Introduction - -- $introduction - - -- * Install Clash - -- $installation - - -- * Working with this tutorial - -- $working - - -- * Your first circuit - -- $mac_example - - -- *** Sequential circuit - -- $mac2 - - -- *** Generating VHDL - -- $mac3 - - -- *** Circuit testbench - -- $mac4 - - -- *** Generating Verilog and SystemVerilog - -- $mac5 - - -- *** Alternative specifications - -- $mac6 - - -- * Higher-order functions - -- $higher_order - - -- * Composition of sequential circuits - -- $composition_sequential - - -- * Synthesize annotations: controlling the VHDL\/(System)Verilog generation. - -- $annotations - - -- * Multiple clock domains - -- $multiclock - - -- * Advanced: Primitives - -- $primitives - - -- *** Verilog primitives - -- $vprimitives - - -- *** SystemVerilog primitives - -- $svprimitives - - -- * Conclusion - -- $conclusion - - -- * Troubleshooting - -- $errorsandsolutions - - -- * Limitations of Clash - -- $limitations - - -- * Clash vs Lava - -- $vslava - - -- * Migration guide from Clash 0.99 - -- $migration + -- * The content of this page has been moved + -- $moved ) where -import Clash.Prelude -import Clash.Prelude.Mealy -import Clash.Explicit.Testbench -import Clash.XException (NFDataX) -import Control.Monad.ST -import Data.Array -import Data.Char -import Data.Int -import GHC.Prim -import GHC.TypeLits -import GHC.Word -import GHC.Stack -import Data.Default - -{- $setup ->>> :set -XTemplateHaskell -XDataKinds -XConstraintKinds -XTypeApplications ->>> :m -Prelude ->>> import Clash.Prelude ->>> import Clash.Prelude.Mealy ->>> import Clash.Explicit.Testbench ->>> :{ -let ma :: Num a => a -> (a, a) -> a - ma acc (x,y) = acc + x * y -:} - ->>> :{ -let macT :: Num a => a -> (a,a) -> (a,a) - macT acc (x,y) = (acc',o) - where - acc' = ma acc (x,y) - o = acc -:} - ->>> :set -XFlexibleContexts ->>> :set -fplugin GHC.TypeLits.Normalise ->>> let compareSwapL a b = if a < b then (a,b) else (b,a) ->>> :{ -let sortV xs = map fst sorted :< (snd (last sorted)) - where - lefts = head xs :> map snd (init sorted) - rights = tail xs - sorted = zipWith compareSwapL lefts rights -:} - ->>> :{ -let sortVL xs = map fst sorted :< (snd (last sorted)) - where - lefts = head xs :> map snd (init sorted) - rights = tail xs - sorted = zipWith compareSwapL (lazyV lefts) rights -:} - ->>> let mac = mealy macT 0 ->>> :{ -let topEntity - :: Clock System - -> Reset System - -> Enable System - -> Signal System (Signed 9, Signed 9) - -> Signal System (Signed 9) - topEntity = exposeClockResetEnable mac -:} - ->>> :{ -let testBench :: Signal System Bool - testBench = done - where - testInput = stimuliGenerator clk rst $(listToVecTH [(1,1) :: (Signed 9,Signed 9),(2,2),(3,3),(4,4)]) - expectedOutput = outputVerifier' clk rst $(listToVecTH [0 :: Signed 9,1,5,14,14,14,14]) - done = expectedOutput (topEntity clk rst enableGen testInput) - clk = tbSystemClockGen (not <$> done) - rst = systemResetGen -:} - ->>> :{ -let fibR :: Unsigned 64 -> Unsigned 64 - fibR 0 = 0 - fibR 1 = 1 - fibR n = fibR (n-1) + fibR (n-2) -:} - ->>> :{ -let fibS :: SystemClockResetEnable => Signal System (Unsigned 64) - fibS = r - where r = register 0 r + register 0 (register 1 r) -:} - --} - -{- $introduction -Clash is a functional hardware description language that borrows both its syntax -and semantics from the functional programming language Haskell. It provides a -familiar structural design approach to both combination and synchronous -sequential circuits. The Clash compiler transforms these high-level descriptions -to low-level synthesizable VHDL, Verilog, or SystemVerilog. - -Features of Clash: - - * Strongly typed, but with a very high degree of type inference, enabling - both safe and fast prototyping using concise descriptions. - * Interactive REPL: load your designs in an interpreter and easily test all - your component without needing to setup a test bench. - * Compile your designs for fast simulation. - * Higher-order functions, in combination with type inference, result in - designs that are fully parametric by default. - * Synchronous sequential circuit design based on streams of values, called - @Signal@s, lead to natural descriptions of feedback loops. - * Multiple clock domains, with type safe clock domain crossing. - * Template language for introducing new VHDL/(System)Verilog primitives. - -Although we say that Clash borrows the semantics of Haskell, that statement -should be taken with a grain of salt. What we mean to say is that the Clash -compiler views a circuit description as /structural/ description. This means, -in an academic handwavy way, that every function denotes a component and every -function application denotes an instantiation of said component. Now, this has -consequences on how we view /recursively/ defined functions: structurally, a -recursively defined function would denote an /infinitely/ deep / structured -component, something that cannot be turned into an actual circuit -(See also <#limitations Limitations of Clash>). - -On the other hand, Haskell's by-default non-strict evaluation works very well -for the simulation of the feedback loops, which are ubiquitous in digital -circuits. That is, when we take our structural view to circuit descriptions, -value-recursion corresponds directly to a feedback loop: - -@ -counter = s - where - s = 'register' 0 (s + 1) -@ - -The above definition, which uses value-recursion, /can/ be synthesized to a -circuit by the Clash compiler. - -Over time, you will get a better feeling for the consequences of taking a -/structural/ view on circuit descriptions. What is always important to -remember is that every applied functions results in an instantiated component, -and also that the compiler will /never/ infer / invent more logic than what is -specified in the circuit description. - -With that out of the way, let us continue with installing Clash and building -our first circuit. --} - -{- $installation -For installation instructions, see . --} - -{- $working -This tutorial can be followed best whilst having the Clash interpreter running -at the same time. If you followed the installation instructions based on -, you can -start the Clash compiler in interpretive mode by: - -> stack exec --resolver lts-19 --package clash-ghc -- clashi - -If instead you followed the [instructions](https://clash-lang.org/install/linux/) -to setup a starter project with Stack, you can also run @clashi@ inside such a -project. Change to the directory of the project, and invoke - -> stack run -- clashi - -If you instead set up the starter project with GHC and Cabal, change to the -directory of the project and invoke - -> cabal run -- clashi - -For those familiar with Haskell/GHC, this is indeed just @GHCi@, with three -added commands (@:vhdl@, @:verilog@, and @:systemverilog@). You can load files -into the interpreter using the @:l \@ command. Now, depending on your -choice in editor, the following @edit-load-run@ cycle probably work best for you: - - * __Commandline (e.g. emacs, vim):__ - - * You can run system commands using @:!@, for example @:! touch \@ - * Set the /editor/ mode to your favourite editor using: @:set editor \@ - * You can load files using @:l@ as noted above. - * You can go into /editor/ mode using: @:e@ - * Leave the editor mode by quitting the editor (e.g. @:wq@ in @vim@) - - * __GUI (e.g. SublimeText, Notepad++):__ - - * Just create new files in your editor. - * Load the files using @:l@ as noted above. - * Once a file has been edited and saved, type @:r@ to reload the files in - the interpreter - -You are of course free to deviate from these suggestions as you see fit :-). It -is just recommended that you have the Clash interpreter open during this -tutorial. --} - -{- $mac_example -The very first circuit that we will build is the \"classic\" multiply-and-accumulate -(MAC) circuit. This circuit is as simple as it sounds, it multiplies its inputs -and accumulates them. Before we describe any logic, we must first create the -file we will be working on and input some preliminaries: - -* Create the file: - - @ - MAC.hs - @ - -* Write on the first line the module header: - - @ - module MAC where - @ - - Module names must always start with a __C__apital letter. Also make sure that - the file name corresponds to the module name. - -* Add the import statement for the Clash prelude library: - - @ - import Clash.Prelude - @ - - This imports all the necessary functions and datatypes for circuit description. - -We can now finally start describing the logic of our circuit, starting with just -the multiplication and addition: - -@ -ma acc (x, y) = acc + x * y -@ - -The circuit we just wrote is a combinational circuit: no registers are inserted -(you describe explicitly where Clash will insert registers, as we'll later see). We usually -refer to circuits as /functions/, similar to programming languages such as C, -Python, or Haskell. In this case, the function we just defined is called @ma@. -Its first argument is @acc@, its second is @(x, y)@ - a composite type called a -tuple. This component is "unpacked", and its first element is called @x@, its -second @y@. Everything to the right of the equals symbol is @ma@'s -result. -If you followed the instructions of running the interpreter side-by-side, you -can already test this function: - ->>> ma 4 (8, 9) -76 ->>> ma 2 (3, 4) -14 - -We can also examine the inferred type of @ma@ in the interpreter: - ->>> :t ma -ma :: Num a => a -> (a, a) -> a - -You should read this as follows: - - * __@ma ::@__, @ma@ is of type.. - - * __@Num a@__, there is some type called @a@ that is a 'Num'. Examples of - instances of 'Num' are 'Int', @'Signed' 16@, @'Index' 32@, and 'Float'. - - * __@a@__, @ma@'s first argument is of type @a@ - - * __@(a, a)@__, @ma@'s second argument is of type @(a, a)@ - - * __@a@__, @ma@'s result is of type @a@ - -Note that @ma@ therefore works on multiple types! The only condition we -imposed is that @a@ should be a 'Num'ber type. In Clash this means it should -support the operations 'Prelude.+', 'Prelude.-', 'Prelude.*', and some -others. Indeed, this is why Clash adds the constraint in the first place: the -definition of @ma@ uses @+@ and @*@. Whenever a function works over multiple -types, we call it /polymorphic/ ("poly" meaning "many", "morphic" meaning -"forms"). While powerful, its not clear how Clash should synthesize this as -numbers come in a great variety in (bit)sizes. We will later see how to use this -function in a /monomorphic/ manner. - -Talking about /types/ also brings us to one of the most important parts of this -tutorial: /types/ and /synchronous sequential logic/. Especially how we can -always determine, through the types of a specification, if it describes -combinational logic or (synchronous) sequential logic. We do this by examining -the definition of one of the sequential primitives, the 'register' function: - -@ -register - :: ( 'HiddenClockResetEnable' dom - , 'NFDataX' a ) - => a - -> 'Signal' dom a - -> 'Signal' dom a -register i s = ... -@ - -Where we see that the second argument and the result are not just of the -/polymorphic/ @a@ type, but of the type: @'Signal' dom a@. All (synchronous) -sequential circuits work on values of type @'Signal' dom a@. Combinational -circuits always work on values of, well, not of type @'Signal' dom a@. A 'Signal' -is an (infinite) list of samples, where the samples correspond to the values -of the 'Signal' at discrete, consecutive, ticks of the /clock/. All (sequential) -components in the circuit are synchronized to this global /clock/. For the -rest of this tutorial, and probably at any moment where you will be working with -Clash, you should probably not actively think about 'Signal's as infinite lists -of samples, but just as values that are manipulated by sequential circuits. To -make this even easier, it actually not possible to manipulate the underlying -representation directly: you can only modify 'Signal' values through a set of -primitives such as the 'register' function above. - -Now, let us get back to the functionality of the 'register' function: it is -a simple that -only changes state at the tick of the global /clock/, and -it has an initial value @a@ which is its output at time 0. We can further -examine the 'register' function by taking a look at the first 4 samples of the -'register' functions applied to a constant signal with the value 8: - ->>> sampleN @System 4 (register 0 (pure (8 :: Signed 8))) -[0,0,8,8] - -Where we see that the initial value of the signal is the specified 0 value, -followed by 8's. You might be surprised to see /two/ zeros instead of just a -single zero. What happens is that in Clash you get to see the output of the -circuit /before/ the clock becomes active. In other words, in Clash you get to -describe the powerup values of registers too. Whether this is a defined or -unknown value depends on your hardware target, and can be configured by using a -different synthesis 'Domain'. The default synthesis domain, @'System', assumes -that registers do have a powerup value - as is true for most FPGA platforms in -most contexts. --} - -{- $mac2 -The 'register' function is our primary sequential building block to capture -/state/. It is used internally by one of the "Clash.Prelude" function that we -will use to describe our MAC circuit. Note that the following paragraphs will -only show one of many ways to specify a sequential circuit, in the section -<#mac6 Alternative specifications> we will show a couple more. - -A principled way to describe a sequential circuit is to use one of the classic -machine models, within the Clash prelude library offer standard function to -support the . -To improve sharing, we will combine the transition function and output function -into one. This gives rise to the following Mealy specification of the MAC -circuit: - -@ -macT acc (x, y) = (acc', o) - where - acc' = ma acc (x, y) - o = acc -@ - -Note that the @where@ clause and explicit tuple are just for demonstrative -purposes, without loss of sharing we could've also written: - -@ -macT acc inp = (ma acc inp, acc) -@ - -Going back to the original specification we note the following: - - * @acc@ is the current /state/ of the circuit. - * @(x, y)@ is its input. - * @acc'@ is the updated, or next, /state/. - * @o@ is the output. - -When we examine the type of @macT@ we see that is still completely combinational: - ->>> :t macT -macT :: Num a => a -> (a, a) -> (a, a) - -The "Clash.Prelude" library contains a function that creates a sequential -circuit from a combinational circuit that has the same Mealy machine type / -shape of @macT@: - -@ -mealy - :: ('HiddenClockResetEnable' dom, 'NFDataX' s) - => (s -> i -> (s,o)) - -> s - -> ('Signal' dom i -> 'Signal' dom o) -mealy f initS = ... -@ - -The complete sequential MAC circuit can now be specified as: - -@ -mac inp = 'mealy' macT 0 inp -@ - -Where the first argument of 'mealy' is our @macT@ function, and the second -argument is the initial state, in this case 0. We can see it is functioning -correctly in our interpreter: - ->>> import qualified Data.List as L ->>> L.take 4 $ simulate @System mac [(1,1),(2,2),(3,3),(4,4)] -[0,1,5,14] - -Where we simulate our sequential circuit over a list of input samples and take -the first 4 output samples. We have now completed our first sequential circuit -and have made an initial confirmation that it is working as expected. --} - -{- $mac3 -We are now almost at the point that we can create actual hardware, in the form -of a netlist, from our sequential -circuit specification. The first thing we have to do is create a function -called @topEntity@ and ensure that it has a __monomorphic__ type. In our case -that means that we have to give it an explicit type annotation. It might not -always be needed, you can always check the type with the @:t@ command and see -if the function is monomorphic: - -@ -topEntity - :: 'Clock' 'System' - -> 'Reset' 'System' - -> 'Enable' 'System' - -> 'Signal' 'System' ('Signed' 9, 'Signed' 9) - -> 'Signal' 'System' ('Signed' 9) -topEntity = 'exposeClockResetEnable' mac -@ - -Which makes our circuit work on 9-bit signed integers. Including the above -definition, our complete @MAC.hs@ should now have the following content: - -@ -module MAC where - -import "Clash.Prelude" - -ma acc (x,y) = acc + x * y - -macT acc (x,y) = (acc',o) - where - acc' = ma acc (x,y) - o = acc - -mac xy = 'mealy' macT 0 xy - -topEntity - :: 'Clock' 'System' - -> 'Reset' 'System' - -> 'Enable' 'System' - -> 'Signal' 'System' ('Signed' 9, 'Signed' 9) - -> 'Signal' 'System' ('Signed' 9) -topEntity = 'exposeClockResetEnable' mac -@ - -The @topEntity@ function is the starting point for the Clash compiler to -transform your circuit description into a VHDL netlist. It must meet the -following restrictions in order for the Clash compiler to work: - - * It must be completely monomorphic - * It must be completely first-order - * Although not strictly necessary, it is recommended to /expose/ 'Hidden' - clock and reset arguments, as it makes user-controlled - in the generated HDL - easier to do. - -Our @topEntity@ meets those restrictions, and so we can convert it successfully -to VHDL by executing the @:vhdl@ command in the interpreter. This will create -a directory called @vhdl@, which contains a directory called @MAC@, which -ultimately contains all the generated VHDL files. You can now load these files -into your favourite VHDL synthesis tool, marking @topentity.vhdl@ as the file -containing the top level entity. --} - -{- $mac4 -There are multiple reasons as to why you might want to create a so-called -/test bench/ for the generated HDL: - - * You want to compare post-synthesis / post-place&route behavior to that of - the behavior of the original generated HDL. - * Need representative stimuli for your dynamic power calculations. - * Verify that the HDL output of the Clash compiler has the same behavior as - the Haskell / Clash specification. - -For these purposes, you can have the Clash compiler generate a /test bench/. In -order for the Clash compiler to do this you need to do one of the following: - - * Create a function called /testBench/ in the root module. - * Annotate your /topEntity/ function (or function with a - annotation) - with a 'TestBench' annotation. - -For example, you can test the earlier defined /topEntity/ by: - -@ -import "Clash.Explicit.Testbench" - -topEntity - :: 'Clock' System - -> 'Reset' System - -> 'Enable' System - -> 'Signal' System ('Signed' 9, 'Signed' 9) - -> 'Signal' System ('Signed' 9) -topEntity = 'exposeClockResetEnable' mac - -testBench :: 'Signal' System Bool -testBench = done - where - testInput = 'stimuliGenerator' clk rst $('listToVecTH' [(1,1) :: ('Signed' 9,'Signed' 9),(2,2),(3,3),(4,4)]) - expectOutput = 'outputVerifier'' clk rst $('listToVecTH' [0 :: 'Signed' 9,1,5,14,14,14,14]) - done = expectOutput (topEntity clk rst en testInput) - en = 'enableGen' - clk = 'tbSystemClockGen' (not '<$>' done) - rst = 'systemResetGen' -@ - -This will create a stimulus generator that creates the same inputs as we used -earlier for the simulation of the circuit, and creates an output verifier that -compares against the results we got from our earlier simulation. We can even -simulate the behavior of the /testBench/: - ->>> sampleN 8 testBench -[False,False,False,False,False -cycle(): 5, outputVerifier -expected value: 14, not equal to actual value: 30 -,False -cycle(): 6, outputVerifier -expected value: 14, not equal to actual value: 46 -,False -cycle(): 7, outputVerifier -expected value: 14, not equal to actual value: 62 -,False] - -We can see that for the first 4 samples, everything is working as expected, -after which warnings are being reported. The reason is that 'stimuliGenerator' -will keep on producing the last sample, (4,4), while the 'outputVerifier'' will -keep on expecting the last sample, 14. In the VHDL testbench these errors won't -show, as the global clock will be stopped after 4 ticks. - -You should now again run @:vhdl@ in the interpreter; this time the compiler -will take a bit longer to generate all the circuits. Inside the @.\/vhdl\/MAC@ -directory you will now also find a /testbench/ subdirectory containing all the -@vhdl@ files for the /test bench/. - - -After compilation is finished you load all the files in your favourite VHDL -simulation tool. Once all files are loaded into the VHDL simulator, run the -simulation on the @testbench@ entity. -On questasim / modelsim: doing a @run -all@ will finish once the output verifier -will assert its output to @true@. The generated testbench, modulo the clock -signal generator(s), is completely synthesizable. This means that if you want to -test your circuit on an FPGA, you will only have to replace the clock signal -generator(s) by actual clock sources, such as an onboard PLL. --} - -{- $mac5 -Aside from being able to generate VHDL, the Clash compiler can also generate Verilog -and SystemVerilog. You can repeat the previous two parts of the tutorial, but -instead of executing the @:vhdl@ command, you execute the @:verilog@ or -@:sytemverilog@ command in the interpreter. This will create a directory called -@verilog@, respectively @systemverilog@, which contains a directory called @MAC@, -which ultimately contains all the generated Verilog and SystemVerilog files. -Verilog files end in the file extension @v@, while SystemVerilog files end in -the file extension @sv@. - -This concludes the main part of this section on \"Your first circuit\", read on -for alternative specifications for the same @mac@ circuit, or just skip to the -next section where we will describe another DSP classic: an FIR filter -structure. --} - -{- $mac6 #mac6# - -* __'Num' instance for 'Signal'__: - - @'Signal' a@ is also also considered a 'Num'eric type as long as the value - type /a/ is also 'Num'eric. This means that we can also use the standard - numeric operators, such as ('GHC.Num.*') and ('GHC.Num.+'), directly on signals. An - alternative specification of the @mac@ circuit will also use the 'register' - function directly: - - @ - macN xy = acc - where - (x,y) = 'unbundle' xy - acc = 'register' 0 (acc + x * y) - @ - -* __'Applicative' instance for 'Signal'__: - - We can also mix the combinational @ma@ function, with the sequential - 'register' function, by lifting the @ma@ function to the sequential 'Signal' - domain using the operators ('<$>' and '<*>') of the 'Applicative' type - class: - - @ - macA xy = acc - where - acc = 'register' 0 acc' - acc' = ma '<$>' acc '<*>' xy - @ - -* __t'Control.Monad.State.Strict.State' Monad__ - - We can also implement the original @macT@ function as - a t'Control.Monad.State.Strict.State' monadic computation. First we must add - an extra import statement, right after the import of "Clash.Prelude": - - @ - import Control.Monad.State.Strict - @ - - We can then implement macT as follows: - - @ - macTS (x,y) = do - acc <- 'Control.Monad.State.Strict.get' - 'Control.Monad.State.Strict.put' (acc + x * y) - return acc - @ - - We can use the 'mealyS' function to run our stateful implementation, this - can simplify translating algorithms which are described imperatively. - - @ - mealyS - :: ( HiddenClockResetEnable dom, NFDataX s ) - => (i -> State s o) - -> s - -> (Signal dom i -> Signal dom o) - mealyS f initS = ... - @ - - We can then create the complete @mac@ circuit as: - - @ - macS xy = 'mealyS' macTS 0 xy - @ --} - -{- $higher_order -An FIR filter is defined as: the dot-product of a set of filter coefficients and -a window over the input, where the size of the window matches the number -of coefficients. - -@ -dotp as bs = 'sum' ('zipWith' (*) as bs) - -fir coeffs x_t = y_t - where - y_t = dotp coeffs xs - xs = 'window' x_t - -topEntity - :: 'Clock' 'System' - -> 'Reset' 'System' - -> 'Enable' 'System' - -> 'Signal' 'System' ('Signed' 16) - -> 'Signal' 'System' ('Signed' 16) -topEntity = exposeClockResetEnable (fir (0 ':>' 1 ':>' 2 ':>' 3 ':>' 'Nil')) -@ - -Here we can see that, although the Clash compiler handles recursive function -definitions poorly, many of the regular patterns that we often encounter in -circuit design are already captured by the higher-order functions that are -present for the 'Vec'tor type. --} - -{- $composition_sequential -Given a function @f@ of type: - -@ -__f__ :: Int -> (Bool, Int) -> (Int, (Int, Bool)) -@ - -When we want to make compositions of @f@ in @g@ using 'mealy', we have to -write: - -@ -g a b c = (b1,b2,i2) - where - (i1,b1) = 'unbundle' ('mealy' f 0 ('bundle' (a,b))) - (i2,b2) = 'unbundle' ('mealy' f 3 ('bundle' (c,i1))) -@ - -Why do we need these 'bundle', and 'unbundle' functions you might ask? When we -look at the type of 'mealy': - -@ -__mealy__ - :: HiddenClockResetEnable dom - => (s -> i -> (s,o)) - -> s - -> ('Signal' dom i -> 'Signal' dom o) -@ - -we see that the resulting function has an input of type @'Signal' dom i@, and -an output of @'Signal' dom o@. However, the type of @(a,b)@ in the definition -of @g@ is: @('Signal' dom Bool, 'Signal' dom Int)@. And the type of @(i1,b1)@ -is of type @('Signal' dom Int, 'Signal' dom Bool)@. - -Syntactically, @'Signal' dom (Bool,Int)@ and @('Signal' dom Bool, -'Signal' dom Int)@ are /unequal/. -So we need to make a conversion between the two, that is what 'bundle' and -'unbundle' are for. In the above case 'bundle' gets the type: - -@ -__bundle__ :: ('Signal' dom Bool, 'Signal' dom Int) -> 'Signal' dom (Bool,Int) -@ - -and 'unbundle': - -@ -__unbundle__ :: 'Signal' dom (Int,Bool) -> ('Signal' dom Int, 'Signal' dom Bool) -@ - -The /true/ types of these two functions are, however: - -@ -__bundle__ :: 'Bundle' a => 'Unbundled' dom a -> 'Signal' dom a -__unbundle__ :: 'Bundle' a => 'Signal' dom a -> 'Unbundled' dom a -@ - -'Unbundled' is an -belonging to the 'Bundle' , -which, together with 'bundle' and 'unbundle' defines the isomorphism between a -product type of 'Signal's and a 'Signal' of a product type. That is, while -@('Signal' dom a, 'Signal' dom b)@ and @'Signal' dom (a,b)@ are not equal, -they are /isomorphic/ and can be converted from, or to, the other using -'bundle' and 'unbundle'. - -Instances of this 'Bundle' type-class are defined as /isomorphisms/ for: - - * All tuples up to and including 62-tuples (GHC limit) - * The 'Vec'tor type - -But they are defined as /identities/ for: - - * All elementary / primitive types such as: 'Bit', 'Bool', @'Signed' n@, etc. - -That is: - -@ -instance 'Bundle' (a,b) where - type 'Unbundled' dom (a,b) = ('Signal' dom a, 'Signal' dom b) - bundle (a,b) = (,) '<$>' a '<*>' b - unbundle tup = (fst '<$>' tup, snd '<*>' tup) -@ - -but, - -@ -instance 'Bundle' Bool where - type 'Unbundled' dom Bool = 'Signal' dom Bool - bundle s = s - unbundle s = s -@ - -What you need take away from the above is that a product type (e.g. a tuple) of -'Signal's is not syntactically equal to a 'Signal' of a product type, but that -the functions of the 'Bundle' type class allow easy conversion between the two. - -As a final note on this section we also want to mention the 'mealyB' function, -which does the bundling and unbundling for us: - -@ -mealyB - :: ('Bundle' i, 'Bundle' o) - => (s -> i -> (s,o)) - -> s - -> 'Unbundled' dom i - -> 'Unbundled' dom o -@ - -Using 'mealyB' we can define @g@ as: - -@ -g a b c = (b1,b2,i2) - where - (i1,b1) = 'mealyB' f 0 (a,b) - (i2,b2) = 'mealyB' f 3 (c,i1) -@ - -The general rule of thumb is: always use 'mealy', unless you do pattern matching -or construction of product types, then use 'mealyB'. --} - -{- $annotations #annotations# -'Synthesize' annotations allow us to control hierarchy and naming aspects of the -Clash compiler, specifically, they allow us to: - - * Assign names to entities (VHDL) \/ modules ((System)Verilog), and their - ports. - * Put generated HDL files of a logical (sub)entity in their own directory. - * Use cached versions of generated HDL, i.e., prevent recompilation of - (sub)entities that have not changed since the last run. Caching is based - on a @.manifest@ which is generated alongside the HDL; deleting this file - means deleting the cache; changing this file will result in /undefined/ - behavior. - -Functions with a 'Synthesize' annotation must adhere to the following -restrictions: - - * Although functions with a 'Synthesize' annotation can of course depend - on functions with another 'Synthesize' annotation, they must not be - mutually recursive. - * Functions with a 'Synthesize' annotation must be completely /monomorphic/ - and /first-order/, and cannot have any /non-representable/ arguments or - result. - -Also take the following into account when using 'Synthesize' annotations. - - * The Clash compiler is based on the GHC Haskell compiler, and the GHC - machinery does not understand 'Synthesize' annotations and it might - subsequently decide to inline those functions. You should therefor also - add a @{\-\# NOINLINE f \#-\}@ pragma to the functions which you give - a 'Synthesize' functions. - * Functions with a 'Synthesize' annotation will not be specialized - on constants. - -Finally, the root module, the module which you pass as an argument to the -Clash compiler must either have: - - * A function with a 'Synthesize' annotation. - * A function called /topEntity/. - -You apply 'Synthesize' annotations to functions using an @ANN@ pragma: - -@ -{\-\# ANN topEntity (Synthesize {t_name = ..., ... }) \#-\} -topEntity x = ... -@ - -For example, given the following specification: - -@ -module Blinker where - -import "Clash.Signal" -import "Clash.Prelude" -import "Clash.Intel.ClockGen" - -'createDomain' vSystem{vName=\"DomInput\", vPeriod=20000, vResetPolarity=ActiveLow} -'createDomain' vSystem{vName=\"Dom100\", vPeriod=10000} - -topEntity - :: Clock DomInput - -> Reset DomInput - -> Signal Dom100 Bit - -> Signal Dom100 (BitVector 8) -topEntity clk rst = - 'exposeClockResetEnable' ('mealy' blinkerT (1,False,0) . 'Clash.Prelude.isRising' 1) pllOut pllRst 'enableGen' - where - (pllOut,pllRst) = 'Clash.Intel.ClockGen.altpllSync' clk rst - -blinkerT (leds,mode,cntr) key1R = ((leds',mode',cntr'),leds) - where - -- clock frequency = 100e6 (100 MHz) - -- led update rate = 333e-3 (every 333ms) - cnt_max = 'maxBound' :: ('Index' 33300000) -- 100e6 * 333e-3 - - cntr' | cntr == cnt_max = 0 - | otherwise = cntr + 1 - - mode' | key1R = not mode - | otherwise = mode - - leds' | cntr == 0 = if mode then complement leds - else rotateL leds 1 - | otherwise = leds -@ - -The Clash compiler will normally generate the following @topentity.vhdl@ file: - -> -- Automatically generated VHDL-93 -> library IEEE; -> use IEEE.STD_LOGIC_1164.ALL; -> use IEEE.NUMERIC_STD.ALL; -> use IEEE.MATH_REAL.ALL; -> use std.textio.all; -> use work.all; -> use work.Blinker_topEntity_types.all; -> -> entity topEntity is -> port(-- clock -> clk : in Blinker_topEntity_types.clk_DomInput; -> -- reset -> rst : in Blinker_topEntity_types.rst_DomInput; -> eta : in std_logic; -> result : out std_logic_vector(7 downto 0)); -> end; -> -> architecture structural of topEntity is -> ... -> end; - -However, if we add the following 'Synthesize' annotation in the file: - -@ -{\-\# ANN topEntity - ('Synthesize' - { t_name = "blinker" - , t_inputs = [PortName \"CLOCK_50\", PortName \"KEY0\", PortName \"KEY1\"] - , t_output = PortName \"LED\" - }) \#-\} -@ - -The Clash compiler will generate the following @blinker.vhdl@ file instead: - -> -- Automatically generated VHDL-93 -> library IEEE; -> use IEEE.STD_LOGIC_1164.ALL; -> use IEEE.NUMERIC_STD.ALL; -> use IEEE.MATH_REAL.ALL; -> use std.textio.all; -> use work.all; -> use work.blinker_types.all; -> -> entity blinker is -> port(-- clock -> CLOCK_50 : in blinker_types.clk_DomInput; -> -- reset -> KEY0 : in blinker_types.rst_DomInput; -> KEY1 : in std_logic; -> LED : out std_logic_vector(7 downto 0)); -> end; -> -> architecture structural of blinker is -> ... -> end; - -Where we now have: - -* A top-level component that is called @blinker@. -* Inputs and outputs that have a /user/-chosen name: @CLOCK_50@, @KEY0@, @KEY1@, @LED@, etc. - -See the documentation of 'Synthesize' for the meaning of all its fields. --} - -{- $primitives #primitives# -There are times when you already have an existing piece of IP, or there are -times where you need the VHDL to have a specific shape so that the VHDL -synthesis tool can infer a specific component. In these specific cases you can -resort to defining your own VHDL primitives. Actually, most of the primitives -in Clash are specified in the same way as you will read about in this section. -There are perhaps 10 (at most) functions which are truly hard-coded into the -Clash compiler. You can take a look at the files in - -(or -for the Verilog primitives or -for the SystemVerilog primitives) if you want to know which functions are defined -as \"regular\" primitives. The compiler looks for primitives in four locations: - -* The official install location: e.g. - - * @$CABAL_DIR\/share\/\\/clash-lib\-\/prims\/common@ - * @$CABAL_DIR\/share\/\\/clash-lib\-\/prims\/commonverilog@ - * @$CABAL_DIR\/share\/\\/clash-lib\-\/prims\/systemverilog@ - * @$CABAL_DIR\/share\/\\/clash-lib\-\/prims\/verilog@ - * @$CABAL_DIR\/share\/\\/clash-lib\-\/prims\/vhdl@ - -* Directories indicated by a 'Clash.Annotations.Primitive.Primitive' annotation -* The current directory (the location given by @pwd@) -* The include directories specified on the command-line: @-i\@ - -Where redefined primitives in the current directory or include directories will -overwrite those in the official install location. For now, files containing -primitive definitions must have a @.primitives.yaml@ file-extension. - -Clash differentiates between two types of primitives, /expression/ primitives -and /declaration/ primitives, corresponding to whether the primitive is a VHDL -/expression/ or a VHDL /declaration/. We will first explore /expression/ -primitives, using 'Signed' multiplication (@*@) as an example. The -"Clash.Sized.Internal.Signed" module specifies multiplication as follows: - -@ -(*#) :: 'KnownNat' n => 'Signed' n -> 'Signed' n -> 'Signed' n -(S a) *# (S b) = fromInteger_INLINE (a * b) -{\-\# NOINLINE (*#) \#-\} -@ - -For which the VHDL /expression/ primitive is: - -> BlackBox: -> name: Clash.Sized.Internal.Signed.*# -> kind: Expression -> type: '(*#) :: KnownNat n => Signed n -> Signed n -> Signed n' -> template: resize(~ARG[1] * ~ARG[2], ~LIT[0]) - -The @name@ of the primitive is the /fully qualified/ name of the function you -are creating the primitive for. Because we are creating an /expression/ -primitive the kind must be set to @Expression@. As the name suggest, it is a VHDL -/template/, meaning that the compiler must fill in the holes heralded by the -tilde (~). Here: - - * @~ARG[1]@ denotes the second argument given to the @(*#)@ function, which - corresponds to the LHS of the (@*@) operator. - * @~ARG[2]@ denotes the third argument given to the @(*#)@ function, which - corresponds to the RHS of the (@*@) operator. - * @~LIT[0]@ denotes the first argument given to the @(*#)@ function, with - the extra condition that it must be a @LIT@eral. If for some reason this - first argument does not turn out to be a literal then the compiler will - raise an error. This first arguments corresponds to the \"@'KnownNat' n@\" - class constraint. - -An extensive list with all of the template holes will be given the end of this -section. What we immediately notice is that class constraints are counted as -normal arguments in the primitive definition. This is because these class -constraints are actually represented by ordinary record types, with fields -corresponding to the methods of the type class. In the above case, 'KnownNat' -is actually just like a @newtype@ wrapper for 'Integer'. - -The second kind of primitive that we will explore is the /declaration/ primitive. -We will use @blockRam#@ as an example, for which the Haskell/Clash code is: - -@ -{\-\# LANGUAGE BangPatterns \#\-\} - -module BlockRam where - -import Clash.Explicit.Prelude -import Clash.Annotations.Primitive (hasBlackBox) -import Clash.Signal.Internal (Clock, Signal (..), (.&&.)) -import Clash.Sized.Vector (Vec, toList) -import Clash.XException (defaultSeqX) - -import qualified Data.Vector as V -import GHC.Stack (HasCallStack, withFrozenCallStack) - -blockRam# - :: ( KnownDomain dom - , HasCallStack - , NFDataX a ) - => 'Clock' dom -- ^ Clock to synchronize to - -> 'Enable' dom -- ^ Global enable - -> 'Vec' n a -- ^ Initial content of the BRAM, also - -- determines the size, \@n\@, of the BRAM. - -- - -- \_\_NB\_\_: \_\_MUST\_\_ be a constant. - -> 'Signal' dom Int -- ^ Read address \@r\@ - -> 'Signal' dom Bool -- ^ Write enable - -> 'Signal' dom Int -- ^ Write address \@w\@ - -> 'Signal' dom a -- ^ Value to write (at address \@w\@) - -> 'Signal' dom a -- ^ Value of the BRAM at address \@r\@ from - -- the previous clock cycle -blockRam# (Clock _) gen content rd wen = - go - (V.fromList ('toList' content)) - (withFrozenCallStack ('deepErrorX' "blockRam: intial value undefined")) - (fromEnable gen) - rd - (fromEnable gen '.&&.' wen) - where - go !ram o ret\@(~(re :- res)) rt\@(~(r :- rs)) et\@(~(e :- en)) wt\@(~(w :- wr)) dt\@(~(d :- din)) = - let ram' = d ``defaultSeqX`` upd ram e (fromEnum w) d - o' = if re then ram V.! r else o - in o ``seqX`` o :- (ret ``seq`` rt ``seq`` et ``seq`` wt ``seq`` dt ``seq`` go ram' o' res rs en wr din) - - upd ram we waddr d = case maybeIsX we of - Nothing -> case maybeIsX waddr of - Nothing -> V.map (const (seq waddr d)) ram - Just wa -> ram V.// [(wa,d)] - Just True -> case maybeIsX waddr of - Nothing -> V.map (const (seq waddr d)) ram - Just wa -> ram V.// [(wa,d)] - _ -> ram -{\-\# NOINLINE blockRam# \#\-\} -{\-\# ANN blockRam# hasBlackBox \#\-\} -@ - -And for which the /declaration/ primitive is: - -> BlackBox: -> name: Clash.Explicit.BlockRam.blockRam# -> kind: Declaration -> type: |- -> blockRam# -> :: ( KnownDomain dom ARG[0] -> , HasCallStack -- ARG[1] -> , NFDataX a ) -- ARG[2] -> => Clock dom -- clk, ARG[3] -> -> Enable dom -- en, ARG[4] -> -> Vec n a -- init, ARG[5] -> -> Signal dom Int -- rd, ARG[6] -> -> Signal dom Bool -- wren, ARG[7] -> -> Signal dom Int -- wr, ARG[8] -> -> Signal dom a -- din, ARG[9] -> -> Signal dom a -> template: |- -> -- blockRam begin -> ~GENSYM[~RESULT_blockRam][1] : block -> signal ~GENSYM[~RESULT_RAM][2] : ~TYP[5] := ~CONST[5]; -> signal ~GENSYM[rd][4] : integer range 0 to ~LENGTH[~TYP[5]] - 1; -> signal ~GENSYM[wr][5] : integer range 0 to ~LENGTH[~TYP[5]] - 1; -> begin -> ~SYM[4] <= to_integer(~ARG[6]) -> -- pragma translate_off -> mod ~LENGTH[~TYP[5]] -> -- pragma translate_on -> ; -> ~SYM[5] <= to_integer(~ARG[8]) -> -- pragma translate_off -> mod ~LENGTH[~TYP[5]] -> -- pragma translate_on -> ; -> ~IF ~VIVADO ~THEN -> ~SYM[6] : process(~ARG[3]) -> begin -> if ~IF~ACTIVEEDGE[Rising][0]~THENrising_edge~ELSEfalling_edge~FI(~ARG[3]) then -> if ~ARG[7] ~IF ~ISACTIVEENABLE[4] ~THEN and ~ARG[4] ~ELSE ~FI then -> ~SYM[2](~SYM[5]) <= ~TOBV[~ARG[9]][~TYP[9]]; -> end if; -> ~RESULT <= fromSLV(~SYM[2](~SYM[4])) -> -- pragma translate_off -> after 1 ps -> -- pragma translate_on -> ; -> end if; -> end process; ~ELSE -> ~SYM[6] : process(~ARG[3]) -> begin -> if ~IF~ACTIVEEDGE[Rising][0]~THENrising_edge~ELSEfalling_edge~FI(~ARG[3]) then -> if ~ARG[7] ~IF ~ISACTIVEENABLE[4] ~THEN and ~ARG[4] ~ELSE ~FI then -> ~SYM[2](~SYM[5]) <= ~ARG[9]; -> end if; -> ~RESULT <= ~SYM[2](~SYM[4]) -> -- pragma translate_off -> after 1 ps -> -- pragma translate_on -> ; -> end if; -> end process; ~FI -> end block; -> --end blockRam - -Again, the @name@ of the primitive is the fully qualified name of the function -you are creating the primitive for. Because we are creating a /declaration/ -primitive the /kind/ must be set to @Declaration@. Instead of discussing what the -individual template holes mean in the above context, we will instead just give -a general listing of the available template holes: - -* @~RESULT@: Signal to which the result of a primitive must be assigned - to. NB: Only used in a /declaration/ primitive. -* @~ARG[N]@: @(N+1)@'th argument to the function. -* @~CONST[N]@: @(N+1)@'th argument to the function. Like @~ARG@, but Clash will - try to reduce this to a literal, even if it would otherwise consider it too - expensive. And if Clash fails to reduce this argument to a literal it will - produce an error. -* @~LIT[N]@: @(N+1)@'th argument to the function. Like @~CONST~ but values are - rendered as a bare literals, without any size or type annotations. - This only works for numeric types, and not for BitVector. -* @~TYP[N]@: VHDL type of the @(N+1)@'th argument. -* @~TYPO@: VHDL type of the result. -* @~TYPM[N]@: VHDL type/name/ of the @(N+1)@'th argument; used in /type/ - /qualification/. -* @~TYPMO@: VHDL type/name/ of the result; used in /type qualification/. -* @~ERROR[N]@: Error value for the VHDL type of the @(N+1)@'th argument. -* @~ERRORO@: Error value for the VHDL type of the result. -* @~GENSYM[\][N]@: Create a unique name, trying to stay as close to - the given @\@ as possible. This unique symbol can be referred to in - other places using @~SYM[N]@. -* @~SYM[N]@: a reference to the unique symbol created by @~GENSYM[\][N]@. -* @~SIGD[\][N]@: Create a signal declaration, using @\@ as the name - of the signal, and the type of the @(N+1)@'th argument. -* @~SIGDO[\]@: Create a signal declaration, using @\@ as the name - of the signal, and the type of the result. -* @~TYPEL[\]@: The element type of the vector type represented by @\@. - The content of @\@ must either be: @~TYP[N]@, @~TYPO@, or @~TYPEL[\]@. -* @~COMPNAME@: The name of the component in which the primitive is instantiated. -* @~LENGTH[\]@: The vector length of the type represented by @\@. -* @~DEPTH[\]@: The tree depth of the type represented by @\@. - The content of @\@ must either be: @~TYP[N]@, @~TYPO@, or @~TYPEL[\]@. -* @~SIZE[\]@: The number of bits needed to encode the type represented by @\@. - The content of @\@ must either be: @~TYP[N]@, @~TYPO@, or @~TYPEL[\]@. -* @~IF \ ~THEN \ ~ELSE \ ~FI@: renders the @\@ - part when @\@ evaluates to /0/, and renders the @\@ in all - other cases. Valid @\@s are @~LENGTH[\]@, @~SIZE[\]@, - @~CMPLE[\][\]@, - @~DEPTH[\]@, @~VIVADO@, @~IW64@, @~ISLIT[N]@, @~ISVAR[N]@, @~ISACTIVEENABLE[N]@, - @~ISSYNC[N]@, and @~AND[\,\,..]@. -* @~VIVADO@: /1/ when Clash compiler is invoked with the @-fclash-xilinx@ or - @-fclash-vivado@ flag. To be used with in an @~IF .. ~THEN .. ~ELSE .. ~FI@ - statement. -* @~CMPLE[\][\]@: /1/ when @\ \<= \@, otherwise /0/ -* @~IW64@: /1/ when @Int@\/@Word@\/@Integer@ types are represented with 64 bits in HDL. - /0/ when they're represented by 32 bits. -* @~TOBV[\][\]@: create conversion code that so that the - expression in @\@ is converted to a bit vector (@std_logic_vector@). - The @\@ hole indicates the type of the expression and must be either - @~TYP[N]@, @~TYPO@, or @~TYPEL[\]@. -* @~FROMBV[\][\]@: create conversion code that so that the - expression in @\@, which has a bit vector (@std_logic_vector@) type, - is converted to type indicated by @\@. The @\@ hole must be - either @~TYP[N]@, @~TYPO@, or @~TYPEL[\]@. -* @~INCLUDENAME[N]@: the generated name of the @N@'th included component. -* @~FILE[\]@: The argument mentioned in @\@ is a file which - must be copied to the location of the generated HDL. -* @~GENERATE@: Verilog: create a /generate/ statement, except when already in - a /generate/ context. -* @~ENDGENERATE@: Verilog: create an /endgenerate/ statement, except when already - in a /generate/ context. -* @~ISLIT[N]@: Is the @(N+1)@'th argument to the function a literal. -* @~ISVAR[N]@: Is the @(N+1)@'th argument to the function explicitly not a - literal. -* @~ISSCALAR[N]@: Is the @(N+1)@'th argument to the function a scalar. Note - that this means different things for different HDLs. In (System)Verilog only - @Bit@ and @Bool@ are considered scalar. In VHDL, in addition to those two, - enumeration types and integers are considered scalar. -* @~TAG[N]@: Name of given domain. Errors when called on an argument which is not - a 'KnownDomain', 'Reset', or 'Clock'. -* @~PERIOD[N]@: Clock period of given domain. Errors when called on an argument - which is not a 'Clock', 'Reset', 'KnownDomain' or 'KnownConf'. -* @~ISACTIVEENABLE[N]@: Is the @(N+1)@'th argument a an Enable line __not__ set to a - constant True. Can be used instead of deprecated (and removed) template tag -* @~ISSYNC[N]@: Does synthesis domain at the @(N+1)@'th argument have synchronous resets. Errors - when called on an argument which is not a 'Reset', 'Clock', 'Enable', 'KnownDomain' or 'KnownConf'. -* @~ISINITDEFINED[N]@: Does synthesis domain at the @(N+1)@'th argument have defined initial - values. Errors when called on an argument which is not a 'Clock', 'Reset', 'Enable', 'KnownDomain' or 'KnownConf'. -* @~ACTIVEEDGE[edge][N]@: Does synthesis domain at the @(N+1)@'th argument respond to - /edge/. /edge/ must be one of 'Falling' or 'Rising'. Errors when called on an - argument which is not a 'Clock', 'Reset', 'Enable', 'KnownDomain' or 'KnownConf'. -* @~AND[\,\,..]@: Logically /and/ the conditions in the @\@'s -* @~VAR[\][N]@: Like @~ARG[N]@ but binds the argument to a variable named NAME. - The @\@ can be left blank, then Clash will come up with a (unique) name. -* @~VARS[N]@: VHDL: Return the variables at the @(N+1)@'th argument. -* @~NAME[N]@: Render the @(N+1)@'th string literal argument as an identifier - instead of a string literal. Fails when the @(N+1)@'th argument is not a - string literal. -* @~DEVNULL[\]@: Render all dependencies of @\@, but disregard direct output. -* @~REPEAT[\][N]@: Repeat literal value of @\@ a total of @N@ times. -* @~TEMPLATE[\][\]@: Render a file @\@ with contents @\@. - - -Some final remarks to end this section: VHDL primitives are there to instruct the -Clash compiler to use the given VHDL template, instead of trying to do normal -synthesis. As a consequence you can use constructs inside the Haskell -definitions that are normally not synthesizable by the Clash compiler. However, -VHDL primitives do not give us /co-simulation/: where you would be able to -simulate VHDL and Haskell in a /single/ environment. If you still want to -simulate your design in Haskell, you will have to describe, in a cycle- and -bit-accurate way, the behavior of that (potentially complex) IP you are trying -to include in your design. - -Perhaps in the future, someone will figure out how to connect the two simulation -worlds, using e.g. VHDL's foreign function interface VHPI. --} - -{- $vprimitives -For those who are interested, the equivalent Verilog primitives are: - -> BlackBox: -> name: Clash.Sized.Internal.Signed.*# -> kind: Expression -> type: '(*#) :: KnownNat n => Signed n -> Signed n -> Signed n' -> template: ~ARG[1] * ~ARG[2] - -and - -> BlackBox: -> name: Clash.Explicit.BlockRam.blockRam# -> kind: Declaration -> outputUsage: NonBlocking -> type: |- -> blockRam# -> :: ( KnownDomain dom ARG[0] -> , HasCallStack -- ARG[1] -> , NFDataX a ) -- ARG[2] -> => Clock dom -- clk, ARG[3] -> => Enable dom -- en, ARG[4] -> -> Vec n a -- init, ARG[5] -> -> Signal dom Int -- rd, ARG[6] -> -> Signal dom Bool -- wren, ARG[7] -> -> Signal dom Int -- wr, ARG[8] -> -> Signal dom a -- din, ARG[9] -> -> Signal dom a -> template: |- -> // blockRam begin -> reg ~TYPO ~GENSYM[~RESULT_RAM][1] [0:~LENGTH[~TYP[5]]-1]; -> -> reg ~TYP[5] ~GENSYM[ram_init][3]; -> integer ~GENSYM[i][4]; -> initial begin -> ~SYM[3] = ~CONST[5]; -> for (~SYM[4]=0; ~SYM[4] < ~LENGTH[~TYP[5]]; ~SYM[4] = ~SYM[4] + 1) begin -> ~SYM[1][~LENGTH[~TYP[5]]-1-~SYM[4]] = ~SYM[3][~SYM[4]*~SIZE[~TYPO]+:~SIZE[~TYPO]]; -> end -> end -> ~IF ~ISACTIVEENABLE[4] ~THEN -> always @(~IF~ACTIVEEDGE[Rising][0]~THENposedge~ELSEnegedge~FI ~ARG[3]) begin : ~GENSYM[~RESULT_blockRam][5]~IF ~VIVADO ~THEN -> if (~ARG[4]) begin -> if (~ARG[7]) begin -> ~SYM[1][~ARG[8]] <= ~ARG[9]; -> end -> ~RESULT <= ~SYM[1][~ARG[6]]; -> end~ELSE -> if (~ARG[7] & ~ARG[4]) begin -> ~SYM[1][~ARG[8]] <= ~ARG[9]; -> end -> if (~ARG[4]) begin -> ~RESULT <= ~SYM[1][~ARG[6]]; -> end~FI -> end~ELSE -> always @(~IF~ACTIVEEDGE[Rising][0]~THENposedge~ELSEnegedge~FI ~ARG[3]) begin : ~SYM[5] -> if (~ARG[7]) begin -> ~SYM[1][~ARG[8]] <= ~ARG[9]; -> end -> ~RESULT <= ~SYM[1][~ARG[6]]; -> end~FI -> // blockRam end - --} - -{- $svprimitives -And the equivalent SystemVerilog primitives are: - -> BlackBox: -> name: Clash.Sized.Internal.Signed.*# -> kind: Expression -> type: '(*#) :: KnownNat n => Signed n -> Signed n -> Signed n' -> template: ~ARG[1] * ~ARG[2] - -and - -> BlackBox: -> name: Clash.Explicit.BlockRam.blockRam# -> kind: Declaration -> type: |- -> blockRam# -> :: ( KnownDomain dom ARG[0] -> , HasCallStack -- ARG[1] -> , NFDataX a ) -- ARG[2] -> => Clock dom -- clk, ARG[3] -> -> Enable dom -- en, ARG[4] -> -> Vec n a -- init, ARG[5] -> -> Signal dom Int -- rd, ARG[6] -> -> Signal dom Bool -- wren, ARG[7] -> -> Signal dom Int -- wr, ARG[8] -> -> Signal dom a -- din, ARG[9] -> -> Signal dom a -> template: |- -> // blockRam begin -> ~SIGD[~GENSYM[RAM][1]][5]; -> logic [~SIZE[~TYP[9]]-1:0] ~GENSYM[~RESULT_q][2]; -> initial begin -> ~SYM[1] = ~CONST[5]; -> end~IF ~ISACTIVEENABLE[4] ~THEN -> always @(~IF~ACTIVEEDGE[Rising][0]~THENposedge~ELSEnegedge~FI ~ARG[3]) begin : ~GENSYM[~COMPNAME_blockRam][3]~IF ~VIVADO ~THEN -> if (~ARG[4]) begin -> if (~ARG[7]) begin -> ~SYM[1][~ARG[8]] <= ~TOBV[~ARG[9]][~TYP[9]]; -> end -> ~SYM[2] <= ~SYM[1][~ARG[6]]; -> end~ELSE -> if (~ARG[7] & ~ARG[4]) begin -> ~SYM[1][~ARG[8]] <= ~TOBV[~ARG[9]][~TYP[9]]; -> end -> if (~ARG[4]) begin -> ~SYM[2] <= ~SYM[1][~ARG[6]]; -> end~FI -> end~ELSE -> always @(~IF~ACTIVEEDGE[Rising][0]~THENposedge~ELSEnegedge~FI ~ARG[3]) begin : ~SYM[3] -> if (~ARG[7]) begin -> ~SYM[1][~ARG[8]] <= ~TOBV[~ARG[9]][~TYP[9]]; -> end -> ~SYM[2] <= ~SYM[1][~ARG[6]]; -> end~FI -> assign ~RESULT = ~FROMBV[~SYM[2]][~TYP[9]]; -> // blockRam end - --} - -{- $multiclock #multiclock# -Clash supports designs multiple /clock/ (and /reset/) domains, though perhaps in -a slightly limited form. What is possible is: - -* Create clock primitives, such as PLLs, which have an accompanying HDL primitive - (described <#primitives later on> in this tutorial). -* Explicitly assign clocks to memory primitives. -* Synchronize between differently-clocked parts of your design in a type-safe - way. - -What is /not/ possible is: - -* Directly generate a clock signal in module A, and assign this clock signal to - a memory primitive in module B. For example, the following is not possible: - - @ - pow2Clocks - :: ( 'KnownConfiguration' domIn (''DomainConfiguration' domIn pIn eIn rIn iIn polIn) - , 'KnownConfiguration' dom2 (''DomainConfiguration' dom2 (2*pIn) e2 r2 i2 p2) - , 'KnownConfiguration' dom4 (''DomainConfiguration' dom4 (4*pIn) e4 r4 i4 p4) - , 'KnownConfiguration' dom8 (''DomainConfiguration' dom8 (8*pIn) e8 r8 i8 p8) - , 'KnownConfiguration' dom16 (''DomainConfiguration' dom16 (16*pIn) e16 r16 i16 p16) - => 'Clock' domIn - -> 'Reset' domIn - -> ( 'Clock' dom16 - , 'Clock' dom8 - , 'Clock' dom4 - , 'Clock' dom2 ) - pow2Clocks clk rst = (cnt!3, cnt!2, cnt!1, cnt!0) - where - cnt = 'Clash.Explicit.Signal.register' clk rst 0 (cnt + 1) - @ - - As it is not possible to convert the individual bits to a 'Clock'. - - However! What is possible is to do the following: - - @ - pow2Clocks' - :: ( 'KnownConfiguration' domIn (''DomainConfiguration' domIn pIn eIn rIn iIn polIn) - , 'KnownConfiguration' dom2 (''DomainConfiguration' dom2 (2*pIn) e2 r2 i2 p2) - , 'KnownConfiguration' dom4 (''DomainConfiguration' dom4 (4*pIn) e4 r4 i4 p4) - , 'KnownConfiguration' dom8 (''DomainConfiguration' dom8 (8*pIn) e8 r8 i8 p8) - , 'KnownConfiguration' dom16 (''DomainConfiguration' dom16 (16*pIn) e16 r16 i16 p16) - => 'Clock' domIn - -> 'Reset' domIn - -> ( 'Clock' dom16 - , 'Clock' dom8 - , 'Clock' dom4 - , 'Clock' dom2 ) - pow2Clocks' clk rst = ('clockGen', 'clockGen', 'clockGen', 'clockGen') - {\-\# NOINLINE pow2Clocks' \#-\} - @ - - And then create a HDL primitive, as described in later on in - this <#primitives tutorial>, to implement the desired behavior in HDL. - -What this means is that when Clash converts your design to VHDL/(System)Verilog, -you end up with a top-level module/entity with multiple clock and reset ports -for the different clock domains. If you're targeting an FPGA, you can use e.g. a - or - -to provide the clock signals. - -== Building a FIFO synchronizer - -This part of the tutorial assumes you know what -is, and how it can never truly be avoided in any asynchronous circuit. Also -it assumes that you are familiar with the design of synchronizer circuits, and -why a dual flip-flop synchronizer only works for bit-synchronization and not -word-synchronization. -The explicitly clocked versions of all synchronous functions and primitives can -be found in "Clash.Explicit.Prelude", which also re-exports the functions in -"Clash.Signal.Explicit". We will use those functions to create a FIFO where -the read and write port are synchronized to different clocks. Below you can find -the code to build the FIFO synchronizer based on the design described in: - - -We start with enable a few options that will make writing the type-signatures for -our components a bit easier. Instead of importing the standard "Clash.Prelude" -module, we will import the "Clash.Explicit.Prelude" module where all our clocks -and resets must be explicitly routed (other imports will be used later): - -@ -module MultiClockFifo where - -import "Clash.Explicit.Prelude" -import "Clash.Prelude" (mux) -import Data.Maybe (isJust) -import Data.Constraint (Dict (..), (:-)( Sub )) -import Data.Constraint.Nat (leTrans) -@ - -Then we'll start with the /heart/ of the FIFO synchronizer, an asynchronous RAM -in the form of 'asyncRam'. It's called an asynchronous RAM because the read -port is not synchronized to any clock (though the write port is). Note that in -Clash we don't really have asynchronous logic, there is only combinational and -synchronous logic. As a consequence, we see in the type signature of -'Clash.Explicit.Prelude.asyncRam': - -@ -__asyncRam__ - :: ( 'Enum' addr - , 'HasCallStack' - , 'KnownDomain' wdom - , 'KnownDomain' rdom - , 'NFDataX' a - ) - => 'Clock' wdom -- ^ Clock to which to synchronize the write port of the RAM - -> 'Clock' rdom -- ^ Clock to which the read address signal, \@r\@, is synchronized to - -> 'Enable' wdom -- ^ Global enable - -> 'SNat' n -- ^ Size \@n\@ of the RAM - -> 'Signal' rdom addr -- ^ Read address \@r\@ - -> 'Signal' wdom (Maybe (addr, a)) -- ^ (write address \@w\@, value to write) - -> 'Signal' rdom a -- ^ Value of the RAM at address \@r\@ -@ - -that the signal containing the read address __r__ is synchronized to a different -clock. That is, there is __no__ such thing as an @AsyncSignal@ in Clash. - -We continue by instantiating the 'Clash.Explicit.Prelude.asyncRam': - -@ -fifoMem wclk rclk en addrSize\@SNat full raddr writeM = - 'Clash.Explicit.Prelude.asyncRam' - wclk rclk en - ('pow2SNat' addrSize) - raddr - ('mux' full (pure Nothing) writeM) -@ - -We see that we give it @2^addrSize@ elements, where @addrSize@ is the bit-size -of the address. Also, we only write new values to the RAM when a new write is -requested, indicated by @wdataM@ having a 'Data.Maybe.Just' value, and the -buffer is not full, indicated by @wfull@. - -The next part of the design calculates the read and write address for the -asynchronous RAM, and creates the flags indicating whether the FIFO is full -or empty. The address and flag generator is given in 'mealy' machine style: - -@ -ptrCompareT - :: SNat addrSize - -> (BitVector (addrSize + 1) -> BitVector (addrSize + 1) -> Bool) - -> ( BitVector (addrSize + 1) - , BitVector (addrSize + 1) - , Bool ) - -> ( BitVector (addrSize + 1) - , Bool ) - -> ( ( BitVector (addrSize + 1) - , BitVector (addrSize + 1) - , Bool ) - , ( Bool - , BitVector addrSize - , BitVector (addrSize + 1) - ) - ) -ptrCompareT addrSize\@SNat flagGen (bin, ptr, flag) (s_ptr, inc) = - ( (bin', ptr', flag') - , (flag, addr, ptr) ) - where - -- GRAYSTYLE2 pointer - bin' = bin + 'boolToBV' (inc && not flag) - ptr' = (bin' \`shiftR\` 1) \`xor\` bin' - addr = 'truncateB' bin - flag' = flagGen ptr' s_ptr -@ - -It is parametrized in both address size, @addrSize@, and status flag generator, -@flagGen@. It has two inputs, @s_ptr@, the synchronized pointer from the other -clock domain, and @inc@, which indicates we want to perform a write or read of -the FIFO. It creates three outputs: @flag@, the full or empty flag, @addr@, the -read or write address into the RAM, and @ptr@, the Gray-encoded version of the -read or write address which will be synchronized between the two clock domains. - -Next follow the initial states of address generators, and the flag generators -for the empty and full flags: - -@ --- FIFO empty: when next pntr == synchronized wptr or on reset -isEmpty = (==) -rptrEmptyInit = (0, 0, True) - --- FIFO full: when next pntr == synchronized {~wptr[addrSize:addrSize-1],wptr[addrSize-2:0]} -isFull - :: forall addrSize - . (2 <= addrSize) - => 'SNat' addrSize - -> 'BitVector' (addrSize + 1) - -> 'BitVector' (addrSize + 1) - -> Bool -isFull addrSize\@SNat ptr s_ptr = case leTrans \@1 \@2 \@addrSize of - Sub Dict -> - let a1 = 'SNat' \@(addrSize - 1) - a2 = 'SNat' \@(addrSize - 2) - in ptr == ('complement' ('slice' addrSize a1 s_ptr) '++#' 'slice' a2 d0 s_ptr) - -wptrFullInit = (0, 0, False) -@ - -We create a dual flip-flop synchronizer to be used to synchronize the -Gray-encoded pointers between the two clock domains: - -@ -ptrSync clk1 clk2 rst2 en2 = - 'Clash.Explicit.Signal.register' clk2 rst2 en2 0 . 'Clash.Explicit.Signal.register' clk2 rst2 en2 0 . 'Clash.Explicit.Signal.unsafeSynchronizer' clk1 clk2 -@ - -It uses the 'Clash.Explicit.Signal.unsafeSynchronizer' primitive, which is -needed to go from one clock domain to the other. The 'Clash.Explicit.Signal.unsafeSynchronizer' -primitive is turned into a (bundle of) wire(s) by the Clash compiler, so -developers must ensure that it is only used as part of a proper synchronizer. - -Finally we combine all the components in: - -@ -asyncFIFOSynchronizer - :: ( 'KnownDomain' wdom - , 'KnownDomain' rdom - , 2 <= addrSize ) - => SNat addrSize - -- ^ Size of the internally used addresses, the FIFO contains \@2^addrSize\@ - -- elements. - -> 'Clock' wdom - -- ^ Clock to which the write port is synchronized - -> 'Clock' rdom - -- ^ Clock to which the read port is synchronized - -> 'Reset' wdom - -> 'Reset' rdom - -> 'Enable' wdom - -> 'Enable' rdom - -> 'Signal' rdom Bool - -- ^ Read request - -> 'Signal' wdom (Maybe a) - -- ^ Element to insert - -> ('Signal' rdom a, 'Signal' rdom Bool, 'Signal' wdom Bool) - -- ^ (Oldest element in the FIFO, \@empty\@ flag, \@full\@ flag) -asyncFIFOSynchronizer addrSize\@SNat wclk rclk wrst rrst wen ren rinc wdataM = - (rdata, rempty, wfull) - where - s_rptr = ptrSync rclk wclk wrst wen rptr - s_wptr = ptrSync wclk rclk rrst ren wptr - - rdata = - fifoMem - wclk rclk wen - addrSize wfull raddr - (liftA2 (,) \<$\> (pure \<$\> waddr) \<*\> wdataM) - - (rempty, raddr, rptr) = - 'mealyB' - rclk rrst ren - (ptrCompareT addrSize isEmpty) - (0, 0, True) - (s_wptr, rinc) - - (wfull, waddr, wptr) = - 'mealyB' - wclk wrst wen - (ptrCompareT addrSize (isFull addrSize)) - (0, 0, False) - (s_rptr, isJust \<$\> wdataM) -@ - -where we first specify the synchronization of the read and the write pointers, -instantiate the asynchronous RAM, and instantiate the read address \/ pointer \/ -flag generator and write address \/ pointer \/ flag generator. - -Ultimately, the whole file containing our FIFO design will look like this: - -@ -module MultiClockFifo where - -import "Clash.Explicit.Prelude" -import "Clash.Prelude" (mux) -import Data.Maybe (isJust) -import Data.Constraint (Dict (..), (:-)( Sub )) -import Data.Constraint.Nat (leTrans) - -fifoMem wclk rclk en addrSize\@SNat full raddr writeM = - 'Clash.Explicit.Prelude.asyncRam' - wclk rclk en - ('pow2SNat' addrSize) - raddr - ('mux' full (pure Nothing) writeM) - -ptrCompareT - :: SNat addrSize - -> (BitVector (addrSize + 1) -> BitVector (addrSize + 1) -> Bool) - -> ( BitVector (addrSize + 1) - , BitVector (addrSize + 1) - , Bool ) - -> ( BitVector (addrSize + 1) - , Bool ) - -> ( ( BitVector (addrSize + 1) - , BitVector (addrSize + 1) - , Bool ) - , ( Bool - , BitVector addrSize - , BitVector (addrSize + 1) - ) - ) -ptrCompareT addrSize\@SNat flagGen (bin, ptr, flag) (s_ptr, inc) = - ( (bin', ptr', flag') - , (flag, addr, ptr) ) - where - -- GRAYSTYLE2 pointer - bin' = bin + 'boolToBV' (inc && not flag) - ptr' = (bin' \`shiftR\` 1) \`xor\` bin' - addr = 'truncateB' bin - flag' = flagGen ptr' s_ptr - --- FIFO empty: when next pntr == synchronized wptr or on reset -isEmpty = (==) -rptrEmptyInit = (0, 0, True) - --- FIFO full: when next pntr == synchronized {~wptr[addrSize:addrSize-1],wptr[addrSize-2:0]} -isFull - :: forall addrSize - . (2 <= addrSize) - => 'SNat' addrSize - -> 'BitVector' (addrSize + 1) - -> 'BitVector' (addrSize + 1) - -> Bool -isFull addrSize\@SNat ptr s_ptr = case leTrans \@1 \@2 \@addrSize of - Sub Dict -> - let a1 = 'SNat' \@(addrSize - 1) - a2 = 'SNat' \@(addrSize - 2) - in ptr == ('complement' ('slice' addrSize a1 s_ptr) '++#' 'slice' a2 d0 s_ptr) - -wptrFullInit = (0, 0, False) - --- Dual flip-flop synchronizer -ptrSync clk1 clk2 rst2 en2 = - 'Clash.Explicit.Signal.register' clk2 rst2 en2 0 . 'Clash.Explicit.Signal.register' clk2 rst2 en2 0 . 'Clash.Explicit.Signal.unsafeSynchronizer' clk1 clk2 - --- Async FIFO synchronizer -asyncFIFOSynchronizer - :: ( 'KnownDomain' wdom - , 'KnownDomain' rdom - , 2 <= addrSize ) - => SNat addrSize - -- ^ Size of the internally used addresses, the FIFO contains \@2^addrSize\@ - -- elements. - -> 'Clock' wdom - -- ^ Clock to which the write port is synchronized - -> 'Clock' rdom - -- ^ Clock to which the read port is synchronized - -> 'Reset' wdom - -> 'Reset' rdom - -> 'Enable' wdom - -> 'Enable' rdom - -> 'Signal' rdom Bool - -- ^ Read request - -> 'Signal' wdom (Maybe a) - -- ^ Element to insert - -> ('Signal' rdom a, 'Signal' rdom Bool, 'Signal' wdom Bool) - -- ^ (Oldest element in the FIFO, \@empty\@ flag, \@full\@ flag) -asyncFIFOSynchronizer addrSize\@SNat wclk rclk wrst rrst wen ren rinc wdataM = - (rdata, rempty, wfull) - where - s_rptr = ptrSync rclk wclk wrst wen rptr - s_wptr = ptrSync wclk rclk rrst ren wptr - - rdata = - fifoMem - wclk rclk wen - addrSize wfull raddr - (liftA2 (,) \<$\> (pure \<$\> waddr) \<*\> wdataM) - - (rempty, raddr, rptr) = - 'mealyB' - rclk rrst ren - (ptrCompareT addrSize isEmpty) - (0, 0, True) - (s_wptr, rinc) - - (wfull, waddr, wptr) = - 'mealyB' - wclk wrst wen - (ptrCompareT addrSize (isFull addrSize)) - (0, 0, False) - (s_rptr, isJust \<$\> wdataM) -@ - -== Instantiating a FIFO synchronizer - -Having finished our FIFO synchronizer it's time to instantiate with concrete -clock domains. Let us assume we have part of our system connected to an ADC -which runs at 20 MHz, and we have created an FFT component running at only 9 -MHz. We want to connect part of our design connected to the ADC, and running -at 20 MHz, to part of our design connected to the FFT running at 9 MHz. - -We can calculate the clock periods using 'hzToPeriod': - ->>> hzToPeriod 20e6 -50000 ->>> hzToPeriod 9e6 -111111 - -We can then create the clock and reset domains: - -@ -'createDomain' vSystem{vName=\"ADC\", vPeriod=hzToPeriod 20e6} -'createDomain' vSystem{vName=\"FFT\", vPeriod=hzToPeriod 9e6} -@ - -and subsequently a 256-space FIFO synchronizer that safely bridges the ADC clock -domain and to the FFT clock domain: - -@ -adcToFFT - :: 'Clock' \"ADC\" - -> 'Clock' \"FFT\" - -> 'Reset' \"ADC\" - -> 'Reset' \"FFT\" - -> 'Enable' \"ADC\" - -> 'Enable' \"FFT\" - -> 'Signal' \"FFT\" Bool - -> 'Signal' \"ADC\" (Maybe (SFixed 8 8)) - -> ( 'Signal' \"FFT\" (SFixed 8 8) - , 'Signal' \"FFT\" Bool - , 'Signal' \"ADC\" Bool ) -adcToFFT = asyncFIFOSynchronizer d8 -@ - --} - -{- $conclusion -For now, this is the end of this tutorial. We will be adding updates over time, -so check back from time to time. We recommend that you continue with -exploring the "Clash.Prelude" module, and get a better understanding of the -capabilities of Clash in the process. --} - -{- $errorsandsolutions -A list of often encountered errors and their solutions: - -* __Type error: Couldn't match expected type @'Signal' dom (a,b)@ with actual type__ - __@('Signal' dom a, 'Signal' dom b)@__: - - Signals of product types and product types of signals are __isomorphic__ - due to synchronisity principle, but are not (structurally) equal. Tuples - are a product type. Use the 'bundle' function to convert from a product - type to the signal type. So if your code which gives the error looks like: - - @ - ... = f a b (c,d) - @ - - add the 'bundle' function like so: - - @ - ... = f a b ('bundle' (c,d)) - @ - - Product types supported by 'bundle' are: - - * All tuples up to and including 62-tuples (GHC limit) - * The 'Vec'tor type - -* __Type error: Couldn't match expected type @('Signal' dom a, 'Signal' dom b)@ with__ - __ actual type @'Signal' dom (a,b)@__: - - Product types of signals and signals of product types are __isomorphic__ - due to synchronicity principle, but are not (structurally) equal. Tuples - are a product type. Use the 'unbundle' function to convert from a signal - type to the product type. So if your code which gives the error looks - like: - - @ - (c,d) = f a b - @ - - add the 'unbundle' function like so: - - @ - (c,d) = 'unbundle' (f a b) - @ - - Product types supported by 'unbundle' are: - - * All tuples up to and including 62-tuples (GHC limit) - * The 'Vec'tor type - -* __Clash.Netlist(..): Not in normal form: \: \__: - - A function could not be transformed into the expected normal form. This - usually means one of the following: - - * The @topEntity@ has higher-order arguments, or a higher-order result. - * You are using types which cannot be represented in hardware. - - The solution for all the above listed reasons is quite simple: remove them. - That is, make sure that the @topEntity@ is completely monomorphic and - first-order. Also remove any variables and constants/literals that have a - non-representable type; see <#limitations Limitations of Clash> to find - out which types are not representable. - -* __Clash.Normalize(..): Clash can only normalize monomorphic functions, but this is polymorphic__: - - If this happens for a @topEntity@ or something with a @Synthesize@ annotation, - add a monomorphic type signature. - Non topEntites should be type-specialized by clash automatically, if not please report this as a bug. - But adding a monomorphic type signature should still help (when possible). - - -* __Clash.Normalize(..): Expr belonging to bndr: \ remains__ - __recursive after normalization__: - - * If you actually wrote a recursive function, rewrite it to a non-recursive - one using e.g. one of the higher-order functions in "Clash.Sized.Vector" :-) - - * You defined a recursively defined value, but left it polymorphic: - - @ - topEntity x y = acc - where - acc = 'register' 3 (acc + x * y) - @ - - The above function, works for any number-like type. This means that @acc@ is - a recursively defined __polymorphic__ value. Adding a monomorphic type - annotation makes the error go away: - - @ - topEntity - :: 'SystemClockResetEnable' - => 'Signal' 'System' ('Signed' 8) - -> 'Signal' 'System' ('Signed' 8) - -> 'Signal' 'System' ('Signed' 8) - topEntity x y = acc - where - acc = 'register' 3 (acc + x * y) - @ - -* __Clash.Normalize.Transformations(..): InlineNonRep: \ already__ - __inlined 100 times in:\, \__: - - You left the @topEntity@ function polymorphic or higher-order: use - @:t topEntity@ to check if the type is indeed polymorphic or higher-order. - If it is, add a monomorphic type signature, and / or supply higher-order - arguments. - -* __\<*** Exception: \<\\>__ or "blinking cursor" - - You are using value-recursion, but one of the 'Vec'tor functions that you - are using is too /strict/ in one of the recursive arguments. For example: - - @ - -- Bubble sort for 1 iteration - sortV xs = 'map' fst sorted ':<' (snd ('last' sorted)) - where - lefts = 'head' xs :> 'map' snd ('init' sorted) - rights = 'tail' xs - sorted = 'zipWith' compareSwapL lefts rights - - -- Compare and swap - compareSwapL a b = if a < b then (a,b) - else (b,a) - @ - - Will not terminate because 'zipWith' is too strict in its second argument. - - In this case, adding 'lazyV' on 'zipWith's second argument: - - @ - sortVL xs = 'map' fst sorted ':<' (snd ('last' sorted)) - where - lefts = 'head' xs :> map snd ('init' sorted) - rights = 'tail' xs - sorted = 'zipWith' compareSwapL ('lazyV' lefts) rights - @ - - Results in a successful computation: - - >>> sortVL (4 :> 1 :> 2 :> 3 :> Nil) - 1 :> 2 :> 3 :> 4 :> Nil --} - -{- $limitations #limitations# -Here is a list of Haskell features for which the Clash compiler has only -/limited/ support (for now): - -* __Recursively defined functions__ - - At first hand, it seems rather bad that a compiler for a functional language - cannot synthesize recursively defined functions to circuits. However, when - viewing your functions as a /structural/ specification of a circuit, this - /feature/ of the Clash compiler makes sense. Also, only certain types of - recursion are considered non-synthesizable; recursively defined values are - for example synthesizable: they are (often) synthesized to feedback loops. - - Let us distinguish between three variants of recursion: - - * __Dynamic data-dependent recursion__ - - As demonstrated in this definition of a function that calculates the - n'th Fibbonacci number: - - @ - fibR 0 = 0 - fibR 1 = 1 - fibR n = fibR (n-1) + fibR (n-2) - @ - - To get the first 10 numbers, we do the following: - - >>> import qualified Data.List as L - >>> L.map fibR [0..9] - [0,1,1,2,3,5,8,13,21,34] - - The @fibR@ function is not synthesizable by the Clash compiler, because, - when we take a /structural/ view, @fibR@ describes an infinitely deep - structure. - - In principal, descriptions like the above could be synthesized to a - circuit, but it would have to be a /sequential/ circuit. Where the most - general synthesis would then require a stack. Such a synthesis approach - is also known as /behavioral/ synthesis, something which the Clash - compiler simply does not do. One reason that Clash does not do this is - because it does not fit the paradigm that only functions working on - values of type 'Signal' result in sequential circuits, and all other - (non higher-order) functions result in combinational circuits. This - paradigm gives the designer the most straightforward mapping from the - original Haskell description to generated circuit, and thus the greatest - control over the eventual size of the circuit and longest propagation - delay. - - * __Value-recursion__ - - As demonstrated in this definition of a function that calculates the - n'th Fibbonaci number on the n'th clock cycle: - - @ - fibS :: SystemClockResetEnable => Signal System (Unsigned 64) - fibS = r - where r = 'register' 0 r + 'register' 0 ('register' 1 r) - @ - - To get the first 10 numbers, we do the following: - - >>> sampleN @System 11 fibS - [0,0,1,1,2,3,5,8,13,21,34] - - Unlike the @fibR@ function, the above @fibS@ function /is/ synthesizable - by the Clash compiler. Where the recursively defined (non-function) - value /r/ is synthesized to a feedback loop containing three registers - and one adder. - - Note that not all recursively defined values result in a feedback loop. - An example that uses recursively defined values which does not result - in a feedback loop is the following function that performs one iteration - of bubble sort: - - @ - sortVL xs = 'map' fst sorted ':<' (snd ('last' sorted)) - where - lefts = 'head' xs :> map snd ('init' sorted) - rights = 'tail' xs - sorted = 'zipWith' compareSwapL ('lazyV' lefts) rights - @ - - Where we can clearly see that @lefts@ and @sorted@ are defined in terms - of each other. Also the above @sortV@ function /is/ synthesizable. - - * __Static/Structure-dependent recursion__ - - Static, or, structure-dependent recursion is a rather /vague/ concept. - What we mean by this concept are recursive definitions where a user can - sensibly imagine that the recursive definition can be completely - unfolded (all recursion is eliminated) at compile-time in a finite - amount of time. - - Such definitions would e.g. be: - - @ - mapV :: (a -> b) -> Vec n a -> Vec n b - mapV _ Nil = Nil - mapV f (Cons x xs) = Cons (f x) (mapV f xs) - - topEntity :: Vec 4 Int -> Vec 4 Int - topEntity = mapV (+1) - @ - - Where one can imagine that a compiler can unroll the definition of - @mapV@ four times, knowing that the @topEntity@ function applies @mapV@ - to a 'Vec' of length 4. Sadly, the compile-time evaluation mechanisms in - the Clash compiler are very poor, and a user-defined function such as - the @mapV@ function defined above, is /currently/ not synthesizable. - We /do/ plan to add support for this in the future. In the mean time, - this poor support for user-defined recursive functions is amortized by - the fact that the Clash compiler has built-in support for the - higher-order functions defined in "Clash.Sized.Vector". Most regular - design patterns often encountered in circuit design are captured by the - higher-order functions in "Clash.Sized.Vector". - -* __Recursive datatypes__ - - The Clash compiler needs to be able to determine a bit-size for any value - that will be represented in the eventual circuit. More specifically, we need - to know the maximum number of bits needed to represent a value. While this - is trivial for values of the elementary types, sum types, and product types, - putting a fixed upper bound on recursive types is not (always) feasible. - This means that the ubiquitous list type is unsupported! The only recursive - types that are currently supported by the Clash compiler is the 'Vec'tor and - 'RTree' types, for which the compiler has hard-coded knowledge. - - For \"easy\" 'Vec'tor literals you should use Template Haskell splices and - the 'listToVecTH' /meta/-function that as we have seen earlier in this tutorial. - -* __GADTs__ - - Clash has experimental support for GADTs. Similar to recursive types, Clash - can't determine bit-sizes of GADTs. Notable exceptions to this rule are - 'Vec' and 'RTree'. You can still use your own GADTs, as long as they can be - removed through static analysis. For example, the following case will be - optimized away and is therefore fine to use: - - @ - x = - case 'resetKind' @'System' of - SAsynchronous -> \'a\' - SSynchronous -> \'b\' - @ - -* __Floating point types__ - - There is no support for the 'Float' and 'Double' types, if you need numbers - with a /fractional/ part you can use the 'Fixed' point type. - - As to why there is no support for these floating point types: - - 1. In order to achieve reasonable operating frequencies, arithmetic - circuits for floating point data types must be pipelined. - 2. Haskell's primitive arithmetic operators on floating point data types, - such as 'plusFloat#' - - @ - __plusFloat#__ :: 'Float#' -> 'Float#' -> 'Float#' - @ - - which underlie 'Float'\'s 'Num' instance, must be implemented as - purely combinational circuits according to their type. Remember, - sequential circuits operate on values of type \"@'Signal' a@\". - - Although it is possible to implement purely combinational (not pipelined) - arithmetic circuits for floating point data types, the circuit would be - unreasonable slow. And so, without synthesis possibilities for the basic - arithmetic operations, there is no point in supporting the floating point - data types. - -* __Haskell primitive types__ - - Only the following primitive Haskell types are supported: - - * 'Integer' - * 'Int' - * 'Int8' - * 'Int16' - * 'Int32' - * 'Int64' (not available when compiling with @-fclash-intwidth=32@ on a 64-bit machine) - * 'Word' - * 'Word8' - * 'Word16' - * 'Word32' - * 'Word64' (not available when compiling with @-fclash-intwidth=32@ on a 64-bit machine) - * 'Char' - - There are several aspects of which you should take note: - - * 'Int' and 'Word' are represented by the same number of bits as is - native for the architecture of the computer on which the Clash - compiler is executed. This means that if you are working on a 64-bit - machine, 'Int' and 'Word' will be 64-bit. This might be problematic - when you are working in a team, and one designer has a 32-bit - machine, and the other has a 64-bit machine. In general, you should - be avoiding 'Int' in such cases, but as a band-aid solution, you can - force the Clash compiler to use a specific bit-width for `Int` and - `Word` using the @-fclash-intwidth=N@ flag, where /N/ must either be - /32/ or /64/. - - * When you use the @-fclash-intwidth=32@ flag on a /64-bit/ machine, - the 'Word64' and 'Int64' types /cannot/ be translated. This - restriction does /not/ apply to the other three combinations of - @-fclash-intwidth@ flag and machine type. - - * The translation of 'Integer' is not meaning-preserving. 'Integer' in - Haskell is an arbitrary precision integer, something that cannot - be represented in a statically known number of bits. In the Clash - compiler, we chose to represent 'Integer' by the same number of bits - as we do for 'Int' and 'Word'. As you have read in a previous - bullet point, this number of bits is either 32 or 64, depending on - the architecture of the machine the Clash compiler is running on, or - the setting of the @-fclash-intwidth@ flag. - - Consequently, you should use `Integer` with due diligence; be - especially careful when using `fromIntegral` as it does a conversion - via 'Integer'. For example: - - > signedToUnsigned :: Signed 128 -> Unsigned 128 - > signedToUnsigned = fromIntegral - - can either lose the top 64 or 96 bits depending on whether 'Integer' - is represented by 64 or 32 bits. Instead, when doing such conversions, - you should use 'bitCoerce': - - > signedToUnsigned :: Signed 128 -> Unsigned 128 - > signedToUnsigned = bitCoerce - -* __Side-effects: 'IO', 'ST', etc.__ - - There is no support for side-effecting computations such as those in the - 'IO' or 'ST' monad. There is also no support for Haskell's - . --} - -{- $vslava -In Haskell land the most well-known way of describing digital circuits is the -Lava family of languages: - -* -* -* -* - -The big difference between Clash and Lava is that Clash uses a \"standard\" -compiler (static analysis) approach towards synthesis, where Lava is an -embedded domain specific language. One downside of static analysis vs. the -embedded language approach is already clearly visible: synthesis of recursive -descriptions does not come for \"free\". This will be implemented in Clash in -due time, but that doesn't help the circuit designer right now. As already -mentioned earlier, the poor support for recursive functions is amortized by -the built-in support for the higher-order in "Clash.Sized.Vector". - -The big upside of Clash and its static analysis approach is that Clash can -do synthesis of \"normal\" functions: there is no forced encasing datatype (often -called /Signal/ in Lava) on all the arguments and results of a synthesizable -function. This enables the following features not available to Lava: - -* Automatic synthesis for user-defined ADTs -* Synthesis of all choice constructs (pattern matching, guards, etc.) -* 'Applicative' instance for the 'Signal' type -* Working with \"normal\" functions permits the use of e.g. - the t'Control.Monad.State.Strict.State' monad to describe the functionality of - a circuit. - -Although there are Lava alternatives to some of the above features (e.g. -first-class patterns to replace pattern matching) they are not as \"beautiful\" -and / or easy to use as the standard Haskell features. --} - -{- $migration - -* Clash has overhauled the way synthesis options are represented. You can read - about this change in the blogpost: . - The executive summary is as follows: - -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| __0.99__ | __1.0__ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @topEntity (clk::Clock d 'Source) rst = withClockReset f clk rst@ | @topEntity clk rst = withClockResetEnable clk rst enableGen f@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @topEntity (clk::Clock d 'Gated) rst = withClockReset f clk rst@ | @topEntity clk rst enable = withClockResetEnable clk rst enable f@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @data A = ... @ (and @A@ is used as state, for example in register or mealy) | @data A = ... deriving (Generic,NFDataX)@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @SystemClockReset@ | @SystemClockResetEnable@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @HiddenClockReset dom gated sync@ | @HiddenClockResetEnable dom@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @HiddenClock dom gated@ | @HiddenClock dom@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @HiddenReset dom sync@ | @HiddenReset dom@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @Clock dom gated@ | @Clock dom@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ -| @Reset dom sync@ | @Reset dom@ | -+------------------------------------------------------------------------------+--------------------------------------------------------------------+ - -* @outputVerifier@ now operates on two domains. If you only need one, simply - change it to @outputVerifier'@ - -* For an overview of all other changes, check out - -=== Examples - -==== FIR filter - -FIR filter in Clash 0.99: - -@ -module FIR where - -import Clash.Prelude -import Clash.Explicit.Testbench - -dotp :: SaturatingNum a - => Vec (n + 1) a - -> Vec (n + 1) a - -> a -dotp as bs = fold boundedPlus (zipWith boundedMult as bs) - -fir - :: (Default a, KnownNat n, SaturatingNum a, HiddenClockReset domain gated synchronous) - => Vec (n + 1) a -> Signal domain a -> Signal domain a -fir coeffs x_t = y_t - where - y_t = dotp coeffs \<$\> bundle xs - xs = window x_t - -topEntity - :: Clock System Source - -> Reset System Asynchronous - -> Signal System (Signed 16) - -> Signal System (Signed 16) -topEntity = exposeClockReset (fir (2:>3:>(-2):>8:>Nil)) -{\-\# NOINLINE topEntity \#-\} - -testBench :: Signal System Bool -testBench = done - where - testInput = stimuliGenerator clk rst (2:>3:>(-2):>8:>Nil) - expectedOutput = outputVerifier' clk rst (4:>12:>1:>20:>Nil) - done = expectedOutput (topEntity clk rst testInput) - clk = tbSystemClockGen (not \<$\> done) - rst = systemResetGen -@ - -FIR filter in Clash 1.0: - -@ - -module FIR where - -import Clash.Prelude -import Clash.Explicit.Testbench - -dotp :: 'SaturatingNum' a - => 'Vec' (n + 1) a - -> 'Vec' (n + 1) a - -> a -dotp as bs = 'fold' 'boundedAdd' ('zipWith' 'boundedMul' as bs) - -fir - :: ( 'HiddenClockResetEnable' dom - , 'KnownNat' n - , 'SaturatingNum' a - , 'NFDataX' a - , 'Default' a ) - => 'Vec' (n + 1) a -> 'Signal' dom a -> 'Signal' dom a -fir coeffs x_t = y_t - where - y_t = dotp coeffs \<$\> 'bundle' xs - xs = 'window' x_t - -topEntity - :: 'Clock' 'System' - -> 'Reset' 'System' - -> 'Enable' 'System' - -> 'Signal' 'System' ('Signed' 16) - -> 'Signal' 'System' ('Signed' 16) -topEntity = 'exposeClockResetEnable' (fir (2:>3:>(-2):>8:>'Nil')) -{\-\# NOINLINE topEntity \#-\} - -testBench :: 'Signal' 'System' 'Bool' -testBench = done - where - testInput = 'stimuliGenerator' clk rst (2:>3:>(-2):>8:>'Nil') - expectedOutput = 'outputVerifier'' clk rst (4:>12:>1:>20:>'Nil') - done = expectedOutput (topEntity clk rst 'enableGen' testInput) - clk = 'tbSystemClockGen' (not \<$\> done) - rst = 'systemResetGen' -@ - -==== Blinker circuit - -Blinker circuit in Clash 0.99: - -@ -{\-\# LANGUAGE NoMonoLocalBinds \#-\} - -module Blinker where - -import Clash.Prelude -import Clash.Promoted.Symbol -import Clash.Intel.ClockGen - -type Dom50 = Dom \"System\" 20000 - -{\-\# ANN topEntity - (Synthesize - { t_name = \"blinker\" - , t_inputs = [ PortName \"CLOCK_50\" - , PortName \"KEY0\" - , PortName \"KEY1\" - ] - , t_output = PortName \"LED\" - }) \#-\} -topEntity - :: Clock Dom50 Source - -> Reset Dom50 Asynchronous - -> Signal Dom50 Bit - -> Signal Dom50 (BitVector 8) -topEntity clk rst = - exposeClockReset (mealy blinkerT (1,False,0) . isRising 1) pllOut rstSync - where - (pllOut,pllStable) = altpll \@Dom50 (SSymbol \@\"altpll50\") clk rst - rstSync = resetSynchronizer pllOut (unsafeToAsyncReset pllStable) - -blinkerT (leds,mode,cntr) key1R = ((leds',mode',cntr'),leds) - where - -- clock frequency = 50e6 (50 MHz) - -- led update rate = 333e-3 (every 333ms) - cnt_max = 16650000 -- 50e6 * 333e-3 - - cntr' | cntr == cnt_max = 0 - | otherwise = cntr + 1 - - mode' | key1R = not mode - | otherwise = mode - - leds' | cntr == 0 = if mode then complement leds - else rotateL leds 1 - | otherwise = leds -@ - -Blinker in Clash 1.0: - -@ -module Blinker where - -import "Clash.Signal" -import "Clash.Prelude" -import "Clash.Intel.ClockGen" - -'createDomain' vSystem{vName=\"DomInput\", vPeriod=20000} -'createDomain' vSystem{vName=\"Dom100\", vPeriod=10000} - -topEntity - :: Clock DomInput - -> Signal DomInput Bool - -> Signal Dom100 Bit - -> Signal Dom100 (BitVector 8) -topEntity clk rst = - 'exposeClockResetEnable' ('mealy' blinkerT (1,False,0) . Clash.Prelude.isRising 1) pllOut rstSync 'enableGen' - where - (pllOut,pllStable) = 'Clash.Intel.ClockGen.altpll' \@Dom100 (SSymbol \@\"altpll100\") clk ('unsafeFromActiveLow' rst) - rstSync = 'Clash.Signal.resetSynchronizer' pllOut ('unsafeFromActiveLow' pllStable) - -blinkerT (leds,mode,cntr) key1R = ((leds',mode',cntr'),leds) - where - -- clock frequency = 100e6 (100 MHz) - -- led update rate = 333e-3 (every 333ms) - cnt_max = 'maxBound' :: ('Index' 33300000) -- 100e6 * 333e-3 - - cntr' | cntr == cnt_max = 0 - | otherwise = cntr + 1 +{- $moved +The content of this page has been moved: - mode' | key1R = not mode - | otherwise = mode +* The tutorial can now be found at: https://docs.clash-lang.org/tutorial/ +* Compiler user guide material can now be found at: https://docs.clash-lang.org/compiler-user-guide/ - leds' | cntr == 0 = if mode then complement leds - else rotateL leds 1 - | otherwise = leds -@ -} From 819b99a49e6edaf290d8513760f716667dd20261 Mon Sep 17 00:00:00 2001 From: Peter Lebbing Date: Thu, 20 Nov 2025 17:38:45 +0100 Subject: [PATCH 2/2] Read the Docs: just link to new home And remove all the documentation that was there, including STYLE.rst and HACKING.rst in the root. --- .readthedocs.yml | 9 +- HACKING.rst | 75 -- STYLE.rst | 652 ------------------ .../2025-09-26T14_06_42+02_00_move_tutorial | 2 +- docs/CHANGELOG.md | 1 - docs/README.md | 73 -- docs/changelog.rst | 6 - docs/conf.py | 2 +- docs/developing-hardware/flags.rst | 285 -------- docs/developing-hardware/index.rst | 11 - docs/developing-hardware/language.rst | 58 -- docs/developing-hardware/prelude.rst | 172 ----- docs/general/LICENSE | 24 - docs/general/faqs.rst | 224 ------ docs/general/index.rst | 12 - docs/general/intro.rst | 133 ---- docs/general/license.rst | 8 - docs/general/relnotes.rst | 15 - docs/getting-started/first-circuit.rst | 117 ---- docs/getting-started/index.rst | 10 - docs/getting-started/installing.rst | 75 -- docs/hacking-on-clash/hacking.rst | 4 - docs/hacking-on-clash/index.rst | 10 - docs/hacking-on-clash/style.rst | 4 - docs/index.rst | 42 +- docs/refs.rst | 129 ---- docs/requirements.txt | 4 +- 27 files changed, 12 insertions(+), 2145 deletions(-) delete mode 100644 HACKING.rst delete mode 100644 STYLE.rst delete mode 120000 docs/CHANGELOG.md delete mode 100644 docs/README.md delete mode 100644 docs/changelog.rst delete mode 100644 docs/developing-hardware/flags.rst delete mode 100644 docs/developing-hardware/index.rst delete mode 100644 docs/developing-hardware/language.rst delete mode 100644 docs/developing-hardware/prelude.rst delete mode 100644 docs/general/LICENSE delete mode 100644 docs/general/faqs.rst delete mode 100644 docs/general/index.rst delete mode 100644 docs/general/intro.rst delete mode 100644 docs/general/license.rst delete mode 100644 docs/general/relnotes.rst delete mode 100644 docs/getting-started/first-circuit.rst delete mode 100644 docs/getting-started/index.rst delete mode 100644 docs/getting-started/installing.rst delete mode 100644 docs/hacking-on-clash/hacking.rst delete mode 100644 docs/hacking-on-clash/index.rst delete mode 100644 docs/hacking-on-clash/style.rst delete mode 100644 docs/refs.rst diff --git a/.readthedocs.yml b/.readthedocs.yml index 2ac21bbc62..587f2eb0a7 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,16 +1,15 @@ version: 2 -formats: all build: - image: latest + os: "ubuntu-24.04" + tools: + python: "3.13" python: - version: 3.7 install: - - requirements: docs/requirements.txt + - requirements: docs/requirements.txt sphinx: builder: html configuration: docs/conf.py fail_on_warning: true - diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index ad304bed94..0000000000 --- a/HACKING.rst +++ /dev/null @@ -1,75 +0,0 @@ -The Clash Compiler -================== - -Prerequisites -------------- - -Hacking on Clash requires more dependencies than simply running Clash. The -test suite requires having a tool available to synthesize any backend being -tested. This means you need - -- ghdl_ installed to test *VHDL* -- iverilog_ installed to test *Verilog* -- ModelSim_ installed to test *System Verilog* -- SymbiYosys_ and Z3_ installed to test *Verilog* and *System Verilog* - -.. _ghdl: https://github.com/ghdl/ghdl -.. _iverilog: https://github.com/steveicarus/iverilog -.. _ModelSim: https://fpgasoftware.intel.com/?product=modelsim_ae#tabs-2 -.. _SymbiYosys: https://github.com/YosysHQ/SymbiYosys -.. _Z3: https://github.com/Z3Prover/z3 - -Subprojects ------------ - -The Clash compiler consists of different cabal libraries, which together -provide a complete compiler. Primarily, this consists of - -``clash-ghc`` - - The front-end of the compiler, using parts of the GHC front-end. This - provides the ability to load modules, translate GHC Core to Clash Core, and - implements the ``clash`` and ``clashi`` executables. - - A lot of the code in this library is separated by the version of GHC it works - with. For example, ``src-bin-9.0`` is specific to GHC 9.0.x. - -``clash-lib`` - - The back-end of the compiler, exposed as a library. This is the largest - library in the project, and includes the various ASTs (e.g. Core, Netlist), - normalization, code generation, and primitives / black boxes. - -``clash-prelude`` - - The standard library for Clash as a language. This includes anything that - is used to develop hardware in Clash, such as Signals, Clocks and combinators - for common forms of state machine. - - The ``clash-prelude`` library also re-exports parts of the Haskell ``base`` - library, allowing circuit designs to re-use common functions and definitions. - -The repository also contains other libraries. These either provide additional -functionality which is not required, or are not yet production-ready. These are - -``clash-cosim`` - - Co-simulation for Clash, allowing Verilog to be run inline as though it were - a normal Haskell function. This provides a QuasiQuoter for use in Haskell. - - .. warning:: This library is very experimental, and is not guaranteed to work - with the most recent development version of Clash. - -``clash-term`` - - A development tool for analysing how the normalizer in ``clash-lib`` affects - the core of a particular design. It allows the result of each different - optimizer pass to be seen for debugging purposes. - -``clash-lib-hedgehog`` - - Hedgehog Generators for ``clash-lib``. - -``clash-prelude-hedgehog`` - - Hedgehog Generators for ``clash-prelude``. diff --git a/STYLE.rst b/STYLE.rst deleted file mode 100644 index 0e158737cf..0000000000 --- a/STYLE.rst +++ /dev/null @@ -1,652 +0,0 @@ -Clash/Haskell Style Guide -========================= - -This is a short document describing the preferred coding style for this -project. When something isn't covered by this guide you should stay -consistent with the code in the other modules. The code style rules -should be considered strong suggestions but shouldn't be dogmatically -applied - if there's a good reason for breaking them *do it*. If you -can't or don't want to apply a guideline or if a guideline is missing, -consider: - -- **How your style affects future changes.** Does changing part of it - cause a lot of realignments? Is it easily extendable by copy-pasting - lines? -- **Whether whitespace is effectively used.** Do new indent-blocks - start 2 spaces deeper than the previous one? Is it easy to see which - block is which? -- **How it scales.** Is the style applicable to small examples as well - as large ones? - -The guidelines formulated below try to balance the points above. - -Formatting ----------- - -Line Length -~~~~~~~~~~~ - -Try to keep below *80 characters* (soft), never exceed *90* (hard). - -Indentation -~~~~~~~~~~~ - -Tabs are illegal. Use spaces for indenting. Indent your code blocks with -*2 spaces*. Indent the ``where`` keyword 1 space to set it apart from -the rest of the code and indent the definitions in a ``where`` clause 1 -space. Some examples: - -.. code:: haskell - - sayHello :: IO () - sayHello = do - name <- getLine - putStrLn $ greeting name - where - greeting name = "Hello, " ++ name ++ "!" - - filter - :: (a -> Bool) - -> [a] - -> [a] - filter _ [] = [] - filter p (x:xs) - | p x = x : filter p xs - | otherwise = filter p xs - -Blank Lines -~~~~~~~~~~~ - -One blank line between top-level definitions. No blank lines between -type signatures and function definitions. Add one blank line between -functions in a type class instance declaration if the function bodies -are large. Use your judgement. - -Whitespace -~~~~~~~~~~ - -Surround binary operators with a single space on either side. Use your -better judgement for the insertion of spaces around arithmetic operators -but always be consistent about whitespace on either side of a binary -operator. Don't insert a space after a lambda. Add a space after each -comma in a tuple: - -.. code:: haskell - - good = (a, b, c) - bad = (a,b,c) - -Refuse the temptation to use the latter when almost hitting the -line-length limit. Restructure your code or use multiline notation -instead. An example of a multiline tuple declaration is: - -.. code:: haskell - - goodMulti = - ( a - , b - , c ) - - goodMulti2 = - ( a - , b - , c - ) - -Use nested tuples as such: - -.. code:: haskell - - nested = - ( ( a1 - , a2 ) - , b - , c ) - -Similar to ``goodMulti2``, you can put the trailing ``)`` on a new line. -Use your judgement. - -Data Declarations -~~~~~~~~~~~~~~~~~ - -Align the constructors in a data type definition. If a data type has -multiple constructors, each constructor will get its own line. Example: - -.. code:: haskell - - data Tree a - = Branch !a !(Tree a) !(Tree a) - | Leaf - deriving (Eq, Show) - -Data types deriving lots of instances may be written like: - -.. code:: haskell - - data Tree a - = Branch !a !(Tree a) !(Tree a) - | Leaf - deriving - ( Eq, Show, Ord, Read, Functor, Generic, NFData - , NFDataX, BitPack, ShowX) - -Data types with a single constructor may be written on a single line: - -.. code:: haskell - - data Foo = Foo Int - -Format records as follows: - -.. code:: haskell - - data Person = Person - { firstName :: !String - -- ^ First name - , lastName :: !String - -- ^ Last name - , age :: !Int - -- ^ Age - } deriving (Eq, Show) - -List Declarations -~~~~~~~~~~~~~~~~~ - -Align the elements in the list. Example: - -.. code:: haskell - - exceptions = - [ InvalidStatusCode - , MissingContentHeader - , InternalServerError ] - -You may put the closing bracket on a new line. Use your judgement. - -.. code:: haskell - - exceptions = - [ InvalidStatusCode - , MissingContentHeader - , InternalServerError - ] - -You may not skip the first newline. - -.. code:: haskell - - -- WRONG! - directions = [ North - , East - , South - , West - ] - -*unless* it fits on a single line: - -.. code:: haskell - - directions = [North, East, South, West] - -Vector Declarations -~~~~~~~~~~~~~~~~~~~ - -Small vectors may be written on a single line: - -.. code:: haskell - - nrs = 1 :> 2 :> 3 :> 4 :> 5 :> Nil - -Large vectors should be written like: - -.. code:: haskell - - exceptions = - North - :> East - :> South - :> West - :> Nil - -Or: - -.. code:: haskell - - exceptions = - North :> East :> South - :> West :> Middle :> Nil - -Language pragmas -~~~~~~~~~~~~~~~~ - -Place LANGUAGE pragmas right after a module's documentation. Do not -align the ``#-}``\ s. ``Safe``, ``Unsafe``, or in some way "special" -language pragmas should follow the normal ones separated by a single -blank line. Pragmas should be ordered alphabetically. Example: - -.. code:: haskell - - {-| - .. docs .. - -} - - {-# LANGUAGE CPP #-} - {-# LANGUAGE DataKinds #-} - {-# LANGUAGE FlexibleInstances #-} - {-# LANGUAGE QuasiQuotes #-} - - {-# LANGUAGE Safe #-} - -Pragmas -~~~~~~~ - -Put pragmas immediately following the function they apply to. Example: - -.. code:: haskell - - id :: a -> a - id x = x - {-# NOINLINE id #-} - -Hanging Lambdas -~~~~~~~~~~~~~~~ - -You may or may not indent the code following a "hanging" lambda. Use -your judgement. Some examples: - -.. code:: haskell - - bar :: IO () - bar = - forM_ [1, 2, 3] $ \n -> do - putStrLn "Here comes a number!" - print n - - foo :: IO () - foo = - alloca 10 $ \a -> - alloca 20 $ \b -> - cFunction a b - -Export Lists -~~~~~~~~~~~~ - -Format export lists as follows: - -.. code:: haskell - - module Data.Set - ( - -- * The @Set@ type - Set - , empty - , singleton - - -- * Querying - , member - ) where - -If-then-else clauses -~~~~~~~~~~~~~~~~~~~~ - -Generally, guards and pattern matches should be preferred over -if-then-else clauses. Short cases should usually be put on a single -line. - -When writing non-monadic code (i.e. when not using ``do``) and guards -and pattern matches can't be used, you can align if-then-else clauses -like you would normal expressions: - -.. code:: haskell - - foo = - if cond0 then - ... - else - ... - -When used in monadic contexts, use: - -.. code:: haskell - - foo = - if cond0 then do - ... - else do - ... - -The same rule applies to nested do blocks: - -.. code:: haskell - - foo = do - instruction <- decodeInstruction - skip <- load Memory.skip - if skip == 0x0000 then do - execute instruction - addCycles $ instructionCycles instruction - else do - store Memory.skip 0x0000 - addCycles 1 - -Case expressions -~~~~~~~~~~~~~~~~ - -The alternatives in a case expression can be indented using either of -the two following styles: - -.. code:: haskell - - foobar = - case something of - Just j -> foo - Nothing -> bar - -or as - -.. code:: haskell - - foobar = - case something of - Just j -> - foo - Nothing -> - bar - -In monadic contexts, use: - -.. code:: haskell - - foobar = - case something of - Just j -> do - foo - bar - Nothing -> do - fizz - buzz - -Align the ``->`` arrows when it helps readability, but keep in mind that -any changes potentially trigger a lot of realignments. This increases -your VCS's diff sizes and becomes tedious quickly. - -Type signatures -~~~~~~~~~~~~~~~ - -Small type signatures can be put on a single line: - -.. code:: haskell - - f :: a -> a -> b - -Longer ones should be put on multiple lines: - -.. code:: haskell - - toInt - :: Int - -- ^ Shift char by /n/ - -> Char - -- ^ Char to convert to ASCII integer - -> Int - -Multiple constraints can be added with a "tuple": - -.. code:: haskell - - toInt - :: (Num a, Show a) - => a - -- ^ Shift char by /n/ - -> Char - -- ^ Char to convert to ASCII integer - -> Int - -Many constraints need to be split accross multiple lines too: - -.. code:: haskell - - toInt - :: ( Num a - , Show a - , Foo a - , Bar a - , Fizz a - ) - => a - -- ^ Shift char by /n/ - -> Char - -- ^ Char to convert to ASCII integer - -> Int - -``forall``'s dot must be aligned: - -.. code:: haskell - - toInt - :: forall a - . (Num a , Show a) - => a - -- ^ Shift char by /n/ - -> Char - -- ^ Char to convert to ASCII integer - -> Int - -If you have many type variables, many constraints, and many arguments, -your function would end up looking like: - -.. code:: haskell - - doSomething - :: forall - clockDomain - resetDomain - resetKind - domainGatedness - . ( NFDataX a - , Ord b - , NFData c - , Functor f ) - => f a - -> f b - -> f c - -Imports -------- - -Imports should be grouped in the following order: - -0. ``clash-prelude``\ † -1. standard library imports -2. related third party imports -3. local application/library specific imports - -Put a blank line between each group of imports. Create subgroups per -your own judgement. The imports in each group should be sorted -alphabetically, by module name. - -Always use explicit import lists or ``qualified`` imports for standard -and third party libraries. This makes the code more robust against -changes in these libraries. Exception: The Prelude. - -† *When writing circuit designs. Does not apply when hacking on the -compiler itself.* - -Comments --------- - -Language -~~~~~~~~ - -Use American English. Initiali\ **z**\ ation, synchroni\ **z**\ ation, -.. - -Punctuation -~~~~~~~~~~~ - -Write proper sentences; start with a capital letter and use proper -punctuation. - -Top-Level Definitions -~~~~~~~~~~~~~~~~~~~~~ - -Comment every top level function (particularly exported functions), and -provide a type signature; use Haddock syntax in the comments. Comment -every exported data type. Function example: - -.. code:: haskell - - -- | Send a message on a socket. The socket must be in a connected - -- state. Returns the number of bytes sent. Applications are - -- responsible for ensuring that all data has been sent. - send - :: Socket - -- ^ Connected socket - -> ByteString - -- ^ Data to send - -> IO Int - -- ^ Bytes sent - -For functions the documentation should give enough information apply the -function without looking at the function's definition. - -Record example: - -.. code:: haskell - - -- | Bla bla bla. - data Person = Person - { age :: !Int - -- ^ Age - , name :: !String - -- ^ First name - } - -For fields that require longer comments format them like so: - -.. code:: haskell - - data Record = Record - { field1 :: !Text - -- ^ This is a very very very long comment that is split over - -- multiple lines. - - , field2 :: !Int - -- ^ This is a second very very very long comment that is split - -- over multiple lines. - } - -End-of-Line Comments -~~~~~~~~~~~~~~~~~~~~ - -Separate end-of-line comments from the code using 2 spaces. Align -comments for data type definitions. Some examples: - -.. code:: haskell - - data Parser = - Parser - !Int -- Current position - !ByteString -- Remaining input - - foo :: Int -> Int - foo n = salt * 32 + 9 - where - salt = 453645243 -- Magic hash salt. - -Links -~~~~~ - -Use in-line links economically. You are encouraged to add links for API -names. It is not necessary to add links for all API names in a Haddock -comment. We therefore recommend adding a link to an API name if: - -- The user might actually want to click on it for more information (in - your judgment), and - -- Only for the first occurrence of each API name in the comment (don't - bother repeating a link) - -Naming ------- - -Use camel case (e.g. ``functionName``) when naming functions and upper -camel case (e.g. ``DataType``) when naming data types. - -For readability reasons, don't capitalize all letters when using an -abbreviation. For example, write ``HttpServer`` instead of -``HTTPServer``. Exception: Two letter abbreviations, e.g. ``IO``. - -Use American English. That is, ``synchronizer``, not ``synchroniser``. - -Modules -~~~~~~~ - -Use singular when naming modules e.g. use ``Data.Map`` and -``Data.ByteString.Internal`` instead of ``Data.Maps`` and -``Data.ByteString.Internals``. - -Dealing with laziness ---------------------- - -By default, use strict data types and lazy functions. - -Data types -~~~~~~~~~~ - -Constructor fields should be strict, unless there's an explicit reason -to make them lazy. This avoids many common pitfalls caused by too much -laziness and reduces the number of brain cycles the programmer has to -spend thinking about evaluation order. - -.. code:: haskell - - -- Good - data Point = Point - { pointX :: !Double - , pointY :: !Double - } - -.. code:: haskell - - -- Bad - data Point = Point - { pointX :: Double - , pointY :: Double - } - -Functions -~~~~~~~~~ - -Have function arguments be lazy unless you explicitly need them to be -strict. - -The most common case when you need strict function arguments is in -recursion with an accumulator: - -.. code:: haskell - - mysum :: [Int] -> Int - mysum = go 0 - where - go !acc [] = acc - go acc (x:xs) = go (acc + x) xs - -Misc ----- - -Point-free style -~~~~~~~~~~~~~~~~ - -Avoid over-using point-free style. For example, this is hard to read: - -.. code:: haskell - - -- Bad: - f = (g .) . h - -Warnings -~~~~~~~~ - -Code should be compilable with ``-Wall -Werror``. There should be no -warnings. diff --git a/changelog/2025-09-26T14_06_42+02_00_move_tutorial b/changelog/2025-09-26T14_06_42+02_00_move_tutorial index 37ad3bf128..8466a4d8a9 100644 --- a/changelog/2025-09-26T14_06_42+02_00_move_tutorial +++ b/changelog/2025-09-26T14_06_42+02_00_move_tutorial @@ -1,4 +1,4 @@ -CHANGED: The content from the `Clash.Tutorial` module has been split and moved to two new locations. +CHANGED: The content from the `Clash.Tutorial` module and from https://clash-lang.readthedocs.io/ has been split and moved to two new locations. 1. The actual tutorial parts has been moved to: https://docs.clash-lang.org/tutorial/ 2. Parts that fit better in the clash compiler user guide have been moved to: https://docs.clash-lang.org/compiler-user-guide/ diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md deleted file mode 120000 index 04c99a55ca..0000000000 --- a/docs/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../CHANGELOG.md \ No newline at end of file diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 3eb66342f7..0000000000 --- a/docs/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Clash documentation - -[![Documentation Status][badge-link]][badge-img] - -[badge-img]: https://clash-lang.readthedocs.io/en/latest/?badge=latest -[badge-link]: http://readthedocs.org/projects/clash-lang/badge/?version=latest - -Documentation for [Clash](http://clash-lang.org), using Sphinx and -[readthedocs.io](https://readthedocs.io) - -Builds for all versions are available [here][http-docs]. PDF, HTML and Epub -downloads are available on the [RtD downloads page][rtd]. - -[http-docs]: https://clash-lang.readthedocs.io -[rtd]: https://readthedocs.org/projects/clash-lang/downloads - -## Current versions - -The format is **repository branch**: `readthedocs documentation branch` - - - **master**: `latest` - The latest Clash documentation for the `master` - branches is always available on the `latest` RtD build branch. - - **1.0**: `1.0` - The Clash 1.0.x documentation for the `1.0` branches - are available in the `1.0` RtD build branch (**TODO FIXME**: NIH!) - -## How to use this repository - -There are a few pointers on how to use this repository, if you're hacking on it. - -### Local builds - -Local testing can easily and quickly be done using [Nix]: - -[Nix]: https://nixos.org/nix - -```bash -$ cd clash-docs/ -$ nix-shell --pure -[nix-shell:...]$ make help -[nix-shell:...]$ make html -[nix-shell:...]$ make latexpdf # TODO FIXME: nix deps -[nix-shell:...]$ make epub # TODO FIXME: nix deps -``` - -The results are in `_build/html`, which can be viewed locally. (**TODO FIXME**: -provide `sphinx-autobuild` for easier automatic hacking.) - -Repository pushes are automatically built by RtD, and the results are available -on the corresponding branches on https://clash-lang.readthedocs.io (see "Current -versions" above). RtD provides builds for all of the above formats. - -### Updating `nixpkgs` - -`clash-docs` uses a fixed version of `nixpkgs` that allows atomic upgrades, and -ensures everyone doing builds locally uses the same version and configuration -for all documentation. (While this isn't true of https://readthedocs.io, it's -still *very* useful.) - -The version of nixpkgs used is specified in `nixpkgs.json`. To update this file, -you can use `nix-prefetch-git` which is available under `nix-shell`: - -```bash -$ nix-shell --pure -[nix-shell:...]$ nix-prefetch-git https://github.com/nixos/nixpkgs.git > nixpkgs.json -``` - -This will atomically upgrade all packages upon the next invocation of -`nix-shell`. - -# License - -BSD2. See `LICENSE` for details. - diff --git a/docs/changelog.rst b/docs/changelog.rst deleted file mode 100644 index 983245d358..0000000000 --- a/docs/changelog.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - ../CHANGELOG.md - diff --git a/docs/conf.py b/docs/conf.py index d6f535ab9f..fe309fa99e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ # Project information project = 'Clash' -copyright = '2017-2019, The Clash Developers' +copyright = '2017-2025, The Clash Developers' author = 'The Clash Developers' version = '1.9.0' release = version diff --git a/docs/developing-hardware/flags.rst b/docs/developing-hardware/flags.rst deleted file mode 100644 index c4e0cbcbde..0000000000 --- a/docs/developing-hardware/flags.rst +++ /dev/null @@ -1,285 +0,0 @@ -.. _flags: - -Clash Compiler Flags -==================== - ---vhdl - Use the VHDL backend for code generation. This currently emits VHDL 1993 - source which can be consumed by other tools. - ---verilog - Use the Verilog backend for code generation. This currently emits - Verilog 2001 source which can be consumed by other tools. - ---systemverilog - Use the SystemVerilog backend for code generation. This currently emits - SystemVerilog 2012 source which can be consumed by other tools. - --fclash-debug - Set the debugging mode for the compiler, exposing additional output. The - available options are - - - ``DebugNone`` to show no debug messages - - ``DebugSilent`` to test invariants and error if any are violated. - This is implicitly enabled by any debug flag - - - ``DebugFinal`` to show expressions after they have been completely - normalized - - ``DebugCount`` to count how often each transformation is applied - - ``DebugName`` to show the names of transformations as they are applied - - ``DebugTry`` to show names of tried and applied transformations - - ``DebugApplied`` to show sub-expressions after they are rewritten - - ``DebugAll`` to show all sub-expressions when a rewrite is attempted - - **Default:** ``DebugNone`` - - .. note:: This flag exists for backwards compatibility. It is now possible to - set debugging flags individually with `-fclash-debug-invariants`, - `-fclash-debug-info` and `-fclash-debug-count-transformations`. - --fclash-debug-invariants - Check invariants while debugging and print warnings / errors which may be - useful, such as alterting when unexpected changes occur or when a - transformation introduces free variables / shadowing. - --fclash-debug-info - Specify the information to show about individual transformations while - debugging. From least to most information, these are - - - ``None`` to show no information - - ``FinalTerm`` to show the final result of normalization - - ``AppliedName`` to show the names of applied transformations - - ``AppliedTerm`` to show the result of applied transformations - - ``TryName`` to show the names of attempted transforamtions, as well as the - result of any transformations which are applied - - ``TryTerm`` to show the names and results of all transformations attempted - whether they were applied or not - - **Default:** ``None`` - --fclash-debug-count-transformations - Count the transformations that are applied and print a summary at the end - of the normalization phase. - --fclash-debug-history[=FILENAME] - Saves all applied rewrites into ``FILENAME``, - for later analysis with the clash-term tool. - When no filename is given it defaults to ``history.dat``. - --fclash-debug-transformations - List the transformations that are to be debugged. This is given as a - comma-separated list of transformations, e.g. - - .. code-block:: bash - - clash -fclash-debug-transformations inlineNonRep,topLet,appProp - - **Default:** [] - --fclash-debug-transformations-from=N - Only print debug output from applied transformation ``N`` and onwards. - - .. code-block:: bash - - clash -fclash-debug-transformations-from=21570 - - **Default:** 0 - --fclash-debug-transformations-limit=N - Only print debug output for ``N`` applied transformations. - - .. code-block:: bash - - clash -fclash-debug-transformations-limit=12 - - **Default:** MAX_INT - --fclash-hdldir - Specify the directory that generated HDL is written into. For example - - .. code-block:: bash - - clash -fclash-hdldir build/hdl - - will create a directory ``build/hdl`` - - **Default:** Either ``vhdl``, ``verilog``, or ``systemverilog`` depending on the synthesis target. - --fclash-hdlsyn - Specify the HDL synthesis tool which will be used. Available options are - ``Vivado``, ``Quartus`` and ``Other``, but some synonyms for these exist - (``Xilinx`` and ``ISE`` are synonyms for ``Vivado``, ``Altera`` and - ``Intel`` are synyonyms for ``Quartus``). - - **Default:** ``Other`` - --fclash-no-cache - Don't reuse previously generated output from Clash, instead generating HDL - from a clean state. While this leads to longer builds, it can be useful in - development. - - .. warning:: Previously this flag was called ``-fclash-nocache``, however - this is now deprecated. - - **Default:** Cache generated HDL - --fclash-no-check-inaccessible-idirs - Check that all include directories (containing primitives) exist when running - Clash. If any directory does not exist, an error is thrown. - - **Default:** Check directories - --fclash-clear - Remove HDL directories before writing to them (if cache can't be used). By - default, Clash will only write to non-empty directories if it can prove all - files in it are generated by a previous run. This option applies to directories - of the various top entities, i.e., the subdirectories made in the directory passed - in with ``-fclash-hdldir``. - - **Default:** Clean before build - --fclash-no-prim-warn - Disable warnings for primitives that are annotated with ``warnAlways``. This - means warnings from annotations like - - .. code-block:: haskell - - {-# ANN f (warnAlways "This primitive is dangerous") #-} - - will not be shown when compiling. - - **Default:** Show warnings - --fclash-spec-limit - Change the number of times a function can undergo specialization. - - **Default:** 20 - --fclash-inline-limit - Change the number of times a function ``f`` can undergo inlining inside some - other function ``g``. This prevents the size of ``g`` growing dramatically. - - **Default:** 20 - --fclash-inline-function-limit - Set the threshold for function size. Below this threshold functions are - always inlined (if it is not recursive). - - **Default:** 15 - --fclash-inline-constant-limit - Set the threshold for constant size. Below this threshold constants are - always inlined. A value of 0 inlines all constants. - - **Default:** 0 - --fclash-evaluator-fuel-limit - Set the threshold for unfolding potentially non-terminating bindings in the - evaluator. A value of 0 only unfolds terminating bindings. - - **Default:** 20 - --fclash-intwidth - Set the bit width for the ``Int/Word/Integer`` types in the generated HDL. - Clash simulation is not affected, and neither are ``BitPack`` instances. The - only allowed values are 32 or 64. - - **Default:** Machine word size (``WORD_SIZE_IN_BITS``) - --fclash-error-extra - Print additional information with compiler errors if it as available. If - there is extra information and this flag is not enabled, a message will be - printed suggesting this flag. - - **Default:** False - --fclash-float-support - Enable support for floating point numbers. If this is disabled, Clash will - not attempt to convert Float and Double values for hardware. - - **Default:** False - --fclash-component-prefix - Prefix the names of generated HDl components with a string. For example a - component ``foo`` would be called ``xcorp_foo`` if run with - - .. code-block:: bash - - clash -fclash-component-prefix "xcorp" - - **Default:** "" - --fclash-old-inline-strategy - The new inlining strategy for Clash inlines all functions which are not - marked with ``NOINLINE`` or a synthesize attribute. The old inlining strategy - differed, attempting only to inline functions which were deemed "cheap". - The old inlining strategy may be quicker in practice for some circuits. - - **Default:** False - --fclash-no-escaped-identifiers - Disable extended identifiers, as used in some HDLs like VHDL to allow more - flexibility with names. Clash will only generate basic identifiers if this - is used. - - **Default:** Escaped identifiers are allowed - --fclash-lower-case-basic-identifiers - Clash will only generate lower case basic identifiers if this is used. This - affects places where the various HDLs only allow basic identifiers to be used, - most notably module and file names. - - **Default:** Disabled - --fclash-compile-ultra - Aggressively run the normalizer, potentially gaining much better runtime - performance at the expense of compile time. - - **Default:** False - --fclash-force-undefined{,0,1} - Set the value to use when an undefined value is inserted into generated HDL. - This flag can be suffixed with either 0 or 1 to force use of that bit, or - left without a suffix to use a HDL-specific default (e.g. ``x`` in Verilog). - - **Default:** Disabled - --fclash-aggressive-x-optimization - Remove all undefined branches from case expressions, replacing them with - another defined value in the expression. If only one branch is defined, the - case expression is elided completely. If no branches are defined the entire - expression is replaced with a call to ``errorX``. - - **Implies:** ``-fclash-aggressive-x-optimization-blackboxes`` - - **Default:** False - --fclash-aggressive-x-optimization-blackboxes - Allow blackboxes to detect undefined values and change their behavior - accordingly. For example, if ``register`` is used in combination with an - undefined reset value, it will leave out the reset logic entirely. This - flag is enabled when using ``-fclash-aggressive-x-optimization``. - - **Default:** False - --fclash-edalize - Generate metadata for use with Edalize_. This generates edam.py files in - all top entities with the configuration for building that entity. Users still - need to edit this file to specify the EDA tool to use, and if necessary the - device to target (for Quartus, Vivado etc.) - - **Default:** False - -.. _`Edalize`: https://github.com/olofk/edalize - --main-is - When using one of ``--vhdl``, ``--verilog``, or ``--systemverilog``, this - flag refers to synthesis target. For example, running Clash with - ``clash My.Module -main-is top --vhdl`` would synthesize ``My.Module.top``. - --fclash-timescale-precision - Sets the second part of Verilog's ``timescale 100fs/100fs``. E.g., setting this - flag to ``1fs`` would make Clash generate Verilog files with ``timescale 100fs/1fs`` - as their header. - - **Default:** ``100fs`` diff --git a/docs/developing-hardware/index.rst b/docs/developing-hardware/index.rst deleted file mode 100644 index ba6d1c9a3b..0000000000 --- a/docs/developing-hardware/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -Developing Hardware with Clash -============================== - -.. toctree:: - :maxdepth: 2 - :name: toc-clash - - language - prelude - flags - diff --git a/docs/developing-hardware/language.rst b/docs/developing-hardware/language.rst deleted file mode 100644 index b025c553de..0000000000 --- a/docs/developing-hardware/language.rst +++ /dev/null @@ -1,58 +0,0 @@ -.. _language: - -Clash as a Language -=================== - -As Clash reuses parts of the GHC compiler for its front-end, the syntax and -semantics should be familiar to Haskell programmers. For people unfamiliar -with Haskell, there are many resources to learn the language, such as - -- `Learn You a Haskell `_ -- `Real World Haskell `_ -- `The Haskell Wikibook `_ - -Clash does make some use of more advanced features of GHC Haskell, which are -exposed by GHC as language extensions. The extensions used by Clash are - -- `BinaryLiterals `_ -- `ConstraintKinds `_ -- `DataKinds `_ -- `DeriveAnyClass `_ -- `DeriveGeneric `_ -- `DeriveLift `_ -- `DerivingStrategies `_ -- `ExplicitForAll `_ -- `ExplicitNamespaces `_ -- `FlexibleContexts `_ -- `FlexibleInstances `_ -- `KindSignatures `_ -- `MagicHash `_ -- `MonoLocalBinds `_ -- `NumericUnderscores `_ -- `NoImplicitPrelude `_ -- `NoStarIsType `_ -- `NoStrictData `_ -- `NoStrict `_ -- `QuasiQuotes `_ -- `ScopedTypeVariables `_ -- `TemplateHaskellQuotes `_ -- `TemplateHaskell `_ -- `TypeApplications `_ -- `TypeFamilies `_ -- `TypeOperators `_ - -.. warning:: - Since GHC 8.6, the ``StarIsType`` extension is defined. This extension is - explicitly turned off by Clash, meaning ``Data.Kind.Type`` must be used to - refer to Haskell types. - -Clash also enables some GHC plugins by default which improve the type inference -for type level numbers. The plugins enabled by default are - -- `ghc-typelits-extra `_ -- `ghc-typelits-knownnat `_ -- `ghc-typelits-natnormalise `_ - -Users are free to control the language extensions and GHC options with the -normal ``OPTIONS_GHC`` and ``LANGUAGE`` pragmas in source files. For more -information, see the `GHC User's Guide `_. diff --git a/docs/developing-hardware/prelude.rst b/docs/developing-hardware/prelude.rst deleted file mode 100644 index 555c35a9c9..0000000000 --- a/docs/developing-hardware/prelude.rst +++ /dev/null @@ -1,172 +0,0 @@ -.. _prelude: - -Clash Prelude -============= - -Basic Types ------------ - -The Clash prelude includes many different numeric types, which are used to -safely define other types / functions. These include, but may not be limited to - -- Type level natural numbers (``Nat``), which allow numbers to be used in - types. Conceptually, this is similar to *const generics* in *C++*. - - It is possible to have term level values which refer to a type level number. - This is called ``SNat n`` (for *singleton natural number*). These are defined - up to 1024 with the prefix "d" (e.g. ``d256``). - -- ``Unsigned n`` and ``Signed n`` numbers with an arbitrary width (given as a - type level natural number). These allow fixed-width arithmetic to be used on - arbitrary numbers. - -- ``Index n`` provides natural numbers up to an arbitrary value (given as a - type level natural number). These allow indexing into fixed width structures - like ``Vec n a``. - -Another commonly used type is ``BitVector n``. This provides a fixed size -vector of ``Bit`` values which can be indexed, and used to perform *unsigned -integer arithmetic*. Any type that can be marshalled to / from a ``BitVector -n`` implements the ``BitPack`` class, which defines the conversion. - -.. note:: It is also possible to derive instances of ``BitPack`` using - ``Generic``, by writing ``deriving (Generic, BitPack)`` in the type - definition. This automatically determines how to do the conversion at - compile-time. - -More generally, there is a ``Vec n a`` type which allows collections of -arbitrary values to be used. These vectors are tagged with their length, to -prevent out of bounds access at compile-time. - -.. warning:: - The ``Vec n a`` type exports pattern synonyms for inserting at the left and - right of a vector. The types of the ``Cons`` constructor and ``(:>)`` pattern - are slightly different, and may behave differently in practice. - - The ``Cons`` constructor has a more general type, allowing it to be used in - some cases where the pattern cannot be used. However, this additional power - comes at the cost of type inference. It is recommended that users use the - ``(:>)`` pattern by default, and only use ``Cons`` when necessary. - -Synthesis Domains ------------------ - -Synchronous circuits have a synthesis domain, which determines the behaviour -of things which can affect signals in the domain. Domains consist of - -- a name, which uniquely refers to the domain -- the clock period in ps -- the active edge of the clock -- whether resets are synchronous (edge-sensitive) or not -- whether the initial (power up) behaviour is defined -- whether resets are high or low polarity - -The prelude provides some common domains, namely ``XilinxSystem`` and -``IntelSystem`` for the standard configurations of each vendor. There is also -a generic domain, ``System``, which can be used for vendor-agnostic purposes -(i.e. writing a generic test bench). It is possible to define new synthesis -domains for custom hardware using the ``createDomain`` function, which also -defines the necessary instances for domains. - -A value in a synchronous circuit is wrapped in the ``Signal dom a`` type, which -specifies the synthesis domain and the type of value. Any function which needs -access to a domain can use the constraints ``HasDomain`` (to find it's domain) -or ``KnownDomain`` (to extract configuration). - -The default API exposed by the prelude is implicit with regards to clocks, -reset lines and enable lines -- as these can be determined at compile time. -However, if they are needed the ``Clash.Explicit`` module contains explicit -versions of the API which expose these directly in function arguments. It is -also possible to use functions like ``exposeClockResetEnable`` to turn an -implicitly defined function to an explicitly defined function. - -State Machines --------------- - -The Clash prelude contains combinators for two classical finite state machines -which can be used to define synchronous circuits. The first of these is -``mealy``, which encodes a `Mealy machine`_. This is a machine specified by - -- A transfer function of type ``state -> input -> (state, output)`` -- An initial state -- An input signal which can change at each cycle - -.. note:: The Mealy machine is similar to the State monad, which Haskell - programmers may already be familar with. Practically speaking, the only - difference is that this machine also has an input signal which is changed - externally to the definition of the machine. - -.. _`Mealy machine`: https://en.wikipedia.org/wiki/Mealy_machine - -It is also possible to define a `Moore machine`_ using the ``moore`` function -in the Clash prelude. This differs to the Mealy machine by providing output -based on the previous state (as oppoesd to the newly calculated state), and is -specified by - -- A transfer function of type ``state -> input -> state`` -- An output function of type ``state -> output`` -- An initial state -- An input signal which can change at each cycle - -.. _`Moore machine`: https://en.wikipedia.org/wiki/Moore_machine - -Sometimes, there may be multiple inputs / outputs needed for a machine. As -machines only input and output a single signal, there is a way to combine and -separate multiple signals. The ``Bundle`` class specifies how to convert -between some type which is a signal of a product, and some type which is a -product of signals, e.g. - -.. code-block:: haskell - - bundle :: (Signal dom a, Signal dom b) -> Signal dom (a, b) - unbundle :: Signal dom (a, b) -> (Signal dom a, Signal dom b) - -There are combinators which can automatically perform this bundling and -unbundling for you as required, called ``mealyB`` and ``mooreB``. The -``Bundle`` class is already defined for many types, including tuples (up to -62 elements), ``Maybe a``, ``Either a b`` and ``Vec n a``. - -RAM and ROM ------------ - -The Clash prelude provides the ability to work with synchronous and -asynchronous ROM, asynchronous RAM and synchronous Block RAM. The simplest of -these are ROM, which only allow indexing into a ``Vec n a`` of elements. ROM -is defined using the functions in ``Clash.Prelude.ROM``. - -RAM is more complex, as it allows both reading and writing. The function to -define a RAM takes in a signal for the address to read, and a signal for an -optional address to update (bundled with the new value). At each cycle it -outputs the value of the memory address read in the previous cycle. -Asynchronous RAM is defined in ``Clash.Prelude.RAM``. - -An FPGA may include a block RAM, which is a larger memory structure and more -suitable for some applications. Block RAM also has a synchronous read port, -allowing memory access to be synchronized to a clock. Block RAM is used the -same way as async RAM, allowing the two to be compared quickly. Block RAM is -defined in ``Clash.Prelude.BlockRam``. - -Undefined Values ----------------- - -When working with hardware designs, there are times when undefined values may -be encountered in simulation. Clash provides a custom exception type, -``XException``, for cases when an undefined value is encountered. There are -also many utility functions for working with exceptions, such as - -- ``errorX``, which throws an ``XException`` -- ``isX`` and ``hasX``, which check for ``XExceptions`` when evaluating -- ``maybeIsX`` and ``maybeHasX``, which discard inforamtion about exceptions - -There are also implementations of typical classes in Haskell which have been -changed to work with undefined values. Currently these are - -- ``ShowX``, which works like the ``Show`` class in Haskell. When an undefined - value is encountered an "X" is printed. ``Show`` can still be used, but will - throw an exception if an undefined value is encountered. - -- ``NFDataX``, which works like the ``NFData`` class in the ``deepseq`` - library. This allows evaluating values to normal form in code when undefined - may be present. ``NFData`` can still be used, but will bubble up exceptions - if undefined is encountered. - diff --git a/docs/general/LICENSE b/docs/general/LICENSE deleted file mode 100644 index ecc65d9634..0000000000 --- a/docs/general/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (c) 2012-2016, University of Twente, - 2016-2019, Myrtle Software Ltd, - 2017-2019, QBayLogic B.V., Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/docs/general/faqs.rst b/docs/general/faqs.rst deleted file mode 100644 index 2792d42866..0000000000 --- a/docs/general/faqs.rst +++ /dev/null @@ -1,224 +0,0 @@ -.. _faqs: - -Frequently Asked Questions -========================== - -Basic Questions ---------------- - -- **Q**: How do I install Clash? - - **A**: Check out the :ref:`installing` page in the *Getting Started* section - of the manual. - ----- - -- **Q**: Is the name "Clash", "CLaSH", or "CλaSH"? - - **A**: It's **Clash**. - - In its research stages Clash was called "CλaSH", an acronym for the **C**\ AES - **La**\ nguage for **S**\ ynchronous **H**\ ardware. CAES is a group of the - Faculty of Electrical Engineering, Mathematics and Computer Science at the - University of Twente. Clash was originally developed by Christaan Baaij and - supervisor Jan Kuper. The stylization "CλaSH" is an homage to Haskell_, - whose official logo has long been the venerable Greek *lambda* character. - -.. _Haskell: https://haskell.org - ----- - -- **Q**: Is Clash a "high level synthesis" tool? - - **A**: While clash provides a high level language features, hardware - descriptions written in Clash are not decoupled from clock-level - timing. Clash does therefore not offer what is generally understood as - "high level synthesis". Compared to the big three hardware description - languages, *VHDL*, *Verilog*, and *SystemVerilog*, Clash arguably *is* - high-level. It offers many of the powerful abstractions that modern - software programming languages offer. In fact, it inherits many of - the software's industry bleeding-edge features by virtue of basing its - implemenation on Haskell. - -Clash Support -------------- - -- **Q**: Is Clash production ready? - - **A**: Clash is constantly evolving, and since the 1.0 release there is - a focus on maintaining API backwards compatibility. Clash is used - successfully in real-world scenarios, and `QBayLogic Clash support`_ can help - with education and implementation of Clash projects. - -.. _`QBayLogic Clash support`: https://qbaylogic.com/clash-support.html - ----- - -- **Q**: Will Clash work with my EDA tools? - - **A**: In general, Clash should work well with Xilinx and Intel FPAGs and - their EDA tools -- as development typically focuses on these vendors. Clash - has also been successfully used on Microsemi (formerly Actel) SmartFusion 2 - and Lattice Semiconductor iCE40 FPGAs, and some basic IP for these exist. - - For most toolchains, the default primitives supplied by Clash should work - with minimal effort. If not, it is possible to call your vendor's library - manually, or use a tool like Yosys_ to do mapping. It is also possible to - consult `QBayLogic Clash support`_ for more assistance. - -.. _Yosys: http://clifford.at/yosys - ----- - -- **Q**: Does Clash support `Project IceStorm `_? - - **A**: The Verilog backend for Clash emits Verilog 2001, which is supported - by Yosys_. This means it can be placed and packed with *arachne-pnr* and - *icestorm*. Additionally, Clash has some support for the Lattice - Semiconductor iCE40 FPGA. - ----- - -- **Q**: Can Clash be used for ASIC designs, as well as FPGA designs? - - Clash can be used for ASIC designs, however the RTL produced by Clash may not - be immediately suitable as it is largely platform agnostic. While this is - not a problem for FPGAs, it can make developing ASICs more complicated as - many ASIC vendors have different proprietary tool flows, with limited - information available about their workings. - - If you are using Clash to develop for ASIC, and need assitance with getting - your toolchain to work, you can contact `QBayLogic Clash support`_ for - assistance. - -Clash and Haskell ------------------ - -- **Q**: Is Clash its own programming language, or is it "Haskell"? - - **A**: Clash is a programming language in its own right, complete with its - own executable and standard library. Clash is also related to the Haskell - programming language, and may be thought of as a dialect of Haskell for - developing hardware. While the surface syntax and typing rules are the same, - the semantics change as code progresses through the compilation pipeline. - - Do to the shared behavior in the early stages of the compiler, components - from GHC (the most common Haskell compiler) are reused in the Clash compiler. - This is how Clash achieves such high interoperability with existing Haskell - projects. - ----- - -- **Q**: Clash has better inference for type level natural numbers than GHC. - How is this possible? - - **A**: Clash's enhanced type checking functionality is due to the use of GHC - compiler plugins, which can be used in any Haskell project. To enable these - plugins, pass the following compiler flags to GHC: - - .. code-block:: haskell - - {-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-} - {-# OPTIONS_GHC -fplugin GHC.TypeLits.Extra.Solver #-} - {-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-} - - These plugins come from the ``ghc-typelits-natnormalise``, - ``ghc-typelits-extra``, and ``ghc-typelits-knownnat`` packages respectively, - which are all available from Hackage and Stackage. - ----- - -- **Q**: Do I need to know Haskell in order to use Clash? - - **A**: As Clash is deeply integrated with Haskell, it is recommended that - users have some familiarity with Haskell, or functional programming in - general. Clash uses some advanced features of Haskell, and real-world designs - will often want to leverage the existing Haskell ecosystem. - - For developers who are particularly familiar with either Haskell or hardware - design, Clash should be relatively intuitive to use. Additionally, obvious - mistakes with designs will be identified and reported due to the strong type - system identifying mistakes at compile-time. - -Clash and other HDLs --------------------- - -- **Q**: Do I need to know existing RTL/HDL languages in order to use Clash? - - **A**: Clash currently outputs VHDL, Verilog, and SystemVerilog. While it's - not necessary to understand these descriptions, you will need to some - understanding of vendor tools to actually deploy it. - ----- - -- **Q**: What's the difference between Clash and "Lava"? - - **A**: Lava dialects (including the modern variant - `Blarney `_) are all embedded domain specific - languages (EDSLs) inside Haskell. On top of that they use a so-called - *deep* embedding to be able to transform a circuit description into a netlist - (to subsequently output that as a VHDL/Verilog file). Clash on the other hand - uses "standard" compiler techniques to create a netlist from the Haskell - abstract syntax tree (AST). This "standard" compiler technique enables the - following features not available in (Haskell-based) EDSLs: - - 1. Clash allows the use of normal Haskell operations such as (==) on both the - meta-level (how the program is structured/generated), and the object-level - (the functionality of the program). - 2. Clash allows the use of regular Haskell syntax to model the concept of - 'choice' at the object-level (the functionality of the program): - if-expressions, guards, case, etc. - 3. Clash allows programmers to use native Haskell pattern matching. - -Basically, with Clash you can use regular Haskell to describe the behavior of -the circuit, most importantly all of it's choice-constructs (case-expressions, -guards, etc.). With an EDSL you are "limited" by the constructs of the DSL, -making your circuit descriptions look less like regular Haskell functions. - ----- - -- **Q**: What's the difference between Clash and Chisel/Spinal/Migen/Hardcaml? - - **A**: The biggest difference between these toolchains and Clash is that Clash - exists as a Haskell derivative, with a full synthesizing compiler to RTL -- - while Chisel/Spinal/Migen/Hardcaml exists as an embedding of hardware semantics - inside Scala/Scala/Python/OCaml. Aside from the "host language" differences, - this means that Chisel/Spinal/Migen/Hardcaml are conceptually closer to - something like *Lava/Blarney* than Clash. So within these languages you can - only use the host language constructs to structure and compose the constructs - of the EDSL, and you can't use host language constructs to describe the - behavior of the circuit; i.e. you cannot use the host language's regular - if-expression to model the concept of choice, but you have to use e.g. Chisel's - *when*-function. - - Aside from the above, there is also a varying degree of *native* simulation - and interactivity. In Clash you can evaluate/simulate any (sub-)component in - the interactive interpreter for an immediate and localized design feedback loop. - The only EDSLs that have a similar interactive interpreter for fast design - feedback are the older variants of Lava. They used a so-called dual-embedding, - where the EDSL primitives also contained a normal Haskell function which - described their behavior, and so the composition of these primitives could be - evaluated as a regular Haskell function. - - The other EDSLs all offer simulation, but there is a higher latency to get - from a design to a simulation of a design, and they are not as interactive. - Blarney emits Verilog, and you can then use a Verilog simulator to simulate - the Blarney design. Spinal also emits Verilog, but it then uses Verilator to - compile it to an object-file which is loaded back into Scala, allowing you - to interact with your Spinal design from within Scala. Chisel is also not - interpreted directly, instead, a Chisel description is "lowered" to FIRRTL - where that FIRRTL description is then executed inside Scala by the FIRRTL - interpreter. Migen works similarly to Chisel as far as the approach to - simulation goes, although perhaps more direct: it directly interprets its own - deep embedding data structure (its *IR*) to enable native simulation. - - All of this influences the style in which you write circuits and the creative - process by which you come to a solution; the effects of this on the - quality of results (QoR) and development time are, however, both hard to - qualify and hard to quantify. That is, although all of these languages, both - the EDSLs and Clash, enable full control over the QoR (i.e. you can get as - many registers and as much logic as you intended), the way in which you get - there can vary from problem domain to problem domain and person to person. - If you have enough time, we encourage to try several of them and see which - style is the most natural fit for you; if you're limited on time, we of course - recommend that you just go with Clash ;-) diff --git a/docs/general/index.rst b/docs/general/index.rst deleted file mode 100644 index 66e066bbea..0000000000 --- a/docs/general/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -General -======= - -.. toctree:: - :maxdepth: 1 - :name: toc-general - - intro - relnotes - faqs - license - diff --git a/docs/general/intro.rst b/docs/general/intro.rst deleted file mode 100644 index 108c0d3fec..0000000000 --- a/docs/general/intro.rst +++ /dev/null @@ -1,133 +0,0 @@ -.. _intro: - -Introduction to Clash -===================== - -Functional Hardware -------------------- - -Clash_ is an open-source functional hardware description -language (HDL) that closely mirrors the syntax and semantics of the Haskell_ -programming language. It is used for creating hardware designs, typically for -running on *field programmable gate arrays* (FPGAs) or *application-specific -integrated circuits* (ASICs). - -.. _`Clash`: https://clash-lang.org -.. _`Haskell`: https://www.haskell.org - -Clash is both a compiler, and a set of libraries for circuit design, that -transform high level Haskell descriptions of synchronous, sequential logic into -low-level VHDL_, Verilog_, or SystemVerilog_. It provides a unique approach to -design of sequential circuits, but with a high amount of abstraction power that -blurs the line between strictly behavioral or structural synthesis approaches. - -.. _VHDL: https://en.wikipedia.org/wiki/VHDL -.. _Verilog: https://en.wikipedia.org/wiki/Verilog -.. _SystemVerilog: https://en.wikipedia.org/wiki/SystemVerilog - -Clash aims to modernize the hardware development experience, making it easier -to quickly and correctly develop complex circuit designs. This is achieved -by making Clash: - -Expressive - Clash uses the Haskell type system to its full potential -- including modern - extensions and techniques -- to being a high level of type safety and - expressiveness to hardware design. - - This expressive typing makes it easier to develop safe, maintainable - hardware. Combinational and sequential logic is separated by type, and global - safety invariants such as separating incompatible clock domains are enforced - in the type system. - -Intuitive - Clash makes it easy to express circuit designs in an intuitive manner, - allowing high level structural components to be easily connected in designs. - Moreover, unlike most "high level synthesis" tools, this extends to precise - control over register placement and pipelining. - -Interactive - Unlike traditional HDL tools, Clash has a fully interactive read-eval-print - loop (REPL), allowing circuits to be interactively designed and tested. - -Performant - Clash reuses parts of the `Glasgow Haskell Compiler`_ to provide fast - simulation of circuits for development and testing. - -Efficient - Clash uses a "whole program synthesis" approach in order to view the entire - circuit at once, and optimizes this design before translating to a specific - target. This allows meaningful optimizations to be performed on the entire - design. - -Extensible - Additional primitives and black boxes can be added to Clash in the language - of your choice, allowing you to use your own vendor or IP library within - projects. - - Clash allows seamless interoperability with libraries written in Haskell, - including ``mtl``, ``lens`` and ``QuickCheck``. This makes it even easier to - quickly prototype complex designs. - -.. _`Glasgow Haskell Compiler`: https://ghc.haskell.org - -Intended Audience ------------------ - -Clash is ideal for developers from different backgrounds, although the main -intended audiences are - -Hardware Engineers - You are a hardware engineer, used to using tools like VHDL_ and Verilog_ to - implement circuit designs. Clash offers the familar mixed simulation / - synthesis capabilities of these tools, while providing a langauge with - powerful abstractions. - -Haskell Programmers - You are a Haskell_ programmer, looking to start developing hardware. Clash - offers the ability to start prototyping and simulating designs in a familiar - environment -- lowering the learning curve significantly. - -Maturity and Support --------------------- - -Clash is a continually evolving tool, having been actively developed since -2009. With the release of Clash 1.0 there has been an increased focus on -maintaining API stability between releases, meaning circuit designs written -in Clash should continue to work between minor releases. Today, the Clash -Compiler is actively developed by QBayLogic B.V. and volunteers. - -Several companies and enthusiasts are already using Clash to develop circuit -designs, ranging from small designs on hobbyist boards to larger designs on -modern FPGA and ASIC architectures. - -While care is taken to thoroughly test the Clash compiler, some bugs may exist. -We encourage users to file issues, or contribute pull requests on our -`GitHub repository`_. - -.. _`GitHub repository`: https://github.com/clash-lang/clash-compiler - -Meta-information: Web Sites, Mailing Lists, etc. ------------------------------------------------- - -**Mailing list**: for updates and questions join the mailing list clash-language+subscribe@googlegroups.com or read the `forum `_ - -**Slack**: Invite yourself at `fpchat-invite.herokuapp.com `_. To join #clash, click on "Channels" and search for "clash". - -**IRC**: `freenode#clash-lang `_ - -Clash Version Numbering Policy ------------------------------- - -Clash follows the `Haskell PVP Specification `_ for -its version numbers, for all packages. The main libraries that make up the -Clash compiler maintain the same version numbers, making it easy to identify -which versions are compatible. - -.. note:: - Due to the Clash's tight integration with GHC, updates to the GHC version - that Clash uses result in changes to the Clash version. As GHC's internals - change frequently, even for minor bumps, it cannot be guaranteed that these - changes will not result in Clash changes. - -It is recommended (but not required) that downstream Clash packages and -published Clash code also follow the PVP specification. diff --git a/docs/general/license.rst b/docs/general/license.rst deleted file mode 100644 index b11c730d2c..0000000000 --- a/docs/general/license.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _license: - -License -======= - -.. literalinclude:: LICENSE - :language: text - diff --git a/docs/general/relnotes.rst b/docs/general/relnotes.rst deleted file mode 100644 index 6f18f40c45..0000000000 --- a/docs/general/relnotes.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _relnotes: - -Release Notes -============= - -Clash 1.0.1 ------------ - -https://github.com/clash-lang/clash-compiler/releases/tag/v1.0.1 - -Clash 1.0.0 ------------ - -https://github.com/clash-lang/clash-compiler/releases/tag/v1.0.0 - diff --git a/docs/getting-started/first-circuit.rst b/docs/getting-started/first-circuit.rst deleted file mode 100644 index 9904ef8a11..0000000000 --- a/docs/getting-started/first-circuit.rst +++ /dev/null @@ -1,117 +0,0 @@ -.. _example_mac: - -Example: Multiply and Accumulate -================================ - -Combinational MAC ------------------ - -With Clash installed, it is now possible to begin creating hardware designs. -To give a brief overview of Clash, we will define a simple -*multiply-and-accumulate* circuit. Make a new file called ``MAC.hs``, and enter -the following preamble: - -.. code-block:: haskell - - module MAC where - - import Clash.Prelude - import Clash.Explicit.Testbench - -This declares the module and imports some useful modules from the Clash -standard library. The standard library contains necessary functions and data -types for writing circuit descriptions. As with Haskell, module identifiers in -Clash must always start with a capital letter and correspond to the name of the -file. - -The logic of our circuit is expressed as a function which takes an accumulator -and two extra inputs, and outputs the new value of the accumulator -- which is -the old value plus the product of the two other inputs. - -.. code-block:: haskell - - mac :: (Num a) => a -> (a, a) -> a - mac acc (x, y) = acc + x * y - -The type of the function is given after the ``::``, and says that the type -``a`` is some numeric type (e.g. ``Int``, ``Signed 8``, ``Double``), the first -argument is a number, the second value is a pair of numbers, and the result is -a number. - -Synchronous MAC ---------------- - -By adding another output parameter to this function, with the previous value of -the accumulator, we can define the function as a `Mealy machine`_. This allows -us to use our combinational definition of ``mac`` to create a synchronous -circuit (which we call ``macS``). - -.. code-block:: haskell - - mac :: (Num a) => a -> (a, a) -> (a, a) - mac acc (x, y) = (acc + x * y, acc) - - macS :: (HiddenClockResetEnable dom, Num a, NFDataX a) => Signal dom (a, a) -> Signal dom a - macS = mealy mac 0 - -.. _`Mealy machine`: https://en.wikipedia.org/wiki/Mealy_machine - -The input and output of ``macS`` are values of the ``Signal`` type. This type -represents synchronous values (functions without signals are combinational). -There is also an additional ``dom`` type, for synthesis domain, and a -constraint ``HiddenClockResetEnable`` -- which says the synthesis domain has a -clock, reset and enable line. These are implicit, although they can be exposed -using the ``exposeClockResetEnable`` funcion. - -HDL Generation and Testing --------------------------- - -To generate HDL from a synchronous circuit, a function needs to be marked as -a ``topEntity``. The simplest way to achieve this is to create a function with -this name, as Clash will use this definition automatically (similar to how -``main`` is a special function in other languages). - -.. code-block:: haskell - - topEntity - :: Clock System - -> Reset System - -> Enable System - -> Signal System (Int, Int) - -> Signal System Int - topEntity = exposeClockResetEnable macS - -It is now possible to generate HDL for this circuit description, by running -either ``clash --HDL`` from the command line, or running ``:HDL`` in ``clashi`` -(where ``HDL`` is either ``vhdl``, ``verilog`` or ``systemverilog``). This -will generate the HDL in a subdirectory named after the HDL being output. - -.. warning:: - Any function used to generate HDL from must have a monomorphic type. This - means there can be no type variables in the type signature (i.e. for the - circuit defined so far you need to specify both ``dom`` and ``a``. - -We can test that this circuit works as expected by defining a test bench. -This allows an input to be used and the actual output to be compared against -an expected output. - -.. code-block:: haskell - - testBench :: Signal System Bool - testBench = done - where - testInput = stimuliGenerator clk rst ((1,1) :> (2,2) :> (3,3) :> (4,4) :> Nil) - expectOutput = outputVerifier' clk rst (0 :> 1 :> 5 :> 14 :> 30 :> 46 :> 62 :> Nil) - done = expectOutput (topEntity clk rst en testInput) - en = enableGen - clk = tbSystemClockGen (fmap not done) - rst = systemResetGen - -From ``clashi`` it is possible to sample this test bench, using the ``sampleN`` -function, which takes in the number of samples to draw and the signal which -generates samples. - -.. code-block:: haskell - - >>> sampleN 8 testBench - [False, False, False, False, False, False, False, False] diff --git a/docs/getting-started/index.rst b/docs/getting-started/index.rst deleted file mode 100644 index 65bc68cc66..0000000000 --- a/docs/getting-started/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -Getting Started -=============== - -.. toctree:: - :maxdepth: 2 - :name: toc-getting-started - - installing - first-circuit - diff --git a/docs/getting-started/installing.rst b/docs/getting-started/installing.rst deleted file mode 100644 index a0ef2d0108..0000000000 --- a/docs/getting-started/installing.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. _installing: - -Installing Clash -================ - -Check out `clash-lang.org/install `__ to install -the latest stable release of Clash, or to setup a Clash project. - -Get Clash from source ---------------------- - -Get the source code using -`Git `__ and -enter the cloned directory: - -.. code:: bash - - git clone git@github.com:clash-lang/clash-compiler.git - - # Alternatively, if you haven't setup SSH keys with GitHub: - # git clone https://github.com/clash-lang/clash-compiler.git - - cd clash-compiler - -To check out a released version, use: - -.. code:: bash - - git checkout v1.2.3 - -To checkout a release *branch* use: - -.. code:: bash - - git checkout 1.2 - -Note that release branches might contain non-released patches. - -Cabal -^^^^^ -To use Cabal you need both Cabal and GHC installed on your system. For Linux and -MacOS users we recommend using `ghcup `__. -Windows users are recommended to use the -`Haskell Platform `__. - -To run `clash` use: - -.. code:: bash - - cabal v2-run --write-ghc-environment-files=always -- clash - - -If this fails, make sure you've got an up-to-date package index: - -.. code:: bash - - cabal update - -Stack -^^^^^ -`Install Stack `__ -and run: - -.. code:: bash - - stack run -- clash - -Nix -^^^ -Or `use Nix `__ to get a shell with the -``clash`` and ``clashi`` binaries on your PATH: - -.. code:: bash - - nix-shell diff --git a/docs/hacking-on-clash/hacking.rst b/docs/hacking-on-clash/hacking.rst deleted file mode 100644 index 246826545c..0000000000 --- a/docs/hacking-on-clash/hacking.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _hacking: - -.. include:: ../../HACKING.rst - diff --git a/docs/hacking-on-clash/index.rst b/docs/hacking-on-clash/index.rst deleted file mode 100644 index a2254cd34b..0000000000 --- a/docs/hacking-on-clash/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -Hacking on Clash -================ - -.. toctree:: - :maxdepth: 1 - :name: toc-hacking - - style - hacking - diff --git a/docs/hacking-on-clash/style.rst b/docs/hacking-on-clash/style.rst deleted file mode 100644 index 937141d351..0000000000 --- a/docs/hacking-on-clash/style.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _style: - -.. include:: ../../STYLE.rst - diff --git a/docs/index.rst b/docs/index.rst index 192ab2c186..8127d3d3d0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,39 +1,5 @@ -Clash Language User Guide -========================= - -Welcome to the Clash Language User Guide, the official documentation of the -`Clash Compiler`_. Clash is an open-source functional hardware description -language (HDL) that borrows syntax and semantics from the `Haskell`_ -programming language. To learn more, we suggest reading the -:ref:`introduction to Clash `. - -.. _`Clash Compiler`: https://clash-lang.org -.. _`Haskell`: https://www.haskell.org - -The table of contents below (and in the sidebar) allows easy access to -different pages in the documentation. You can also use the search function in -the top left corner. - -.. note:: The Clash Compiler and Clash Language User Guide are open-source - efforts developed by QBayLogic B.V. and other volunteers. The Clash Team - always appreciates feedback and contributions to the project to help improve - the development experience. - - If you don't understand something, or think something is missing or incorrect - in the documentation you can open an issue or pull request in the - `GitHub repository`_. - -.. _`GitHub repository`: https://github.com/clash-lang/clash-compiler - -.. toctree:: - :maxdepth: 3 - :name: sec-index - :numbered: - - general/index - getting-started/index - developing-hardware/index - hacking-on-clash/index - changelog - refs +Clash documentation has moved +============================= +.. tip:: + Our documentation has moved to https://docs.clash-lang.org diff --git a/docs/refs.rst b/docs/refs.rst deleted file mode 100644 index 1baffa35ee..0000000000 --- a/docs/refs.rst +++ /dev/null @@ -1,129 +0,0 @@ -.. _refs: - -References -========== - -- Appel, R.N. and Folmer, H.H. (2016) `Analysis, optimization, and design of a - SLAM solution for an implementation on reconfigurable hardware (FPGA) using - CλaSH `_. MSc thesis, University of Twente, - Enschede, The Netherlands, December 2016. - -- Vossen, J.J. (2016) `Offloading Haskell functions onto an - FPGA `_. MSc thesis, University of Twente, - Enschede, The Netherlands, December 2016. - -- Verheij, J.G.J. (2016) `Co-simulation between CλaSH and traditional HDLs - `_. MSc thesis, University of Twente, - Enschede, The Netherlands, August 2016. - -- Raa, I. te (2015) `Recursive functional hardware descriptions using CλaSH - `_. MSc thesis, University of Twente, - Enschede, The Netherlands, November 2015. - -- Wester, R. (2015) `A transformation-based approach to hardware design using - higher-order functions `_. PhD thesis, - University of Twente, Enschede, The Netherlands, July 2015. - -- Bakker, M. (2015) `Numerical mathematics on FPGAs using CλaSH - `_. BSc thesis, University of Twente, - Enschede, The Netherlands, July 2015. - -- Dam, M.R. (2015) `Auditory processing using CλaSH - `_. MSc thesis, University of Twente, - Enschede, The Netherlands, May 2015. - -- Harmsen, R. (2015) `Specifying the WaveCore in CλaSH - `_. MSc thesis, University of Twente, - Enschede, The Netherlands, March 2015. - -- Baaij, C.P.R. (2015) `Digital Circuits in CλaSH: Functional Specifications and - Type-Directed Synthesis `_. PhD thesis, - University of Twente, Enschede, The Netherlands, January 2015. - -- Wester, R. and Kuper, J. (2014) `Design space exploration of a particle filter - using higher-order functions `_. In: - *Reconfigurable Computing: Architectures, Tools, and Applications*. Lecture - Notes in Computer Science 8405. Springer Verlag, London, pp. 219-226. ISSN - 0302-9743 ISBN 978-3-319-05959-4. - -- Bos, J.C.H. (2014) `Synthesizable Specification of a VLIW Processor in the - Functional Hardware Description Language CλaSH - `_. MSc thesis, University of Twente, - Enschede, The Netherlands, September 2014. - -- Niedermeier, A. (2014) `A Fine-Grained Parallel Dataflow-Inspired Architecture - for Streaming Applications `_. PhD thesis, - University of Twente, Enschede, The Netherlands, August 2014. - -- Kuper, J. and Wester, R. (2014) `N Queens on an FPGA: Mathematics, - Programming, or Both? `_. In: *Communicating - Processes Architectures 2014*, 24-27 August 2014, Oxford, UK. Open Channel - Publishing. ISBN 978-0-9565409-8-0. - -- Bronkhorst, T.A.W. (2014) `Hardware design of a cooperative adaptive cruise - control system using a functional programming language - `_. MSc thesis, University of Twente, - Enschede, The Netherlands, August 2014. - -- Jin, X. (2014) `Implementation of the MUSIC Algorithm in CλaSH - `_. MSc thesis, University of Twente, - Enschede, The Netherlands, June 2014. - -- Nee, F. van (2014) `To a new hardware design methodology: A case study of the - cochlea model `_. MSc thesis, University of - Twente, Enschede, The Netherlands, March 2014. - -- Baaij, C.P.R. and Kuper, J. (2014) `Using Rewriting to Synthesize Functional - Languages to Digital Circuits `_. In: *Jay - McCarthy, editor, Trends in Functional Programming (TFP)*, Provo, UT, USA, May - 14-16, 2013. Volume 8322 of Lecture Notes in Computer Science (LNCS). pages - 17–33. Springer-Verlag. ISBN 978-3-642-45340-3. - -- Wester, R. and Baaij, C.P.R. and Kuper, J. (2012) `A two step hardware design - method using CλaSH `_. In: *Proceedings of the - 22nd International Conference on Field Programmable Logic and Applications - (FPL)*, Aug 29-31, 2012, Oslo, Norway. pages 181-188. IEEE Computer Society. - ISBN 978-1-4673-2257-7. - -- Wester, R. and Sarakiotis, D. and Kooistra, E. and J. Kuper. (2012) - `Specifications of APERTIF Polyphase Filter Bank in CλaSH - `_. In: *Communicating Process Architectures - (CPA)*, pages 53-64, United Kingdom, August 2012. Open Channel Publishing. - ISBN 978-0-9565409-5-9. - -- Gerards, M.E.T. and Baaij, C.P.R. and Kuper, J. and Kooijman, M. (2011) - `Higher-Order Abstraction in Hardware Descriptions with CλaSH - `_. In: *Proceedings of the 14th Conference on - Digital System Design (DSD)*, Oulu, Finland. pages 495-502, 31 Aug - 2 - September, 2011. IEEE Computer Society. ISBN 978-0-7695-4494-6. - -- Niedermeier, A. and Wester, R. and Rovers, K.C. and Baaij, C.P.R. and - Kuper, J. and Smit, G.J.M. (2010) `Designing a dataflow processor using CλaSH - `_. In: *28th Norchip Conference*, 15-16 - November 2010, Tampere, Finland. 69. IEEE Circuits and Systems Society. ISBN - 978-1-4244-8971-8. - -- Kuper, J. and Baaij, C.P.R. and Kooijman, M. and Gerards, M.E.T. (2010) - `Exercises in architecture specification using CλaSH - `_. In: *Proceedings of Forum on Specification - and Design Languages (FDL)*, 2010, Southampton, England, Sept 13-16. pages - 178-183. Electronic Chips & Systems design Initiative (ECSI). ISSN 1636-9874. - -- Baaij, C.P.R. and Kooijman, M. and Kuper, J. and Boeijink, W.A. and Gerards, - M.E.T. (2010) `CλaSH: Structural Descriptions of Synchronous Hardware using - Haskell `_. In: *Proceedings of the 13th - Conference on Digital System Design (DSD)*, Lille, France, Sept 1-3, 2010. - pages 714-721. IEEE Computer Society. ISBN 978-0-7695-4171-6. - -- Smit, G.J.M. and Kuper, J. and Baaij, C.P.R (2010) `A mathematical approach - towards hardware design `_. In: *Dagstuhl - Seminar on Dynamically Reconfigurable Architectures*, 11-16 July 2010, - Dagstuhl, Germany. - -- Baaij, C.P.R. (2009) `CλasH : from Haskell to hardware - `_. MSc thesis, University of Twente, - Enschede, The Netherlands, December 2009. - -- Kooijman, M. (2009) `Haskell as a higher order structural hardware description - language `_. MSc thesis, University of Twente, - Enschede, The Netherlands, December 2009. diff --git a/docs/requirements.txt b/docs/requirements.txt index 316517b818..2dd87663fa 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ -Sphinx==4.0.2 -sphinx_rtd_theme==0.5.2 +Sphinx==8.2.3 +sphinx-rtd-theme==3.0.2 recommonmark==0.7.1