一、对循环体的展开
C语言的循环体都是折叠起来的,当综合后会顺序执行,映射到RTL的话就相当于一套电路被分时复用;
进行展开的话就相当于是对电路的复制。
HLS Directive Editor->Directive->UNROOL->factor=N(N就是要展开成几份)。
二、for循环合并
loop regin:{
add:
for(int i=0;i<N;i++){
c[i]=a[i]+b[i];
}
sub:
for(int i=0;i<N;i++){
d[i]=a[i]+b[i];
}
}
对于这种循环,我们所期望的是程序在执行加法的同时,也执行减法;但是默认情况下它是顺序执行的,也就是执行完加法,再执行减法,这时我们可以将其进行合并 (LOOP_MERGE)这样add和sub可以同时进行。
合并的一些规则:a)边界不同但都为常数的,合并和边界为较大的那个。
b)边界一个为常数,另一个为变量时,此时无法进行合并。
c)边界都为变量时,合并后为一个范围。
三、数据流(data_flow)
a) Loop_A:
for(i=0;i<N;i++){}
Loop_B:
for(i=0;i<N;i++){}
Loop_C:
for(i=0;i<N;i++){}
数据流动过程:D->TaskA->TaskB->TaskC->out
b)dataflow for "For_loop"
LoopA->channel->LoopB->channel->LoopC channel中可以使用ping-pong,FIFO,register
正常流程:LoopA->LoopB->LoopC 使用dataflow之后:LoopA|LoopA|LoopA
LoopB|LoopB|LoopB
LoopC|LoopC|LoopC
b)data_flow的限制
I)
Loop1:
for(i=0;i<N;i++){
temp1[i]=din[i[*scale;
}
Loop2:
for(i=0;j<N;j++){
dout1[j]=temp1[j]*2;
}
Loop3:
for(k=0;k<N;k++){
dout2[k]=temp1[k]*4;
}
对这种Loop1中的结果在Loop2和Loop3中都被使用的情况(single-producer-consumer model)我们可以在Loop1下面加个Loop_copy将temp1复制一份及:
Loop1:
for(i=0;i<N;i++){
temp1[i]=din[i[*scale;
}
Loop_copy:
for(m=0;m<N;m++){
temp2[m]=temp1[m];
temp3[m]=temp1[m];
}
Loop2:
for(i=0;j<N;j++){
dout1[j]=temp2[j]*2;
}
Loop3:
for(k=0;k<N;k++){
dout2[k]=temp3[k]*4;
}
II)
Loop1:
for(i=0;i<N;i++){
temp1[i]=din[i[*scale;
temp2[i]=din[i]>>scale;
}
Loop2:
for(i=0;j<N;j++){
temp3[j]=temp1[j]*2;
}
Loop3:
for(k=0;k<N;k++){
dout[k]=temp2[k]+temp3[k];
}
对于这种,Loop1产生2个结果,其中一个经Loop2到Loop3,另一个直接被Loop3引用,可以在Loop2中添加一个temp4对temp2进行复制。
Loop1:
for(i=0;i<N;i++){
temp1[i]=din[i[*scale;
temp2[i]=din[i]>>scale;
}
Loop2:
for(i=0;j<N;j++){
temp3[j]=temp1[j]*2;
temp4[j]=temp2[j];
}
Loop3:
for(k=0;k<N;k++){
dout[k]=temp4[k]+temp3[k];
}
四、嵌套式的for循环
对于2层的嵌套,若对外部的for循环做流水,则其内部所有的for循环均会被打开;一般对最内层的做流水。
五、其它的补充
a)rewind可以消除2个周期之间的间隔;
b)当循环边界为变量的时候无法确定其latency,我们可以进行设定或者把值设定为任意精度的。