写Verilog通用模块的一些代码----持续更新
在编写代码为了能够方便移植或者说为了一劳永逸,往往会考虑把模块代码写得更加的通用。比如可以进行传参配置,这里主要是通过位宽传参。笔者写过不少的代码,觉得写通用模块代码需要思考挺长的时间去处理数据赋值之类的,需要总结出公式才能使代码通用,为了方便查找,这里就总结下笔者常用到的一些写法,大部分的通用代码都使用了for循环进行遍历。
1.位宽计数
在节省资源的情况下会使用,能够精准计算出当前计数器需要的位宽,或者FIFO的位宽。不过这也只能对parameter或者localparam参数进行计算,否则vivado貌似会编译不过。这里把功能封装成一个函数,纯组合逻辑实现。功能就是计算当前数值需要的位宽,就是log2。假设要算DATA_WIDTH= 10;则log2(DATA_WIDTH)结果就为4。
1 function integer log2; 2 input [WIDTH-1:0] i_data; 3 begin 4 for(log2 = 0; i_data >0; log2 = log2 + 1) 5 begin 6 i_data = i_data >> 1; 7 end 8 end 9 endfunction
2.通用的译码器编码器
正常译码解码器会使用case,这样就能够遍历所有情况。不过case没办法对通用的情况进行赋值。
2.1编码:
1 integer i; 2 always@(*) 3 begin 4 for(i = 0; i <= WIDTH - 1; i = i + 1)//WIDTH是i_din位宽 5 begin 6 if(i_din[i]) 7 o_encode = i; //o_encode位宽是log2(WIDTH) 8 end 9 end
例如3-8译码以下是网上其他博主写的代码截图,笔者的编码器把对应的位宽传进去,再把判断条件改成if(i_din[i] == 0)即可。
2.2 解码:
1 integer j; 2 always@(*) 3 begin 4 o_decode = 'd0; 5 for(j = 0; j <= WIDTH - 1; j = j + 1)//WIDTH是i_din位宽 6 begin 7 if(i_din == j) 8 o_decode[j] = 1'b1; //o_decode位宽是2^(WIDTH-1) 9 end 10 end
例如3-8译码以下是网上其他博主写的代码截图