Skip to content

Commit

Permalink
Update book
Browse files Browse the repository at this point in the history
  • Loading branch information
minseongg committed Sep 25, 2024
1 parent 57b8802 commit 5396aa7
Show file tree
Hide file tree
Showing 9 changed files with 1,765 additions and 63 deletions.
4 changes: 0 additions & 4 deletions doc/docs/figure/combinator.drawio.svg

This file was deleted.

514 changes: 514 additions & 0 deletions doc/docs/figure/masked-merge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions doc/docs/figure/masked_merge.drawio.svg

This file was deleted.

487 changes: 487 additions & 0 deletions doc/docs/figure/tutorial-combinator.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
364 changes: 364 additions & 0 deletions doc/docs/figure/tutorial-hazard.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
280 changes: 280 additions & 0 deletions doc/docs/figure/tutorial-module.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions doc/docs/tutorial/fir_filter.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn fir_filter(input: Valid<u32>) -> Valid<u32> {
```

We can describe the FIR filter with `window`, `weight`, and `sum` combinators in the HazardFlow HDL and we assume the input interface `Valid<u32>` is provided.
`Valid<u32>` is a **valid interface**, its payload is `Opt<u32>`, the resolver is empty `()`, and its `ready` function always returns `true`.
`Valid<u32>` is a **valid interface**, its payload is `Option<u32>`, the resolver is empty `()`, and its `ready` function always returns `true`.
In other words, as long as the input interface's forward signal is `Some(u32)` at a specific clock cycle, the receiver receives a valid payload.
We can interpret this input interface as a stream of signal values flowing through the wires.

Expand Down Expand Up @@ -100,7 +100,7 @@ The anonymous function is where we specify the fsm logic from the `(ingress payl

<!-- * `impl<P: Copy + Default> Valid<P>` is how we define a custom combinator for the input interface `Valid<P>`, where `P` should be able to be copied and should have a default value.
* Then we define the `window` combinator as `pub fn window<const N: usize>(self) -> Valid<Array<P, N>>`, where `N` is the size of the FIR filter, and the egress interface's type is `Valid<Array<P, N>>`. -->
<!-- * The egress interface's payload is `Opt<Array<P, N>>`, an optional type of array with `P` type elements, and the array size is `N`. The resolver is empty `()`. -->
<!-- * The egress interface's payload is `Option<Array<P, N>>`, an optional type of array with `P` type elements, and the array size is `N`. The resolver is empty `()`. -->
<!-- * The anonymous function takes the ingress payload and the current state as inputs and returns the egress payload and next state.
* The `append` function concats two arrays together.
* The `ip.repeat::<1>()` function transforms `ip` into an array of one element `ip`.
Expand Down
31 changes: 16 additions & 15 deletions doc/docs/tutorial/masked_merge.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

## Specification

The `masked_merge` combinator performs the following operation:

<p align="center">
<img src="../figure/masked_merge.drawio.svg" />
<img src="../figure/masked-merge.svg" width=80%/>
</p>

### `masked_merge` combinator
<!-- TODO: to explain masked merge, we don't need to think of FIFO queue. It can be an example of using masked merge, but the current text *assumes* there should be a FIFO queue: "It indicates which ingress interfaces are present in the current queue." -->

The `masked_merge` combinator takes `N` valid-ready `Vr<P>` interfaces as the ingress interface.

* We can think of a valid-ready Interface as a valid interface `Valid<P>` with an extra ready signal (Boolean value) in its resolver.
* The transfer happens only when the payload is `Some(P)`, and the ready signal in the resolver is `true`.
* We can represent the ingress interface type as `[Vr<u32>; N]`.
Expand All @@ -17,25 +20,17 @@ The `masked_merge` combinator takes `N` valid-ready `Vr<P>` interfaces as the in
The Masked Merge combinator egress interface is also a valid-ready hazard interface `I<Self::EH, { Dep::Demanding }>`.
* We define the egress hazard as `type EH = VrH<(P, U<{ clog2(N) }>), Array<bool, N>>`.
* The payload type is a tuple type.
* `Opt<P>` contains the real data we want to send through the wires.
* `Option<P>` contains the real data we want to send through the wires.
* `U<{ clog2(N) }>` is the index of the ingress interfaces represented in bits. `clog2(N)` is the bit-width for representing integer `N`.
* The payload will be sent to the FIFO queue.
* The element in the FIFO queue is a tuple containing the actual data and the index of the ingress interface that sends the data.
* The resolver is an array of `bool` of size `N`.
* This resolver is send back from the FIFO queue.
* This resolver is sent back from the FIFO queue.
* It indicates which ingress interfaces are present in the current queue.
* If there are 4 ingress interfaces and the array is `[true, false, false, true]`, it indicates the ingress interface 1's and ingress interface 2's payloads are not currently in the queue.

The Masked Merge combinator will try to choose the ingress interface whose payload is not in the queue and send it to the FIFO queue in the next clock cycle.

### FIFO Queue

The FIFO Queue ingress interface:
* The payload is a tuple containing the actual data we want to transfer and also the index of the ingress interface of the Masked Merge combinator that sends the data.
* The resolver indicates which ingress interfaces are present in the current queue.

The FIFO Queue egress interface is a simple valid-ready interface `Vr<P>`.

## Modular Design

<p align="center">
Expand All @@ -55,17 +50,23 @@ The FIFO Queue egress interface is a simple valid-ready interface `Vr<P>`.
* `FifoS` indicates the current state of the FIFO queue.
* This combinator will leave the payload untouched and transfer it from ingress interface to egress interface.

**`naked_fifo` combinator:**
**`transparent_fifo` combinator:**

* This is a primitive combinator offered by the standard library.
* It takes one element from the ingress payload and stores it in the queue every clock cycle.
* It returns the current queue status `FifoS`, including the inner elements of the queue, the reader address, the writer address, and the length of the current queue as the ingress resolver.
* It pops out one element from the queue as the egress payload every clock cycle.
* The egress resolver is a simple ready signal.

<!-- The FIFO Queue ingress interface:
* The payload is a tuple containing the actual data we want to transfer and also the index of the ingress interface of the Masked Merge combinator that sends the data.
* The resolver indicates which ingress interfaces are present in the current queue.
The FIFO Queue egress interface is a simple valid-ready interface `Vr<P>`. -->

**`map` combinator:**

* It transforms the ingress payload `Opt<P, idx>` into `Opt<P>` for filtering out the unnecessary index information.
* It transforms the ingress payload `Option<P, idx>` into `Option<P>` for filtering out the unnecessary index information.

## Implementation

Expand All @@ -82,7 +83,7 @@ The FIFO Queue egress interface is a simple valid-ready interface `Vr<P>`.
* The implementation of the `masked_merge()` combinator will be explained in the [Implementing Combinators](../advanced/combinator.md) section.

```rust,noplayground
/// Masked Merge Combinator
/// Example module using `masked_merge` combinator.
pub fn m(ingress: [Vr<u32>; 5]) -> Vr<u32> {
ingress
.masked_merge()
Expand Down
140 changes: 102 additions & 38 deletions doc/docs/tutorial/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

We will introduce some basic concepts in the HazardFlow HDL programming model and use HazardFlow HDL to describe an [FIR (finite impulse response) filter](https://en.wikipedia.org/wiki/Finite_impulse_response) and a masked merge combinator.

## Hazard Interface and Combinator

HazardFlow HDL's implementation is based on two important concepts: [hazard interface](./interface.md) and [combinator](./module.md).
HazardFlow HDL's implementation is based on the concept of [hazard interface](../lang/interface.md). <!-- and [combinator](./module.md). -->
We will give a brief explanation here about the interface and combinator for you to understand how to use them to implement the FIR filter and fair multiplexer.
For more details please refer to the [Language Reference](./reference.md) section.
For more details please refer to the [Concepts](../lang/concepts.md) section.

### Hazard Interface

Expand All @@ -15,73 +13,139 @@ We model the hazard interface as a structure containing its forward signal, back
We define the hazard protocol as `H`, its payload and resolver as `H::P` and `H::R` respectively.

<p align="center">
<img src="../figure/interface.drawio.svg" />
<img src="../figure/tutorial-hazard.svg" width=60% />
</p>

**Forward signal:**
* The forward signal is the payload of the interface.
```rust,noplayground
// Hazard specification.
trait Hazard {
type P: Copy;
type R: Copy;
fn ready(p: Self::P, r: Self::R) -> bool;
}
// Hazard interface.
struct I<H: Hazard>;
impl<H: Hazard> Interface for I<H> {
type Fwd = Option<H::P>,
type Bwd = H::R,
}
```

**Forward signal:** the payload of the interface
* It is the data will be sent from the sender to the receiver.
* We define it as an `Opt<H::P>` type. When it is `Some(p)`, the sender is sending a valid payload, else it is sending an invalid payload.

**Backward signal:**
* The backward signal is the resolver of the interface.
**Backward signal:** the resolver of the interface
* It represents the hazard generated by the later stage from the circuits and it will be sent from the receiver to the sender.
* We define the resolver signal as `H::R`

**Ready condition:**
* Indicates whether the receiver is ready to receive the payload.
**Ready condition:** the indicator whether the receiver is ready to receive the payload
* We define the ready condition as `fn ready(p: Self::P, r: Self::R) -> bool;` where the `p` is the payload and `r` is the resolver.
* When the forward signal is `Some(p)`, which means the forward signal is valid, **and** the ready condition returns `true`, which means the receiver is ready to receive the valid payload, then the transfer happens.
* When the forward signal is `None`, which means the forward signal is invalid, **or** the ready condition returns `false`, which means the receiver is not ready to receive the valid payload, then the transfer is not happening.

<!-- For more details, please refer to the [Interfaces](../lang/interface.md) section. -->

### Module

A module has a state of type `S` and ingress and egress hazard interface types, say `IH` and `EH`.

Conceptually, the module's behavior can be represented as a function of the following signature:

<p align="center">
<img src="../figure/tutorial-module.svg" width=70% />
</p>

```rust,noplayground
comb: impl Fn(Option<IH::P>, EH::R, S) -> (Option<EH::P>, IH::R, S)
```

It takes three input signals:

- Ingress interface's forward signal (`Option<IH::P>`)
- Egress interface's backward signal (`EH::R`)
- Current state (`S`)

and returns three output signals:

- Egress interface's forward signal (`Option<EH::P>`)
- Ingress interface's backward signal (`IH::R`)
- Next state (`S`)

Here, `Option<H::P>` is `Some` is the payload is *valid*; otherwise it's `None`.

<!-- TODO: a simple figure is necessary. -->

<!-- For more details, please refer to the [Modules](../lang/module.md) section. -->

### Combinator

Combinator is the idiomatic mechanism of chaining two interfaces together in HazardFlow HDL.
Combinator is the idiomatic mechanism of attaching a module to an interface.

<p align="center">
<img src="../figure/combinator.drawio.svg" />
<img src="../figure/tutorial-combinator.svg" width=80% />
</p>

We define a combinator as a function `fsm` within each hazard interface in the HazardFlow HDL and it will be called each clock cycle.
It will take the initial state of the combinator and an anonymous function as input return the new interface and chain these two interfaces together as shown in the above figure.
The anonymous function specifies the logic of calculating the payload will be sent to the next combinator, the resolver will be sent to the previous combinator, and the next state of the current combinator.
<!-- TODO: I think the figure is wrong. The figure seems like all combinators are no-op. Can you add some combinational cloud and states to represent proper sequential logic? -->

We define a combinator as a function `fsm` within each hazard interface in the HazardFlow HDL and it will be called each clock cycle:

```rust,noplayground
impl<IH: Hazard> I<IH> {
fn fsm<S: Copy, EH: Hazard>(
self,
init_state: S,
f: impl Fn(Option<IH::P>, EH::R, S) -> (Option<EH::P>, IH::R, S),
) -> I<EH> {
..
}
}
```

<!-- TODO: dependence is not introduced in this document, right? then explicitly mention "don't care about it now." -->

<!-- TODO: change the following paragraph as if we're explaining the signature of the above function. -->

We define the hazard type for the ingress interface as `H` and `EH` for the egress interface.
It specifies the type of ingress, egress, and state.

**Ingress payload:**
* This is the forward signal of the ingress interface.
- Ingress hazard interface type (`IH`)
- Egress hazard interface type (`EH`)
- State type (`S`)

Also, it accepts two arguments for representing the module's behavior:

- Initial state when reset happened (`init_state`)
- Combinational logic of the module's behavior (`f`)

<!-- We define the hazard type for the ingress interface as `H` and `EH` for the egress interface. -->

<!--
**Ingress payload:** the forward signal of the ingress interface
* It is considered as a given input and it will be taken as an argument for the anonymous function.
**Egress resolver:**
* This is the backward signal of the egress interface.
**Egress resolver:** the backward signal of the egress interface
* It is considered as a given input and it will be taken as an argument for the anonymous function.
**Egress payload:**
* This is the forward signal of the egress interface.
**Egress payload:** the forward signal of the egress interface
* This signal will be calculated within the anonymous function.
* This signal will be sent as the payload to the next combinator.
**Ingress resolver:**
* This is the backward signal of the ingress interface.
**Ingress resolver:** the backward signal of the ingress interface
* This signal will be calculated within the anonymous function.
* This signal will be sent as the resolver to the previous combinator.
**State:**
* We interpret this as the register status within the combinator.
**State:** the register status within the combinator
* The current state of the combinator will be taken as an argument for the anonymous function.
* The next state of the combinator will be calculated within the anonymous function.
**The anonymous function:**
**The sequential logic:**
* This is the function we used to update the payload to the next combinator, resolver for the previous combinator, and the next state of the current combinator.
* We define the signature of the `fsm` as:

```rust,noplayground
pub unsafe fn fsm<S: Copy, const ED: Dep, EH: Hazard>(
self, init_state: S, f: impl Fn(HOption<H::P>, EH::R, S) -> (HOption<EH::P>, H::R, S),
) -> I<EH, ED>
```

* We can ignore the `Dep` and `unsafe` for now.
-->

HazardFlow HDL provide standard combinator library for developers to facilitate their work.

HazardFlow HDL defines some primitive combinators and hazard interfaces for developers.
The users can use these primitive combinators and hazard interfaces to construct their own combinational logic conveniently.
For more details, please refer to the [Interface Combinators](../lang/combinators.md) section.

0 comments on commit 5396aa7

Please sign in to comment.