一、verilog语法
1、计数器(课本上的版本)
本来一直使用case版本,最近翻书看到的下面版本。
module counter(input clk,input rst,output reg [2:0]Q);parameter M = 5;//循环计数长度为5parameter MM = M - 1;wire Id;assign Id = Q >= MM;always @(posedge clk)beginif(!rst) Q <= 1'b0;else Q <= Id ? 1'b0 : Q+1'b1;endendmodule
2、generate/for(可综合)
generate用于和 for/if/case 在 always块外 选择/批量 生成电路
generate-for
用法:
(1) 必须有genvar关键字定义for语句的变量。
(2)for语句的内容必须加begin和end(即使就一句)。
(3)for语句必须有个名字。
[参看:verilog中generate语句的用法](https://blog.csdn.net/sinat_25326461/article/details/52384968)
generate-if/case
选择性生成电路
[参看:基础项目(7)generate语句块的讲解](https://www.cnblogs.com/mengyi1989/p/11521058.html)
for 循环单独用在**always**块内可以将需要**重复**编写的代码简化,可以使用 interger 做for循环判断变量(可综合)
例:使用pipeline方式将输入数据与本地数据相乘相乘并求和(为简化例子改为只求和)
`timescale 1ns / 1psmodule test_sum(input clk,input rst,input [9:0]data_real,input [9:0]data_imag,input data_valid,output reg [13:0]dout_real,output reg [13:0]dout_imag,output reg dout_valid);integer i,j,k,l,h,m,n;reg [9:0]data_temp_real[7:0];//数据缓存 8->8reg [9:0]data_temp_imag[7:0];reg [10:0]data_temp_real_1[7:0];// 8->8reg [10:0]data_temp_imag_1[7:0];reg [11:0]data_temp_real_2[3:0];// 8->4reg [11:0]data_temp_imag_2[3:0];reg [12:0]data_temp_real_3[1:0];// 4->2reg [12:0]data_temp_imag_3[1:0];reg [4:0]int;always @(posedge clk or negedge rst)beginif(!rst)begin//复位并赋初值 int <= 5'b0;for(i=0;i<=7;i=i+1)begin data_temp_real[i] <= 10'b0; data_temp_imag[i] <= 10'b0; data_temp_real_1[i] <= 11'b0; data_temp_imag_1[i] <= 11'b0;endfor(j=0;j<=3;j=j+1)begin data_temp_real_2[j] <= 12'b0; data_temp_imag_2[j] <= 12'b0;endfor(k=0;k<=1;k=k+1)begin data_temp_real_3[k] <= 13'b0; data_temp_imag_3[k] <= 13'b0;end dout_real <= 14'b0; dout_imag <= 14'b0; dout_valid <= 1'b0;end else if(data_valid)begin//输出产生 case (int) 5'd11:begin dout_valid <= 1'b1; int <= int; end default: int <= int + 1'b1; endcase for(l=0;l<=6;l=l+1)begin data_temp_real[l+1] <= data_temp_real[l];//数据地址搬移 data_temp_imag[l+1] <= data_temp_imag[l]; end data_temp_real[0] <= data_real;//数据输入 data_temp_imag[0] <= data_imag; for(h=0;h<=7;h=h+1)begin data_temp_real_1[h] <= data_temp_real[h]; //+ data_temp_imag[h]; //当前未设置共轭运算 data_temp_imag_1[h] <= data_temp_imag[h]; //- data_temp_imag[h]; end for(m=0;m<=6;m=m+2)begin data_temp_real_2[m/2] <= data_temp_real_1[m] + data_temp_real_1[m+1];//求和 8->4 data_temp_imag_2[m/2] <= data_temp_imag_1[m] + data_temp_imag_1[m+1]; end for(n=0;n<=2;n=n+2)begin data_temp_real_3[n/2] <= data_temp_real_2[n] + data_temp_real_2[n+1];//求和 4->2 data_temp_imag_3[n/2] <= data_temp_imag_2[n] + data_temp_imag_2[n+1]; end dout_real <= data_temp_real_3[0] + data_temp_real_3[1];//求和 2->1 dout_imag <= data_temp_imag_3[0] + data_temp_imag_3[1]; end else begin//输入结束后剩余数据延迟输出 if(int > 0) case (int) 5'd7:begin dout_valid <= 1'b0; int <= 5'd0; end default: int <= int - 1'b1; endcase else int <= int; if(int >= 8)begin for(h=0;h<=7;h=h+1)begin data_temp_real_1[h] <= data_temp_real[h]; //+ data_temp_imag[h]; data_temp_imag_1[h] <= data_temp_imag[h]; //- data_temp_imag[h]; end for(m=0;m<=6;m=m+2)begin data_temp_real_2[m/2] <= data_temp_real_1[m] + data_temp_real_1[m+1]; data_temp_imag_2[m/2] <= data_temp_imag_1[m] + data_temp_imag_1[m+1]; end for(n=0;n<=2;n=n+2)begin data_temp_real_3[n/2] <= data_temp_real_2[n] + data_temp_real_2[n+1]; data_temp_imag_3[n/2] <= data_temp_imag_2[n] + data_temp_imag_2[n+1]; end dout_real <= data_temp_real_3[0] + data_temp_real_3[1]; dout_imag <= data_temp_imag_3[0] + data_temp_imag_3[1]; end else begin//输出归零 dout_real <= 14'b0; dout_imag <= 14'b0; endendendendmodule
3、verilog零散语法
<<>> 算数左移/右移
需要注意>>>作用于有符号数,左边会补符号位;<<
例:4'sb1011>>>1 结果为 1101,4'sb1011<<<1 结果为 0110
part-select (这里考虑左边为msb)即引用数组中一个元素的某几位
例:reg [9:0]a[9:0] 引用第0个元素的后四位:a[0][0+:4] 或 a[0][3-:4],其中 -:和+:左边可以是常数或者变量,右边必须是常数
表达式位长
例1:a,b,c为16bit数,(a+b+17'b0)此中间量为17bit,c=(a+b+17'b0)>>1,可以正确保留进位
例2:testbench中延迟 25/2 结果为12,写为25/2.0结果为12.5
1'sb1表示 -1,1'sb0 表示 0
单纯的十进制数为 32bit interger 有符号数
+-运算赋值运算 所有操作数是有符号数,那么结果才是有符号数。
二、数电知识点
1、竞争与冒险
内容
由于逻辑门存在延迟时间以及信号的传输路径不同,当输入信号电平发生瞬间变化时,电路可能产生与稳态时逻辑功能不一致的错误输出(冒险:毛刺)。
判别
X +~X:0形冒险(负向毛刺);X ×~X:1形冒险(正向毛刺)
K图存在相切,该处未被其他K圈包围。
冒险现象的消除
1、增加冗余项,消除逻辑冒险。(即在相切处加圈)
2、加滤波电路,消除毛刺的影响。
3、加选通信号,消除毛刺。
2、格雷(Gray)码记忆方法(异步FIFO地址跨时钟域交互)
1位:
0
1
2位(先竖着写出一位gray码,在下方将上方一位gray码倒写,再在上面两个数第二位补0,下面两个数第二位补1)
0 00
1 01
1 11
0 10
依此法依次写出需要的gray码,如三位
00 000
01 001
11 011
10 010
10 110
11 111
01 101
00 100