burst访问-高层次综合设计
一、案例举例案例一读取操作放在if内降低突发传输效率int sum 0;for (int i 0; i N; i) {if (valid[i]) {sum A[i]; // 访问被条件包裹}}上面代码对A数组的访问放在if内那么A数组的访问是有条件的只有在valid为高的时候才会读取A数组这个造成在某些周期没有读请求发出或者在访问的时候存在气泡所以没有办法打包为一次突发传输。案例二始终读取数据条件判断只是用于结果选择int sum 0;for (int i 0; i N; i) {int tmp A[i]; // 无条件读取if (valid[i]) {sum tmp; // 条件只影响计算不影响访存}}二、常见违规场景导致无法生成AXI Bursst1.读取在if内2.写入在if内3.嵌套循环中的条件访问4.依赖数据的条件访问5.复杂的if-else结构6.与循环变量无关的条件7.多个数组访问部分在条件内8.循环内switch-case中的访问9.使用循环携带依赖但是条件包裹10.带有函数调用的条件访问以上的几种类型都会造成AXI burst无法访问。有的案例会将传输变成单拍传输有的案例会造成burst访问中断有的案例会导致访问的抵消。三、十个案例说明1.有条件的load加载for (int i 0; i 256; i) {if (enable[i]) {int tmp A[i]; // 读访问在条件内sum tmp;}}只有 enable[i] 为真时才发出读请求多个迭代可能连续空缺地址流出现断点无法形成从 A[0] 到 A[255] 的连续突发。综合工具看到某些拍无访存只能退化为单拍读取。。2.写入操作被条件遮蔽for (int i 0; i 128; i) {if (valid[i]) {B[i] data[i]; // 写访问在条件内}}当 valid[i] 为假时该拍完全没有写事务突发写序列被打断。AXI 突发要求连续的地址和数据相位空拍会导致一次突发被拆分成多次短事务甚至单拍写。3.if-else 内各自访问不同数组for (int i 0; i 64; i) {if (sel[i]) {C[i] A[i];} else {C[i] B[i];}}虽然每次迭代都有写操作但读取 A[i] 和 B[i] 分别位于互斥的条件分支中。任一分支被选中时另一个数组的读访问就被跳过编译器无法保证 A 或 B 的地址在每个周期都连续发出请求无法形成对 A 或 B 的突发。最终可能生成针对每个元素的单次读取多路选择而不是突发。4.基于计算结果的动态条件for (int i 0; i 256; i) {int tmp A[i];if (tmp threshold) {B[i] tmp; // 写访问受数据值影响}}虽然读取 A 形成了突发但对 B 的写入完全由 A[i] 的数值决定多个迭代可能不写入导致写地址序列出现大量空洞突发写无法建立。工具会转而采用单次写操作失去突发性能。5.循环不变条件导致整个突发消失for (int i 0; i 512; i) {if (global_flag) {dst[i] src[i];}}尽管 global_flag 在循环外确定但从综合工具视图看if 依然包裹访存。当 global_flag 为假时整个循环内完全没有访存工具必须推断出一种兼容所有情况的硬件因此在优化时会认为访存不是每个周期必然发生从而放弃突发生成。6.嵌套循环内层写被条件包裹for (int i 0; i 10; i) {for (int j 0; j 32; j) {if (mask[i][j]) {B[i][j] A[i][j];}}}内层循环原本可以生成 32 个连续地址的突发写但 mask 条件导致部分 j 位置不执行写操作地址序列不再连续、写使能出现气泡。硬件上 32 拍突发会被撕裂为多段甚至每拍独立握手的非突发写极大降低带宽利用率。7.switch-case 中分散的访存for (int i 0; i 128; i) {switch (op[i]) {case 0: sum A[i]; break;case 1: sum B[i]; break;case 2: sum C[i]; break;default: break; // 无访存}}每次迭代根据 op[i] 选择读取 A、B 或 C且 default 不访问任何数组。对于任一数组如 A其读请求只在 op[i]0 时发出其他拍没有请求无法构成连续的突发读。同时三个数组的地址流都不连续突发全部失效。8.函数调用内含条件访存void conditional_load(int *arr, int i, bool cond, int *val) {if (cond) {*val arr[i];}}for (int i 0; i 256; i) {int v;conditional_load(A, i, flag[i], v);sum v;}函数 conditional_load 内部将 arr[i] 的读取置于条件内在循环迭代展开后等同于读取被 flag[i] 包裹。综合工具跨函数分析时依然会识别出该读访存不是循环必然执行从而无法对 A 进行突发优化。9.循环携带依赖 条件访存复杂模式for (int i 0; i 256; i) {if (i 0 || B[i-1] 0) {B[i] A[i] offset;}}对 B 的写入不仅受条件 i0 || B[i-1]0 控制还携带了循环间的数据依赖。条件会导致大量迭代不写入同时读取 B[i-1] 也可能因条件短路而不执行在某些仿真/综合语义下。无论如何写入序列不完整突发写无法生成且可能破坏流水线调度。10.字节掩码被条件误用手动实现掩码却未连续发出写事务for (int i 0; i 64; i) {if (be[i] ! 0) {// 意图使用字节使能但将整个写事务放入ifwrite_with_byte_enable(B[i], data[i], be[i]);}}虽然使用了字节使能函数但由于整个写调用被 if (be[i] ! 0) 包裹当 be[i] 为 0 时连写事务本身都不发起。正确的突发写要求每个周期都发起事务并通过字节使能关闭实际写入而不是跳过事务。此处跳过事务等同于案例 2突发被切断。