Verilog几个这样的写法-转自 宁河川

数字电路设计主要就是,选择器、全加器、比较器,几个常用逻辑门,再加个D触发器,电路基本都能实现了。

组合逻辑+时序逻辑

组合逻辑用assign或always@(*)实现,

时序逻辑用always@(posedge clk or negedge rst_n)

有人说掌握Verilog 20%的语法就可以描述 90%以上的电路,说的对。

casez

 1 always @(*)begin
 2     casez(code)
 3         8'b1???_???? : data[2:0] = 3'd7;
 4         8'b01??_???? : data[2:0] = 3'd6;
 5         8'b001?_???? : data[2:0] = 3'd5;
 6         8'b0001_???? : data[2:0] = 3'd4;
 7         8'b0000_1??? : data[2:0] = 3'd3;
 8         8'b0000_01?? : data[2:0] = 3'd2;
 9         8'b0000_001? : data[2:0] = 3'd1;
10         8'b0000_0001 : data[2:0] = 3'd0;
11         default : data[2:0] = 3'd0;
12     endcase
13 end

这样的case有优先级选择,虽然可综合,但是不推荐使用,有优先用if-else,没有直接用case。

synopsys的EDA工具有关于full case与parallel case可以查看下面博客链接。

https://blog.csdn.net/li_hu/article/details/10336511

 

generate+for

合理使用generate+for循环可以提高编码效率,同样的赋值语句需要赋值多次。

1 generate
2     genvar i;
3     for(i=0;i<16;i=i+1)
4         begin: neg_data
5             assign neg_data_out[i*DATA_WIDTH +:DATA_WIDTH] = 
6                 -data_in[i*DATA_WIDTH +:DATA_WIDTH]
7         end
8 endgenerate

同一个模块需要实例化多次

 1 generate 
 2     genvar i;
 3     for(i=0;i<16;i=i+1)
 4         begin: mult_12x12
 5             DW02_mult #(
 6                 .A_WIDTH(12),
 7                 .B_WIDTH(12)
 8             ) u_DW02_mult0(
 9                 .A(mult_a[i*12 +:12]),
10                 .B(mult_b[i*12 +:12]),
11                 .TC(1'b0),
12                 .PRODUCT(product[i*24 +:24])
13             );
14         end
15 endgenerate

当然这样写debug会有一些困扰,Verdi会显示每一个generate块,选中对应的块,加进去的波形就会是对应的bit信号。

generate if/case

做一些通用IP的方法,比如要做一个选择器通用IP,支持二选一,三选一,四选一。

 1 generate if(MUX_NUM == 0)begin : mux4_1
 2     always@(*)begin
 3         case(sel[1:0])
 4                2'b00:data_out = data_in0;
 5             2'b01:data_out = data_in1;
 6             2'b10:data_out = data_in2;
 7             default:data_out = data_in3;
 8         endcase
 9     end
10 end else if(MUX_NUM = 1) begin : mux3_1
11     always@(*)begin
12         case(sel[1:0])
13                2'b00:data_out = data_in0;
14             2'b01:data_out = data_in1;
15             default:data_out = data_in2;
16         endcase
17     end
18 end else begin : mux2_1
19     always@(*)begin
20         case(sel[1:0])
21                2'b00:data_out = data_in0;
22             default:data_out = data_in1;
23         endcase
24     end
25 end endgenerate

generate case可以写更多的分支

 1 generate
 2     case(MUX_NUM)
 3         0:begin:mux_2
 4         end
 5         1:begin: mux_3
 6         end
 7         2:begin: mux_4
 8         end
 9         default:begin
10         end
11     endcase
12 end endgenerate

调用的时候只需要

1 mux #(
2     .MUX_NUM(0)
3 )
4 u_mux(
5     ...
6 );

参数化定义

模块化设计,功能模块的划分尽可能细, 差别不大的代码通过参数化达到重复使用的目的。

1 always @(*)begin
2     case(sel)
3         CASE0:data_out = data_in0;
4         CASE1:data_out = data_in1;
5         CASE2。。。
6         default:;
7     endcase    
8 end

实例化

1 mux #(
2     .CASE0(8'd11),
3     .CASE1(8'd44)
4     ...
5 )
6 u_mux(
7     ...
8 );

移位操作

对于移位操作直接用位拼接,

1 assign data_shift[6:0] = data[4:0] << 2;
2 assign data_shift[7:0] = data[4:0] << shift[1:0];

写成

1 assign data_shift[6:0] = {data[4:0], 2'b0};
2 always @(*)begin
3     case(shift[1:0])
4         2'b00: data_shift[7:0] = {3'b0, data[4:0]};
5         2'b01: data_shift[7:0] = {2'b0, data[4:0], 1'b0};
6         2'b10: data_shift[7:0] = {1'b0, data[4:0], 2'b0};
7         default:data_shift[7:0] = {data[4:0], 3'b0};
8     endcase
9 end

如果是有符号数,高位要补符号位。也就是算术移位。

1 always @(*)begin
2     case(shift[1:0])
3         2'b00: data_shift[7:0] = {{3{data[4]}}, data[4:0]};
4         2'b01: data_shift[7:0] = {{2{data[4]}}, data[4:0], 1'b0};
5         2'b10: data_shift[7:0] = {data[4], data[4:0], 2'b0};
6         default:data_shift[7:0] = {data[4:0], 3'b0};
7     endcase
8 end

shift也可能是有符号数,正数左移,负数右移。右移方法同理。

$clog2系统函数

Verilog-2005引入了$clog2系统函数,为了方便计算数据位宽,避免位浪费。这个其实是来凑数的。

 1 parameter   DATA_WIDTH = 4,
 2 parameter   CNT_WIDTH  = log2(DATA_WIDTH)
 3 parameter   CNT_WIDTH  = clog2(DATA_WIDTH-1)
 4 parameter   CNT_WIDTH  = $clog2(DATA_WIDTH)
 5 
 6 reg   [DATA_WIDTH-1:0]   data_r0;
 7 
 8 reg     [CNT_WIDTH-1:0]   cnt;
 9 
10 //-------------------------------------------------------
11 //以下两个函数任用一个
12 //求2的对数函数
13 function integer log2;
14   input integer value;
15   begin
16     value = value-1;
17     for (log2=0; value>0; log2=log2+1)
18       value = value>>1;
19   end
20 endfunction
21 
22 //求2的对数函数
23 function integer clogb2 (input integer bit_depth);
24 begin
25     for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
26         bit_depth = bit_depth>>1;
27 end
28 endfunction

最后

欢迎指点,有哪些Verilog的奇技淫巧,留言告诉我吧。

 

转自:https://ninghechuan.com/2020/03/14/2020-3-14-Verilog%E5%87%A0%E4%B8%AA%E8%BF%99%E6%A0%B7%E7%9A%84%E5%86%99%E6%B3%95/

上一篇:verilog modelsim 对文件进行仿真读写


下一篇:Verilog中的时间尺度与延迟