Skip to content

Commit 9795f14

Browse files
Merge pull request #21 from clash-lang/dfs-as-main
Remove Dfs, rewrite DFLike
2 parents fb0547e + 0283cfe commit 9795f14

File tree

18 files changed

+1599
-1967
lines changed

18 files changed

+1599
-1967
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,6 @@ stack.yaml.lock
4545
/systemverilog
4646

4747
log
48+
49+
# Created by .ci/build_docs.sh
50+
/docs

.gitlab-ci.yml

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@
2020
after_script:
2121
- tar -cf - $(ls -d /root/.cabal /root/.stack /nix || true) | zstd -T0 -3 > cache.tar.zstd
2222

23-
.common-806:
24-
extends: .common
25-
image: docker.pkg.github.com/clash-lang/clash-protocols/protocols-focal-ghc-cabal-stack-8.6.5:2020-12-07
26-
variables:
27-
GHC_VERSION: "8.6.5"
28-
CABAL_VERSION: "3.2.0.0"
29-
3023
.common-810:
3124
extends: .common
3225
image: docker.pkg.github.com/clash-lang/clash-protocols/protocols-focal-ghc-cabal-stack-8.10.2:2020-12-07
@@ -44,14 +37,12 @@ haddock:
4437
script:
4538
- .ci/build_docs.sh
4639

47-
# Circuit-notation is broken on 810.
48-
# https://github.com/cchalmers/circuit-notation/pull/8#issuecomment-739844352
49-
cabal-8.6.5:
50-
extends: .common-806
40+
cabal-8.10.2:
41+
extends: .common-810
5142
script:
5243
- .ci/test_cabal.sh
5344

5445
stack:
55-
extends: .common-806
46+
extends: .common-810
5647
script:
5748
- .ci/test_stack.sh

.gitmodules

Lines changed: 0 additions & 3 deletions
This file was deleted.

README.md

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ A battery-included library for writing on-chip protocols, such as AMBA AXI and A
55
<!-- omit in toc -->
66
# Table of Contents
77
- [Introduction](#introduction)
8-
- [Using `Dfs`/`Df` `Circuit`s](#using-dfsdf-circuits)
8+
- [Using `Df` `Circuit`s](#using-df-circuits)
99
- [Invariants](#invariants)
1010
- [Note [Deasserting resets]](#note-deasserting-resets)
1111
- [Tutorial: `catMaybes`](#tutorial-catmaybes)
@@ -22,12 +22,12 @@ A battery-included library for writing on-chip protocols, such as AMBA AXI and A
2222
`clash-protocols` exists to make it easy to develop and use on-chip communication protocols, with a focus on protocols in need of bidirectional communication, such as _AMBA AXI_. To familiarize yourself with `clash-protocols`, read [hackage.haskell.org/package/clash-protocols](http://hackage.haskell.org/package/clash-protocols). To read the next section, read at least:
2323

2424
* `Protocols`
25-
* `Protocols.Df.Simple`
25+
* `Protocols.Df`
2626

27-
The next section will guide you through the creation of a single `Dfs` based circuit.
27+
The next section will guide you through the creation of a single `Df` based circuit.
2828

29-
# Using `Dfs`/`Df` `Circuit`s
30-
The basic handshaking of `Dfs` and `Df` are heavily inspired by _AMBA AXI_:
29+
# Using `Df` `Circuit`s
30+
The basic handshaking of `Df` is heavily inspired by _AMBA AXI_:
3131

3232
* `Df` circuits _send_ data to their right hand side
3333
* `Df` circuits _receive_ data from their left hand side.
@@ -36,7 +36,7 @@ The basic handshaking of `Dfs` and `Df` are heavily inspired by _AMBA AXI_:
3636

3737
## Invariants
3838

39-
The protocols `Df` and `Dfs` impose a contract each component should follow. These are, where possible, checked by the various test harnesses in `Protocols.Hedgehog`.
39+
The protocols `Df` imposes a contract each component should follow. These are, where possible, checked by the various test harnesses in `Protocols.Hedgehog`.
4040

4141
* _Fwd a_ cannot depend on the _Bwd a_. In other words, deciding whether or not to send data cannot depend on the acknowledgment of that same data.
4242

@@ -105,7 +105,7 @@ should be deasserted as follows: `a`, `b,` `c`, `d`/`e`, `f`. Resets might also
105105
This order is imposed by the fact that there is an invariant stating a component in reset must not acknowledge data while in reset, but there is - for performance reasons - no invariant stating a component must not send data while in reset.
106106

107107
## Tutorial: `catMaybes`
108-
At this point you should have familiarized with the basic structures of the `Dfs`: its dataconstructors (`Data`, `NoData`, and `Ack`) and its invariants, as well as the structure of a `Circuit` itself. To quickly try things it's useful to keep a repl around. With `stack`:
108+
At this point you should have familiarized with the basic structures of the `Df`: its dataconstructors (`Data`, `NoData`, and `Ack`) and its invariants, as well as the structure of a `Circuit` itself. To quickly try things it's useful to keep a repl around. With `stack`:
109109

110110
```
111111
stack exec --package clash-protocols ghci
@@ -122,7 +122,7 @@ Both should give you the same shell. Import the necessary modules:
122122

123123
```bash
124124
>>> import qualified Clash.Prelude as C
125-
>>> import qualified Protocols.Df.Simple as Dfs
125+
>>> import qualified Protocols.Df as Df
126126
```
127127

128128
You should now be able to query various things. For example:
@@ -140,21 +140,21 @@ module CatMaybes where
140140

141141
import Protocols
142142
import qualified Clash.Prelude as C
143-
import qualified Protocols.Df.Simple as Dfs
143+
import qualified Protocols.Df as Df
144144
```
145145

146146
Then, we define the type and name of the component we'd like to write:
147147

148148
```haskell
149-
catMaybes :: Circuit (Dfs dom (Maybe a)) (Dfs dom a)
149+
catMaybes :: Circuit (Df dom (Maybe a)) (Df dom a)
150150
```
151151

152-
I.e., a circuit that takes a `Dfs` stream of `Maybe a` on the left hand side (LHS) and produces a stream of `a` on the right hand side (RHS). Note that the data carried on `Dfs`s _forward_ path very much looks like a `Maybe` in the first place:
152+
I.e., a circuit that takes a `Df` stream of `Maybe a` on the left hand side (LHS) and produces a stream of `a` on the right hand side (RHS). Note that the data carried on `Df`s _forward_ path very much looks like a `Maybe` in the first place:
153153

154154
```
155-
>>> :kind! Fwd (Dfs C.System Int)
155+
>>> :kind! Fwd (Df C.System Int)
156156
..
157-
= Signal "System" (Dfs.Data Int)
157+
= Signal "System" (Df.Data Int)
158158
```
159159
160160
..because `Data Int` itself has two constructors: `Data Int` and `NoData`. In effect, we'd like squash `Data (Just a)` into `Data a`, and `Data Nothing` into `NoData`. Not unlike the way [join](https://hackage.haskell.org/package/base-4.14.0.0/docs/Control-Monad.html#v:join) would work on two `Maybe`s.
@@ -171,8 +171,8 @@ At this point, GHC will tell us:
171171
CatMaybes.hs:8:21: error:
172172
Variable not in scope:
173173
go
174-
:: (C.Signal dom (Dfs.Data (Maybe a)), C.Signal dom (Dfs.Ack a))
175-
-> (C.Signal dom (Dfs.Ack (Maybe a)), C.Signal dom (Dfs.Data a))
174+
:: (C.Signal dom (Df.Data (Maybe a)), C.Signal dom (Df.Ack a))
175+
-> (C.Signal dom (Df.Ack (Maybe a)), C.Signal dom (Df.Data a))
176176
|
177177
8 | catMaybes = Circuit go
178178
| ^^
@@ -200,8 +200,8 @@ Now GHC will tell us:
200200
CatMaybes.hs:8:35: error:
201201
Variable not in scope:
202202
go
203-
:: C.Signal dom (Dfs.Data (Maybe a), Dfs.Ack a)
204-
-> C.Signal dom (Dfs.Ack (Maybe a), Dfs.Data a)
203+
:: C.Signal dom (Df.Data (Maybe a), Df.Ack a)
204+
-> C.Signal dom (Df.Ack (Maybe a), Df.Data a)
205205
|
206206
8 | catMaybes = Circuit (C.unbundle . go . C.bundle)
207207
| ^^
@@ -219,8 +219,8 @@ after which GHC will tell us:
219219
CatMaybes.hs:8:40: error:
220220
Variable not in scope:
221221
go
222-
:: (Dfs.Data (Maybe a), Dfs.Ack a)
223-
-> (Dfs.Ack (Maybe a), Dfs.Data a)
222+
:: (Df.Data (Maybe a), Df.Ack a)
223+
-> (Df.Ack (Maybe a), Df.Data a)
224224
|
225225
8 | catMaybes = Circuit (C.unbundle . fmap go . C.bundle)
226226
| ^^
@@ -230,19 +230,19 @@ CatMaybes.hs:8:40: error:
230230
This is something we can write, surely! If the LHS does not send data, there's not much we can do. We send `NoData` to the RHS and send a /nack/:
231231

232232
```haskell
233-
go (Dfs.NoData, _) = (Dfs.Ack False, Dfs.NoData)
233+
go (Df.NoData, _) = (Df.Ack False, Df.NoData)
234234
```
235235

236236
If we _do_ receive data from the LHS but it turns out to be _Nothing_, we'd like to acknowledge that we received the data and send `NoData` to the RHS:
237237

238238
```haskell
239-
go (Dfs.Data Nothing, _) = (Dfs.Ack True, Dfs.NoData)
239+
go (Df.Data Nothing, _) = (Df.Ack True, Df.NoData)
240240
```
241241

242242
Finally, if the LHS sends data and it turns out to be a _Just_, we'd like to acknowledge that we received it and pass it onto the RHS. But we should be careful, we should only acknowledge it if our RHS received our data! In effect, we can just passthrough the ack:
243243

244244
```haskell
245-
go (Dfs.Data (Just d), Dfs.Ack ack) = (Dfs.Ack ack, Dfs.Data d)
245+
go (Df.Data (Just d), Df.Ack ack) = (Df.Ack ack, Df.Data d)
246246
```
247247

248248
### Testing
@@ -268,7 +268,7 @@ genCatMaybesInput =
268268

269269
The explanation for the definition is out of scope for this tutorial, but it basically says: this generator generates a list with 0 to 100 elements, each a `Just` or a `Nothing`. If it is a `Just` it will contain an `Int` between 10 and 20. If you'd like to learn more about Hedgehog head over to [hackage.haskell.org/package/hedgehog](http://hackage.haskell.org/package/hedgehog).
270270

271-
For `Dfs` circuits we can define a pretty strong property: a `Circuit (Dfs dom a) (Dfs dom a)` is functionally the same as a function `[a] -> [a]` if we strip all the backpressure and `Signal` abstractions. Similarly, we for our `Circuit (Dfs dom (Maybe a)) (Dfs dom a)` our _pure model_ would be `[Maybe a] -> [a]`, i.e. [`Data.catMaybes`](https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Maybe.html#v:catMaybes)!
271+
For `Df` circuits we can define a pretty strong property: a `Circuit (Df dom a) (Df dom a)` is functionally the same as a function `[a] -> [a]` if we strip all the backpressure and `Signal` abstractions. Similarly, we for our `Circuit (Df dom (Maybe a)) (Df dom a)` our _pure model_ would be `[Maybe a] -> [a]`, i.e. [`Data.catMaybes`](https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Maybe.html#v:catMaybes)!
272272

273273
The function `Protocols.Hedgehog.idWithModel` takes advantage of exactly that fact. You tell it:
274274

@@ -292,7 +292,7 @@ prop_catMaybes =
292292
(catMaybes @C.System)
293293
```
294294

295-
From that point on, it will do the rest. By driving the circuit with arbitrary input and backpressure (among other things), it effectively tests whether a circuit implements the invariants of the `Dfs` protocol and whether it is (functionally) equivalent to its pure model. To actually run the tests we need some more boilerplate:
295+
From that point on, it will do the rest. By driving the circuit with arbitrary input and backpressure (among other things), it effectively tests whether a circuit implements the invariants of the `Df` protocol and whether it is (functionally) equivalent to its pure model. To actually run the tests we need some more boilerplate:
296296

297297

298298

@@ -345,13 +345,13 @@ We'll try and upstream these patches.
345345

346346
----------------
347347

348-
Writing a `Dfs` component can be tricky business. Even for relatively simple circuits such as `catMaybes` it's easy to send a wrong acknowledgment. The test harness is supposed to catch this, but its output isn't always easy to parse. We'll go over a few common mistakes.
348+
Writing a `Df` component can be tricky business. Even for relatively simple circuits such as `catMaybes` it's easy to send a wrong acknowledgment. The test harness is supposed to catch this, but its output isn't always easy to parse. We'll go over a few common mistakes.
349349

350350
Let's introduce one:
351351

352352
```diff
353-
- go (Dfs.Data Nothing, _) = (Dfs.Ack True, Dfs.NoData)
354-
+ go (Dfs.Data Nothing, _) = (Dfs.Ack False, Dfs.NoData)
353+
- go (Df.Data Nothing, _) = (Df.Ack True, Df.NoData)
354+
+ go (Df.Data Nothing, _) = (Df.Ack False, Df.NoData)
355355
```
356356

357357
Rerunning the tests will give us a big error, which starts out as:
@@ -448,8 +448,8 @@ The test tells us that no output was sampled, even though it expected to sample
448448
Let's revert the "mistake" we made and make another:
449449

450450
```diff
451-
- go (Dfs.Data (Just d), Dfs.Ack ack) = (Dfs.Ack ack, Dfs.Data d)
452-
+ go (Dfs.Data (Just d), Dfs.Ack ack) = (Dfs.Ack True, Dfs.Data d)
451+
- go (Df.Data (Just d), Df.Ack ack) = (Df.Ack ack, Df.Data d)
452+
+ go (Df.Data (Just d), Df.Ack ack) = (Df.Ack True, Df.Data d)
453453
```
454454

455455
Again, we get a pretty big error report. Let's skip right to the interesting bits:
@@ -476,15 +476,15 @@ Circuit did not produce enough output. Expected 1 more values. Sampled only 0:
476476
[]
477477
```
478478

479-
In this case, Hedgehog pretty much constrained us to pretty much one case in our implementation: the one where it matches on `Dfs.Data (Just d)`. Weirdly, no backpressure was needed to trigger this error, but we still see dropped values. This usually means we generated an _ack_ while the reset was asserted. And sure enough, we don't check for this. (Note that the "right" implementation moved the responsibility of this problem to the component on the RHS, hence not failing.)
479+
In this case, Hedgehog pretty much constrained us to pretty much one case in our implementation: the one where it matches on `Df.Data (Just d)`. Weirdly, no backpressure was needed to trigger this error, but we still see dropped values. This usually means we generated an _ack_ while the reset was asserted. And sure enough, we don't check for this. (Note that the "right" implementation moved the responsibility of this problem to the component on the RHS, hence not failing.)
480480

481-
At this point it might be tempting to use `Dfs.forceAckLow` to force proper reset behavior. To do so, apply the patch:
481+
At this point it might be tempting to use `Df.forceAckLow` to force proper reset behavior. To do so, apply the patch:
482482

483483
```diff
484-
- catMaybes :: Circuit (Dfs dom (Maybe a)) (Dfs dom a)
484+
- catMaybes :: Circuit (Df dom (Maybe a)) (Df dom a)
485485
- catMaybes = Circuit (C.unbundle . fmap go . C.bundle
486-
+ catMaybes :: C.HiddenClockResetEnable dom => Circuit (Dfs dom (Maybe a)) (Dfs dom a)
487-
+ catMaybes = Dfs.forceAckLow |> Circuit (C.unbundle . fmap go . C.bundle
486+
+ catMaybes :: C.HiddenClockResetEnable dom => Circuit (Df dom (Maybe a)) (Df dom a)
487+
+ catMaybes = Df.forceAckLow |> Circuit (C.unbundle . fmap go . C.bundle
488488
```
489489

490490
Because our function is now stateful, we also need to change the test to:
@@ -551,10 +551,6 @@ instead, this would have mean that the circuit would be stalled for _4_ cycles o
551551
At this point we're forced to conclude that `forceAckWithLow` did not fix our woes and we should persue a proper fix.
552552

553553
## Connecting multiple circuits
554-
**HEADS UP**: The following instructions only work on GHC 8.6.5. Due to internal GHC changes we can't easily port this to newer versions. This is in the works.
555-
556-
-----------------------
557-
558554
Check out [tests/Tests/Protocols/Plugin.hs](https://github.com/clash-lang/clash-protocols/blob/main/tests/Tests/Protocols/Plugin.hs) for examples on how to use `Protocols.Plugin` to wire up circuits using a convenient syntax.
559555

560556

@@ -563,7 +559,7 @@ Check out [tests/Tests/Protocols/Plugin.hs](https://github.com/clash-lang/clash-
563559

564560
# Project goals
565561

566-
- Include basic dataflow protocols (e.g., `Df`/`Dfs`) and industry supported ones (e.g., AMBA AXI)
562+
- Include basic protocols (e.g., `Df`) and industry supported ones (e.g., AMBA AXI)
567563
- Include lots of basic operators on circuits and its protocols
568564
- Export a consistent interface across protocols
569565
- 100% documentation coverage, preferably with lots of examples
@@ -581,7 +577,7 @@ No formal guidelines yet, but feel free to open a PR!
581577

582578
- [x] README
583579
- [x] Add more convenient functions: `fanin`, `roundrobin`, ..
584-
- [ ] Make `Dfs` base implementation instead of `Df` (performance / cleanliness)
580+
- [x] Make `DfLike` base implementation instead of `Df` (performance / cleanliness)
585581
- [x] Decide what to do with `Protocols.Ack`
586582
- [ ] Check dead doc links on CI
587583
- [x] Upstream all changes to `circuit-notation` (where possible)
@@ -591,7 +587,7 @@ No formal guidelines yet, but feel free to open a PR!
591587

592588
0.2
593589

594-
- [ ] Make DSL plugin work with GHC 8.10
590+
- [x] Make DSL plugin work with GHC 8.10 ([github.com/cchalmers/circuit-notation/pull/9](https://github.com/cchalmers/circuit-notation/pull/9))
595591
- [ ] AXI AMBA (in terms of `DfLike`!)
596592
- [ ] Test framework for "chunked" designs
597593
- [ ] Improve errors for multichannel tests

cabal.project

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
packages:
22
clash-protocols.cabal
3-
deps/circuit-notation/circuit-notation.cabal
43

54
package clash-prelude
65
-- 'large-tuples' generates tuple instances for various classes up to the
@@ -9,6 +8,11 @@ package clash-prelude
98
-- it by default. This will be the default for Clash >=1.4.
109
flags: -large-tuples
1110

11+
source-repository-package
12+
type: git
13+
location: https://github.com/cchalmers/circuit-notation.git
14+
tag: 0fe897cb95bd1be87abed044f4072f104dec2f7d
15+
1216
source-repository-package
1317
type: git
1418
location: https://github.com/martijnbastiaan/haskell-hedgehog.git

clash-protocols.cabal

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ description:
1212
Suggested reading order:
1313
.
1414
* 'Protocols' + README.md
15-
* 'Protocols.Df.Simple'
16-
* 'Protocols.DfLike'
15+
* 'Protocols.Df'
1716
* 'Protocols.Plugin'
1817
* 'Protocols.Hedgehog'
1918

@@ -83,8 +82,8 @@ common common-options
8382

8483
default-language: Haskell2010
8584
build-depends:
86-
-- GHC >= 8.6
87-
base >= 4.12.0.0,
85+
-- GHC >= 8.10
86+
base >= 4.14.0.0,
8887
Cabal,
8988

9089
-- clash-prelude will set suitable version bounds for the plugins
@@ -140,7 +139,6 @@ library
140139
Protocols
141140
Protocols.Df
142141
Protocols.DfLike
143-
Protocols.Df.Simple
144142
Protocols.Hedgehog
145143
Protocols.Hedgehog.Internal
146144
Protocols.Internal
@@ -167,7 +165,6 @@ test-suite unittests
167165
other-modules:
168166
Tests.Protocols
169167
Tests.Protocols.Df
170-
Tests.Protocols.Df.Simple
171168
Tests.Protocols.Plugin
172169

173170
Util

deps/circuit-notation

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/Protocols.hs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ i.e. using:
66
import Protocols
77
@
88
9-
Definitions of 'Circuit', 'Fwd', 'Bwd', 'Protocols.Dfs.Dfs', inspired by
9+
Definitions of 'Circuit', 'Fwd', 'Bwd', 'Protocols.Df.Df', inspired by
1010
definitions in @circuit-notation@ at <https://github.com/cchalmers/circuit-notation>.
1111
-}
1212

@@ -23,7 +23,6 @@ module Protocols
2323

2424
-- * Protocol types
2525
, Df
26-
, Dfs
2726

2827
-- * Basic circuits
2928
, idC
@@ -54,4 +53,3 @@ module Protocols
5453
import Data.Default (def)
5554
import Protocols.Internal
5655
import Protocols.Df (Df)
57-
import Protocols.Df.Simple (Dfs)

0 commit comments

Comments
 (0)