实验对CPU的修改不多,如果完全按照RISC-V的要求设计CPU,将mul归类为R-Type的话,改动较多。但是我们可以单独设计一跟op_mul电线,然后单独设计乘法指令。
乘法指令的实现,直接使用其提供的乘法部件即可:
wire [31: 0] Result_MUL = RF_rdata1*RF_rdata2;
随后在选数里增加一项MUL的指令:
assign RF_wdata = {32{op_shift}}&shift_result|{32{op_J_Type}}&PC_4|{32{op_lui}}&extend|{32{op_auipc}}&(PC_temp+extend)|{32{(op_I_Type|op_R_Type)&~op_shift}}&ALU_result|{32{op_lw}}&load_word|{32{op_lb }}& {{24{load_byte[7]}},load_byte}|{32{op_lbu}}& {{24{1'b0}},load_byte}|{32{op_lh}}& {{16{load_half[15]}},load_half}|{32{op_lhu}}& {{16{1'b0}},load_half}|{32{op_mul}}& Result_MUL;
并按照R-Type的指令设计,设计自动机的转移:
`state_EX : beginif(op_B_Type)next_state = `state_IF;else if(op_R_Type|op_I_Type|op_U_Type|op_J_Type|op_mul)next_state = `state_WB;else if(op_S_Type)next_state = `state_ST;else if(op_L_Type)next_state = `state_LD;else next_state= `state_EX; end
其次是DNN相关的代码:
按照定义,需要设计几种中间变量:
short bias;short num_out;//outputshort num_in;//inputshort y,x,ky,kx;short k_square=1+mul(weight_size.d2,weight_size.d3);short in_square=mul(input_fm_h,input_fm_w);
bias指的是偏移量,存在 F i l t e r [ i ] [ 0 ] [ 0 ] Filter\left[i\right]\left[0\right]\left[0\right] Filter[i][0][0]位置。
其次num_in和num_out分别是吗枚举读入的图片通道数和输出的特征图片通道数。
x、y枚举的是当前图像处理的像素点位置,kx、ky指的是每一次卷积操作的时候卷积核的相对位置。
k_square和in_square是计算下标的中间变量。
在设计out的赋值时我发现,其赋值规律是顺序的,所以可以设计一个outoffset来计算位置。
int out_offset=0;short bias_offset=mul(rd_size.d1,k_square);
在第一重循环,枚举的是当前输出的通道数,在这一层可以计算bias的值。在第二层,枚举输入的通道数,随后枚举当前通道这张图片的像素点位置。在这种过程中,更据定义,需要增加当前图片间的步长Stride_X、Stride_Y。对于每个卷积核,其每个方块的由kx、ky两个块进行枚举。在这里由于存在边界填充,所以存在一个pad的偏移,于是在这里需要作差的得到iw和ih。随后求出当前的像素值和卷积的权重,随后便可以计算卷积后的结果,在这里中间变量需要用32位整数存储。在这里,值得注意的是16位定点数的符号位需要由32位定点数的符号位求出。最后,由于发现输出特征图的像素顺序是良序的,所以可以直接不断加1得到结果。另外一个比较重要的步骤是池化操作,池化操作本质是取最大值,所以实现起来比较简单。
池化操作的计算也就是找到对应像素点位置,然后比个大小就可以了。注意到这里最大值max的初始值是0x8000,这在16位定点数里表示最小值,因此一定会被更大的数所替换。
硬件加速器就很简单了:
#ifdef USE_HW_ACCELvoid launch_hw_accel(){volatile int* gpio_start = (void*)(GPIO_START_ADDR);volatile int* gpio_done = (void*)(GPIO_DONE_ADDR);* gpio_start =(* gpio_start )|0x01;while(1){if((*(volatile char*)gpio_done)&0x01)break;}return;}#endif
按照流程图,如果开始将对应位置低位赋值1,如果检测到结束位置低位赋值1就结束。