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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
---
layout: docs
title: "Modules"
section: "chisel3"
---
Chisel *modules* are very similar to Verilog *modules* in
defining a hierarchical structure in the generated circuit.
The hierarchical module namespace is accessible in downstream tools
to aid in debugging and physical layout. A user-defined module is
defined as a *class* which:
- inherits from `Module`,
- contains at least one interface wrapped in a Module's `IO()` method (traditionally stored in a port field named ```io```), and
- wires together subcircuits in its constructor.
As an example, consider defining your own two-input multiplexer as a
module:
```scala mdoc:silent
import chisel3._
class Mux2IO extends Bundle {
val sel = Input(UInt(1.W))
val in0 = Input(UInt(1.W))
val in1 = Input(UInt(1.W))
val out = Output(UInt(1.W))
}
class Mux2 extends Module {
val io = IO(new Mux2IO)
io.out := (io.sel & io.in1) | (~io.sel & io.in0)
}
```
The wiring interface to a module is a collection of ports in the
form of a ```Bundle```. The interface to the module is defined
through a field named ```io```. For ```Mux2```, ```io``` is
defined as a bundle with four fields, one for each multiplexer port.
The ```:=``` assignment operator, used here in the body of the
definition, is a special operator in Chisel that wires the input of
left-hand side to the output of the right-hand side.
### Module Hierarchy
We can now construct circuit hierarchies, where we build larger modules out
of smaller sub-modules. For example, we can build a 4-input
multiplexer module in terms of the ```Mux2``` module by wiring
together three 2-input multiplexers:
```scala mdoc:silent
class Mux4IO extends Bundle {
val in0 = Input(UInt(1.W))
val in1 = Input(UInt(1.W))
val in2 = Input(UInt(1.W))
val in3 = Input(UInt(1.W))
val sel = Input(UInt(2.W))
val out = Output(UInt(1.W))
}
class Mux4 extends Module {
val io = IO(new Mux4IO)
val m0 = Module(new Mux2)
m0.io.sel := io.sel(0)
m0.io.in0 := io.in0
m0.io.in1 := io.in1
val m1 = Module(new Mux2)
m1.io.sel := io.sel(0)
m1.io.in0 := io.in2
m1.io.in1 := io.in3
val m3 = Module(new Mux2)
m3.io.sel := io.sel(1)
m3.io.in0 := m0.io.out
m3.io.in1 := m1.io.out
io.out := m3.io.out
}
```
We again define the module interface as ```io``` and wire up the
inputs and outputs. In this case, we create three ```Mux2```
children modules, using the ```Module``` constructor function and
the Scala ```new``` keyword to create a
new object. We then wire them up to one another and to the ports of
the ```Mux4``` interface.
Note: Chisel `Module`s have an implicit clock (called `clock`) and
an implicit reset (called `reset`). To create modules without implicit
clock and reset, Chisel provides `RawModule`.
> Historical Note: Prior to Chisel 3.5, Modules were restricted to only
having a single user-defined port named `io`. There was also a type called
`MultiIOModule` that provided implicit clock and reset while allowing the
user to define as many ports as they want. This is now the functionality
of `Module`.
### `RawModule`
A `RawModule` is a module that **does not provide an implicit clock and reset.**
This can be useful when interfacing a Chisel module with a design that expects
a specific naming convention for clock or reset.
Then we can use it in place of *Module* usage :
```scala mdoc:silent
import chisel3.{RawModule, withClockAndReset}
class Foo extends Module {
val io = IO(new Bundle{
val a = Input(Bool())
val b = Output(Bool())
})
io.b := !io.a
}
class FooWrapper extends RawModule {
val a_i = IO(Input(Bool()))
val b_o = IO(Output(Bool()))
val clk = Input(Clock())
val rstn = Input(Bool())
val foo = withClockAndReset(clk, !rstn){ Module(new Foo) }
foo.io.a := a_i
b_o := foo.io.b
}
```
In the example above, the `RawModule` is used to change the reset polarity
of module `SlaveSpi`. Indeed, the reset is active high by default in Chisel
modules, then using `withClockAndReset(clock, !rstn)` we can use an active low
reset in entire design.
The clock is just wired as it, but if needed, `RawModule` can be used in
conjunction with `BlackBox` to connect a differential clock input for example.
|