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
four-dimensional space, which can be visited with configurable strides in all
four 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 tot_len // d0,d1,total length (in number of transactions)
int d0_stride, int d1_stride, int d2_stride, // d0,d1,d2 strides (in bytes)
int *d0_addr, int *d1_addr, int *d2_addr, // d0,d1,d2 addresses (by reference)
int *d0_cnt, int *d1_cnt, int *ov_cnt // d0,d1,overall counters (by reference)
) {
// compute current address
int current_addr = 0;
int done = 0;
if (dim_enable & 0x1 == 0) { // 1-dimensional streaming
current_addr = base_addr + *d0_addr;
}
else if(dim_enable & 0x2 == 0) { // 2-dimensional streaming
current_addr = base_addr + *d1_addr + *d0_addr;
}
else { // 3-dimensional streaming
// On the last d1 iter pick d2_addr_last_d1 (parallel accumulator); set d2_stride_last_d1 = d2_stride to disable
current_addr = base_addr +
(*d1_cnt == d1_len ? *d2_addr_last_d1 : *d2_addr) +
*d1_addr + *d0_addr;
}
// update counters and dimensional addresses
if(*ov_cnt == tot_len) {
done = 1;
}
if((*d0_cnt < d0_len) || (dim_enable & 0x1 == 0)) {
// Each d0_stride_last_dN is active iff it differs from d0_stride; outermost active dN wins; set _dN = d0_stride to disable
*d0_addr = *d0_addr + (*d2_cnt == d2_len && d0_stride_last_d2 != d0_stride ? d0_stride_last_d2 :
*d1_cnt == d1_len && d0_stride_last_d1 != d0_stride ? d0_stride_last_d1 : d0_stride);
*d0_cnt = *d0_cnt + 1;
}
else if ((*d1_cnt < d1_len) || (dim_enable & 0x2 == 0)) {
*d0_addr = 0;
*d1_addr = *d1_addr + d1_stride;
*d0_cnt = 1;
*d1_cnt = *d1_cnt + 1;
}
else if ((*d2_cnt < d2_len) || (dim_enable & 0x4 == 0)) {
*d0_addr = 0;
*d1_addr = 0;
*d2_addr = *d2_addr + d2_stride;
*d2_addr_last_d1 = *d2_addr_last_d1 + d2_stride_last_d1;
*d0_cnt = 1;
*d1_cnt = 1;
*d2_cnt = *d2_cnt + 1;
}
else {
*d0_addr = 0;
*d1_addr = 0;
*d2_addr = 0;
*d3_addr = *d3_addr + d3_stride;
*d0_cnt = 1;
*d1_cnt = 1;
*d2_cnt = 1;
}
*ov_cnt = *ov_cnt + 1;
return current_addr, done;
}
Name |
Default |
Description |
TRANS_CNT |
32 |
Number of bits supported in the transaction counter, which will overflow at 2^ TRANS_CNT. |
CNT |
32 |
Number of bits supported in non-transaction counters, which will overflow at 2^ CNT. |
PARTIAL_TILING |
0 |
When 1, enables d0_stride_last_d1/d2 and d2_stride_last_d1 partial-tile boundary handling. |
dim_enable_1h | logic[2:0] | One-hot switch to enable 4-d counting (111), 3-d (011), 2-d (001), or 1-d (000). |
Name |
Type |
Description |
done |
logic |
1 when the address generation has finished. |
This module instantiates no other module.
Clocks
Resets
Ports 8
Inputs 6
| Dir | Name | Type | Width |
|---|---|---|---|
| in | clk_i | logic | 1 |
| in | rst_ni | logic | 1 |
| in | enable_i | logic | 1 |
| in | clear_i | logic | 1 |
| in | presample_i | logic | 1 |
| in | ctrl_i | hwpe_stream_package::ctrl_addressgen_v4_t | 452 |
Outputs 2
| Dir | Name | Type | Width |
|---|---|---|---|
| out | addr_o | hwpe_stream_intf_stream .source | - |
| out | flags_o | hwpe_stream_package::flags_addressgen_v4_t | 1 |
Parameters 4
| Name | Resolved value |
|---|---|
| TRANS_CNT | 32'd32 |
| CNT | 32'd32 |
| PARTIAL_TILING | 1'b0 |
| DIM_ENABLE_1H | 4'b1111 |