Modules
Modules are the basic unit of reusable hardware.
Module Definitions
Modules are declared using the mod
keyword.
A module has a list of pins, a list of components, and a list of wires.
The following example is a Buffer
module, which demonstrates all three parts:
1mod Buffer {
2 incoming in of Word[1];
3 outgoing out of Word[1];
4
5 reg queue of Word[1] reset 0;
6
7 queue <= in;
8 out := queue;
9}
This module has two ports, an incoming port in
and and outgoing port out
.
Both carry a value of type Word[1]
(that is, a bit) to and from the module.
This module contains one subcomponent: a reg
(register) named queue
.
It stores a value of type Word[1]
.
The reset
clause declares that the reset value of the register is 0
.
The final two statements are wires.
The first wire, queue <= in
, will connect the incoming port in
to the register queue
.
The syntax <=
is a latching wire.
It is only used with reg
s, and it tells us that the register will latch the value of in
on the next clock cycle.
The second wire, out := queue
, will connect the register queue
to the outgoing port out
.
The syntax :=
is a direct connect.
It is used with ports and with nodes,
and it tells us that the value of queue
will be sent to the port out
on the same clock cycle.
In Bitsy, clocks and resets are usually passed implicitly to a module. There is no need to declare them for synchronous circuits.
Module Instances
Once a module is defined, it may be instantiated.
Let’s assume the above definition for Buffer
has been given.
We can use several buffers in a row to make a 4-bit shift register:
1mod Buffer {
2 incoming in of Word[1];
3 outgoing out of Word[1];
4
5 reg queue of Word[1] reset 0w1;
6
7 queue <= in;
8 out := queue;
9}
10
11mod ShiftReg {
12 incoming cin of Word[1];
13 outgoing cout of Word[1];
14 outgoing val of Word[4];
15
16 mod buf0 of Buffer;
17 mod buf1 of Buffer;
18 mod buf2 of Buffer;
19 mod buf3 of Buffer;
20
21 buf0.in <= cin;
22 buf1.in <= buf0.out;
23 buf2.in <= buf1.out;
24 buf3.in <= buf2.out;
25 cout := buf3.out;
26
27 val := cat(buf3.out, buf2.out, buf1.out, buf0.out);
28}
You can see the experssion cat(buf3.out, buf2.out, buf1.out, buf0.out)
is used
to concatenate the output of each of the buffers together.
Since each of the four values is a single bit, the result is a Word[4]
.
You can see at a glance that because the module has four latch wires (<=
),
a value will take four cycles to get from cin
to cout
.
External Modules
In Bitsy, you can declare modules whose behavior is determined by the simulator.
These are called external modules.
They are declared with the ext
keyword, together with their list of ports.
The following would be a declaration for an external module
which might log the value presented on the port in
on every cycle.
ext mod Monitor {
incoming in of Word[8];
}
These can be instantiated with the mod
keyword just like a normal module.
1pub mod Top {
2 mod monitor of Monitor;
3 reg counter of Word[8] reset 0w8;
4 counter <= counter + 2w8;
5 monitor.in := counter;
6}
7
8ext mod Monitor {
9 incoming in of Word[8];
10}