summaryrefslogtreecommitdiff
path: root/docs/src/explanations/combinational-circuits.md
blob: b9e5b8c681a4673d3ed00dc7df020d0589179369 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
---
layout: docs
title:  "Combinational Circuits"
section: "chisel3"
---

# Combinational Circuits

A circuit is represented as a graph of nodes in Chisel.  Each node is
a hardware operator that has zero or more inputs and that drives one
output.  A literal, introduced above, is a degenerate kind of node
that has no inputs and drives a constant value on its output.  One way
to create and wire together nodes is using textual expressions.  For
example, we can express a simple combinational logic circuit
using the following expression:

```scala
(a & b) | (~c & d)
```

The syntax should look familiar, with `&` and `|`
representing bitwise-AND and -OR respectively, and `~`
representing bitwise-NOT.  The names `a` through `d`
represent named wires of some (unspecified) width.

Any simple expression can be converted directly into a circuit tree,
with named wires at the leaves and operators forming the internal
nodes.  The final circuit output of the expression is taken from the
operator at the root of the tree, in this example, the bitwise-OR.

Simple expressions can build circuits in the shape of trees, but to
construct circuits in the shape of arbitrary directed acyclic graphs
(DAGs), we need to describe fan-out.  In Chisel, we do this by naming
a wire that holds a subexpression that we can then reference multiple
times in subsequent expressions.  We name a wire in Chisel by
declaring a variable.  For example, consider the select expression,
which is used twice in the following multiplexer description:
```scala
val sel = a | b
val out = (sel & in1) | (~sel & in0)
```

The keyword `val` is part of Scala, and is used to name variables
that have values that won't change.  It is used here to name the
Chisel wire, `sel`, holding the output of the first bitwise-OR
operator so that the output can be used multiple times in the second
expression.

### Wires

Chisel also supports wires as hardware nodes to which one can assign values or connect other nodes.

```scala
val myNode = Wire(UInt(8.W))
when (isReady) {
  myNode := 255.U
} .otherwise {
  myNode := 0.U
}
```

```scala
val myNode = Wire(UInt(8.W))
when (input > 128.U) {
  myNode := 255.U
} .elsewhen (input > 64.U) {
  myNode := 1.U
} .otherwise {
  myNode := 0.U
}
```

Note that the last connection to a Wire takes effect. For example, the following two Chisel circuits are equivalent:

```scala
val myNode = Wire(UInt(8.W))
myNode := 10.U
myNode := 0.U
```

```scala
val myNode = Wire(UInt(8.W))
myNode := 0.U
```