google / google/xls

[enhancement] Add latency-sensitive block construct to DSLX

Open
#1,467 2 comments 0 reactions 1 assignee Claimed by @cdleary View on GitHub
dslx:syntax enhancement
Dominant language
C++
Stars
1.9k
Forks
283
Avg merge
2d 10h
Merged PRs (30d)
135

Description

### What's hard to do? (limit 100 words)

Expressing cycle-by-cycle latency-sensitive components is difficult in DSLX. It'd be good to have a mechanism for writing things at the RTL-level of abstraction. Many components can be built in a latency insenstive way, but invariably every design needs some latency-sensitive parts.

### Current best alternative workaround (limit 100 words)

There is no workaround.

### Your view of the "best case XLS enhancement" (limit 100 words)

XLS IR has a `block` construct which is an RTL-level representation. We need a syntax in DSLX which can lower directly to IR Blocks. This proposal mimics proc dslx syntax.

To express things at the RTL-level we need roughly need ports, registers, and combinational logic.

This syntax adds the following constructs:

* `block`: a container analogous to a proc which maps to a verilog module. It is guaranteed to iterate every cycle.

* `wire`: a latency-sensitive analog to a channel. It maps to directly to ports and connections between them. Wire inputs can be used directly in expressions. Wire outputs use `set` to indicate what value is presented on the output port each cycle.

* block state: analogous to proc state. This maps to registers.

Example syntax of a block which accumulates the value at input port `x` every cycle and presents the accumulated value on the output port `result` every cycle. The block has one 32-bit state element.

```
block accum {
x: wire in;
result: wire out;

init { u32:0 }

config(x: wire in, result: wire out) {
(x, result)
}

next(sum: u32) {
let next_sum = x + sum;
set(result, next_sum);
next_sum
}
}
```

Instantiations should also be supported. Possible syntax:

```
block accum_wrapper {
x: wire in;
a: wire out;
b: wire in;
result: wire out;

init { () }

config(x: wire in, result: wire out) {
let (a_accum_in, a_out) = wire;
let (b_in, b_out) = wire;
spawn accum(a_out, b_in);
(x, a_in, b_out, result)
}

next(st: ()) {
set(a, x + u32:1);
set(result, -2 * b);
()
}
}
```

TBD: Interrop with latency senstive components. Rough idea is channels can be composed/decomposed from wires to connect blocks and procs.

FYI @cdleary

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.