Skip to content

Commit

Permalink
Merge pull request #49 from ispras/dfcxx_sim
Browse files Browse the repository at this point in the history
DFCxx simulation
  • Loading branch information
ssmolov authored Sep 5, 2024
2 parents eac27e3 + 97d413d commit be9a08f
Show file tree
Hide file tree
Showing 59 changed files with 1,835 additions and 1,661 deletions.
58 changes: 18 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,12 @@ The compiled Utopia HLS executable has a CLI to accept a number of parameters af

For the executable there are three general arguments: `-h,--help`, `-H,--help-all` and `-v,--version` for printing simple and extended help-messages, and printing current executable's version respectively.

Unless neither of the three arguments is used, first argument is the mode which the executable has to function in. Currently there is only one available mode `hls`.
Unless neither of the three arguments is used, first argument is the mode which the executable has to function in. Currently there are only two available modes: `hls` and `sim`.

The list of arguments for `hls`-mode is presented below:
`hls` mode is used to perform the high-level synthesis of digital hardware description from the input DFCxx kernel. The list of arguments for `hls`-mode is presented below:

* `-h,--help`: *optional* flag; used to print the help-message about other arguments.
* `--config <PATH>`: *required* filesystem-path option; used to specify the file for a JSON latency configuration file. Its format is presented in *JSON Configuration* section.
* `--config <PATH>`: *required* filesystem-path option; used to specify the file for a JSON latency configuration file. Its format is presented in `docs/latency_config.md`.
* `--out-sv <PATH>`: *optional* filesystem-path option; used to specify the output SystemVerilog file.
* `--out-sv-lib <PATH>`: *optional* filesystem-path option; used to specify the output SystemVerilog file for generated operations library.
* `--out-dfcir <PATH>`: *optional* filesystem-path option; used to specify the output DFCIR file.
Expand All @@ -232,43 +232,13 @@ Here is an example of an Utopia HLS CLI call:
umain hls --config ~/utopia-user/config.json --out-sv ~/outFile.sv --out-dfcir ~/outFile2.mlir -a
```

### JSON Configuration
`sim` mode is used to simulate the input DFCxx kernel. The list of arguments for `sim`-mode is presented below:

Latency configuration for each computational operation (number of pipeline stages) used in a DFCxx kernel is provided via a JSON file.

Currently each operation has two specifications: for integer values (`INT`) and floating point (`FLOAT`) values.

The list of all computational operations is provided below:

* `ADD` - Addition
* `SUB` - Subtraction
* `MUL` - Multiplication
* `DIV` - Division
* `AND` - Logical conjunction
* `OR` - Logical disjunction
* `XOR` - Exclusive logical disjunction
* `NOT` - Logical inversion
* `NEG` - Negation
* `LESS` - "less" comparison
* `LESSEQ` - "less or equal" comparison
* `GREATER` - "greater" comparison
* `GREATEREQ` - "greater or equal" comparison
* `EQ` - "equal" comparison
* `NEQ` - "not equal" comparison

JSON configuration structure states that for every operation with a specific configuration (each pair is represented as a separate JSON-field with `_` between pair's elements) present in the kernel, operation's latency will be provided.

Here is an example of a JSON configuration file, containing latencies for multiplication, addition and subtraction of integer numbers:

```json
{
"MUL_INT": 3,
"ADD_INT": 1,
"SUB_INT": 1
}
```
* `-h,--help`: *optional* flag; used to print the help-message about other arguments.
* `--in <PATH>`: *optional* filesystem-path option; used to specify the input file for simulation data (default: `sim.txt`). Its format is presented in `docs/simulation.md`.
* `--out <PATH>`: *optional* filesystem-path option; used to specify the output VCD file (default: `sim_out.vcd`).

## Examples
### Examples

Root subdirectory `examples` contains different examples of DFCxx kernels, `start`-function definitions and JSON configuration files.

Expand All @@ -280,9 +250,17 @@ cmake --build build
build/src/umain hls --config examples/polynomial2/add_int_2_mul_int3.json -a --out-sv output
```

The execution command is going to pass a JSON configuration file (with 2 and 3 pipeline stages for integer addition
The execution command is going to pass a JSON configuration file (with latencies 2 and 3 for integer addition
and multiplication respectively) to Utopia HLS, resulting in the creation of the file `output`, containing a SystemVerilog
module for Polynomial2 kernel with a greedy ASAP-scheduling.
module for `Polynomial2` kernel with a greedy ASAP-scheduling.

The same kernel can be simulated with:

```bash
build/src/umain sim --in examples/polynomial2/sim.txt --out output.vcd
```

This command uses the simulation data from `sim.txt` file and stores the simulation trace in the output file `output.vcd`.

## DFCxx Documentation

Expand Down
4 changes: 4 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@
"out_dfcir" : "",
"out_firrtl" : "",
"out_dot" : ""
},
"sim": {
"in" : "sim.txt",
"out" : "sim_out.vcd"
}
}
35 changes: 35 additions & 0 deletions docs/latency_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Latency Configuration

Latency configuration is a JSON-based file describing characteristics of computational operations for the specific DFCxx kernel.

Currently each operation has two specifications based on the types of its arguments: for integer values (`INT`) and floating point (`FLOAT`) values respectively.

All the supported computational operations are listed below:

* `ADD` - Addition
* `SUB` - Subtraction
* `MUL` - Multiplication
* `DIV` - Division
* `AND` - Logical conjunction
* `OR` - Logical disjunction
* `XOR` - Exclusive logical disjunction
* `NOT` - Logical inversion
* `NEG` - Negation
* `LESS` - "less" comparison
* `LESSEQ` - "less or equal" comparison
* `GREATER` - "greater" comparison
* `GREATEREQ` - "greater or equal" comparison
* `EQ` - "equal" comparison
* `NEQ` - "not equal" comparison

JSON configuration structure states that for every operation with a specific configuration (each pair is represented as a separate JSON-field with `_` between pair's elements) present in the kernel, operation's latency has to be provided.

Here is an example of a JSON configuration file, containing latencies for multiplication, addition and subtraction of integer numbers:

```json
{
"MUL_INT": 3,
"ADD_INT": 1,
"SUB_INT": 1
}
```
32 changes: 32 additions & 0 deletions docs/simulation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## DFCxx Simulation

DFCxx kernels can be simulated to check that they describe computations as expected. The simulation doesn't take scheduling into account and requires every computational node to use **and** accept some values at every simulation tick.

### Input format

The format to provide simulation input data is the following:

* input data is divided into blocks separated with a newline character (`\n`) - one block for each simulation step
* every block has a number of lines, each of which has the case-sensitive name of some **input** stream/scalar variable and its hex-value (these values do not have an explicit type - they will be casted to the types of related computational nodes)
* stream/scalar value name and the hex-value are separated with a single space character (` `)
* the provided value must be a valid hex-value: with or without `0x`, with either lower- or uppercase letters
* if some stream/scalar hex-value is present twice or more in the same block - its latest described value is used

Here is an example of an input simulation file for `MuxMul` kernel, which has two input streams: `x` (unsigned 32-bit integer values) and `ctrl` (unsigned 1-bit integer values).

```txt
x 0x32
ctrl 0x1
x 0x45
ctrl 0x0
x 0x56
ctrl 0x1
```

In this example, `x` accepts values `50` (`0x32`), `69` (`0x45`) and `86` (`0x56`), while `ctrl` accepts `1`, `0` and `1`. This means that 3 simulation ticks will be performed for the provided kernel.

### Not Supported Constructions

* *offsets*
5 changes: 5 additions & 0 deletions examples/addconst/sim.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
x 0x32

x 0x45

x 0x56
30 changes: 15 additions & 15 deletions examples/idct/idct.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,17 @@ class IDCT : public dfcxx::Kernel {
DFVariable x7 = (values[kDIM * i + 3]);

DFVariable x8 = (x4 + x5) * W7;
x4 = x8 + (W1 - W7) * x4;
x5 = x8 - (W1 - W7) * x5;
x8 = W3 * (x6 + x7);
x6 = x8 - (W3 - W5) * x6;
x7 = x8 - (W3 + W5) * x7;
x4 = x8 + x4 * (W1 - W7);
x5 = x8 - x5 * (W1 + W7);
x8 = (x6 + x7) * W3;
x6 = x8 - x6 * (W3 - W5);
x7 = x8 - x7 * (W3 + W5);

x8 = x0 + x1;
x0 = x0 - x1;
x1 = (x3 + x2) * W6;
x2 = x1 - (W2 + W6) * x2;
x3 = x1 + (W2 - W6) * x3;
x2 = x1 - x2 * (W2 + W6);
x3 = x1 + x3 * (W2 - W6);
x1 = x4 + x6;
x4 = x4 - x6;
x6 = x5 + x7;
Expand Down Expand Up @@ -97,17 +97,17 @@ class IDCT : public dfcxx::Kernel {
DFVariable x7 = values[kDIM * 3 + i];

DFVariable x8 = ((x4 + x5) * W7) + const4;
x4 = (x8 + (W1 - W7) * x4) >> 3;
x5 = (x8 - (W1 - W7) * x5) >> 3;
x8 = (W3 * (x6 + x7)) + const4;
x6 = (x8 - (W3 - W5) * x6) >> 3;
x7 = (x8 - (W3 + W5) * x7) >> 3;
x4 = (x8 + x4 * (W1 - W7)) >> 3;
x5 = (x8 - x5 * (W1 + W7)) >> 3;
x8 = ((x6 + x7) * W3) + const4;
x6 = (x8 - x6 * (W3 - W5)) >> 3;
x7 = (x8 - x7 * (W3 + W5)) >> 3;

x8 = x0 + x1;
x0 = x0 - x1;
x1 = ((x3 + x2) * W6) + const4;
x2 = (x1 - (W2 + W6) * x2) >> 3;
x3 = (x1 + (W2 - W6) * x3) >> 3;
x2 = (x1 - x2 * (W2 + W6)) >> 3;
x3 = (x1 + x3 * (W2 - W6)) >> 3;
x1 = x4 + x6;
x4 = x4 - x6;
x6 = x5 + x7;
Expand All @@ -119,7 +119,7 @@ class IDCT : public dfcxx::Kernel {
x0 = x0 - x2;
x2 = (((x4 + x5) * const181) + const128) >> 8;
x4 = (((x4 - x5) * const181) + const128) >> 8;

values[kDIM * 0 + i] = (x7 + x1) >> 14;
values[kDIM * 1 + i] = (x3 + x2) >> 14;
values[kDIM * 2 + i] = (x0 + x4) >> 14;
Expand Down
64 changes: 64 additions & 0 deletions examples/idct/sim.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
x0 0x0
x1 0x1
x2 0x2
x3 0x3
x4 0x4
x5 0x5
x6 0x6
x7 0x7
x8 0x8
x9 0x9
x10 0xA
x11 0xB
x12 0xC
x13 0xD
x14 0xE
x15 0xF
x16 0x10
x17 0x11
x18 0x12
x19 0x13
x20 0x14
x21 0x15
x22 0x16
x23 0x17
x24 0x18
x25 0x19
x26 0x1A
x27 0x1B
x28 0x1C
x29 0x1D
x30 0x1E
x31 0x1F
x32 0x20
x33 0x21
x34 0x22
x35 0x23
x36 0x24
x37 0x25
x38 0x26
x39 0x27
x40 0x28
x41 0x29
x42 0x2A
x43 0x2B
x44 0x2C
x45 0x2D
x46 0x2E
x47 0x2F
x48 0x30
x49 0x31
x50 0x32
x51 0x33
x52 0x34
x53 0x35
x54 0x36
x55 0x37
x56 0x38
x57 0x39
x58 0x3A
x59 0x3B
x60 0x3C
x61 0x3D
x62 0x3E
x63 0x3F
8 changes: 8 additions & 0 deletions examples/matrixmul2/sim.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
x11 0x32
x12 0x64
x21 0x48
x22 0x99
y11 0x1
y12 0x0
y21 0x0
y22 0x1
8 changes: 8 additions & 0 deletions examples/muxmul/sim.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
x 0x32
ctrl 0x1

x 0x45
ctrl 0x0

x 0x56
ctrl 0x1
5 changes: 5 additions & 0 deletions examples/polynomial2/sim.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
x 0x32

x 0x45

x 0x56
6 changes: 6 additions & 0 deletions examples/scalar3/sim.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
x1 0x2
y1 0x32
x2 0x3
y2 0x32
x3 0x4
y3 0x32
44 changes: 30 additions & 14 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,42 @@

INITIALIZE_EASYLOGGINGPP

// User-defined function to specify functional behaviour of top-level kernel.
std::unique_ptr<dfcxx::Kernel> start();

//===-----------------------------------------------------------------------===/
// High-Level Synthesis
//===-----------------------------------------------------------------------===/

struct HlsContext {
HlsContext(const HlsOptions &options):
options(options)
{}
HlsContext(const HlsOptions &options) : options(options) {}

const HlsOptions &options;
};

// User-defined function to specify functional behaviour of top-level kernel.
std::unique_ptr<dfcxx::Kernel> start();
//===-----------------------------------------------------------------------===/
// DFCxx Simulation.
//===-----------------------------------------------------------------------===/

struct SimContext {
SimContext(const SimOptions &options): options(options) {}

int hlsMain(HlsContext &context) {
const SimOptions &options;
};

int hlsMain(const HlsContext &context) {
auto kernel = start();
bool useASAP = context.options.asapScheduler;
kernel->compile(context.options.latConfig,
context.options.outNames,
(useASAP) ? dfcxx::Scheduler::ASAP
: dfcxx::Scheduler::Linear);
return 0;
return !kernel->compile(context.options.latencyCfg,
context.options.outNames,
(useASAP) ? dfcxx::Scheduler::ASAP
: dfcxx::Scheduler::Linear);
}

int simMain(const SimContext &context) {
auto kernel = start();
return !kernel->simulate(context.options.inFilePath,
context.options.outFilePath);
}

int main(int argc, char **argv) {
Expand All @@ -63,7 +76,10 @@ int main(int argc, char **argv) {
catch(const CLI::ParseError &e) {
return options.exit(e);
}

HlsContext context(options.hls);
return hlsMain(context);

if (options.hls) {
return hlsMain(HlsContext(options.hls));
} else {
return simMain(SimContext(options.sim));
}
}
Loading

0 comments on commit be9a08f

Please sign in to comment.