calyx 0.7.1

Compiler Infrastructure for Hardware Accelerator Generation
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
# Calyx Language Reference

## Top-Level Constructs

Calyx programs are a sequence of `import` statements followed by a sequence of
`extern` statements or `component` definitions.

### `import` statements

`import "<path>"` has almost exactly the same semantics to that of `#include` in
the C preprocessor: it copies the code from the file at `path` into
the current file.

### `extern` definitions

`extern` definitions allow Calyx programs to link against arbitrary RTL code.
An `extern` definition looks like this:
```
extern "<path>" {
  <primitives>...
}
```

`<path>` should be a valid file system path that points to a Verilog module that
defines the same names as the *primitives* defined in the `extern` block.
When run with the `-b verilog` flag, the Calyx compiler will copy the contents
of every such Verilog file into the generated output.

### `primitive` definitions

The `primitive` construct allows specification of the signature of an external
Verilog module that the Calyx program uses.
It has the following syntax:

```
[comb] primitive name<attributes>[PARAMETERS](ports) -> (ports);
```

The syntax for primitives resembles that for [components][],
with some additional pieces:

- The `comb` keyword signals that the primitive definition wraps purely
  combinational RTL code. This is useful for certain optimizations.
- *[Attributes][]* specify useful metadata for optimization.
- *PARAMETERS* are named compile-time (metaprogramming) parameters to pass to
  the Verilog module definition. The primitive definition lists the names of
  integer-valued parameters; the corresponding Verilog module definition should
  have identical `parameter` declarations. Calyx code provides values for these
  parameters when instantiating a primitive as a [cell][cells].
- The *ports* section contain sized port definitions that can either be positive number
  or one of the parameter names.

For example, the following is the signature of the `std_reg` primitive from the
Calyx standard library:
```
{{#include ../../primitives/compile.futil:std_reg_def}}
```

The primitive defines one parameter called `WIDTH`, which describes the sizes for
the `in` and the `out` ports.

### Inlined Primitives

*Inlined primitives* do not have a corresponding Verilog file, and are defined within Calyx. The Calyx backend then converts these definitions into Verilog.

For example, the `std_unsyn_mult` primitive is inlined:
```
{{#include ../../primitives/unsynthesizable.futil:std_unsyn_mult_def}}
```

This can be useful when a frontend needs to generate both Calyx and Verilog code at the same time. The backend ensures that the generated Verilog module has the correct signature.

## Calyx Components

Components are the primary encapsulation unit of a Calyx program.
They look like this:

```
component name<attributes>(ports) -> (ports) {
  cells { ... }
  wires { ... }
  control { ... }
}
```

Like [`primitive` definitions][prim], `component` signatures consist of a name, an optional list of attributes, and input/output ports.
Unlike `primitive`s, `component` definitions do not have parameters; ports must have a concrete (integer) width.
A component encapsulates the control and the hardware structure that implements
a hardware module.

> **Well-formedness**: The `control` program of a component must take at least one cycle to finish executing.

### Combinational Components

Using the `comb` keyword before a component definition marks it as a purely combinational component:
```
comb component add(left: 32, right: 32) -> (out: 32) {
  cells {
    a = std_add(32);
  }
  wires {
    a.left = left;
    a.right = right;
    out = a.out;
  }
}
```

A combinational component does not have a `control` section, can only use other `comb` components or primitives, and performs its computation combinationally.

### Ports

A port definition looks like this:

```
[@<attr>...] <name>: <width>
```

Ports have a bit width but are otherwise untyped.
They can also include optional [attributes][].
For example, this component definition:

```
component counter(left: 32, right: 32) -> (@stable out0: 32, out1: 32) { .. }
```

defines two input ports, `left` and `right`, and two output ports,
`out0` and `out1`.
All four ports are 32-bit signals.
Additionally, the `out0` port has the [attribute][attributes] `@stable`.

### `cells`

A component's `cells` section instantiates a set of sub-components.
It contains a list of declarations with this syntax:

```
[ref]? <name> = <comp>(<param...>);
```

Here, `<comp>` is the name of an existing [primitive][prim] or [component definition][components], and
`<name>` is the fresh, local name of the instance.
The optional `ref` parameter turns the cell into a [by-reference cell](#ref-cells).
Parameters are only allowed when instantiating primitives, not Calyx-defined components.

For example, the following definition of the `counter` component instantiates a
`std_add` and `std_reg` primitive as well as a `foo` Calyx component

```
component foo() -> () { ... }
component counter() -> () {
  cells {
    r = std_reg(32);
    a = std_add(32);
    f = foo();
  }
  wires { ... }
  control { ... }
}
```

When instantiating a [`primitive` definition][prim], the parameters are passed within the
parenthesis.
For example, we pass `32` for the `WIDTH` parameter of the `std_reg` in the above
instantiation.
Since an instantiation of a Calyx component does not take any parameters, the parameters
are always empty.

## The `wires` Section

A component's `wires` section contains *guarded assignments* that connect ports
together. The assignments can either appear at the top level, making them
*[continuous assignments][continuous]*, or be organized into named
[`group`][group] and [`comb group` definitions][comb].

### Guarded Assignments

Assignments connect ports between two cells together, with this syntax:

```
<cell>.<port> = [<guard> ?] <cell>.<port>;
```

The left-hand and right-hand side are both *port references*, which name a
specific input or output port within a [cell][cells] declared within the same
component. The optional *guard condition* is a logical expression that
determines whether the connection is active.

For example, this assignment:

```
r.in = add.out;
```

unconditionally transfers the value from a port named `out` in the `add` cell to `r`'s `in` port.

Assignments are *simultaneous* and *non-blocking*. When a block of assignments
runs, they all first read their right-hand sides and then write into their
left-hand sides; they are not processed in order. The result is that the order
of assignments does not matter. For example, this block of assignments:

```
r.in = add.out;
add.left = y.out;
add.right = z.out;
```

is a valid way to take the values from registers `y` and `z` and put the sum into `r`. Any permutation of these assignments is equivalent.

### Guards

An assignment's optional *guard* expression is a logical expression that produces a 1-bit value, as in these examples:

```
r.in = cond.out ? add.out;
r.in = !cond.out ? 32'd0;
```

Using guards, Calyx programs can assign multiple different values to the same
port. Omitting a guard expression is equivalent to using `1'd1` (a constant
"true") as the guard.

Guards can use the following constructs:
- `port`: A port access on a defined cell
- `port op port`: A comparison between values on two ports. Valid `op` are: `>`, `<`, `>=`, `<=`, `==`
- `!guard`: Logical negation of a guard value
- `guard || guard`: Disjunction between two guards
- `guard && guard`: Conjunction of two guards

In the context of guards, a port can also be a literal (i.e., `counter.out == 3'd2` is a valid guard).

> **Well-formedness**: For each input port on the LHS, only one guard should be active in any given cycle during the execution of a Calyx program.

### Continuous Assignments

When an assignment appears directly inside a component's `wires` section, it
is called a *continuous assignment* and is permanently active, even when the
[control program](#the-control-operators) of the component is inactive.

### `group` definitions

A `group` is a way to name a set of assignments that together represent some
meaningful action:

```
group name<attributes> {
  assignments...
  name[done] = done_cond;
}
```

Assignments within a group can be reasoned about in isolation from assignments
in other groups.
Unlike [continuous assignments][continuous], a group's encapsulated assignments
only execute as dictated by the [control program][control].
This means that seemingly conflicting writes to the same ports are allowed:

```
group foo {
  r.in = 32'd10;
  foo[done] = ...;
}
group bar {
  r.in = 32'd22;
  bar[done] = ...;
}
```

However, group assignments must not conflict with [continuous assignments][continuous] defined in the component:

```
group foo {
  r.in = 32'd10; ... // Malformed because it conflicts with the write below.
  foo[done] = ...
}
r.in = 32'd50;
```

Groups can take any (nonzero) number of cycles to complete. To indicate to the
outside world when their execution has completed, every group has a special
*done signal*, which is a special port written as `<group>[done]`. The group
should assign 1 to this port to indicate that its execution is complete.

Groups can have an optional list of [attributes][].

> **Well-formedness**: All groups are required to run for at least one cycle. (Sub-cycle logic should use `comb group` instead.)

### `comb group` definitions

Combinational groups are a restricted version of groups which perform their
computation purely combinationally and therefore run for "less than one cycle":

```
comb group name<attributes> {
  assignments...
}
```

Because their computation is required to run for less than a cycle, `comb group`
definitions do not specify a `done` condition.

Combinational groups cannot be used within normal [control
operators][control].
Instead, they only occur after the `with` keyword in a control program.


## The Control Operators

The `control` section of a component contains an imperative program that
describes the component's behavior. The statements in the control program
consist of the following operators:

### Group Enable

Simply naming a group in a control statement, called a group enable, executes
the group to completion.
This is a leaf node in the control program.

### `invoke`

`invoke` acts like the function call operator for Calyx and has the following
syntax:

```
invoke instance[ref cells](inputs)(outputs) [with comb_group];
```

- `instance` is the name of the cell instance that needs to be invoked.
- `inputs` and `outputs` define connections for a subset of input and output
  ports of the instance.
- The `with comb_group` section is optional and names a [combinational
  group][comb] that is active during the execution of the `invoke`
  statement.
- `ref cells` is a list of cell names to pass to the invoked component's
  required [*cell reference*][ref]. (It can be omitted if the invoked component
  contains no cell references.)

Invoking an instance runs its control program to completion before returning.
Any Calyx component or primitive that implements the [go-done interface](#the-go-done-interface) can be invoked.
Like the [group enable](#group-enable) statement, `invoke` is a leaf node in the control program.

### `seq`

The syntax for sequential composition is:

```
seq { c1; ...; cn; }
```

where each `ci` is a nested control statement.
Sequences run the control programs `c1`...`cn` in sequence, guaranteeing that
each program runs fully before the next one starts executing.
`seq` **does not** provide any cycle-level guarantees on when a succeeding
group starts executing after the previous one finishes.

### `par`

The syntax for parallel composition is:

```
par { c1; ...; cn; }
```

The statement runs the nested control programs `c1`...`cn` in parallel, guaranteeing that
each program only runs once.
`par` **does not** provide any guarantees on how the execution of child programs
is scheduled.
It is therefore not safe to assume that all children begin execution at the
same time.

> **Well-formedness**: The assignments in the children `c1`...`cn` should never conflict with each other.

### `if`

The syntax is:
```
if <port> [with comb_group] {
  true_c
} else {
  false_c
}
```

The conditional execution runs either `true_c` or `false_c` using the value of
`<port>`.
The optional `with comb_group` syntax allows running a [combinational group][comb]
that computes the value of the port.

> **Well-formedness**: The combinational group is considered to be running during the entire execution
> of the control program and therefore should not have conflicting assignments
> with either `true_c` or `false_c`.

### `while`

The syntax is:
```
while <port> [with comb_group] {
  body_c
}
```

Repeatedly executes `body_c` while the value on `port` is non-zero.
The optional `with comb_group` enables a [combinational group][comb] that computes the
value of `port`.

> **Well-formedness**: The combinational group is considered active during the execution of the while
> loop and therefore should not have conflicting assignments with `body_c`.

### `repeat`

The syntax is:
```
repeat <num_repeats> {
  body_c
}
```

Repeatedly executes the control program `body_c` `num_repeat` times in a row.


## The `go`-`done` Interface

By default, Calyx components implement a one-sided ready-valid interface called
*the `go`-`done` interface*.
During compilation, the Calyx compiler will add an input port marked with the attribute [`@go`][godoneattr] and an output port marked with the attribute [`@done`][godoneattr] to the interface of the component:

```
component counter(left: 32, right: 32, @go go: 1) -> (out: 32, @done done: 1)
```

The interface provides a way to trigger the control program of the counter using
assignments.
When the `go` signal of the component is set to 1, the control program starts
executing.
When the component sets the `done` signal to 1, its control program has finished
executing.

> **Well-formedness**: The `go` signal to the component must remain set to 1 while the done signal is not 1. Lowering the `go` signal before the `done` signal is set to 1 will lead to undefined behavior.

## The `clk` and `reset` Ports

The compiler also adds special input ports marked with [`@clk` and `@reset`][clkreset] to the
interface.
By default, Calyx components are not allowed to look at or use these signals.
They are automatically threaded to any primitive that defines `@clk` or
`@reset` ports.


## Advanced Concepts

### `ref` cells

Calyx components can specify that a cell needs to be passed "by reference":

```
// Component that performs mem[0] += 1;
component update_memory() -> () {
  cells {
    ref mem = comb_mem_d1(...)
  }
  wires { ... }
  control { ... }
}
```

When invoking such a component, the calling component must provide a binding for each defined cell:
```
component main() -> () {
  cells {
    upd = update_memory();
    m1 = comb_mem_d1(...);
    m2 = comb_mem_d2(...);
  }
  wires { ... }
  control {
    seq {
      invoke upd[mem=m1]()(); // Pass `m1` by reference
      invoke upd[mem=m2]()(); // Pass `m2` by reference
    }
  }
}
```
As the example shows, each invocation can take different bindings for each `ref` cell.
See [the tutorial][ref-tut] for longer example on how to use this feature.

[attributes]: ./attributes.md
[components]: #calyx-components
[cells]: #cells
[prim]: #primitive-definitions
[group]: #group-definitions
[comb]: #comb-group-definitions
[continuous]: #continuous-assignments
[control]: #the-control-operators
[ref]: #ref-cells
[godoneattr]: ./attributes.md#go-done-clk-and-reset
[clkreset]: ./attributes.md#go-done-clk-and-reset
[ref-tut]: ./memories-by-reference.md