您好,欢迎来到飒榕旅游知识分享网。
搜索
您的当前位置:首页verilog实例代码2

verilog实例代码2

来源:飒榕旅游知识分享网
//与门 module zxhand2(c,a,b);

input a,b; output c; assign c= a & b; endmodule //或门 module zxhor2(c,a,b);

input a,b; output c; assign c= a | b; endmodule //非门 module zxhnot2(c,b);

input b; output c; assign c=~ b; endmodule ////异或门 module zxhxro2(c,a,b);

input b; output c; assign c=a ^ b; endmodule 两选一电路 module data_scan(d0,d1,sel,q); output q;

input d0,d1,sel; wire t1,t2,t3;

n1 zxhand2(t1,d0,sel); n2 zxhnot2 (t4,sel); n3 zxhand2(t2,d1,t4); n4 zxhor2(t3,t1,t2); assign q=t1; endmodule

verilog HDL实例(一) 练习一.简单的组合逻辑设计 目的: 掌握基本组合逻辑电路的实现方法。 这是一个可综合的数据比较器,很容易看出它的功能是比较数据a与数据b,如果两个数据相同,则给出结果1,否则给出结果0。在Verilog HDL中,描述组合逻辑时常使用assign结构。注意equal=(a==b)?1:0,这是一种在组合逻辑实现分支判断时常使用的格式。 模块源代码: //--------------- compare.v ----------------- module compare(equal,a,b); input a,b; output equal; assign equal=(a==b)?1:0; //a等于b时,equal输出为1;a不等于b时, //equal输出为0。 endmodule 测试模块用于检测模块设计得正确与否,它给出模块的输入信号,观察模块的内部信号和输出信号,如果发现结果与预期的有所偏差,则要对设计模块进行修改。 测试模块源代码: `timescale 1ns/1ns //定义时间单位。 module comparetest; reg a,b; wire equal; initial //initial常用于仿真时信号的给出。 begin a=0; b=0; #100 a=0; b=1; #100 a=1; b=1; #100 a=1; b=0; #100 $stop; //系统任务,暂停仿真以便观察仿真波形。 end compare compare1(.equal(equal),.a(a),.b(b)); //调用模块。 Endmodule 【例3.1】4 位全加器 module adder4(cout,sum,ina,inb,cin); output[3:0] sum; output cout; input[3:0] ina,inb; input cin; assign {cout,sum}=ina+inb+cin; endmodule 【例3.2】4 位计数器 module count4(out,reset,clk); output[3:0] out; input reset,clk; reg[3:0] out; always @(posedge clk) begin if (reset) out<=0; //同步复位 else out<=out+1; //计数 end endmodule 09.04.07 【例5.11】模为60 的BCD 码加法计数器 module count60(qout,cout,data,load,cin,reset,clk); output[7:0] qout; output cout; input[7:0] data; input load,cin,clk,reset; reg[7:0] qout; always @(posedge clk) //clk 上升沿时刻计数 begin if (reset) qout<=0; //同步复位 else if(load) qout<=data; //同步置数 else if(cin) begin if(qout[3:0]==9) //低位是否为9,是则 begin qout[3:0]<=0; //回0,并判断高位是否为5 if (qout[7:4]==5) qout[7:4]<=0; else qout[7:4]<=qout[7:4]+1; //高位不为5,则加1 end else //低位不为9,则加1 qout[3:0]<=qout[3:0]+1; end end assign cout=((qout==8'h59)&cin)?1:0; //产生进位输出信号 endmodule 【例9.10】奇偶校验位产生器 module parity(even_bit,odd_bit,input_bus); output even_bit,odd_bit; input[7:0] input_bus; assign odd_bit = ^ input_bus; //产生奇校验位 assign even_bit = ~odd_bit; //产生偶校验位 endmodule  Verilog HDL实例(二) 练习二. 简单时序逻辑电路的设计 目的:掌握基本时序逻辑电路的实现。 在Verilog HDL中,相对于组合逻辑电路,时序逻辑电路也有规定的表述方式。在可综合的Verilog HDL模型,我们通常使用always块和 @(posedge clk)(上升沿)或 @(negedge clk)(下降沿)的结构来表述时序逻辑。下面是一个1/2分频器的可综合模型。 // half_clk.v: module half_clk(reset,clk_in,clk_out); input clk_in,reset; output clk_out; reg clk_out; always @(posedge clk_in) begin if(!reset) clk_out=0; else clk_out=~clk_out; end endmodule 在always块中,被赋值的信号都必须定义为reg型,这是由时序逻辑电路的特点所决定的。对于reg型数据,如果未对它进行赋值,仿真工具会认为它是不定态。为了能正确地观察到仿真结果,在可综合风格的模块中我们通常定义一个复位信号reset,当reset为低电平时,对电路中的寄存器进行复位。 测试模块的源代码: //------------------- clk_Top.v ----------------------------- `timescale 1ns/100ps `define clk_cycle 50 module clk_Top.v; reg clk,reset; wire clk_out; always #`clk_cycle clk = ~clk; initial begin clk = 0; reset = 1; #100 reset = 0; #100 reset = 1; #10000 $stop; end half_clk half_clk(.reset(reset),.clk_in(clk),.clk_out(clk_out)); endmodule  Verilog HDL实例(三) 练习三. 利用条件语句实现较复杂的时序逻辑电路 目的:掌握条件语句在Verilog HDL中的使用。 与常用的高级程序语言一样,为了描述较为复杂的时序关系,Verilog HDL提供了条件语句供分支判断时使用。在可综合风格的Verilog HDL模型中常用的条件语句有if…else和case…endcase两种结构,用法和C程序语言中类似。两者相较,if…else用于不很复杂的分支关系,实际编写可综合风格的模块、特别是用状态机构成的模块时,更常用的是case…endcase风格的代码。这一节我们给的是有关if…else的范例,有关case…endcase结构的代码已后会经常用到。 下面给出的范例也是一个可综合风格的分频器,是将10M的时钟分频为500K的时钟。基本原理与1/2分频器是一样的,但是需要定义一个计数器,以便准确获得1/20分频 模块源代码: // --------------- fdivision.v ----------------------------- module fdivision(reset,f10m,f500k); input f10m,reset; output f500k; reg f500k; reg [7:0]j; always @(posedge f10m)

end if(!RESET) begin f500k <= 0; j <= 0; end else begin if(j==19) begin j <= 0; f500k <= ~f500k; end else j <= j+1; //对计数器进行判断,以确定F500K信号是否反转。 //低电平复位。 endmodule测试模块源代码: //--------------- fdivision_Top.v ------------------------ `timescale 1ns/100ps `define clk_cycle 50 module division_Top; reg f10m=0,reset; wire f500k; always #`clk_cycle f10m = ~ f10m; initial begin reset=1; #100 reset=0; #100 reset=1; #10000 $stop; end fdivision fdivision (.reset(reset),.f10m(f10m),.f500k(f500k)); endmodule  Verilog HDL实例(四) 练习四. 设计时序逻辑时采用阻塞赋值与非阻塞赋值的区别 目的:1.明确掌握阻塞赋值与非阻塞赋值的概念和区别; 2.了解阻塞赋值的使用情况。 阻塞赋值与非阻塞赋值,在教材中我们已经了解了它们之间在语法上的区别以及综合后所得到的电路结构上的区别。在always块中,阻塞赋值可以理解为赋值语句是顺序执行的,而非阻塞赋值可以理解为赋值语句是并发执行的。实际的时序逻辑设计中,一般的情况下非阻塞赋值语句被更多地使用,有时为了在同一周期实现相互关联的操作,也使用了阻塞赋值语句。(注意:在实现组合逻辑的assign结构中,无一例外地都必须采用阻塞赋值语句。 下例通过分别采用阻塞赋值语句和非阻塞赋值语句的两个看上去非常相似的两个模块blocking.v和non_blocking.v来阐明两者之间的区别。 模块源代码: // ------------- blocking.v --------------- module blocking(clk,a,b,c); output [3:0] b,c; input [3:0] a; input clk; reg [3:0] b,c; always @(posedge clk) begin b = a; c = b; end endmodule //------------- non_blocking.v ------------------- module non_blocking(clk,a,b,c); output [3:0] b,c; input [3:0] a; input clk; reg [3:0] b,c; always @(posedge clk) begin b <= a; c <= b; end endmodule 测试模块源代码: //------------- compareTop.v ----------------------------- `timescale 1ns/100ps `include \"./blocking.v\" `include \"./non_blocking.v\" module compareTop; wire [3:0] b1,c1,b2,c2; reg [3:0] a; reg clk; initial begin clk = 0; forever #50 clk = ~clk; end initial begin a = 4'h3; $display(\"____________________________\"); # 100 a = 4'h7; $display(\"____________________________\"); # 100 a = 4'hf; $display(\"____________________________\"); # 100 a = 4'ha; $display(\"____________________________\"); # 100 a = 4'h2; $display(\"____________________________\"); # 100 $display(\"____________________________\"); $stop; end non_blocking non_blocking(clk,a,b2,c2); blocking blocking(clk,a,b1,c1); endmodule Verilog HDL实例(五) 练习五. 用always块实现较复杂的组合逻辑电路 目的: 1.掌握用always实现组合逻辑电路的方法; 2.了解assign与always两种组合逻辑电路实现方法之间的区别。 仅使用assign结构来实现组合逻辑电路,在设计中会发现很多地方会显得冗长且效率低下。而适当地采用always来设计组合逻辑,往往会更具实效。已进行的范例和练习中,我们仅在实现时序逻辑电路时使用always块。从现在开始,我们对它的看法要稍稍改变。 下面是一个简单的指令译码电路的设计示例。该电路通过对指令的判断,对输入数据执行相应的操作,包括加、减、与、或和求反,并且无论是指令作用的数据还是指令本身发生变化,结果都要作出及时的反应。显然,这是一个较为复杂的组合逻辑电路,如果采用assign 语句,表达起来非常复杂。示例中使用了电平敏感的always块,所谓电平敏感的触发条件是指在@后的括号内电平列表中的任何一个电平发生变化,(与时序逻辑不同,它在@后的括号内没有沿敏感关键词,如posedge 或negedge)

就能触发always块的动作,并且运用了case结构来进行分支判断,不但设计思想得到直观的体现,而且代码看起来非常整齐、便于理解。 //--------------- alu.v -------------------------- `define plus 3'd0 `define minus 3'd1 `define band 3'd2 `define bor 3'd3 `define unegate 3'd4 module alu(out,opcode,a,b); output[7:0] out; reg[7:0] out; input[2:0] opcode; input[7:0] a,b; //操作数。 always@(opcode or a or b) //电平敏感的always块 begin case(opcode) `plus: out = a+b; //加操作。 `minus: out = a-b; //减操作。 `band: out = a&b; //求与。 `bor: out = a|b; //求或。 `unegate: out=~a; //求反。 default: out=8'hx;//未收到指令时,输出任意态。 endcase end endmodule 同一组合逻辑电路分别用always块和连续赋值语句assign描述时,代码的形式大相径庭,但是在always中适当运用default(在case结构中)和else(在if…else结构中),通常可以综合为纯组合逻辑,尽管被赋值的变量一定要定义为reg型。不过,如果不使用default或else对缺省项进行说明,则易生成意想不到的锁存器,这一点一定要加以注意。 指令译码器的测试模块源代码: //------------- alu_Top.v ----------------- `timescale 1ns/1ns module alutest; wire[7:0] out; reg[7:0] a,b; reg[2:0] opcode; parameter times=5; initial begin a={$random}%256; //Give a radom number blongs to [0,255] . b={$random}%256; //Give a radom number blongs to [0,255]. opcode=3'h0; repeat(times) begin #100 a={$random}%256; //Give a radom number. b={$random}%256; //Give a radom number. opcode=opcode+1; end #100 $stop; end alu alu1(out,opcode,a,b); endmodule Verilog HDL实例(六) 练习六. 在Verilog HDL中使用函数 目的:掌握函数在模块设计中的使用。 与一般的程序设计语言一样,Veirlog HDL也可使用函数以适应对不同变量采取同一运算的操作。Veirlog HDL函数在综合时被理解成具有独立运算功能的电路,每调用一次函数相当于改变这部分电路的输入以得到相应的计算结果。 下例是函数调用的一个简单示范,采用同步时钟触发运算的执行,每个clk时钟周期都会执行一次运算。并且在测试模块中,通过调用系统任务$display在时钟的下降沿显示每次计算的结果。 模块源代码: module tryfunct(clk,n,result,reset); output[31:0] result; input[3:0] n; input reset,clk; reg[31:0] result; always @(posedge clk) //clk的上沿触发同步运算。 begin

if(!reset)

result<=0; else begin //reset为低时复位。 result <= factorial(n); end end //函数定义。 function [31:0] factorial;

end input [3:0] operand; reg begin factorial = 1; [3:0] index; for(index = 1; index <= operand; index = index + 1) factorial = index * factorial; endfunction endmodule 测试模块源代码: `timescale 1ns/100ps module tryfuctTop; reg[3:0] n,i; reg reset,clk; wire[31:0] result; initial begin

n=0; reset=1; clk=0; #10 reset=0; #10 reset=1; for(i=0;i<=15;i=i+1) begin #20 n=i; end #10 $stop; end always #5 clk=~clk; tryfunct tryfunct(.clk(clk),.n(n),.result(result),.reset(reset)); endmodule 上例中函数factorial(n)实际上就是阶乘运算。必须提醒大家注意的是,在实际的设计中,我们不希望设计中的运算过于复杂,以免在综合后带来不可预测的后果。经常的情况是,我们把复杂的运算分成几个步骤,分别在不同的时钟周期完成。 Verilog HDL实例(七) 练习七. 在Verilog HDL中使用任务(task) 目的:掌握任务在结构化Verilog HDL设计中的应用。 仅有函数并不能完全满足Veirlog HDL中的运算需求。当我们希望能够将一些信号进行运算并输出多个结果时,采用函数结构就显得非常不方便,而任务结构在这方面的优势则十分突出。任务本身并不返回计算值,但是它通过类似C语言中形参与实参的数据交换,非常快捷地实现运算结果的调用。此外,我们还常常利用任务来帮助我们实现结构化的模块设计,将批量的操作以任务的形式独立出来,这样设计的目的通常一眼看过去就很明了。 下面是一个利用task和电平敏感的always块设计比较后重组信号的组合逻辑的实例。可以看到,利用task非常方便地实现了数据之间的交换,如果要用函数实现相同的功能是非常复杂的;另外,task也避免了直接用一般语句来描述所引起的不易理解和综合时产生冗余逻辑等问题。 模块源代码: //----------------- sort4.v ------------------ module ss(ra,rb,rc,rd,a,b,c,d); output[3:0] ra,rb,rc,rd; input[3:0] a,b,c,d; reg[3:0] ra,rb,rc,rd; reg[3:0] va,vb,vc,vd; always @ (a or b or c or d) begin {va,vb,vc,vd}={a,b,c,d}; sort2(va,vc); sort2(vb,vd); sort2(va,vb); sort2(vc,vd); sort2(vb,vc); {ra,rb,rc,rd}={va,vb,vc,vd};

end task sort2; inout[3:0] x,y;

reg[3:0] tmp; //va 与vc互换。 //vb 与vd互换。 //va 与vb互换。 //vc 与vd互换。 //vb 与vc互换。

if(x>y) begin //x与y变量的内容互换,要求顺序执行,所以采用阻塞

tmp=x; 赋值方式。

x=y; y=tmp; end endtask endmodule 值得注意的是task中的变量定义与模块中的变量定义不尽相同,它们并不受输入输出类型的限制。如此例,x与y对于task sort2来说虽然是inout型,但实际上它们对应的是always块中变量,都是reg型变量。 测试模块源代码:                  `timescale 1ns/100ps module task_Top; reg[3:0] a,b,c,d; wire[3:0] ra,rb,rc,rd; ss my (.a(a),.b(b),.c(c),.d(d), .ra(ra),.rb(rb),.rc(rc),.rd(rd)); initial begin a=0;b=0;c=0;d=0; #100 a ={$random}%15; b ={$random}%15; c ={$random}%15; d ={$random}%15; #100 $stop; end endmodule

【例3.5】“与-或-非”门电路 module AOI(A,B,C,D,F); //模块名为AOI(端口列表A,B,C,D,F)

input A,B,C,D; //模块的输入端口为A,B,C,D output F; //模块的输出端口为F wire A,B,C,D,F; //定义信号的数据类型 assign F= ~((A&B)|(C&D)); //逻辑功能描述 endmodule

【例5.2】同步置数、同步清零的计数器 module count(out,data,load,reset,clk); output[7:0] out; input[7:0] data; input load,clk,reset; reg[7:0] out;

always @(posedge clk) //clk 上升沿触发 begin

if (!reset) out = 8'h00; //同步清0,低电平有效 else if (load) out = data; //同步预置 else out = out + 1; //计数 end

endmodule

【例5.14】隐含锁存器举例 module buried_ff(c,b,a); output c; input b,a; reg c;

always @(a or b) begin

if((b==1)&&(a==1)) c=a&b; end

endmodule

【例5.16】用for 语句实现2 个8 位数相乘 module mult_for(outcome,a,b); parameter size=8;

input[size:1] a,b; //两个操作数 output[2*size:1] outcome; //结果 reg[2*size:1] outcome; integer i;

always @(a or b) begin

outcome=0;

for(i=1; i<=size; i=i+1) //for 语句 if(b[i]) outcome=outcome +(a << (i-1)); end

endmodule

【例9.1】基本门电路的几种描述方法 (1)门级结构描述 module gate1(F,A,B,C,D); input A,B,C,D; output F;

nand(F1,A,B); //调用门元件 and(F2,B,C,D); or(F,F1,F2); endmodule

(2)数据流描述 module gate2(F,A,B,C,D); input A,B,C,D; output F;

assign F=(A&B)|(B&C&D); //assign 持续赋值 endmodule

(3)行为描述 module gate3(F,A,B,C,D); input A,B,C,D; output F; reg F;

always @(A or B or C or D) //过程赋值 begin

F=(A&B)|(B&C&D); end

endmodule

【例9.2】用bufif1 关键字描述的三态门 module tri_1(in,en,out); input in,en; output out; tri out;

bufif1 b1(out,in,en); //注意三态门端口的排列顺序 endmodule

【例9.3】用assign 语句描述的三态门 module tri_2(out,in,en); output out; input in,en;

assign out = en ? in : 'bz;

//若en=1,则out=in;若en=0,则out 为高阻态 endmodule

【例9.4】三态双向驱动器 module bidir(tri_inout,out,in,en,b); inout tri_inout;

output out; input in,en,b;

assign tri_inout = en ? in : 'bz; assign out = tri_inout ^ b; endmodule

【例9.5】三态双向驱动器 module bidir2(bidir,en,clk); inout[7:0] bidir; input en,clk; reg[7:0] temp;

assign bidir= en ? temp : 8'bz; always @(posedge clk) begin

if(en) temp=bidir; else temp=temp+1; end

endmodule 【例9.13】用组合电路实现的ROM module rom(addr,data); input[3:0] addr; output[7:0] data; function[7:0] romout; input[3:0] addr; case(addr) 0 : romout = 0; 1 : romout = 1; 2 : romout = 4; 3 : romout = 9; 4 : romout = 16; 5 : romout = 25; 6 : romout = 36; 7 : romout = 49; 8 : romout = 64; 9 : romout = 81; 10 : romout = 100; 11 : romout = 121; 12 : romout = 144; 13 : romout = 169; 14 : romout = 196; 15 : romout = 225;

default : romout = 8'hxx; endcase endfunction

assign data = romout(addr); endmodule

【例9.14】基本D 触发器 module DFF(Q,D,CLK); output Q; input D,CLK; reg Q;

always @(posedge CLK) begin Q <= D; end

endmodule

【例9.15】带异步清0、异步置1 的D 触发器 module DFF1(q,qn,d,clk,set,reset); input d,clk,set,reset; output q,qn; reg q,qn;

always @(posedge clk or negedge set or negedge reset) begin

if (!reset) begin

q <= 0; //异步清0,低电平有效 qn <= 1; end

else if (!set) begin

q <= 1; //异步置1,低电平有效 qn <= 0; end

else begin q <= d; qn <= ~d; end end

endmodule

【例9.16】带同步清0、同步置1 的D 触发器 module DFF2(q,qn,d,clk,set,reset); input d,clk,set,reset; output q,qn; reg q,qn;

always @(posedge clk) begin

if (reset) begin

q <= 0; qn <= 1; //同步清0,高电平有效 end

else if (set) begin

q <=1; qn <=0; //同步置1,高电平有效 end

else begin

q <= d; qn <= ~d; end end

endmodule

【例9.17】带异步清0、异步置1 的JK 触发器 module JK_FF(CLK,J,K,Q,RS,SET); input CLK,J,K,SET,RS; output Q; reg Q;

always @(posedge CLK or negedge RS or negedge SET) begin

if(!RS) Q <= 1'b0;

else if(!SET) Q <= 1'b1; else case({J,K}) 2'b00 : Q <= Q; 2'b01 : Q <= 1'b0; 2'b10 : Q <= 1'b1; 2'b11 : Q <= ~Q; default: Q<= 1'bx; endcase end

endmodule

【例9.18】电平敏感的1 位数据锁存器 module latch_1(q,d,clk); output q; input d,clk;

assign q = clk ? d : q; //时钟信号为高电平时,将输入端数据锁存 endmodule

【例9.19】带置位和复位端的1 位数据锁存器 module latch_2(q,d,clk,set,reset); output q;

input d,clk,set,reset;

assign q = reset ? 0 : (set ? 1 : (clk ? d : q)); endmodule

【例9.20】8 位数据锁存器 module latch_8(qout,data,clk); output[7:0] qout; input[7:0] data; input clk; reg[7:0] qout;

always @(clk or data)

begin

if (clk) qout<=data; end

endmodule

【例9.21】8 位数据寄存器 module reg8(out_data,in_data,clk,clr); output[7:0] out_data; input[7:0] in_data; input clk,clr;

reg[7:0] out_data;

always @(posedge clk or posedge clr) begin

if(clr) out_data <=0; else out_data <=in_data; end

endmodule

【例9.22】8 位移位寄存器 module shifter(din,clk,clr,dout); input din,clk,clr; output[7:0] dout; reg[7:0] dout;

always @(posedge clk) begin

if (clr) dout<= 8'b0; //同步清0,高电平有效 else begin

dout <= dout << 1; //输出信号左移一位 dout[0] <= din; //输入信号补充到输出信号的最低位 end end

endmodule

【例9.23】可变模加法/减法计数器 module updown_count(d,clk,clear,load,up_down,qd); input[7:0] d;

input clk,clear,load; input up_down; output[7:0] qd; reg[7:0] cnt; assign qd = cnt;

always @(posedge clk) begin

if (!clear) cnt = 8'h00; //同步清0,低电平有效 else if (load) cnt = d; //同步预置 else if (up_down) cnt = cnt + 1; //加法计数 else cnt = cnt - 1; //减法计数 end

endmodule

【例9.24】4 位Johnson 计数器(异步复位) module johnson(clk,clr,out); input clk,clr; output[3:0] out; reg[3:0] out;

always @(posedge clk or posedge clr) begin

if (clr) out<= 4'h0; else

begin out<= out<< 1; out[0]<= ~out[3]; end end

endmodule

【例9.25】256×8 RAM 模块 module ram256x8(data,address,we,inclock,outclock,q); input[7:0] data; input[7:0] address;

input we,inclock,outclock; output[7:0] q;

lpm_ram_dq myram(.q(q),.data(data),.address(address), .we(we),.inclock(inclock),.outclock(outclock)); defparam myram.lpm_width=8; //定义数据宽度 defparam myram.lpm_widthad=8; //定义地址宽度 endmodule

【例9.26】256×16 RAM 块 module map_lpm_ram(dataout,datain,addr,we,inclk,outclk); input[15:0] datain; //端口定义 input[7:0] addr;

input we,inclk,outclk; output[15:0] dataout; //lpm_ram_dq 元件例化 lpm_ram_dq ram(.data(datain),.address(addr),.we(we),.inclock(inclk), .outclock(outclk),.q(dataout));

defparam ram.lpm_width=16; //参数赋值 defparam ram.lpm_widthad=8;

defparam ram.lpm_indata=\"REGISTERED\"; defparam ram.lpm_outdata=\"REGISTERED\";

defparam ram.lpm_file=\"map_lpm_ram.mif\"; //RAM 块中的内容取自该文件 endmodule

【例9.27】4 位串并转换器 module serial_pal(clk,reset,en,in,out); input clk,reset,en,in; output[3:0] out; reg[3:0] out;

always @(posedge clk) begin

if(reset) out<=4'h0;

else if(en) out<={out,in}; //使用连接运算符 end

endmodule 【例10.6】自动转换量程频率计控制器 /*信号定义: clk: 输入时钟; clear: 为整个频率计的异步复位信号; reset: 用来在量程转换开始时复位计数器; std_f_sel: 用来选择标准时基; cntover: 代表超量程; cntlow: 代表欠量程。 状态A,B,C,D,E,F 采用一位热码编码 */ module control(std_f_sel,reset,clk,clear,cntover,cntlow); output[1:0] std_f_sel; output reset;

input clk,clear,cntover,cntlow; reg[1:0] std_f_sel; reg reset;

reg[5:0] present,next; //用于保存当前状态和次态的中间变量 parameter start_fl00k=6'b000001, //状态A 编码,采用1 位热码 fl00k_cnt=6'b000010, //状态B start_fl0k=6'b000100, //状态C fl0k_cnt=6'b001000, //状态D start_flk=6'b010000, //状态E flk_cnt=6'b100000; //状态F

always @(posedge clk or posedge clear) begin

if(clear) present<=start_fl0k; //start_fl0k 为起始状态 else present<=next; end

always @(present or cntover or cntlow) begin

case(present) //用case 语句描述状态转换 start_fl00k: next<=fl00k_cnt;

fl00k_cnt: begin

if(cntlow) next<=start_fl0k; else next<=fl00k_cnt; end

start_fl0k: next<=fl0k_cnt; fl0k_cnt: begin

if(cntlow) next<=start_flk;

else if(cntover) next<=start_fl00k; else next<=fl0k_cnt; end

start_flk: next<=flk_cnt; flk_cnt: begin

if(cntover) next<=start_fl0k; else next<=flk_cnt; end

default:next<=start_fl0k; //缺省状态为起始状态 endcase end

always @(present) //该进程产生各状态下的输出 begin

case(present)

start_fl00k: begin reset=1; std_f_sel=2'b00; end fl00k_cnt: begin reset=0; std_f_sel=2'b00; end start_fl0k: begin reset=1; std_f_sel=2'b01; end fl0k_cnt: begin reset=0; std_f_sel=2'b01; end start_flk: begin reset=1; std_f_sel=2'b11; end flk_cnt: begin reset=0; std_f_sel=2'b11; end default: begin reset=1; std_f_sel=2'b01; end endcase end

endmodule

【例10.7】8 位全加器 module add8(sum,cout,b,a,cin); output[7:0] sum; output cout; input[7:0] a,b; input cin;

assign {cout,sum}=a+b+cin; endmodule

【例10.8】8 位寄存器 module reg8(qout,in,clk,clear); output[7:0] qout; input[7:0] in; input clk,clear; reg[7:0] qout;

always @(posedge clk or posedge clear) begin

if(clear) qout=0; //异步清0 else qout=in; end

endmodule 【例10.11】阻塞赋值方式描述的移位寄存器1 module block1(Q0,Q1,Q2,Q3,din,clk); output Q0,Q1,Q2,Q3; input clk,din; reg Q0,Q1,Q2,Q3; always @(posedge clk) begin

Q3=Q2; //注意赋值语句的顺序 Q2=Q1; Q1=Q0; Q0=din; end

endmodule 【例10.13】阻塞赋值方式描述的移位寄存器3 module block3(Q0,Q1,Q2,Q3,din,clk); output Q0,Q1,Q2,Q3; input clk,din;

reg Q0,Q1,Q2,Q3; always @(posedge clk) begin

Q0=din; //4 条赋值语句的顺序与例10.11 完全颠倒 Q1=Q0; Q2=Q1; Q3=Q2; end

endmodule

【例10.14】非阻塞赋值方式描述的移位寄存器 module block4(Q0,Q1,Q2,Q3,din,clk); output Q0,Q1,Q2,Q3; input clk,din;

reg Q0,Q1,Q2,Q3; always @(posedge clk) begin Q3<=Q2; Q1<=Q0; Q2<=Q1; Q0<=din; end

endmodule

【例10.15】长帧同步时钟的产生 module longframe1(clk,strb); parameter delay=8; input clk; output strb; reg strb;

reg[7:0] counter;

always@(posedge clk) begin

if(counter==255) counter=0; else counter=counter+1; end

always@(counter) begin

if(counter<=(delay-1)) strb=1; else strb=0; end

endmodule

【例10.16】引入了D 触发器的长帧同步时钟的产生 module longframe2(clk,strb); parameter delay=8; input clk; output strb;

reg[7:0] counter; reg temp; reg strb;

always@(posedge clk) begin

if(counter==255) counter=0; else counter=counter+1; end

always@(posedge clk) begin

strb=temp; //引入一个触发器 end

always@(counter) begin

if(counter<=(delay-1)) temp=1; else temp=0; end

endmodule 用门级结构描述D触发器 下面的例子是用Verilog HDL语言描述的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

在这个Verilog HDL 结构描述的模块中,flop定义了模块名,设计上层模块时可以用这个名(flop)调用这个模块;module, input, output, endmodule等都是关键字; nand表示与非门;#10表示10个单位时间的延时;nd1,nd2,......,nd8,iv1,iv2分别为图4.1.2中的各个基本部件,而其后面括号中的参数分别为图4.1.2 中各基本部件的输入输出信号。 clearand3nd1clockcnd5end7qdataiv1nd2bnd4dnd6fnd8qbiv2nclock 图4.1.2. D型主从触发器的电路结构图 下面的例子中引用了4.1.2 中已设计的模块flop,用它构成一个四位寄存器。 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 在上面这个结构描述的模块中,hardreg定义了模块名;f1,f2,f3,f4分别为图5中的各个基本部件,而其后面括号中的参数分别为图5中各基本部件的输入输出信号。请注意当f1到f4实例引用已编模块flop时,由于不需要flop端口中的qb口,故在引用时把它省去,但逗号仍需要留着。 显而易见,通过Verilog HDL模块的调用,可以构成任何复杂结构的电路。这

q3dq2dq1dq0df4clrqf3clkclrqf2clkclrqf1clrqclkclkclrbclkd3图4.1.3d2d1d0四位寄存器电路结构图 种以结构方式所建立的硬件模型不仅是可以仿真的,也是可综合的,这就是以门级为基础的结构描述建模的基本思路。 2-4译码器举例   2-4译码器电路的门级描述如下: module DEC2×4 (A,B,Enable,Z); input A,B,Enable; output [0:3] Z; wire Abar, Bbar; not # (1,2) V0 (Abar,A), V1(Bbar, B);

nand # (4,3)

N0 (Z[3], Enable, A,B),

N1 (Z[0], Enable, Abar,Bbar), N2 (Z[1], Enable, Abar,B), N3 (Z[2], Enable, A,Bbar), endmodule

主从触发器举例   主从D触发器的门级描述如下: module MSDFF (D,C,Q,Qbar); input D,C; output Q,Qbar; not

NT1 (NotD,D), NT2 (NotC,C), NT3 (NotY,Y); nand

ND1 (D1,D,C), ND2 (D2,C,NotD), ND3 (Y,D1,Ybar), ND4 (Ybar,Y,D2), ND5 (Y1,Y,NotC),

ND6 (Y2,NotY,NotC), ND7 (Q,Qbar,Y1), ND8 (Qbar,Y2,Q); endmodule

奇偶电路   9位奇偶发生器门级模型描述如下: module Parity_9_Bit (D, Even,Odd); input [0:8] D; output Even, Odd; xor # (5,4)

XE0 (E0,D[0],D[1]), XE1 (E1,D[2],D[3]), XE2 (E2,D[4],D[5]), XE3 (E3,D[6],D[7]), XF0 (F0,E0,E1), XF1 (F1,E2,E3), XH0 (H0,F0,F1),

XEVEN (Even, D[8], H0); not #2

XODD (Odd, Even); endmodule

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- sarr.cn 版权所有

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务