Skip to content

Instantly share code, notes, and snippets.

@rswofxd
Created May 25, 2012 10:24
Show Gist options
  • Save rswofxd/2787183 to your computer and use it in GitHub Desktop.
Save rswofxd/2787183 to your computer and use it in GitHub Desktop.
Verilog:硬件描述语言verilog常用总结
//Verilog硬件设计最高境界:胸中有沟壑,清晰明白每一条语句所代表硬件电路
`timescale 1ns/100ps //0.1ns is allowed
module gray_counter(d_in,
clk,
rst,
ld,
q
);
//input and output
input [3:0] d_in;
input clk,rst,ld;
output [3:0] q;
inout xx
//data type
reg [3:0] im_q; //'wire'映射为总线,'reg'映射为寄存器,应用于需要保存数据信息的连接
reg q; //reg assigned by '<=' symbom
wire [3:0] mem; //wire assigned by '=' symbom
wire xx //'inout'类型必须为net的'wire'
//输入端口永远是线网和只读
//输出端口默认是线网,若在过程块中被赋值,声明为reg
//
initial
$readmemb("mem.dat",mem);
//
always @(d_in or ld or q) //组合电路,敏感列表必须包含所有输入
//如果存在非必要输入的外部信号参与内部运算,仍须加入铭感表
//组合电路输出不允许出现锁存
begin:combinational
if(ld)
im_q = d_in;
else
im_q = mem[q];
end
//
always @(posedge clk) //时序电路,敏感表为时钟信号
begin:register
if(rst)
q <= 4'b0000;
else
q <= im_q;
end
endmodule
module xxx();
//过程模块
(1)initial:初始化执行
(2)always:等待执行
(3)task:描述位于不同位置所执行的共同代码
(4)function:具有输入输出,只能描述组合逻辑
//实例模块
gray_counter counter (.d_in(d_in),
.clk(clk),
.rst(rst),
.ld(ld),
.q(q)
);
//信号赋值
assign w = (a & ~s) | (b & s);
assign #6 w = s ? b : a;
q_out <= #8 d_in;
deassign w; //用于reg解赋值,assign不存在多驱动
force a = 2'd88; //对reg或net进行强制赋值,用release语句解赋值
//delay
wire #(0.6,0.8) //网线延迟声明用于线延迟
im_0 = i0 & ~s, //延迟时序参数不可综合或被忽略
im_1 = i1 & s;
assign #(3,4) y = im_0 |im_1; //连续赋值延迟声明用于门级延迟
//memery
reg [7:0] mem [0:3]; //表示具有4个8位单元的存储器
//深度words = 4,位宽bits = 8
mem [0] [6:4]; //表示存储器0字节单元4,5,6位
mem [0] [6-:3]; //4,5,6
mem [0] [4+:3]; //4,5,6
//logic symble
&, |, ~, ^, ^~ :AND,OR,NOT,XOR,XNOR
Complementary :0-1,1-0,X,Z-X
Shift :<<:left,>>:right //通常情况下填充0,对于
//有符号数右移,填充高位MSB
并置运算符 :x = {a,2{b,c},3{d},2'b11}
:{s1,s2} = a+b+c
//状态机描述中,case语句实现状态迁移
//latch
always @(c or d)
if (c)
begin
q <= #4 d;
q_b <= #3 ~d;
end
//register
always @(posedge clk)
begin
q <= #4 d;
q_b <= #3 ~d;
end
//Synch
always @(posedge clk)
begin
if(s)
begin
end
else if(r)
begin
end
else
begin
end
end
//Seqence checking
specify
$setuphold(posedge clk, d, 5, 3); //时钟信号clk,输入信号d,
//建立时间5ns,保持时间3ns
$width(posedge r, 4); //输入信号脉冲r最小脉宽检测,4ns
$width(posedge s, 4);
$period(negedge clk, 43); //时钟信号周期检测,T=43ns
endspecify
//Asunch
always @(posedge clk,posedge s,posedge r)
begin
if(s)
begin
end
else if(r)
begin
end
else
begin
end
end
//An Mem initiate
module Memery_2Power_M_by_N #(parameter M = 3, N = 4)
(input [M-1:0] adr, input rd, wr, inout [N-1:0] data);
reg [N-1:0] mem [0:2**M-1];
reg [N-1:0] temp;
assign data = rd ? temp : 'bz;
always @(data, adr, rd, wr)
begin
if(wr)
#4 mem[adr] = data;
else if(rd)
#4 temp = mem[adr];
else
#4 temp = 'bz;
end
initial $readmemh('mem.dat',mem);
endmodule
//Shift Register
module shift_reg(
input [3:0] d_in,
input clk, sr, sl, ld, rst,
input [1:0] s_cnt,
output reg [3:0] q
);
reg [3:0] int_q; //中间寄存器(临时寄存器)
/*
组合逻辑与时序逻辑分开是个好习惯
组合逻辑用于功能实现
时序逻辑用于时序实现
*/
always @(d_in, q, s_cnt, sr, sl, ld)
begin:combinational
if(ld)
int_q = d_in;
else if(sr)
int_q = q >> s_cnt;
else if(sl)
int_q = q <<s_cnt;
else
int_q = q;
end
always @(posedge clk)
begin:register
if(rst)
q <= 0; //利用时序逻辑进行置位,复位操作
else
q <= int_q;
end
endmodule
//Counter
module counter(
input [3:0] d_in,
input clk, rst, ld, u_d,
output reg [3:0] q
);
always @(posedge clk)
begin
if(rst)
q = 4'b0000;
else if(ld)
q = d_in;
else if(u_d)
q = q + 1;
else
q = q -1;
end
endmodule
//LFSR:线性反馈移位寄存器
module behavioral_lfsr #(parameter [3:0] poly = 0,seed = 0)
(input clk, init, sin, output reg sout);
reg [3:0] im_data;
always @(posedge clk or posedge init)
begin
if(init)
im_data = seed;
else
im_data = {sin ^ im_data[0]};
im_data[3:1] ^ {poly[2:0] & {3{im_data[0]}}};
sout = im_data[0];
end
endmodule
//MISR:多输入特征寄存器
module misr #(parameter [3:0] poly=0)
(input clk, rst, input [3:0] d_in, output reg [3:0] d_out)
always @(posedge clk)
if(rst)
d_out = 4'b0000;
else
//d_in:并行数据
//poly:配置多项式
//d_out[0]:多项式配置反馈
//{1'b0,d_out[3:1]}:右移输出
d_out = d_in ^ ({4{d_out[0]}} & poly) ^ {1'b0,d_out[3:1]};
endmodule
//FIFO:队列读写结构
module fifo(input [7:0] data_in,
input clk, rd, wr,
output empty, full,
output reg [3:0] fifo_cnt,
output reg [7:0] data_out);
reg [7:0] fifo_ram [0:7];
reg [2:0] rd_ptr, wr_ptr;
//时序并行赋值
assign empty = (fifo_cnt==0);
assign full = (fifo_cnt==8);
//队列写
always @(posedge clk)
begin:write
if(wr && !full)
fifo_ram[wr_ptr] <= data_in;
else if(wr && rd)
fifo_ram[wr_ptr] <= data_in;
end
//队列读
always @(posedge clk)
begin:read
if(rd && !empty)
data_out <= fifo_ram[rd_ptr]
else if(rd && wr && empty)
data_out <= fifo_ram[rd_ptr]
end
//读写指针
always @(posedge clk)
begin:pointer
if(rst)
begin
wr_ptr <= 0;
rd_ptr <= 0;
end
else
begin
wr_ptr <= ((wr && !full) || (wr && rd)) ? wr_ptr+1 : wr_ptr;
rd_ptr <= ((rd && !empty) || (wr && rd)) ? rd_ptr+1 :rd_ptr;
end
end
//计数
always @(posedge clk)
begin:counter
if(rst)
fifo_cnt <= 0;
begin
//计数状态机描述
case({wr,rd}):
2'b00:fifo_cnt <= fifo_cnt;
2'b01:fifo_cnt <= (fifo_cnt==0) ? 0 :fifo_cnt-1;
2'b10:fifo_cnt <= (fifo_cnt==8) ? 8 :fifo_cnt+1;
2'b11:fifo_cnt <= fifo_cnt;
default:fifo_cnt <= fifo_cnt; //处理wr,rd不确定值情况
endcase
end
end
endmodule
//Huffman Mealy_Machine
//Case语句在电路综合时具有优先级,前面的语句会被优先处理,将关键路径放在最后,可以优化延迟
module mealy_detector6(
input x, en, clk, rst,
output reg z,);
localparm [1:0]
reset=2'b00,got1=2'b01,got10=2'b10,got11=2'b11;
reg [1:0] p_state, n_state;
always @(p_state or x)
begin:combinational
case(p_state)
reset:
if(x==1'b1)
n_state = got1;
else
n_state = reset;
got1:
if(x==1'b0)
n_state = got10;
else
n_state = got11;
got10:
if(x==1'b1)
n_state = got1;
else
n_state = reset;
got11:
if(x==1'b1)
n_state = got11;
else
n_state = got10;
default:
n_state = reset;
endcase
end
always @(p_state or x)
begin:output_block
case(p_state)
reset:
z = 1'b0;
got1:
z = 1'b0;
got10:
if(x==1'b1)
z = 1'b1;
else
z = 1'b0;
got11:
if(x==1'b1)
z = 1'b0;
else
z = 1'b1;
default:
z = 1'b0;
endcase
end
always @(posedge clk)
begin:Seqence
if(rst)
p_state <= reset;
else if(en)
p_state <= n_state;
end
endmodule
//////////////////////////////////////////////////////
//测试平台,测试向量及信息打印
//////////////////////////////////////////////////////
initial repeat (44) #10 clk = ~clk;
initial repeat (20) #20 x = $random; //用随机函数设置数据限制
//执行一次,用于初始化
initial
begin
#10 s1 = 4'b0000;
#20 s2 = 4'b0z11;s3 = 4'b1z1x;s4 = 1'bz;
#80 $finish //用于停止仿真控制
end
//利用数据缓存buffer进行测试数据初始化
//通过buffer循环左移对x赋值
initial buffer = 19'b0001101101111001001
always @(posedge clk)
#1 {x,buffer} = {buffer,x};
//多次执行,用于条件等待
always
begin
t = $random;
#(t) x = $random; //采用随机时间间隔测试平台
end
//仿真控制
initial #200 $stop //暂停仿真
//函数
/*
函数名是一个变量,返回一个标量或向量
过程语句用于定义输入输出映射
函数体内部不允许使用时序语句和非阻塞赋值
调用函数,变量顺序与声明一致
允许函数嵌套调用
*/
function [1:0] adder (input a,b,c, output s,co);
begin
adder = {(a&b)|(b&c)|(a&c),a^b^c}
end
endfunction
//打印调试信息
always @(ww)
if (ww ==1)
$dispalay('hello,this is a testbench,at a time = %t',$time);
//断言验证
module BCD_counter(input , , output , ,);
always @()
begin
end
assert_always #(1,0,'Err: Non BCD Counter',0)//检查指定时钟沿表达式是否满足
AA1(clk,1'b1,(cnt>=0)&&(cnt<=9));//实例
//同步
initial forever @(posedge clk) #3 x = $random; //信号与时钟同步
initial forever @(posedge clk) #1 $dispalayb(z); //显示与时钟同步
$finish; //退出仿真环境
$stop; //暂停仿真
$nochange (posedge clk,d_in,3,5); //时序检查,d_in在clk上升沿3-5个
//时钟周期之外出现,则报告违约
endmodule
///////////////////////////////////////////////////////////////////
//完整系统设计与测试平台框架设计
///////////////////////////////////////////////////////////////////
//控制与数据分离
//数据部分:寄存器,组合逻辑单元,互联总线,主要是assign赋值与always模块
//控制部分:时钟控制状态机,主要是case语句
//系统顶层模块:各相应模块的实例调用,构成完整系统
//测试平台框架
//initial,always,task,function等语句
//数据文件读,写
//计算希望结果
//保存计算结果
//将计算结果与希望结果比较,输出比较信息
//验证工具验证,及对验证完整性进行代码覆盖率测试
//行为描述代码综合成为门级网表文件
//网表:加入时序约束的RTL级电气连接
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment