文档库 最新最全的文档下载
当前位置:文档库 › Verilog学习笔记

Verilog学习笔记

端口定义、I/O说明、内部信号声明、功能定义。


parameter size = 8,longsize = 16;
reg [size:1] opa,opb;
reg [longsize:1] result;

begin: mult
reg [longsize:1] shift_opa,shift_opb;
shift_opa = opa;
shift_opb = opb;
reslut = 0;
repeat(size)
begin
if(shift_opb[1])
result = result + shift_opa;

shift_opa = shift_opa << 1;
shift_opb = shift_opb >> 1;
end
end

//这是一个乘法器

reg [7:0] counter;
reg tick;
always @(posedge signal) //信号上升沿
begin
tick = ~tick;
counter = counter + 1;
end
//一个计数器

always @(a or b or c)


//D触发器
module flop(data,clock,clear,q,qb);
input data,clock,clear;
output q,qb;
nand #10 nd1(a,data,clock,clear),
nd2(b,ndata,clock),
nd4(d,c,b,clear),
nd5(e,c,nclock),
nd6(f,d,nclock),
nd8(qb,q,f,clear);
nand #9 nd3(c,a,d),
nd7(q,e,qb);
not #10 iv1(ndata,data),
iv2(nclock,clock);
endmodule

//在此处使用了以上定义的D触发器
module hardreg(d,clk,clrb,q);
input clk,clrb;
input[3:0] d;
output[3:0] q;
flop f1(d[0],clk,clrb,q[0],),
f2(d[1],clk,clrb,q[1],),
f3(d[2],clk,clrb,q[2],),
f4(d[3],clk,clrb,q[3],);
endmodule

//在这使用了以上模块

module hardreg_top;
reg clock, clearb;
reg [3:0] data;
wire [3:0] qout;
`define stim #100 data=4'b //宏定义stim,可使源程序简洁
event end_first_pass; //定义事件end_first_pass
hardreg reg_4bit (.d(data), .clk(clock), .clrb(clearb), .q(qout));
/**********************************************************************************
把本模块中产生的测试信号data、clock、clearb输入实例reg_4bit以观察输出信号qout.实例
reg_4bit引用了hardreg
**********************************************************************************/
initial
begin
clock = 0;
clearb = 1;
end
always #50 clock = ~clock;
always @(end_first_pass)
clearb = ~clearb;
always @(posedge clock)
$display("at time %0d clearb= %b data= %d qout= %d", $time, clearb, data, qout);
/*****************************************************
类似于C语言的 printf 语句,可打印不同时刻的信号值
******************************************************/
initial
begin
repeat(2) //重复两次产生下面的data变化
begin
data=4'b0000;
`stim0001;
/***************************************************************
宏定义stim引用,等同于#100 data=4'b0001;。注意引用时要用 `符号。
****************************************************************/
`stim0010;
`stim0011;
`stim0100;
`stim0101;
.
.
.
`stim1110;
`stim1111;
end
#200 -> end_first_pass;
/***********************************************
延迟200个单位时间,触发事件end_first_pass
************************************************/
$finish; //结束仿真
end
endmodule


//加法器
module adder(sum, cin, count, a, b);
input [2:0] a,b;
output

[3:0] sum;
output [3:0] count;
assign {count,sum} = a + b + cin;
endmodule

//三态门
module san_state_gate(out, in, en);
input en,in_a;
output out;
bufif1 mybuf(out, in, en);
endmodule

//user defined primitives
UDP语言格式

primitive 元件名(输出端口名,输入端口名1,输入端口名2,…)
output 输出端口名;
input 输入端口名1, 输入端口名2,…;
reg 输出端口名;
initial begin
输出端口寄存器或时序逻辑内部寄存器赋初值(0,1,或 X);
end
table

//输入1 输入2 输入3 …: 输出

逻辑值 逻辑值 逻辑值 …: 逻辑值 ;
逻辑值 逻辑值 逻辑值 …: 逻辑值 ;
逻辑值 逻辑值 逻辑值 …: 逻辑值 ;
… … … …: …;
endtable
endprimitive

注意

1) UDP只能有一个输出端,而且必定是端口说明列表的第一项。
2) UDP可以有多个输入端,最多允许有10个输入端。
3) UDP所有端口变量必须是标量,也就是必须是1位的。
4) 在UDP的真值表项中,只允许出现0、1、X三种逻辑值,高阻值状态Z是不允许出现的。
5) 只有输出端才可以被定义为寄存器类型变量。
6) initial语句用于为时序电路内部寄存器赋初值,只允许赋0、1、X三种逻辑值,缺省值为X。


4.2.1仅用于产生仿真测试信号的Verilog HDL行为描述建模


module gen_clk ( clk, reset);
output clk;
output reset;
reg clk, reset;
initial
begin
reset = 1; //initial state
clk=0;
#3 reset = 0;
#5 reset = 1;
end
always #5 clk = ~clk;
endmodule


2.Verilog HDL建模在TOP-DOWN设计中的作用和行为建模的可综合性问题
(1)累加器用寄存器(ACCUMULATOR RREGISTER)
`timescale1ns/1ns
module register(r,clk,data,ena,rst);
output [7:0] r;
input [7:0] data;
input clk, ena, rst;
wire load;
and a1(load,clk,ena);
DFF d7(r[7],,load,data[7],rst);
DFF d6(r[6],,load,data[6],rst);
DFF d5(r[5],,load,data[5],rst);
DFF d4(r[4],,load,data[4],rst);
DFF d3(r[3],,load,data[3],rst);
DFF d2(r[2],,load,data[2],rst);
DFF d1(r[1],,load,data[1],rst);
DFF d0(r[0],,load,data[0],rst);
Endmodule
其中 DFF和and都是Verilog语言中保留的关键字分别表示带复位端的D触发器和与门。
(2)RISC算术运算单元(RISC_ALU)
`timescale1ns/100ps
module riscalu ( alu_out, zero, opcode, data, accum, clock );
output [7:0] alu_out;
reg[7:0] alu_out;
output zero;
input [2:0] opcode;
input [7:0] data, accum;
input clock;
`define Zdly 1.2
`define ALUdly 3.5
wire #`Zdly zero=(!accum);
//***即zero=1'b1 if accum==0,else zero=1'b0

always @(negedge clock)
begin
case(opcode)
3'b000: #`ALUdly alu_out=accum; //Pass Accumulator
3'b001: #`ALUdly alu_out=accum; //Pass Accumulator
3'b010: #`ALUdly alu_out=data+accum; //ADD
3'b011: #`ALUdly alu_out=data&accum; //AND
3'b100: #`ALUdly al

u_out=data^accum; //XOR
3'b101: #`ALUdly alu_out=data; //Pass Data
3'b110: #`ALUdly alu_out=accum; //Pass Accumulator
3'b111: #`ALUdly alu_out=accum; //Pass Accumulator
default: begin
$display("Unknown OPcode");
#`ALUdly alu_out=8'bXXXXXXXX;
end
endcase
end
endmodule


(3)数据控制器(DATACTRL)
module datactrl(data,alu_out,fetch,mem_rd,clk2);
output [7:0] data;
input [7:0] alu_out;
input fetch, mem_rd, clk2;
assign data=(( !fetch & !mem_rd & !clk2 )? alu_out : 8'bz);
endmodule

(4)动态存储器(RAM)
`timescale 1ns/1ns
module mem(data,addr,read,write);
inout [7:0] data;
input [4:0] addr;
input read, write;
reg [7:0] memory[0:'h1F];
wire[7:0] data =( read? memory[addr] : 8'bZZZZZZZZ );
always @(posedge write)
begin
memory[addr]=data;
end
endmodule

(5)STATECONTROLLER
`timescale 1ns/1ns
module control (load_acc, mem_rd, mem_wr, inc_pc, load_pc, load_ir,
halt, opcode, fetch, zero, clk, clk2, reset);

output load_acc, mem_rd, mem_wr, inc_pc, load_pc, load_ir, halt;
reg load_acc, mem_rd, mem_wr, inc_pc, load_pc, load_ir, halt;
input [2:0] opcode;
input fetch, zero, clk, clk2, reset;
`define HLT 3'b000
`define SKZ 3'b001
`define ADD 3'b010
`define AND 3'b011
`define XOR 3'b100
`define LDA 3'b101
`define STO 3'b110
`define JMP 3'b111

always @(posedge fetch)
if(reset)
ctl_cycle;

always @(negedge reset)
begin
disable ctl_cycle;
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000000;
end
always @(posedge reset)
@(posedge fetch) ctl_cycle;

task ctl_cycle;
begin
//state 0—first Address Setup
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000000;
//state1—Instruction Fetch
@(posedge clk)
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000100;
//state2--InstructionLoad
@(negedge clk)
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000110;
//state3--Idle
@(posedge clk)
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000110;
//state4—Second Address Setup
@(negedge clk)
if(opcode==`HLT)
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b1000001;
else
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b1000000;
//state5—Operand Fetch
@(posedge clk)
if((opcode==`ADD)||(opcode==`AND)||(opcode==`XOR)||(opcode==`LDA))
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000100;
else
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000000;
//state6—ALU operation
@(negedge clk)
if(opcode==`JMP)
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0010000;
else if((opcode==`SKZ)&&(zero))
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b1000000;
else if ( ( opcode==`ADD) || (opcode==`AND) || (opcode==`XOR)||(opcode ==`LDA))
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0100100;
else
{inc_pc,l

oad_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000000;
//state7—Store Result
@(posedge clk)
if(opcode ==`JMP)
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b1010000;
else if(opcode==`STO)
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0001000;
else if((opcode==`SKZ)&&(zero))
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b1000000;
else if ((opcode==`ADD) ||(opcode==`AND) ||(opcode==`XOR)|| (opcode==`LDA))
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0100100;
else
{inc_pc,load_acc,load_pc,mem_wr,mem_rd,load_ir,halt}=7'b0000000;
end //task ctl_cycle
endtask
endmodule

这个例子是可以仿真的,但并非其所有的子模块都是可综合的,若需要综合成逻辑网表(EDIF),部
分模块还需按可综合风格改写,若需制成具体的电路芯片,还需要在综合成标准逻辑网表后,编制具
体实现工艺的约束文件,再利用厂家的布局布线工具生成电路制造文件,然后从中提取后仿真模型,
再做后仿真。若在后仿真中发现问题则需降低时钟频率,或改写部分模块并重复前面的过程,直至后
仿真中发现的问题都解决为止。若只做前仿真只需输入表示程序指令的数据文件到RAM中就可按时钟节
拍观测到指令的执行过程和波形。
目前,用门级和RTL级抽象描述的Verilog HDL模块可以用综合器转换成标准的逻辑网表;用
算法级描述的Verilog HDL模块,只有部分综合器能把它转换成标准的逻辑网表;而用系统级描述的模
块,目前尚未有综合器能把它转换成标准的逻辑网表,往往只用于系统仿真。


1.
在算法硬件电路的研制过程中,计算电路的结构和芯片的工艺对运行速度有很大的影响。
所以在电路结构确定之前,必须经过多次仿真:
1) C 语言的功能仿真。
2) C 语言的并行结构仿真。
3) Verilog HDL 的行为仿真。
4) Verilog HDL RTL 级仿真。
5) 综合后门级结构仿真。
6) 布局布线后仿真。
7) 电路实现验证。

//function 与 task

module traffic_lights;
reg clock, red, amber, green;
parameter on=1, off=0, red_tics=350,
amber_tics=30,green_tics=200;
//交通灯初始化
initial red=off;
initial amber=off;
initial green=off;
//交通灯控制时序
always
begin
red=on; //开红灯
light(red,red_tics); //调用等待任务
green=on; //开绿灯 light(green,green_tics); //等待
amber=on; //开黄灯 light(amber,amber_tics); //等待
end
//定义交通灯开启时间的任务
task light(color,tics);
output color;
input[31:0] tics;
begin
repeat(tics) @(posedge clock);//等待tics个时钟的上升沿
color=off;//关灯
end
endtask
//产生时钟脉冲的always块
always
begin
#100 clock=0;
#100 clock=1;
end
endmodule
这个例子描述了一个简单的

交通灯的时序控制,并且该交通灯有它自己的时钟产生器。

module tryfact;
//函数的定义-------------------------------
function[31:0]factorial;
input[3:0]operand;
reg[3:0]index;
begin
factorial = operand? 1 : 0;
for(index=2;index<=operand;index=index+1)
factorial = index * factorial;
end
endfunction


//函数的测试-------------------------------------
reg[31:0]result;
reg[3:0]n;
initial
begin
result=1;
for(n=2;n<=9;n=n+1)
begin
$display("Partial result n= %d result= %d", n, result);
result = n * factorial(n)/((n*2)+1);
end
$display("Finalresult=%d",result);
end
endmodule//模块结束

























相关文档