Created
May 25, 2012 10:24
-
-
Save rswofxd/2787183 to your computer and use it in GitHub Desktop.
Verilog:硬件描述语言verilog常用总结
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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