hwpe_stream_addressgen_v4
The hwpe_stream_addressgen_v4 module is used to generate addresses to
load or store HWPE-Stream stream. In this version of the address generator,
the address is itself carried within a HWPE-Stream, making it easily stallable.
The address generator can be used to generate address from a
five-dimensional space, which can be visited with configurable strides in all
five dimensions.
The multiple loop functionality is partially overlapped by the functionality provided by the microcode processor hwce_ctrl_ucode that can be embedded in HWPEs. The latter is much more flexible and smaller, but less fast.
One iteration is performed per each cycle when enable_i is 1 and the output addr_o stream is ready. presample_i should be 1 in the first cycle in which the address generator can start generating addresses, and no further. The following piece of pseudo-C code resumes the basic functionality provided by the address generator.
hwpe_stream_addressgen_v4(
int base_addr, // base address (byte-aligned)
int d0_len, int d1_len, int d2_len, int d3_len, int tot_len, // d0..d3,total length (in number of transactions)
int d0_stride, int d1_stride, int d2_stride, int d3_stride, int d4_stride, // d0..d4 strides (in bytes)
int *d0_addr, int *d1_addr, int *d2_addr, int *d3_addr, int *d4_addr, // d0..d4 addresses (by reference)
int *d0_cnt, int *d1_cnt, int *d2_cnt, int *d3_cnt, int *ov_cnt // d0..d3,overall counters (by reference)
) {
// A dimension counts dN_cnt from 1 to len_eff(N), so its index is dN_cnt-1
// running up and len_eff(N)-dN_cnt running down. It is at its last index when:
at_top(N) = down(N) ? (*dN_cnt == 1) : (*dN_cnt == len_eff(N));
// A second length, switched by an outer dimension only: bits at or below N are
// masked off, which also keeps at_top -> len_eff -> at_top acyclic. tot_len has
// to account for the shortened sweeps and for the skipped elements.
len_eff(N) = (dN_len_last_1h & at_top & ~((2 << N)-1)) ? dN_len_last : dN_len;
// A second stride, switched by any dimension. A second address stepped next to
// the first always holds idx*dN_stride_last, so no multiplier is needed.
use_last(N) = (dN_last_1h & at_top) != 0;
addr(N) = use_last(N) ? *dN_addr_last : *dN_addr;
step(N) = down(N) ? -dN_stride : dN_stride;
step_last(N) = down(N) ? -dN_stride_last : dN_stride_last;
advance(N) { *dN_addr += step(N); *dN_addr_last += step_last(N); *dN_cnt += 1; }
restart(N) { // the dimension directly above N moved
down(N) = alternate_1h[N] ? !down(N) : 0;
*dN_addr = alt_skip_1h[N] ? *dN_addr - step(N) // skip the repeat
: down(N) ? *dN_addr // resume from the top
: 0; // restart at the bottom
*dN_addr_last = alt_skip_1h[N] ? *dN_addr_last - step_last(N)
: down(N) ? *dN_addr_last
: 0;
*dN_cnt = alt_skip_1h[N] ? 2 : 1;
}
reset(N) { down(N) = 0; *dN_addr = 0; *dN_addr_last = 0; *dN_cnt = 1; }
// compute current address
int current_addr = 0;
int done = 0;
if (dim_enable_1h & 0x1 == 0) { // 1-dimensional streaming
current_addr = base_addr + addr(0);
}
else if(dim_enable_1h & 0x2 == 0) { // 2-dimensional streaming
current_addr = base_addr + addr(1) + addr(0);
}
else if(dim_enable_1h & 0x4 == 0) { // 3-dimensional streaming
current_addr = base_addr + addr(2) + addr(1) + addr(0);
}
else if(dim_enable_1h & 0x8 == 0) { // 4-dimensional streaming
current_addr = base_addr + addr(3) + addr(2) + addr(1) + addr(0);
}
else { // 5-dimensional streaming
current_addr = base_addr + *d4_addr + addr(3) + addr(2) + addr(1) + addr(0);
}
// update counters and dimensional addresses
if(*ov_cnt == tot_len) {
done = 1;
}
if((*d0_cnt < len_eff(0)) || (dim_enable_1h & 0x1 == 0)) {
advance(0);
}
else if ((*d1_cnt < len_eff(1)) || (dim_enable_1h & 0x2 == 0)) {
restart(0); advance(1);
}
else if ((*d2_cnt < len_eff(2)) || (dim_enable_1h & 0x4 == 0)) {
reset(0); restart(1); advance(2);
}
else if ((*d3_cnt < len_eff(3)) || (dim_enable_1h & 0x8 == 0)) {
reset(0); reset(1); restart(2); advance(3);
}
else {
reset(0); reset(1); reset(2); restart(3);
*d4_addr = *d4_addr + d4_stride;
}
*ov_cnt = *ov_cnt + 1;
return current_addr, done;
}
With a parameter bit clear the matching control fields are ignored, so every extension is off by default and a zero-initialised control struct keeps working.
Name |
Type |
Description |
base_addr |
logic[31:0] |
Byte-aligned base address of the stream in the HWPE-accessible memory. |
tot_len |
logic[31:0] |
Total number of transactions in stream; only the TRANS_CNT LSB are actually used. |
dN_len |
logic[31:0] |
dN length in number of transactions (N = 0..3) |
dN_stride |
logic[31:0] |
dN stride in bytes (N = 0..3) |
d4_stride |
logic[31:0] |
d4 stride in bytes |
dim_enable_1h |
logic[3:0] |
One-hot switch to enable 5-d counting (1111), 4-d (0111), 3-d (0011), 2-d (0001), or 1-d (0000). |
dN_stride_last |
logic[31:0] |
Second stride of dimension N, in bytes (N = 0..3). |
dN_last_1h |
logic[3:0] |
Bit j: use dN_stride_last while dimension j is at its last index. 0 turns it off. |
dN_len_last |
logic[31:0] |
Second length of dimension N, in transactions (N = 0..3). |
dN_len_last_1h |
logic[3:0] |
Bit j: use dN_len_last while dimension j is at its last index. Bits at or below N do nothing. |
alternate_1h |
logic[3:0] |
Bit N: dimension N turns around every time dimension N+1 moves. |
alt_skip_1h |
logic[3:0] |
Bit N: with alternate_1h[N], skip the element shared with the previous sweep. |
Name |
Type |
Description |
done |
logic |
1 when the address generation has finished. |
Interface
the boundary of hwpe_stream_addressgen_v4 — it instantiates no other moduleThe ports stand at the walls of the module frame: input, left · output, right · interface — a slanted green box is a stream or a bus; the wide green line carries its data, and the arrow gives the direction · control — the dashed amber line shows which module controls what · flag / status · no direction. A straight box is a module. A hexagon is a port that goes in two directions. A dashed inner box is a generate block. The dashed white node is the logic of the module itself: the processes that drive or read a control net. The clock, reset, clear and test-mode nets are not in the graph; the chips below the diagram give them.
Clocks
Resets
Clears
Ports 8
Inputs 6
| Dir | Name | Type | Width |
|---|---|---|---|
| in | clk_i | logic | 1 |
| in | rst_ni | logic | 1 |
| in | enable_i ctrl | logic | 1 |
| in | clear_i | logic | 1 |
| in | presample_i | logic | 1 |
| in | ctrl_i ctrl | hwpe_stream_package::ctrl_addressgen_v4_t | 652 |
Outputs 2
| Dir | Name | Type | Width |
|---|---|---|---|
| out | addr_o | hwpe_stream_intf_stream .source | - |
| out | flags_o flag | hwpe_stream_package::flags_addressgen_v4_t | 1 |
Parameters 7
| Name | Resolved value |
|---|---|
| TRANS_CNT | 32'd32 |
| CNT | 32'd32 |
| DIM_ENABLE_1H | 4'b1111 |
| STRIDE_LAST_1H | 4'b0 |
| LEN_LAST_1H | 4'b0 |
| ALTERNATE_1H | 4'b0 |
| ALT_SKIP_1H | 4'b0 |