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 regs, 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}