Skip to content

Commit 25a2d9c

Browse files
committed
extended API docs
1 parent 1b46e2c commit 25a2d9c

1 file changed

Lines changed: 210 additions & 19 deletions

File tree

β€ŽREADME.mdβ€Ž

Lines changed: 210 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,64 +6,255 @@
66

77
# REQuest ⇄ ACKnowledge
88

9-
JavaScript Tool set to construct, transform and analyze digital circuits based on elastic transactional [protocol](./docs/protocol.md) and Request-Acknowledge handshake.
9+
JavaScript tool set to construct, transform, and analyze digital circuits based on
10+
an elastic (latency-insensitive) transactional [protocol](./docs/protocol.md) and a
11+
Request-Acknowledge handshake.
1012

11-
User describes circuit JavaScript API, add standard components from the library, or create new componets.
13+
You describe a circuit through a small JavaScript API, wire together standard components
14+
from the library, or define your own. The resulting graph is then rendered to synthesizable
15+
Verilog RTL and to diagrams (SVG / Graphviz dot).
1216

13-
Several standard [controllers](./docs/controller.md) provided.
17+
- **Elastic by construction** β€” every channel carries `req`/`ack`/`dat`. Backpressure and
18+
flow control are generated for you.
19+
- **Correct-by-construction transformations** β€” change a channel's buffer capacity, retime,
20+
or insert bubbles without altering functional behavior.
21+
- **Pluggable components** β€” standard [controllers](./docs/controller.md) (fork, join, MIMO)
22+
plus custom node macros.
1423

15-
User can transform constructed circuit by changing buffer capacity or performing other correct by construction transformations.
16-
17-
## Usage
18-
19-
The package can be installed from `npm`:
24+
## Install
2025

2126
```sh
2227
npm i reqack
2328
```
2429

25-
and imported into your JavaScript code:
26-
2730
```js
2831
const reqack = require('reqack');
2932
```
3033

31-
A **circuit** can be constructed this way:
34+
## Concepts
35+
36+
A circuit is a directed hypergraph:
37+
38+
- **Circuit** β€” the top-level graph. Becomes a Verilog module.
39+
- **Node** β€” an operation, a custom component, or an I/O port. A node with no incoming
40+
edges is a **target** (module input); a node with no outgoing edges is an **initiator**
41+
(module output).
42+
- **Edge (channel)** β€” a link between nodes carrying `{width, capacity}`. The `capacity`
43+
selects the elastic buffer inserted on that channel.
44+
45+
## Constructing a circuit
46+
47+
The core API in [lib/fhyper.js](lib/fhyper.js) is intentionally compact: circuits, nodes,
48+
and edges are built by calling the value returned from the previous step.
49+
50+
A **circuit** is created by calling `reqack.circuit`. The optional label becomes the
51+
Verilog module name.
3252

3353
```js
3454
const g = reqack.circuit('circuit_name');
3555
```
3656

37-
A **node** can be constructed by calling the circuit function. Optional `node_label` string will be used as standard or custom operation or as a root of a signal name.
57+
A **node** is created by calling the circuit. The optional label is used as a standard
58+
operator (see [Operators](#operators)), a custom macro name, or the root of a signal name.
3859

3960
```js
4061
const node1 = g('node_label');
4162
```
4263

43-
A **edge** can be constructed by calling the node function. Optional argument is an `Object` with two major properties (width, capacity).
64+
An **edge** is created by calling a node. The optional argument is an object with two main
65+
properties, `width` and `capacity`.
4466

4567
```js
4668
const edge1 = node1({width: 32, capacity: 1});
4769
```
4870

49-
One node can be **connected** to another node by calling edge with a destination node.
71+
An edge is **connected** to a destination node by calling it with that node. The call
72+
returns the same edge, so connections chain (this is a fork β€” one source, many targets).
73+
74+
```js
75+
edge1(node2)(node3); // fan edge1 out to node2 and node3
76+
```
77+
78+
Nodes also accept upstream edges as extra arguments (a join β€” many sources, one node),
79+
including arrays of edges:
80+
81+
```js
82+
const add = g('+', g()(), g()()); // two inputs feeding an adder
83+
const sum = g('+', [a, b, c].map(x => x())); // n inputs from an array
84+
```
85+
86+
### Edge capacity
87+
88+
`capacity` selects the channel's elastic buffer:
89+
90+
| capacity | buffer | latency | notes |
91+
| ------------- | ----------- | ------- | --------------------------------------- |
92+
| `0` / omitted | wire | 0 | asynchronous, combinational backpressure |
93+
| `1` | EB1 | 1 | async backpressure |
94+
| `1.5` | EB1.5 | 1 | synchronous backpressure, stall cap 2 |
95+
| `1.7` | EB1.7 | 1 | synchronous backpressure |
96+
| integer `>= 2`| FIFO | 1 | N-entry queue |
97+
98+
See [docs/controller.md](docs/controller.md) for the controller logic behind each.
99+
100+
## Operators
101+
102+
A node whose label is a string is treated as a datapath operator. Multi-operator labels
103+
are evaluated in **RPN** (space-separated), consuming the node's inputs in order β€” see
104+
[lib/rpn.js](lib/rpn.js).
105+
106+
```js
107+
g('+'); // add
108+
g('-'); // subtract
109+
g('*'); // signed multiply
110+
g('~ & |'); // (in RPN) invert, AND, OR
111+
```
112+
113+
Supported binary operators: `+ - * / % & | ^ << >> > >= < <= == != && ||`.
114+
Unary: `! ~`. Numeric literals and `swap` are also recognized.
115+
116+
## Custom components (macros)
117+
118+
Pass a `macros` object to `reqack.verilog` to define nodes that emit their own datapath
119+
and/or control logic. A macro may provide `data`, `ctrl`, `ctrl2data`, or `parameters`.
120+
121+
```js
122+
const macros = {
123+
custom: {
124+
// p.t = target (input) sockets, p.i = initiator (output) sockets
125+
data: p => p.i.map(lhs =>
126+
`assign ${lhs.wire} = ${p.t.map(e => e.wire).join(' ^ ')};`)
127+
}
128+
};
129+
130+
const g = reqack.circuit();
131+
const fn = g('custom');
132+
g()()(fn);
133+
g()()(fn);
134+
fn({capacity: 1})();
135+
136+
const rtl = reqack.verilog(g, macros);
137+
```
138+
139+
The built-in `reqack.macros` (currently `deconcat`) and `reqack.ctrl.fork` provide ready
140+
components. See [test/basic.js](test/basic.js) for many worked examples.
141+
142+
## Generating output
50143

51144
```js
52-
edge1(node2); // -> edge1
145+
const rtl = reqack.verilog(g, macros); // synthesizable Verilog (datapath + _ctrl module)
146+
const svg = reqack.svg(g); // SVG diagram (dagre layout)
147+
const dot = reqack.dot(g); // Graphviz dot source
148+
const manifest = reqack.manifest(g, name); // project manifest (module.exports = {...})
53149
```
54150

55-
Resulted Verilog RTL can be produced by calling
151+
`reqack.verilog` emits two modules: the datapath `<name>` and its handshake controller
152+
`<name>_ctrl`.
153+
154+
## Worked example
155+
156+
A single 4-bit channel with a 1-entry elastic buffer:
56157

57158
```js
58-
const verilogString = reqack.verilog(g, {});
159+
const g = reqack.circuit('eb1');
160+
g()({width: 4, capacity: 1})(); // target -> EB1 edge -> initiator
161+
const rtl = reqack.verilog(g, {});
59162
```
60163

61-
SVG image can be rendered by calling
164+
produces the datapath module and its handshake controller:
165+
166+
```verilog
167+
module eb1 (
168+
// per node (target / initiator)
169+
input clk,
170+
input reset_n,
171+
input [3:0] t_0_dat,
172+
input t_0_req,
173+
output t_0_ack,
174+
output [3:0] i_1_dat,
175+
output i_1_req,
176+
input i_1_ack
177+
);
178+
wire [3:0] dat0, dat0_nxt;
179+
// per node
180+
assign dat0_nxt = t_0_dat; // node:0 is target port
181+
assign i_1_dat = dat0; // node:1 is initiator port
182+
// per edge
183+
wire en0; // edge:0 EB1
184+
reg [3:0] dat0_r;
185+
always @(posedge clk) if (en0) dat0_r <= dat0_nxt;
186+
assign dat0 = dat0_r;
187+
188+
eb1_ctrl uctrl (
189+
.clk(clk),
190+
.reset_n(reset_n),
191+
.t_0_req(t_0_req),
192+
.t_0_ack(t_0_ack),
193+
.i_1_req(i_1_req),
194+
.i_1_ack(i_1_ack),
195+
.en0(en0)
196+
);
197+
endmodule // eb1
198+
199+
module eb1_ctrl (
200+
// per node (target / initiator)
201+
input clk,
202+
input reset_n,
203+
input t_0_req,
204+
output t_0_ack,
205+
output i_1_req,
206+
input i_1_ack,
207+
output en0
208+
);
209+
wire req0, ack0, ack0_0, req0_0;
210+
// node:t_0 target
211+
assign req0 = t_0_req;
212+
assign t_0_ack = ack0;
213+
// edge:0 EB1
214+
wire ack0m;
215+
reg req0m;
216+
assign en0 = req0 & ack0;
217+
assign ack0 = ~req0m | ack0m;
218+
always @(posedge clk or negedge reset_n) if (~reset_n) req0m <= 1'b0; else req0m <= ~ack0 | req0;
219+
220+
// edge:0 fork
221+
assign req0_0 = req0m;
222+
assign ack0m = ack0_0;
223+
// node:1 initiator
224+
assign i_1_req = req0_0;
225+
assign ack0_0 = i_1_ack;
226+
endmodule // eb1_ctrl
227+
```
228+
229+
The data path (`eb1`) holds registers and multiplexing; the controller (`eb1_ctrl`)
230+
holds the `req`/`ack` handshake FSM and drives each register's enable (`en0`).
231+
232+
## High-level synthesis (HLS)
233+
234+
`reqack.hls` turns a JavaScript arithmetic expression into a circuit, mapping operators to
235+
elastic nodes β€” see [lib/hls.js](lib/hls.js).
62236

63237
```js
64-
const svg = reqack.svg(g);
238+
const hls = reqack.hls;
239+
const resultEdge = hls((a, b, c) => (a + b) - c)('a', 'b', 'c');
65240
```
66241

242+
## Also exported
243+
244+
- `reqack.dagre` β€” the bundled [dagre](https://github.com/dagrejs/dagre) layout engine.
245+
- `reqack.firrtl` β€” FIRRTL backend (placeholder, not yet implemented).
246+
247+
## Documentation
248+
249+
- [Link protocol](docs/protocol.md) β€” the `req`/`ack`/`dat` signaling rules.
250+
- [Controllers](docs/controller.md) β€” fork, join, MIMO, and edge buffers (EB0/1/1.5/…).
251+
- [Transformations](docs/transformations.md) β€” retiming, bubble insertion, memory bypass.
252+
- [Labeling](docs/labeling.md) β€” how graph/node/edge labels are interpreted.
253+
- [References](docs/references.md) β€” background reading.
254+
- [LLM-friendly API](docs/llm-api.md) β€” **roadmap / proposal**. Describes a future
255+
named-method API (`addNode`, `addEdge`, `connectTo`, validation, types). Not yet
256+
implemented β€” the current API is the one documented above.
257+
67258
## Testing
68259

69260
```sh

0 commit comments

Comments
Β (0)