真双口RAM的verilog源代码
Verilog程序代码集
1.全加器Sum=A⊕B⊕CinCount=AB+Cin(A+B)①数据流module adder(a,b,Cin,Sum,Count); input [2:0]a,b;input Cin;output [2:0] Sum;output Count;assign {Count,Sum}=a+b+Cin; endmodule②行为描述always语句module adder(a,b,c,Cin,Sum,Count); input [4:0] a,b;input Cin;output reg [4:0] Sum;output reg Count;reg T1,T2,T3;always@(a or b or Cin)beginSum=a^b^Cin;T1=A&B;T2=Cin&A;T3=Cin&B;Count=T1|T2|T3;endendmodule③结构体module adder (a,b,Cin,Sum,Count);input a,b,Cin;output Sum,Count;Xor a1(s1,a1,b);Xor a2(Sum,s1,Cin);and a3(T1,a,b);or a4(T2,a,b);and a5(T3,Cin,T2);or a6(Count,T1,T3);Endmodule2.数值比较器①判断两值是否相等module compare(a,b,equal);input [7:0] a,b;output equal;assign equal=(a==b)?|0; ②谁大谁输出module compare(a,b,out);input [7:0] a,b;output reg[7:0] out;always@(a or b)beginif (a>b) out<=a;else if (a==b) out<=a;else out<=b;endendmodule③输出参数module compare(a.b.xgy,xsy,xey);input [7:0] x,y;output reg xgy,xsy,xey;always@(x or y)beginif (x==y) xey=1;else xey=0;if (x>y) begin xgy=1;xsy=0;endelse if (x<y) begin xgy=0;xsy=1;end endendmodule3.编码器(4-2 8-3 16-4编码)①case语句8-3编码(优先)module code (in ,out);input [7:0] in;output reg [2:0] out;always@(in)case x(in)begin f=1;8’b1xxxxxxx:out=3’b111;end begin f=1;8’b01xxxxxx:out=3’b110;end begin f=1;8’b001xxxxx:out=3’b101;end begin f=1;8’b0001xxxx:out=3’b100;end begin f=1;8’b00001xxx:out=3’b011;end begin f=1;8’bxx:out=3’b010;endbegin f=1;8’bx:out=3’b001;endbegin f=1;8’b:out=3’b000;end default:begin f=0:out=3’b000;end endcaseendmodule②if-else语句(4-2优先编码)module code(in,out);input[3:0] in;output reg [1:0] out;always@(in)if (in[3]==1):begin f=1;out=2’b11;end else if (in[2]==1):begin f=1;out=2’b10;end else if (in[1]==1):begin f=1;out=2’b01;end else if (in[0]==1):begin f=1;out=2’b00;end else begin f=0;out=2’b00;end endmodule4.多路选择器①行为描述(4选1)module choice(A,B,C,D,ncs addr out);input [7:0]A,B,C,D;input ncs;input [1:0] addr ;output reg[7:0] out;always@(A or B or C or D or ncs or addr) beginif (!ncs)case(addr)2’b00:out=A;2’b01:out=B;2’b10:out=C;2’b11:out=D;endcaseelse out=0;endendmodule5.设计一个4位双向移位寄存器。
基于FPGA Verilog RS232串口回环测试例程,附源程序仿真源码及测试图片
FPGA Verilog RS232串口回环测试基于FPGA Verilog RS232串口回环测试例程,支持多byte数据传输,附源程序仿真源码及测试图片。
测试基于SSCOM/友善之臂上位机软件测试,测试结果如下图一图二所示。
图一SSCOM图二图三连续发送仿真截图图四连续接收仿真截图后附verilog源程序代码及testbech仿真例程,注释欠。
重点:多byte回环测试要点,上位机串口多位数据连续发送停止位和起始位之间无间隔,回环程序在接收和发送都需要具备在停止位后能立马跳转到下一个起始位的能力。
重点关注cnt_bit的处理方式。
附录1 顶层例化uart_txd uart_txd(.clk_50m(sys_clk_50m),.reset_n(sys_rst_n),.tx_data(rx_data),.baud_set(3'd4),.send_en(rx_done),.send_done(),.send_busy(send_busy),.uart_tx(uart_tx));uart_rxd uart_rxd(.clk_50m(sys_clk_50m),.reset_n(sys_rst_n),.rx_data(rx_data),.baud_set(3'd4),.rx_done(rx_done),.rx_busy(rx_busy),.uart_rx(uart_rx));附录2 串口发送源程序`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 09:45:23// Design Name:// Module Name: uart_txd// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies:// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_txd(clk_50m,reset_n,tx_data,baud_set,send_en,send_done,send_busy,uart_tx);input clk_50m;input reset_n;input[7:0] tx_data;input[2:0] baud_set;input send_en;output reg send_done;output reg send_busy;output reg uart_tx;reg[12:0] cnt;reg[12:0] baud_rate_cnt_max;reg[3:0] cnt_bit;reg[7:0] tx_data_r;localparam baud_rate_9600 =13'd5207;localparam baud_rate_19200 =13'd2603;localparam baud_rate_38400 =13'd1301;localparam baud_rate_57600 =13'd867;localparam baud_rate_115200 =13'd433;always@(posedge clk_50m or negedge reset_n)if(!reset_n)baud_rate_cnt_max <= baud_rate_115200;elsecase(baud_set)3'd0:baud_rate_cnt_max = baud_rate_9600;3'd1:baud_rate_cnt_max = baud_rate_19200;3'd2:baud_rate_cnt_max = baud_rate_38400;3'd3:baud_rate_cnt_max = baud_rate_57600;3'd4:baud_rate_cnt_max = baud_rate_115200;default:baud_rate_cnt_max = baud_rate_115200;endcasealways@(posedge clk_50m or negedge reset_n)if(!reset_n)tx_data_r <=8'd0;else if(send_en)tx_data_r <= tx_data;elsetx_data_r <= tx_data_r;always@(posedge clk_50m or negedge reset_n)if(!reset_n)send_busy <=1'b0;else if(send_en)send_busy <=1'b1;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit ==4'd10)send_busy <=1'b0;elsesend_busy <= send_busy;endelsesend_busy <= send_busy;always@(posedge clk_50m or negedge reset_n)if(!reset_n)send_done <=1'b0;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit ==4'd10)send_done <=1'b1;elsesend_done <=1'b0;endelsesend_done <=1'b0;always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt <=13'd0;else if(send_busy)beginif(cnt == baud_rate_cnt_max)cnt <=13'd0;elsecnt <= cnt +1'b1;endelsecnt <= cnt;/****************************************always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt_bit <= 4'd0;else if(send_en) //send_en needs to be 1 clock high pulse cnt_bit <= 4'd1;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit == 4'd10)cnt_bit <= 4'd0;elsecnt_bit <= cnt_bit + 1'b1;endelsecnt_bit <= cnt_bit;******************************************/always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt_bit <=4'd0;else if(send_busy &&(cnt_bit ==4'd11))cnt_bit <=4'd1;else if(cnt ==1)cnt_bit <= cnt_bit +1'b1;elsecnt_bit <= cnt_bit;always@(posedge clk_50m or negedge reset_n)if(!reset_n)beginuart_tx <=1'b1;endelsecase(cnt_bit)4'd0:;4'd1: uart_tx <=1'b0;//start4'd2: uart_tx <= tx_data_r[0];//bit 04'd3: uart_tx <= tx_data_r[1];4'd4: uart_tx <= tx_data_r[2];4'd5: uart_tx <= tx_data_r[3];4'd6: uart_tx <= tx_data_r[4];4'd7: uart_tx <= tx_data_r[5];4'd8: uart_tx <= tx_data_r[6];4'd9: uart_tx <= tx_data_r[7];//bit 84'd10: uart_tx <=1'b1;//stopdefault:;endcaseendmodule附录3 串口发送testbench`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 11:38:04// Design Name:// Module Name: uart_txd_tb// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_txd_tb();reg clk_50m;reg reset_n;reg[7:0] tx_data;reg[2:0] baud_set;reg send_en;wire send_done;wire send_busy;wire uart_tx;parameter CLK_PERIOD =20;initial clk_50m =0;always#(CLK_PERIOD /2) clk_50m =~clk_50m;initial begintx_data =8'h55;baud_set =4;reset_n =0;send_en =0;#(CLK_PERIOD *100);reset_n =1;# CLK_PERIOD;send_en =1;#(CLK_PERIOD );send_en =0;#(CLK_PERIOD *4340);send_en =1;#(CLK_PERIOD );send_en =0;#(CLK_PERIOD *4340);#(CLK_PERIOD *100);$stop;enduart_txd uart_txd(.clk_50m(clk_50m),.reset_n(reset_n),.tx_data(tx_data),.baud_set(baud_set),.send_en(send_en),.send_done(send_done),.send_busy(send_busy),.uart_tx(uart_tx));endmodule附录4 串口接收源程序`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 15:30:30// Design Name:// Module Name: uart_rxd// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_rxd(clk_50m,reset_n,rx_data,baud_set,rx_done,rx_busy,uart_rx);input clk_50m;input reset_n;output reg[7:0] rx_data;input[2:0] baud_set;output reg rx_done;output reg rx_busy;input uart_rx;reg[12:0] cnt;reg[12:0] baud_rate_cnt_max;reg[3:0] cnt_bit;reg uart_rx_r1;reg uart_rx_r2;wire nedge;localparam baud_rate_9600 =13'd5207;localparam baud_rate_19200 =13'd2603;localparam baud_rate_38400 =13'd1301;localparam baud_rate_57600 =13'd867;localparam baud_rate_115200 =13'd433;always@(posedge clk_50m or negedge reset_n)if(!reset_n)baud_rate_cnt_max <= baud_rate_115200;elsecase(baud_set)3'd0:baud_rate_cnt_max = baud_rate_9600;3'd1:baud_rate_cnt_max = baud_rate_19200;3'd2:baud_rate_cnt_max = baud_rate_38400;3'd3:baud_rate_cnt_max = baud_rate_57600;3'd4:baud_rate_cnt_max = baud_rate_115200;default:baud_rate_cnt_max = baud_rate_115200;endcasealways@(posedge clk_50m or negedge reset_n)if(!reset_n)beginuart_rx_r1 <=8'd0;uart_rx_r2 <=8'd0;endelse beginuart_rx_r1 <= uart_rx;uart_rx_r2 <= uart_rx_r1;endassign nedge = uart_rx_r2 &(!uart_rx_r1);always@(posedge clk_50m or negedge reset_n) if(!reset_n)rx_busy <=1'b0;else if(nedge)rx_busy <=1'b1;else if(cnt == baud_rate_cnt_max)begin if(cnt_bit ==4'd10)rx_busy <=1'b0;elserx_busy <= rx_busy;endelserx_busy <= rx_busy;always@(posedge clk_50m or negedge reset_n) if(!reset_n)rx_done <=1'b0;else if(cnt == baud_rate_cnt_max)begin if(cnt_bit ==4'd10)rx_done <=1'b1;elserx_done <=1'b0;endelserx_done <=1'b0;always@(posedge clk_50m or negedge reset_n) if(!reset_n)cnt <=13'd0;else if(rx_busy)beginif(cnt == baud_rate_cnt_max)cnt <=13'd0;elsecnt <= cnt +1'b1;endelsecnt <= cnt;always@(posedge clk_50m or negedge reset_n) if(!reset_n)cnt_bit <=4'd1;else if(cnt == baud_rate_cnt_max )begin if(cnt_bit ==4'd10)cnt_bit <=4'd1;elsecnt_bit <= cnt_bit +1'b1;endelsecnt_bit <= cnt_bit;always@(posedge clk_50m or negedge reset_n)if(!reset_n)beginrx_data <=8'd0;endelse if(cnt == baud_rate_cnt_max /2)case(cnt_bit)4'd1:;//start4'd2: rx_data[0]<= uart_rx_r2;//bit 04'd3: rx_data[1]<= uart_rx_r2;4'd4: rx_data[2]<= uart_rx_r2;4'd5: rx_data[3]<= uart_rx_r2;4'd6: rx_data[4]<= uart_rx_r2;4'd7: rx_data[5]<= uart_rx_r2;4'd8: rx_data[6]<= uart_rx_r2;4'd9: rx_data[7]<= uart_rx_r2;//bit 74'd10:;//stopdefault:;endcaseelserx_data <= rx_data;endmodule附录5串口接收testbench`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 19:44:29// Design Name:// Module Name: uart_rxd_tb// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_rxd_tb();reg clk_50m;reg reset_n;wire[7:0] rx_data;wire rx_done;wire rx_busy;reg uart_rx;parameter CLK_PERIOD =20;initial clk_50m =0;always#(CLK_PERIOD /2) clk_50m =~clk_50m;initial beginreset_n =0;uart_rx =1;//idle#(CLK_PERIOD *100);reset_n =1;# CLK_PERIOD;uart_rx =0;//start#(CLK_PERIOD *434);uart_rx =1;//bit0#(CLK_PERIOD *434);uart_rx =0;//bit1#(CLK_PERIOD *434);uart_rx =1;//bit2#(CLK_PERIOD *434);uart_rx =0;//bit3#(CLK_PERIOD *434);uart_rx =1;//bit4#(CLK_PERIOD *434);uart_rx =0;//bit5#(CLK_PERIOD *434);uart_rx =1;//bit6#(CLK_PERIOD *434);uart_rx =0;//bit7#(CLK_PERIOD *434);uart_rx =1;//stop#(CLK_PERIOD *434);uart_rx =1;//idle#(CLK_PERIOD *434);#(CLK_PERIOD *434);#(CLK_PERIOD *434);uart_rx =0;//start #(CLK_PERIOD *434);uart_rx =0;//bit0#(CLK_PERIOD *434);uart_rx =1;//bit1#(CLK_PERIOD *434);uart_rx =0;//bit2#(CLK_PERIOD *434);uart_rx =1;//bit3#(CLK_PERIOD *434);uart_rx =0;//bit4#(CLK_PERIOD *434);uart_rx =1;//bit5#(CLK_PERIOD *434);uart_rx =0;//bit6#(CLK_PERIOD *434);uart_rx =1;//bit7#(CLK_PERIOD *434);uart_rx =1;//stop#(CLK_PERIOD *434);uart_rx =1;//idle#(CLK_PERIOD *434);#(CLK_PERIOD *434);#(CLK_PERIOD *434);$stop;enduart_rxd uart_rxd(.clk_50m(clk_50m),.reset_n(reset_n),.rx_data(rx_data),.baud_set(3'd4),.rx_done(rx_done),.rx_busy(rx_busy),.uart_rx(uart_rx));endmodule。
组合-时序逻辑电路Verilog-Testbench代码_带仿真代码和波形_
1组合逻辑电路--基本门电路1.1基本门电路1.1.1结构化描述方式代码如下View Code1 module logics2 (3 input iA,4 input iB,5 output oAnd,6 output oOr,7 output oNot8 );910 and and_inst(oAnd,iA,iB);11 or or_inst(oOr,iA,iB);12 not not_inst(oNot,iA);1314 endmodule最底层的是门级原语and or not RTL级视图testbench如下View Code1 `timescale 1 ns/ 1 ns2 module logics_tb();34 reg ia;5 reg ib;67 wire oAnd;8 wire oOr;9 wire oNot;1011 initial12 begin13 ia=0;14 #40 ia=1;15 #40 ia=0;16 #40 ia=1;17 #40 ia=0;18 end1920 initial21 begin22 ib=0;23 #40 ib=0;24 #40 ib=1;25 #40 ib=1;26 #40 ib=0;27 end2829 logics logics_inst30 (31 .iA(ia),32 .iB(ib),33 .oAnd(oAnd),34 .oOr(oOr),35 .oNot(oNot)36 );3738 endmoduleRTL级仿真图形如下GATE级仿真图如下可见RTL级仿真是理想的,GATE级仿真考虑了延迟和信号开始的不确定。
1.1.2采用流描述方法代码如下View Code1 module logics2 (3 input iA,4 input iB,5 output oAnd,6 output oOr,7 output oNot8 );910 assign oAnd=iA&iB;11 assign oOr=iA|iB;12 assign oNot=~iA;1314 endmoduleRTL级视图,仿真图形同上。
verilog hdl语言100例详解
verilog hdl语言100例详解Verilog HDL语言是一种硬件描述语言,用于描述数字电路和系统的行为和结构。
它是硬件设计工程师在数字电路设计中的重要工具。
本文将介绍100个例子,详细解释Verilog HDL语言的应用。
1. 基本门电路:Verilog HDL可以用于描述基本门电路,如与门、或门、非门等。
例如,下面是一个描述与门电路的Verilog HDL代码:```verilogmodule and_gate(input a, input b, output y);assign y = a & b;endmodule```2. 多路选择器:Verilog HDL也可以用于描述多路选择器。
例如,下面是一个描述2:1多路选择器的Verilog HDL代码:```verilogmodule mux_2to1(input a, input b, input sel, output y);assign y = sel ? b : a;endmodule```3. 寄存器:Verilog HDL可以用于描述寄存器。
例如,下面是一个描述8位寄存器的Verilog HDL代码:```verilogmodule register_8bit(input [7:0] d, input clk, input reset, output reg [7:0] q);always @(posedge clk or posedge reset)if (reset)q <= 0;elseq <= d;endmodule```4. 计数器:Verilog HDL可以用于描述计数器。
例如,下面是一个描述8位计数器的Verilog HDL代码:```verilogmodule counter_8bit(input clk, input reset, output reg [7:0] count);always @(posedge clk or posedge reset)if (reset)count <= 0;elsecount <= count + 1;endmodule```5. 加法器:Verilog HDL可以用于描述加法器。
verilog代码练习题
verilog代码练习题Verilog是一种硬件描述语言,用于描述数字电路的行为和结构。
在学习和掌握Verilog代码编写的过程中,练习题是非常重要的一环。
通过多做一些练习题,可以提高对Verilog语言的理解和运用能力,进而更好地应对实际的电路设计和开发项目。
本文将介绍一些常见的Verilog代码练习题,帮助读者提升自己的编程能力。
具体的练习题如下:练习题一:整数加法器设计一个4位整数加法器,输入两个4位的二进制整数A和B,输出它们的和。
请使用Verilog代码描述该加法器,并给出仿真结果和波形图。
练习题二:时钟分频器设计一个时钟分频器,将输入时钟信号分频为两个输出时钟信号。
其中,输出时钟信号A频率为输入时钟信号的一半,输出时钟信号B 频率为输入时钟信号的四分之一。
请使用Verilog代码描述该时钟分频器,并给出仿真结果和波形图。
练习题三:数字比较器设计一个4位数字比较器,输入两个4位的二进制整数A和B,输出A是否大于B的结果(1表示大于,0表示不大于)。
请使用Verilog代码描述该数字比较器,并给出仿真结果和波形图。
练习题四:有限状态机设计一个简单的有限状态机,实现一个计数器的功能。
输入信号CLK表示时钟信号,每个上升沿计数器加1,输出信号OUT表示计数器的值,初始值为0,最大值为9,超出后回到0。
请使用Verilog代码描述该有限状态机,并给出仿真结果和波形图。
练习题五:位宽可调的加法器设计一个位宽可调的加法器,输入为两个任意位宽的二进制整数A和B,输出为它们的和。
请使用Verilog代码描述该位宽可调的加法器,并给出仿真结果和波形图。
以上是几个常见的Verilog代码练习题,通过多做这些练习题,可以提高对Verilog语言的掌握和运用能力。
在实际的电路设计和开发中,良好的Verilog编程能力是非常重要的。
希望本文对你有所帮助,加油!。
八位移位寄存器verilog代码
一、引言在数字电路设计中,移位寄存器是十分常见的电路元件。
它能够对输入的数据按照特定的规则进行位移操作,常见的有左移、右移、循环移位等。
在Verilog语言中,我们可以通过编写代码来实现八位移位寄存器。
本文将从深度和广度方面展开对八位移位寄存器的Verilog代码进行全面评估,并撰写有价值的文章。
二、基本概念在开始编写八位移位寄存器的Verilog代码之前,我们首先要明确其基本概念。
移位寄存器是一种能够在时钟信号的控制下,对输入数据进行位移操作的寄存器。
而八位移位寄存器则是指这个寄存器能够对八位二进制数据进行位移。
这意味着在Verilog代码中,我们需要定义一个八位的寄存器,并编写移位操作的逻辑。
我们还需要考虑如何控制时钟信号和输入数据,以使得移位操作能够按照我们的期望进行。
三、Verilog代码实现```verilogmodule shift_register(input wire clk, // 时钟信号input wire rst, // 复位信号input wire [7:0] data_in, // 输入数据output reg [7:0] data_out // 输出数据);// 初始化寄存器always @(posedge clk or posedge rst)beginif (rst)data_out <= 8'b00000000; // 复位时,将寄存器清零elsedata_out <= data_in; // 否则将输入数据写入寄存器end// 左移操作always @(*)begindata_out = {data_out[6:0], 1'b0}; // 将寄存器中的数据向左移动一位end// 右移操作always @(*)begindata_out = {1'b0, data_out[7:1]}; // 将寄存器中的数据向右移动一位endendmodule```以上是一个简单的八位移位寄存器的Verilog代码实现。
VerilogHDL代码_AHB总线_master部分
V e r i l o g H D L代码_A H B总线_m a s t e r部分------------------------------------------作者xxxx------------------------------------------日期xxxxmodule ahb_master(HBUSREQ,HLOCK,HTRANS,HADDR,HWRITE,HSIZE,HBURST,HWDATA,HS EL,hcount,HRESETn,HCLK,HGRANT,HREADY,HRESP,HRDATA,BUSREQ,AD DREQ,WRITE,ADDR,SIZE,BURST,SEL,TRANS,WDATA);output HBUSREQ,HLOCK,HWRITE;output [1:0]HTRANS,HSEL;output [31:0]HADDR,HWDATA;output [2:0]HSIZE,HBURST;input HGRANT,HREADY,HCLK,HRESETn,BUSREQ,ADDREQ,WRITE;input [31:0]ADDE,WDATA;input [2:0]SIZE,BURST;input [1:0]HRESP,SEL,TRANS;input [31:0]HRDATA;reg HBUSRREQ,HLOCK,HWRITE,hcount;reg [1:0]HTRANS,HSEL;reg [31:0]HADDR,HWDATA;reg [2:0]HSIZE,HBURST;wire HGRANT,HREADY,HCLK,HRESETn,WRITE;wire [31:0]ADDR,WDATA;wire [2:0]SIZE,BURST;wire [1:0]HRESP,SEL,TRANS;wire [31:0]HRDATA;reg bus_reg,adde_reg,new_hready,old_hready;reg [31:0]RDATA;reg [31:0]h_addr;parameter OKAY=2'b00ERROR=2'b01RETRY=2'b10SPLIT=2'b11;always @(posedge HCLK)beginif(!HRESETn)beginHBUSREQ=0;HLOCK=0;HWRITE=0;HTRANS=2'b00;HSEL=2'b00;HADDR=32'h000000000; HWDATA=32'h000000000; HSIZE=2'b00;HBURST=2'b00;bus_reg=0;addr_reg=0;new_hready=0;old_hready=0;hcount=0;endendalways @(posedge HCLK) beginif(HRESETn)beginif(!addr_reg)beginif(ADDREQ)beginHADDR=ADDR;h_addr=ADDR;HWRITE=WRITE;HSIZE=SIZE;HBURST=BURST;HSEL=SEL;HTRANS=TRANS;addr_reg=1'b1;HWDATA=32'h000000000; endendelse if(addr_reg)beginHADDR=32'h000000000; HWRITE=1'b0;HSIZE=3'b000;HBURST=3'b000;HTRANS=2'b00;addr_reg=1'b0;endif(!ADDREQ)beginif(WRITE)beginhcount=0;case({TRANS})2'b00:beginHWDATA=WDATA;if(HREADY && !new_hready && HRESP==ERROR) new_hready=1;else if(new_hready!=old_hready)HWDATA=32'h00000000;end2'b01:beginhcount=hcount+1;new_hready=0;HWDATA=WDATA;if(HREADY &&!new_hready && HRESP)new_hready=1;else if(new_hready!=old hready)hWDATA=32'h00000000;end2'b10:beginHWDATA=32'h00000000;end2'b11:beginhcount=hcount+1;HWDATA=WDATA;if(HREADY && HRESP==OKAY)beginif(!new_hready)new_hready=1;endelse if(new_hready!=old_hready)beginHWDATA=WDATA;new_hready=0;endelse if(HREADY && HRESP==ERROR)beginHWDATA=32'h00000000;endendendcaseendelse if(!WRITE)begincase({TRANS})2'b00:beginif(!HREADY)RDATA=HRDATA;else if(HREADY)RDATA=32'h00000000; end2'b01:beginif(!HREADY)beginRDATA=HRDATA;if(HBURST==000)h_addr=h_addr+1;elseh_addr=h_addr-1;endelse if(HREADY)RDATA=32'h00000000; end2'b10:beginRDATA=32'h00000000; end2'b11:beginif(!HREADY)beginRDATA=HRDATA;if(HBURST==000)h_addr=h_addr+1;elseh_addr=h_addr-1;endendcaseendendendendmodulemodule ram_top(HCLK ,HRESETn ,HSEL_s ,HADDR_s ,HBURST_s ,HTRANS_s ,HRDATA_s ,HWDATA_s ,HWRITE_s ,HREADY_s ,HRESP_s);input HCLK ;input HRESETn ;input HSEL_s ;input [19:0] HADDR_s ;input [2:0] HBURST_s ;input [1:0] HTRANS_s ;input [31:0] HWDATA_s ; input HWRITE_s ;output [1:0] HRESP_s ;output [31:0] HRDATA_s ; output HREADY_s ;wire [31:0] ram_RDATA ;wire [17:0] ram_ADDR ;wire [31:0] ram_WDATA ; wire ram_WRITE ;ram_ahbif U_ram_ahbif (.HCLK (HCLK ),.HRESETn (HRESETn ),.HSEL_s (HSEL_s ),.HADDR_s (HADDR_s ),.HBURST_s (HBURST_s ),.HTRANS_s (HTRANS_s ),.HRDATA_s (HRDATA_s ),.HWDATA_s (HWDATA_s ), .HWRITE_s (HWRITE_s ),.HREADY_s (HREADY_s ),.HRESP_s (HRESP_s ),.ram_RDATA (ram_RDATA ), .ram_ADDR (ram_ADDR ),.ram_WDATA (ram_WDATA ), .ram_WRITE (ram_WRITE ) );ram_infer U_ram_infer(.q (ram_RDATA ),.a (ram_ADDR ),.d (ram_WDATA ),.we (ram_WRITE ),.clk (HCLK ));endmodulemodule ram_infer(q ,a ,d ,we ,clk);output [31:0] q ;input [31:0] d ;input [17:0] a ;input we ;input clk ;reg [31:0] mem [262143:0] ; always @(posedge clk) beginif (we)beginmem[a] <= d;endendassign q = mem[a]; endmodulemodule ram_ahbif(HCLK ,HRESETn ,HSEL_s ,HADDR_s ,HBURST_s ,HTRANS_s ,HRDATA_s ,HWDATA_s ,HWRITE_s ,HREADY_s ,HRESP_s ,ram_RDATA ,ram_ADDR ,ram_WDATA ,ram_WRITE);/////////////////////////////////////////declaration of input & output///////////////////////////////////////input HCLK ;input HRESETn ;input HSEL_s ;input [19:0] HADDR_s ;input [2:0] HBURST_s ;input [1:0] HTRANS_s ;input [31:0] HWDATA_s ;input HWRITE_s ;output [1:0] HRESP_s ;output [31:0] HRDATA_s ;output HREADY_s ;input [31:0] ram_RDATA ;output [17:0] ram_ADDR ;output [31:0] ram_WDATA ;output ram_WRITE ;/////////////////////////////////////////declaration of registers & wires/////////////////////////////////////// wire [1:0] HRESP_s ;wire [31:0] HRDATA_s ;reg HREADY_s ;wire [31:0] ram_WDATA ;reg [17:0] ram_ADDR ;reg ram_WRITE ;wire wr_en ;wire rd_en ;wire ready_en ;/////////////////////////////////////////program & function///////////////////////////////////////assign HRESP_s = 2'b00;always@(posedge HCLK or negedge HRESETn)begin //HSIZE = 3'b010--32bitsif(!HRESETn) beginram_ADDR <= 18'b000000000000000000;endelse if (HSEL_s == 1'b1)beginram_ADDR <= HADDR_s[19:2];endendassign wr_en = HSEL_s & HTRANS_s[1] & HWRITE_s; always@(posedge HCLK or negedge HRESETn)beginif(!HRESETn)beginram_WRITE <= 1'b0;endelse if(wr_en)beginram_WRITE <= 1'b1;endelsebeginram_WRITE <= 1'b0;endendassign ram_WDATA= HWDATA_s;assign HRDATA_s = ram_RDATA;assign ready_en = HSEL_s & HTRANS_s[1]; always@(posedge HCLK or negedge HRESETn) beginif(!HRESETn)beginHREADY_s <= 1'b0;endelse if(ready_en)beginHREADY_s <= 1'b1;endelsebeginHREADY_s <= 1'b0;endendendmodule。
verilogHDL(王金明版源码)
王金明:《Verilog HDL 程序设计教程》- 1 -【例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)beginif (reset) out<=0; //同步复位else out<=out+1; //计数endendmodule【例3.3】4 位全加器的仿真程序`timescale 1ns/1ns`include "adder4.v"module adder_tp; //测试模块的名字reg[3:0] a,b; //测试输入信号定义为reg 型reg cin;wire[3:0] sum; //测试输出信号定义为wire 型wire cout;integer i,j;adder4 adder(sum,cout,a,b,cin); //调用测试对象always #5 cin=~cin; //设定cin 的取值initialbegina=0;b=0;cin=0;for(i=1;i<16;i=i+1)#10 a=i; //设定a 的取值Endinitialbeginfor(j=1;j<16;j=j+1)#10 b=j; //设定b 的取值Endinitial //定义结果显示格式begin$monitor($time,,,"%d + %d + %b={%b,%d}",a,b,cin,cout,sum);#160 $finish;endendmodule【例3.4】4 位计数器的仿真程序`timescale 1ns/1ns`include "count4.v"module coun4_tp;reg clk,reset; //测试输入信号定义为reg 型wire[3:0] out; //测试输出信号定义为wire 型parameter DELY=100;count4 mycount(out,reset,clk); //调用测试对象always #(DELY/2) clk = ~clk; //产生时钟波形initialbegin //激励信号定义clk =0; reset=0;#DELY reset=1;#DELY reset=0;#(DELY*20) $finish;end//定义结果显示格式initial $monitor($time,,,"clk=%d reset=%d out=%d", clk, reset,out);endmodule【例3.5】“与-或-非”门电路module AOI(A,B,C,D,F); //模块名为AOI(端口列表A,B,C,D,F) input A,B,C,D; //模块的输入端口为A,B,C,Doutput F; //模块的输出端口为Fwire A,B,C,D,F; //定义信号的数据类型assign F= ~((A&B)|(C&D)); //逻辑功能描述endmodule【例5.1】用case 语句描述的4 选1 数据选择器module mux4_1(out,in0,in1,in2,in3,sel);output out;input in0,in1,in2,in3;input[1:0] sel;reg out;always @(in0 or in1 or in2 or in3 or sel) //敏感信号列表case(sel)2'b00: out=in0;2'b01: out=in1;2'b10: out=in2;2'b11: out=in3;default: out=2'bx;endcaseendmodule【例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 上升沿触发beginif (!reset) out = 8'h00; //同步清0,低电平有效else if (load) out = data; //同步预置else out = out + 1; //计数endendmodule【例5.3】用always 过程语句描述的简单算术逻辑单元`define add 3'd0`define minus 3'd1`define band 3'd2`define bor 3'd3`define bnot 3'd4module 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 块begincase(opcode)`add: out = a+b; //加操作`minus: out = a-b; //减操作`band: out = a&b; //求与`bor: out = a|b; //求或`bnot: out=~a; //求反default: out=8'hx; //未收到指令时,输出任意态endcaseendendmodule`timescale 1ns/1ns`include "alu.v"module alu_tb;wire [7:0] out;reg [7:0] a,b;reg [2:0] opcode;initialbegina = 8'h12;b = 8'h34;opcode = `add;#10 opcode = `minus;#10 opcode = `band;#10 opcode = `bor;#10 opcode = `bnot;endalu alu(.out(out),.a(a),.b(b),.opcode(opcode)); endmodule【例5.4】用initial 过程语句对测试变量A、B、C 赋值`timescale 1ns/1nsmodule test;reg A,B,C;initialbeginA = 0;B = 1;C = 0;#50 A = 1; B = 0;#50 A = 0; C = 1;#50 B = 1;#50 B = 0; C = 0;#50 $finish ;endendmodule【例5.5】用begin-end 串行块产生信号波形`timescale 10ns/1nsmodule wave1;reg wave;parameter cycle=10;initialbeginwave=0;#(cycle/2) wave=1;#(cycle/2) wave=0;#(cycle/2) wave=1;#(cycle/2) wave=0;#(cycle/2) wave=1;#(cycle/2) $finish ;endinitial $monitor($time,,,"wave=%b",wave); endmodule【例5.6】用fork-join 并行块产生信号波形`timescale 10ns/1nsmodule wave2;reg wave;parameter cycle=5;initialforkwave=0;#(cycle) wave=1;#(2*cycle) wave=0;#(3*cycle) wave=1;#(4*cycle) wave=0;#(5*cycle) wave=1;#(6*cycle) $finish;joininitial $monitor($time,,,"wave=%b",wave); endmodule【例5.7】持续赋值方式定义的2 选1 多路选择器module MUX21_1(out,a,b,sel);input a,b,sel;output out;assign out=(sel==0)?a:b;//持续赋值,如果sel 为0,则out=a ;否则out=b Endmodule【例5.8】阻塞赋值方式定义的2 选1 多路选择器module MUX21_2(out,a,b,sel);input a,b,sel;output out;reg out;always@(a or b or sel)beginif(sel==0) out=a; //阻塞赋值else out=b;endendmodule【例5.9】非阻塞赋值module non_block(c,b,a,clk);output c,b;input clk,a;reg c,b;always @(posedge clk)beginb<=a;c<=b;endendmodule【例5.10】阻塞赋值module block(c,b,a,clk);output c,b;input clk,a;reg c,b;always @(posedge clk)beginb=a;c=b;endendmodule`timescale 1ns/1ns`include "block.v"module block_tb;wire c,b;reg clk,a;initialbeginclk = 0;a = 0;#30 a = 1;#30 a = 0;#30 a = 1;#30 $stop;endalways #10 clk = ~clk;block block(.c(c),.b(b),.clk(clk),.a(a));endmodule【例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 上升沿时刻计数beginif (reset) qout<=0; //同步复位else if(load) qout<=data; //同步置数else if(cin)beginif(qout[3:0]==9) //低位是否为9,是则beginqout[3:0]<=0; //回0,并判断高位是否为5if (qout[7:4]==5) qout[7:4]<=0;elseqout[7:4]<=qout[7:4]+1; //高位不为5,则加1endelse //低位不为9,则加1qout[3:0]<=qout[3:0]+1;endendassign cout=((qout==8'h59)&cin)?1:0; //产生进位输出信号endmodule`timescale 1ns/1ns`include "count60.v"module count60_tb;wire [7:0] qout;wire cout;reg [7:0] data;reg load,cin,clk,reset;always #5 clk = ~clk;count60cnt(.qout(qout),.cout(cout),.data(data),.load(load),.cin(cin),.cl k(clk),.reset(reset));initialbeginclk = 0;reset = 1;load = 1; cin = 0; data = 8'h25;#20 reset = 0;#20 load = 0;#30 cin = 1;#100 load = 1;#30 load = 0;#300 cin = 0;#50 cin = 1;#500 $stop;endendmodule【例5.12】BCD 码—七段数码管显示译码器module decode4_7(decodeout,indec);output[6:0] decodeout;input[3:0] indec;reg[6:0] decodeout;always @(indec)begincase(indec) //用case 语句进行译码4'd0:decodeout=7'b1111110;4'd1:decodeout=7'b0110000;4'd2:decodeout=7'b1101101;4'd3:decodeout=7'b1111001;4'd4:decodeout=7'b0110011;4'd5:decodeout=7'b1011011;4'd6:decodeout=7'b1011111;4'd7:decodeout=7'b1110000;4'd8:decodeout=7'b1111111;4'd9:decodeout=7'b1111011;default: decodeout=7'bx;endcaseendendmodule【例5.13】用casez 描述的数据选择器module mux_casez(out,a,b,c,d,select); output out;input a,b,c,d;input[3:0] select;reg out;always @(select or a or b or c or d) begincasez(select)4'b1: out = a;4'b??1?: out = b;4'b?1??: out = c;4'b1: out = d;endcaseendendmodule【例5.14】隐含锁存器举例module buried_ff(c,b,a);output c;input b,a;reg c;always @(a or b)beginif((b==1)&&(a==1)) c=a&b;endendmodule【例5.15】用for 语句描述的七人投票表决器module voter7(pass,vote);output pass;input[6:0] vote;reg[2:0] sum;integer i;reg pass;always @(vote)beginsum=0;- 9 -for(i=0;i<=6;i=i+1) //for 语句if(vote[i]) sum=sum+1;if(sum[2]) pass=1; //若超过4 人赞成,则pass=1else pass=0;endendmodule【例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)beginoutcome=0;for(i=1; i<=size; i=i+1) //for 语句if(b[i]) outcome=outcome +(a << (i-1));endendmodule【例5.17】用repeat 实现8 位二进制数的乘法module mult_repeat(outcome,a,b);parameter size=8;input[size:1] a,b;output[2*size:1] outcome;reg[2*size:1] temp_a,outcome;reg[size:1] temp_b;always @(a or b)beginoutcome=0;temp_a=a;temp_b=b;repeat(size) //repeat 语句,size 为循环次数beginif(temp_b[1]) //如果temp_b 的最低位为1,就执行下面的加法outcome=outcome+temp_a;temp_a=temp_a<<1; //操作数a 左移一位程序文本- 10 -temp_b=temp_b>>1; //操作数b 右移一位endendendmodule`include "mult_repeat.v"module mult_repeat_tb;parameter size = 8;reg [size:1] a,b;wire [2*size:1] outcome;initialbegina = 8'h25;b = 8'h16;#10 a = 8'ha4; b = 8'h20;endmult_repeat mult(.a(a),.b(b),.outcome(outcome)); endmodule【例5.18】同一循环的不同实现方式module loop1; //方式1integer i;initialfor(i=0;i<4;i=i+1) //for 语句begin$display(“i=%h”,i);endendmodulemodule loop2; //方式2integer i;initial begini=0;while(i<4) //while 语句begin$display ("i=%h",i);i=i+1;endendendmodulemodule loop3; //方式3integer i;initial begini=0;repeat(4) //repeat 语句begin$display ("i=%h",i);i=i+1;endendendmodule【例5.19】使用了`include 语句的16 位加法器- 11 -`include "adder.v"module adder16(cout,sum,a,b,cin);output cout;parameter my_size=16;output[my_size-1:0] sum;input[my_size-1:0] a,b;input cin;adder my_adder(cout,sum,a,b,cin); //调用adder 模块endmodule//下面是adder 模块代码module adder(cout,sum,a,b,cin);parameter size=16;output cout;output[size-1:0] sum;input cin;input[size-1:0] a,b;assign {cout,sum}=a+b+cin;endmodule【例5.20】条件编译举例module compile(out,A,B);output out;input A,B;`ifdef add //宏名为addassign out=A+B;`elseassign out=A-B;`endifEndmodule【例6.1】加法计数器中的进程module count(data,clk,reset,load,cout,qout);output cout;output[3:0] qout;reg[3:0] qout;input[3:0] data;input clk,reset,load;程序文本- 12 -always @(posedge clk) //进程1,always 过程块beginif (!reset) qout= 4'h00; //同步清0,低电平有效else if (load) qout= data; //同步预置else qout=qout + 1; //加法计数endassign cout=(qout==4'hf)?1:0; //进程2,用持续赋值产生进位信号endmodule【例6.2】任务举例module alutask(code,a,b,c);input[1:0] code;input[3:0] a,b;output[4:0] c;reg[4:0] c;task my_and; //任务定义,注意无端口列表input[3:0] a,b; //a,b,out 名称的作用域范围为task 任务内部output[4:0] out;integer i;beginfor(i=3;i>=0;i=i-1)out[i]=a[i]&b[i]; //按位与endendtaskalways@(code or a or b)begincase(code)2'b00: my_and(a,b,c);/* 调用任务my_and,需注意端口列表的顺序应与任务定义中的一致,这里的a,b,c 分别对应任务定义中的a,b,out */2'b01: c=a|b; //或2'b10: c=a-b; //相减2'b11: c=a+b; //相加endcaseendendmodule- 13 -【例6.3】测试程序`include "alutask.v"module alu_tp;reg[3:0] a,b;reg[1:0] code;wire[4:0] c;parameter DELY = 100;alutask ADD(code,a,b,c); //调用被测试模块initial begincode=4'd0; a= 4'b0000; b= 4'b1111;#DELY code=4'd0; a= 4'b0111; b= 4'b1101;#DELY code=4'd1; a= 4'b0001; b= 4'b0011;#DELY code=4'd2; a= 4'b1001; b= 4'b0011;#DELY code=4'd3; a= 4'b0011; b= 4'b0001;#DELY code=4'd3; a= 4'b0111; b= 4'b1001;#DELY $finish;endinitial $monitor($time,,,"code=%b a=%b b=%b c=%b", code,a,b,c); endmodule【例6.4】函数function[7:0] get0;input[7:0] x;reg[7:0] count;integer i;begincount=0;for (i=0;i<=7;i=i+1)if (x[i]=1'b0) count=count+1;get0=count;endendfunction【例6.5】用函数和case 语句描述的编码器(不含优先顺序)module code_83(din,dout);input[7:0] din;output[2:0] dout;程序文本- 14 -function[2:0] code; //函数定义input[7:0] din; //函数只有输入,输出为函数名本身casex (din)8'b1xxx_xxxx : code = 3'h7;8'b01xx_xxxx : code = 3'h6;8'b001x_xxxx : code = 3'h5;8'b0001_xxxx : code = 3'h4;8'b0000_1xxx : code = 3'h3;8'b0000_01xx : code = 3'h2;8'b0000_001x : code = 3'h1;8'b0000_000x : code = 3'h0;default: code = 3'hx;endcaseendfunctionassign dout = code(din) ; //函数调用endmodule【例6.6】阶乘运算函数module funct(clk,n,result,reset);output[31:0] result;input[3:0] n;input reset,clk;reg[31:0] result;always @(posedge clk) //在clk 的上升沿时执行运算beginif(!reset) result<=0; //复位else beginresult <= 2 * factorial(n); //调用factorial 函数endendfunction[31:0] factorial; //阶乘运算函数定义(注意无端口列表)input[3:0] opa; //函数只能定义输入端,输出端口为函数名本身reg[3:0] i;beginfactorial = opa ? 1 : 0;for(i= 2; i <= opa; i = i+1) //该句若要综合通过,opa 应赋具体的数值factorial = i* factorial; //阶乘运算end- 15 -endfunctionendmodule【例6.7】测试程序`define clk_cycle 50`include "funct.v"module funct_tp;reg[3:0] n;reg reset,clk;wire[31:0] result;initial //定义激励向量beginn=0; reset=1; clk=0;for(n=0;n<=15;n=n+1)#100 n=n;endinitial $monitor($time,,,"n=%d result=%d",n,result);//定义输出显示格式always #1 `clk_cycle clk=~clk; //产生时钟信号funct funct_try(.clk(clk),.n(n),.result(result),.reset(reset)); //调用被测试模块Endmodule【例6.8】顺序执行模块1module serial1(q,a,clk);output q,a;input clk;reg q,a;always @(posedge clk)beginq=~q;a=~q;endendmodule【例6.9】顺序执行模块2module serial2(q,a,clk);output q,a;程序文本- 16 -input clk;reg q,a;always @(posedge clk)begina=~q;q=~q;endendmodule【例6.10】并行执行模块1module paral1(q,a,clk);output q,a;input clk;reg q,a;always @(posedge clk)beginq=~q;endalways @(posedge clk)begina=~q;endendmodule【例6.11】并行执行模块2module paral2(q,a,clk);output q,a;input clk;reg q,a;always @(posedge clk)begina=~q;endalways @(posedge clk)beginq=~q;endendmodule【例7.1】调用门元件实现的4 选1 MUX- 17 -module mux4_1a(out,in1,in2,in3,in4,cntrl1,cntrl2); output out;input in1,in2,in3,in4,cntrl1,cntrl2;wire notcntrl1,notcntrl2,w,x,y,z;not (notcntrl1,cntrl2),(notcntrl2,cntrl2);and (w,in1,notcntrl1,notcntrl2),(x,in2,notcntrl1,cntrl2),(y,in3,cntrl1,notcntrl2),(z,in4,cntrl1,cntrl2);or (out,w,x,y,z);endmodule【例7.2】用case 语句描述的4 选1 MUXmodule mux4_1b(out,in1,in2,in3,in4,cntrl1,cntrl2);output out;input in1,in2,in3,in4,cntrl1,cntrl2;reg out;always@(in1 or in2 or in3 or in4 or cntrl1 or cntrl2)case({cntrl1,cntrl2})2'b00:out=in1;2'b01:out=in2;2'b10:out=in3;2'b11:out=in4;default:out=2'bx;endcaseendmodule【例7.3】行为描述方式实现的4 位计数器module count4(clk,clr,out);input clk,clr;output[3:0] out;reg[3:0] out;always @(posedge clk or posedge clr)beginif (clr) out<=0;else out<=out+1;endendmodule程序文本- 18 -【例7.4】数据流方式描述的4 选1 MUXmodule mux4_1c(out,in1,in2,in3,in4,cntrl1,cntrl2);output out;input in1,in2,in3,in4,cntrl1,cntrl2;assign out=(in1 & ~cntrl1 & ~cntrl2)|(in2 & ~cntrl1 & cntrl2)| (in3 & cntrl1 & ~cntrl2)|(in4 & cntrl1 & cntrl2);Endmodule【例7.5】用条件运算符描述的4 选1 MUXmodule mux4_1d(out,in1,in2,in3,in4,cntrl1,cntrl2);output out;input in1,in2,in3,in4,cntrl1,cntrl2;assign out=cntrl1 ? (cntrl2 ? in4:in3):(cntrl2 ? in2:in1); endmodule【例7.6】门级结构描述的2 选1MUXmodule mux2_1a(out,a,b,sel);output out;input a,b,sel;not (sel_,sel);and (a1,a,sel_),(a2,b,sel);or (out,a1,a2);endmodule【例7.7】行为描述的2 选1MUXmodule mux2_1b(out,a,b,sel); output out;input a,b,sel;reg out;always @(a or b or sel)beginif(sel) out = b;else out = a;endendmodule【例7.8】数据流描述的2 选1MUX module MUX2_1c(out,a,b,sel); output out;- 19 -input a,b,sel;assign out = sel ? b : a; endmodule【例7.9】调用门元件实现的1 位半加器module half_add1(a,b,sum,cout); input a,b;output sum,cout;and (cout,a,b);xor (sum,a,b);endmodule【例7.10】数据流方式描述的1 位半加器module half_add2(a,b,sum,cout); input a,b;output sum,cout;assign sum=a^b;assign cout=a&b;endmodule【例7.11】采用行为描述的1 位半加器module half_add3(a,b,sum,cout); input a,b;output sum,cout;reg sum,cout;always @(a or b)begincase ({a,b}) //真值表描述2'b00: begin sum=0; cout=0; end2'b01: begin sum=1; cout=0; end2'b10: begin sum=1; cout=0; end2'b11: begin sum=0; cout=1; end endcaseendendmodule【例7.12】采用行为描述的1 位半加器module half_add4(a,b,sum,cout); input a,b;output sum,cout;程序文本- 20 -reg sum,cout;always @(a or b)beginsum= a^b;cout=a&b;endendmodule【例7.13】调用门元件实现的1 位全加器module full_add1(a,b,cin,sum,cout); input a,b,cin;output sum,cout;wire s1,m1,m2,m3;and (m1,a,b),(m2,b,cin),(m3,a,cin);xor (s1,a,b),(sum,s1,cin);or (cout,m1,m2,m3);endmodule【例7.14】数据流描述的1 位全加器module full_add2(a,b,cin,sum,cout);input a,b,cin;output sum,cout;assign sum = a ^ b ^ cin;assign cout = (a & b)|(b & cin)|(cin & a);endmodule【例7.15】1 位全加器module full_add3(a,b,cin,sum,cout);input a,b,cin;output sum,cout;assign {cout,sum}=a+b+cin;endmodule【例7.16】行为描述的1 位全加器module full_add4(a,b,cin,sum,cout);input a,b,cin;output sum,cout;- 21 -reg sum,cout; //在always 块中被赋值的变量应定义为reg 型reg m1,m2,m3;always @(a or b or cin)beginsum = (a ^ b) ^ cin;m1 = a & b;m2 = b & cin;m3 = a & cin;cout = (m1|m2)|m3;endendmodule【例7.17】混合描述的1 位全加器module full_add5(a,b,cin,sum,cout);input a,b,cin;output sum,cout;reg cout,m1,m2,m3; //在always 块中被赋值的变量应定义为reg 型wire s1;xor x1(s1,a,b); //调用门元件always @(a or b or cin) //always 块语句beginm1 = a & b;m2 = b & cin;m3 = a & cin;cout = (m1| m2) | m3;endassign sum = s1 ^ cin; //assign 持续赋值语句endmodule【例7.18】结构描述的4 位级连全加器`include "full_add1.v"module add4_1(sum,cout,a,b,cin);output[3:0] sum;output cout;input[3:0] a,b;input cin;full_add1 f0(a[0],b[0],cin,sum[0],cin1); //级连描述full_add1 f1(a[1],b[1],cin1,sum[1],cin2);full_add1 f2(a[2],b[2],cin2,sum[2],cin3);程序文本- 22 -full_add1 f3(a[3],b[3],cin3,sum[3],cout); endmodule【例7.19】数据流描述的4 位全加器module add4_2(cout,sum,a,b,cin);output[3:0] sum;output cout;input[3:0] a,b;input cin;assign {cout,sum}=a+b+cin;endmodule【例7.20】行为描述的4 位全加器module add4_3(cout,sum,a,b,cin);output[3:0] sum;output cout;input[3:0] a,b;input cin;reg[3:0] sum;reg cout;always @(a or b or cin)begin{cout,sum}=a+b+cin;endendmodule【例8.1】$time 与$realtime 的区别`timescale 10ns/1nsmodule time_dif;reg ts;parameter delay=2.6;initialbegin#delay ts=1;#delay ts=0;#delay ts=1;#delay ts=0;endinitial $monitor($time,,,"ts=%b",ts); //使用函数$time- 23 -Endmodule【例8.2】$random 函数的使用`timescale 10ns/1nsmodule random_tp;integer data;integer i;parameter delay=10;initial $monitor($time,,,"data=%b",data);initial beginfor(i=0; i<=100; i=i+1)#delay data=$random; //每次产生一个随机数endendmodule【例8.3】1 位全加器进位输出UDP 元件primitive carry_udp(cout,cin,a,b);input cin,a,b;output cout;table//cin a b : cout //真值表0 0 0 : 0;0 1 0 : 0;0 0 1 : 0;0 1 1 : 1;1 0 0 : 0;1 0 1 : 1;1 1 0 : 1;1 1 1 : 1;endtableendprimitive【例8.4】包含x 态输入的1 位全加器进位输出UDP 元件primitive carry_udpx1(cout,cin,a,b);input cin,a,b;output cout;table// cin a b : cout //真值表0 0 0 : 0;程序文本- 24 -0 1 0 : 0;0 0 1 : 0;0 1 1 : 1;1 0 0 : 0;1 0 1 : 1;1 1 0 : 1;1 1 1 : 1;0 0 x : 0; //只要有两个输入为0,则进位输出肯定为00 x 0 : 0;x 0 0 : 0;1 1 x : 1; //只要有两个输入为1,则进位输出肯定为11 x 1 : 1;x 1 1 : 1;endtableendprimitive【例8.5】用简缩符“?”表述的1 位全加器进位输出UDP 元件primitive carry_udpx2(cout,cin,a,b);input cin,a,b;output cout;// cin a b : cout //真值表0 0 : 0; //只要有两个输入为0,则进位输出肯定为00 ? 0 : 0;0 0 ? : 0;1 1 : 1; //只要有两个输入为1,则进位输出肯定为11 ? 1 : 1;1 1 ? : 1;endtableendprimitive【例8.6】3 选1 多路选择器UDP 元件primitive mux31(Y,in0,in1,in2,s2,s1);input in0,in1,in2,s2,s1;output Y;table//in0 in1 in2 s2 s1 : Y0 ? ? 0 0 : 0; //当s2s1=00 时,Y=in01 ? ? 0 0 : 1;0 0 1 : 0; //当s2s1=01 时,Y=in1- 25 -1 0 1 : 1;0 1 : 0; //当s2s1=1?时,Y=in21 1 : 1;0 0 ? 0 ? : 0;1 1 ? 0 ? : 1;0 ? 0 ? 0 : 0;1 ? 1 ? 0 : 1;0 0 1 : 0;1 1 1 : 1;endtableendprimitive【例8.7】电平敏感的1 位数据锁存器UDP 元件primitive latch(Q,clk,reset,D);input clk,reset,D;output Q;initial Q = 1'b1; //初始化table// clk reset D : state : Q1 : : 0 ; //reset=1,则不管其他端口为什么值,输出都为0 0 0 0 : ? : 0 ; //clk=0,锁存器把D 端的输入值输出0 0 1 : ? : 1 ;1 0 ? : ? : - ; //clk=1,锁存器的输出保持原值,用符号“-”表示endtableendprimitive【例8.8】上升沿触发的D 触__________发器UDP 元件primitive DFF(Q,D,clk);output Q;input D,clk;reg Q;table//clk D : state : Q(01) 0 : ? : 0; //上升沿到来,输出Q=D(01) 1 : ? : 1;(0x) 1 : 1 : 1;(0x) 0 : 0 : 0;(?0) ? : ? : -; //没有上升沿到来,输出Q 保持原值() : : - ; //时钟不变,输出也不变程序文本- 26 -endtableendprimitive【例8.9】带异步置1 和异步清零的上升沿触发的D 触发器UDP 元件primitive DFF_UDP(Q,D,clk,clr,set);output Q;input D,clk,clr,set;reg Q;table// clk D clr set : state : Q(01) 1 0 0 : ? : 0;(01) 1 0 x : ? : 0;0 x : 0 : 0;(01) 0 0 0 : ? : 1;(01) 0 x 0 : ? : 1;x 0 : 1 : 1;(x1) 1 0 0 : 0 : 0;(x1) 0 0 0 : 1 : 1;(0x) 1 0 0 : 0 : 0;(0x) 0 0 0 : 1 : 1;1 : : 1; //异步复位 0 1 : : 0; //异步置1n ? 0 0 : ? : -;* : : -;(0) : : -;(0): : -;: : x;endtableendprimitive【例8.12】延迟定义块举例module delay(out,a,b,c); output out;input a,b,c;and a1(n1,a,b);or o1(out,c,n1);specify(a=>out)=2;(b=>out)=3;(c=>out)=1;- 27 -endspecifyendmodule【例8.13】激励波形的描述'timescale 1ns/1nsmodule test1;reg A,B,C;initialbegin //激励波形描述A = 0;B = 1;C = 0;#100 C = 1;#100 A = 1; B = 0;#100 A = 0;#100 C = 0;#100 $finish;endinitial $monitor($time,,,"A=%d B=%d C=%d",A,B,C); //显示endmodule【例8.15】用always 过程块产生两个时钟信号module test2;reg clk1,clk2;parameter CYCLE = 100;alwaysbegin{clk1,clk2} = 2'b10;#(CYCLE/4) {clk1,clk2} = 2'b01;#(CYCLE/4) {clk1,clk2} = 2'b11;#(CYCLE/4) {clk1,clk2} = 2'b00;#(CYCLE/4) {clk1,clk2} = 2'b10;endinitial $monitor($time,,,"clk1=%b clk2=%b",clk1,clk2); endmodule【例8.17】存储器在仿真程序中的应用module ROM(addr,data,oe);output[7:0] data; //数据信号input[14:0] addr; //地址信号input oe; //读使能信号,低电平有效程序文本- 28 -reg[7:0] mem[0:255]; //存储器定义parameter DELAY = 100;assign #DELAY data=(oe==0) ? mem[addr] : 8'hzz;initial $readmemh("rom.hex",mem); //从文件中读入数据endmodule【例8.18】8 位乘法器的仿真程序`timescale 10ns/1nsmodule mult8_tp; //测试模块的名字reg[7:0] a,b; //测试输入信号定义为reg 型wire [15:0] out; //测试输出信号定义为wire 型integer i,j;mult8 m1(out,a,b); //调用测试对象//激励波形设定initialbegina=0;b=0;for(i=1;i<255;i=i+1)#10 a=i;endinitialbeginfor(j=1;j<255;j=j+1)#10 b=j;endinitial //定义结果显示格式begin$monitor($time,,,"%d * %d= %d",a,b,out); #2560 $finish;endendmodulemodule mult8(out, a, b); //8 位乘法器源代码parameter size=8;input[size:1] a,b; //两个操作数output[2*size:1] out; //结果assign out=a*b; //乘法运算符- 29 -Endmodule【例8.19】8 位加法器的仿真程序`timescale 1ns/1nsmodule add8_tp; //仿真模块无端口列表reg[7:0] A,B; //输入激励信号定义为reg 型reg cin;wire[7:0] SUM; //输出信号定义为wire 型wire cout;parameter DELY = 100;add8 AD1(SUM,cout,A,B,cin); //调用测试对象initial begin //激励波形设定A= 8'd0; B= 8'd0; cin=1'b0;#DELY A= 8'd100; B= 8'd200; cin=1'b1;#DELY A= 8'd200; B= 8'd88;#DELY A= 8'd210; B= 8'd18; cin=1'b0;#DELY A= 8'd12; B= 8'd12;#DELY A= 8'd100; B= 8'd154;#DELY A= 8'd255; B= 8'd255; cin=1'b1;#DELY $finish;end//输出格式定义initial $monitor($time,,,"%d + %d + %b = {%b, %d}",A,B,cin,cout,SUM); endmodulemodule add8(SUM,cout,A,B,cin); //待测试的8 位加法器模块output[7:0] SUM;output cout;input[7:0] A,B;input cin;assign {cout,SUM}=A+B+cin;endmodule【例8.20】2 选1 多路选择器的仿真`timescale 1ns/1nsmodule mux_tp;reg a,b,sel;wire out;程序文本- 30 -MUX2_1 m1(out,a,b,sel); //调用待测试模块initialbegina=1'b0; b=1'b0; sel=1'b0;#5 sel=1'b1;#5 a=1'b1; sel=1'b0;#5 sel=1'b1;#5 a=1'b0; b=1'b1; sel=1'b0;#5 sel=1'b1;#5 a=1'b1; b=1'b1; sel=1'b0;#5 sel=1'b1;endinitial $monitor($time,,,"a=%b b=%b sel=%b out=%b",a,b,sel,out); endmodulemodule MUX2_1(out,a,b,sel); //待测试的2 选1MUX 模块input a,b,sel;output out;not #(0.4,0.3) (sel_,sel); //#(0.4,0.3)为门延时and #(0.7,0.6) (a1,a,sel_);and #(0.7,0.6) (a2,b,sel);or #(0.7,0.6) (out,a1,a2);endmodule【例8.21】8 位计数器的仿真`timescale 10ns/1nsmodule counter8_tp;reg clk,reset; //输入激励信号定义为reg 型wire[7:0] qout; //输出信号定义为wire 型parameter DELY=100;counter8 C1(qout,reset,clk); //调用测试对象always #(DELY/2) clk = ~clk; //产生时钟波形initialbegin //激励波形定义clk =0; reset=0;- 31 -#DELY reset=1;#DELY reset=0;#(DELY*300) $finish;end//结果显示initial $monitor($time,,,"clk=%d reset=%d qout=%d",clk,reset,qout); endmodulemodule counter8(qout,reset,clk); //待测试的8 位计数器模块output[7:0] qout;input clk,reset;reg[7:0] qout;always @(posedge clk)begin if (reset) qout<=0;else qout<=qout+1;endendmodule【例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;程序文本- 32 -reg F;always @(A or B or C or D) //过程赋值beginF=(A&B)|(B&C&D);endendmodule【例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- 33 -if(en) temp=bidir;else temp=temp+1;endendmodule【例9.6】3-8 译码器module decoder_38(out,in);output[7:0] out;input[2:0] in;reg[7:0] out;always @(in)begincase(in)3'd0: out=8'b11111110;3'd1: out=8'b11111101;3'd2: out=8'b11111011;3'd3: out=8'b11110111;3'd4: out=8'b11101111;3'd5: out=8'b11011111;3'd6: out=8'b10111111;3'd7: out=8'b01111111;endcaseendendmodule【例9.7】8-3 优先编码器module encoder8_3(none_on,outcode,a,b,c,d,e,f,g,h); output none_on;output[2:0] outcode;input a,b,c,d,e,f,g,h;reg[3:0] outtemp;assign {none_on,outcode}=outtemp;always @(a or b or c or d or e or f or g or h)beginif(h) outtemp=4'b0111;else if(g) outtemp=4'b0110;else if(f) outtemp=4'b0101;else if(e) outtemp=4'b0100;else if(d) outtemp=4'b0011;。
Verilog语言实现并行(循环冗余码)CRC校验
Verilog语⾔实现并⾏(循环冗余码)CRC校验1 前⾔(1)什么是CRC校验?CRC即循环冗余校验码:是数据通信领域中最常⽤的⼀种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。
循环冗余检查(CRC)是⼀种数据传输检错功能,对数据进⾏多项式计算,并将得到的结果附在帧的后⾯,接收设备也执⾏类似的算法,以保证数据传输的正确性和完整性。
LFSR计算CRC,可以⽤多项式G(x)表⽰,G(x) = X16+X12+X5+1模型可如下图所⽰。
(2)校验原理其根本思想就是先在要发送的帧后⾯附加⼀个数(这个就是⽤来校验的校验码,但要注意,这⾥的数也是⼆进制序列的,下同),⽣成⼀个新帧发送给接收端。
当然,这个附加的数不是随意的,它要使所⽣成的新帧能与发送端和接收端共同选定的某个特定数整除(注意,这⾥不是直接采⽤⼆进制除法,⽽是采⽤⼀种称之为“模2除法”)。
到达接收端后,再把接收到的新帧除以(同样采⽤“模2除法”)这个选定的除数。
因为在发送端发送数据帧之前就已通过附加⼀个数,做了“去余”处理(也就已经能整除了),所以结果应该是没有余数。
如果有余数,则表明该帧在传输过程中出现了差错。
要校验的数据加上此数据计算出来的crc组成新的数据帧,如下图所⽰。
模2除法:模2除法与算术除法类似,但每⼀位除的结果不影响其它位,即不向上⼀位借位,所以实际上就是异或。
在循环冗余校验码(CRC)的计算中有应⽤到模2除法。
(3)步骤CRC校验中有两个关键点,⼀是预先确定⼀个发送送端和接收端都⽤来作为除数的⼆进制⽐特串(或多项式),可以随机选择,也可以使⽤国际标准,但是最⾼位和最低位必须为1;⼆是把原始帧与上⾯计算出的除数进⾏模2除法运算,计算出CRC码。
1. 选择合适的除数2. 看选定除数的⼆进制位数,然后再要发送的数据帧上⾯加上这个位数-1位的0,然后⽤新⽣成的帧以模2除法的⽅式除上⾯的除数,得到的余数就是该帧的CRC校验码。
双口RAM的verilog描述
双口RAM的verilog描述
双口RAM的verilog描述
分类:数字电路
* RAM的verilog描述如下:
module ram(din,ain,dout,aout,rd,wr);//这是一个双口RAM,分别有:
//输入端:输入地址ain;输入数据din;上升沿有效的写信号wr;
//输出端:输出地址aout;输出数据dout;高电平有效的读信号rd;
inout [7:0] din;
input [7:0] ain,aout;
input rd,wr;
output [7:0] dout;
reg [7:0] memory [0:255]; //请注意这是存储阵列的描述方法,描述了一个共有2 56个字的存储阵列,
//每个字是8位
assign dout = rd ? memory[aout] : 8'bz; //"assign"关键字表示并行赋值语句的
开始
//"?"运算符的作用和在C语言中一样
//"?"运算符的作用和在C语言中一样
//"8'bz"是一个常量,表示一个字节的高阻态,其中
//8表示长度是8bit,"'"是固定分割符,"b"表示后面的数据是以比特形式给出的, //"z"表示高阻;
//举例:4'ha表示长4bit的数"1010"
//类似的还可举出5'b10111,6'o33等等
always @(posedge wr)
memory[ain] = din;
endmodule。
IP核——RAM
IP核——RAM⼀、Quartus1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager2.弹出创建页⾯,选择Creat a new custom megafunction variation,点Next3.选择IP核,可以直接搜索ram,选择RAM:2-PORT,右上⽅选择器件型号,语⾔选成Verilog,再填写⼀下路径名字,点Next,后⾯就是参数设置了。
4.设置读写需要⼏个端⼝,深度计算按word还是bit。
Next5.设置深度,位宽,类型。
Next6.设置读写需要⼏个端⼝,深度计算按word还是bit,⼀般选word。
Next7.是否为输出添加⼀个寄存器(加了寄存器可以使RAM输出的数据更稳定)?本来ram的输出就是会慢1clk,勾选后⼜慢1clk,所以⼀般不勾选。
Next8.输出的是新数据还是⽼数据,⼀般是要新数据,所以I don't care就⾏。
Next9.是否添加初始化⽂件mif ? Next10.告诉你此IP核的编译库是什么,Next11.输出的⽂件列表,除了正常IP核,还可以选择例化⽂件,注意bb.v⽂件⽤不到,⼀般是不勾选的。
之后点finish就⽣成IP核了。
⼆、ISE1.创建ISE⼯程,IP核需要在ISE⼯程⾥⾯进⾏调⽤。
点击Tools---Core Generator...2.在新弹出来的界⾯中创建⼀个属于IP核的⼯程:file---new project,并填写⽂件存储位置和⽂件名称,⼀般为ipcore_dir⽂件夹,点击保存3.弹出的Part处填写器件的系列、型号、封装以及速度等级,Generation处设置语⾔为Verilog,点击OK4.点击⽂件夹,找到Memories & Storage Elements---RAMs & ROMs---Block Memory Generator,(也可以直接搜索)双击打开,进⾏参数设置5.设置模块名称,Next6.类型选择,⼀般选Single Dual RAM,该RAM为“a⼝负责写,b⼝负责读”,⽽对于真双⼝RAM来说,a和b都是可读可写。
FIFO
FIFO1、实验目的FIFO(First in First out),使用在需要产生数据接口的部分,用来存储、缓冲在两个异部时钟之间的数据传输。
在异部电路中,由于时钟之间周期和相位完全独立,因此数据丢失概率不为零。
使用FIFO可以在两个不同时钟域系统之间快速而方便地传输实时数据。
这次实验我们就来学习一下如何用 Robei 和Verilog 语言来设计一个8位4深度的FIFO。
2、实验准备图1、fifo原理框图通过分析,我们看到图1中有一个具有独立的读端口和独立的写端口的 RAM 存储器。
这样选择是为了分析方便。
如果是一个单端口的存储器,还应包含一个仲裁器保证同一时刻只能进行一项操作(读或写),我们选择双口 RAM(无需真正的双口 RAM,因为我们只是希望有一个简单的相互独立的读写端口)是因为这些实例非常接近实际情况。
读、写端口拥有两个计数器(wp_p1、rp_p1)产生的互相独立的读、写地址。
计数器的值在读写使能信号来临时传递给“读指针”(rp)和“写指针”(wp)。
写指针指向下一个将要写入的位置,读指针指向下一个将要读取的位置。
每次写操作使写指针加 1,读操作使读指针加 1。
左右两侧的模块为读写指针与满空信号产生模块。
这两个模块的任务是给 FIFO 提供“空”(empty)和“满”(full)信号。
这些信号告诉外部电路 FIFO 已经达到了临界条件:如果出现“满”信号,那么 FIFO 为写操作的临界状态,如果出现“空”信号,则 FIFO 为读操作的临界状态。
写操作的临界状态表示 FIFO 已经没有空间来存储更多的数据,读操作的临界表示 FIFO 没有更多的数据可以读出。
读写指针与满空信号产生模块还可告诉 FIFO 中“满”或“空”位置的数值。
这是由指针的算术运算来完成了。
实际的“满”或“空”位置计算并不是为 FIFO 自身提供的。
它是作为一个报告机构给外部电路用的。
但是,“满”和“空”信号在 FIFO 中却扮演着非常重要的角色,它为了能实现读与写操作各自的独立运行而阻塞性的管理数据的存取。
Verilog语言编程规范
Verilog语⾔编程规范前⾔.................................................................... IV 1范围 (1)2术语 (1)3代码标准 (1)3.1命名规范 (1)3.1.1⽂件命名 (1)3.1.2HDL代码命名总则 (2)3.2注释 (4)3.2.1⽂件头 (4)3.2.2其它注释 (5)3.3编程风格 (7)3.3.1编写代码格式要整齐 (7)3.3.2使⽤⼆到四个空格符缩排 (7)3.3.3⼀⾏⼀条Verilog语句 (7)3.3.4⼀⾏⼀个端⼝声明 (7)3.3.5在定义端⼝时,按照端⼝类型或端⼝功能定义端⼝顺序。
(8) 3.3.6保持端⼝顺序⼀致。
(8)3.3.7声明内部net (8)3.3.8在⼀个段内声明所有内部net (8)3.3.9每⾏长度不超过80字符....................... 错误!未定义书签。
3.3.10代码流中不同结构之间⽤⼀空⾏隔开 (8)3.4模块划分和重⽤ (10)3.4.1不能访问模块外部的net和variable (10)3.4.2不使⽤`include编译指令 (10)3.4.3建议模块的端⼝信号尽可能少。
(10)3.4.4时钟产⽣电路单独构成⼀个模块 (10)3.4.5划分时钟域 (10)3.4.6物理和逻辑边界的匹配 (10)3.4.7特定应⽤代码要单独划分出来 (10)3.4.8关键时序逻辑划分 (10)3.4.9数据流逻辑划分 (11)3.4.10异步逻辑划分 (11)3.4.11状态机划分 (11)3.4.12控制逻辑和存储器划分 (11)3.5逻辑设计经验 (11)3.5.1时钟域要尽可能少,所⽤时钟尽可能加全局BUFF (11) 3.5.2异步接⼝信号同步化 (11)3.5.3避免寄存器的数据与时钟异步 (11)3.5.4使⽤⽆⽑刺的门控时钟使能信号 (11)3.5.5直接作⽤信号⽆⽑刺 (11)3.5.6初始化控制存储元件 (12)3.5.7使⽤同步设计 (12)3.5.8避免组合反馈环 (12)3.6常⽤编程技巧 (12)3.6.1条件表达式的值必须是⼀个单bit值 (12)3.6.2总线位顺序按⾼到低保持⼀致 (12)3.6.3不要给信号赋x值 (12)3.6.4寄存器变量只能在⼀个always语句中赋值 (12)3.6.5对常量使⽤参数⽽不使⽤⽂本宏 (12)3.6.6不能重复定义参数 (12)3.6.7不能重复定义⽂本宏 (12)3.6.8保持常量之间的联系 (12)3.6.9状态编码的参数使⽤ (13)3.6.10`define、`undef配合使⽤ (13)3.6.11⽤基地址+地址偏移量⽣成地址 (13)3.6.12使⽤⽂本宏表⽰寄存器字段位置和值 (13)3.6.13`ifdef的嵌套限制在三层以内 (13)3.6.14操作数的位宽必须匹配 (13)3.6.15模块调⽤时端⼝要显式引⽤ (14)3.6.16⽮量端⼝和net/variable声明的位宽要匹配 (14)3.6.17避免inout类型的端⼝ (14)3.6.18在复杂的表达式中使⽤括号 (14)3.7常⽤综合标准 (14)3.7.1always 的敏感列表要完整 (14)3.7.2⼀个 always 的敏感列表中只能有⼀个时钟 (14)3.7.3只使⽤可综合的结构 (15)3.7.4组合逻辑的条件需完备 (15)3.7.5循环结构中禁⽤disable语句 (15)3.7.6避免⽆界循环 (15)3.7.7端⼝连接禁⽤表达式 (15)3.7.8禁⽤Verilog primitive (15)3.7.9边沿敏感结构中使⽤⾮阻塞赋值(<=) (15)3.7.10Latch使⽤⾮阻塞赋值 (15)3.7.11模块闲置的输⼊端不要悬空 (15)3.7.12连接模块闲置的输出端 (16)3.7.13函数中不要使⽤锁存器 (16)3.7.14禁⽤casex (16)3.7.15多周期路径的信号使⽤单周期使能信号 (16)3.7.16三态元件建模 (16)3.7.17避免顶层胶合逻辑 (16)3.7.18在case语句中使⽤default赋值语句 (16)3.7.19full_case综合命令的使⽤ (16)附录1 HDL编译器不⽀持的Verilog结构 (18)附录2 Verilog和VHDL关键词列表 (19)前⾔编写本标准的⽬的是为了统⼀部门内部FPGA\EPLD设计⽤verilog语⾔编程风格,提⾼Verilog设计源代码的可读性、可靠性和可重⽤性,减少维护成本,最终提⾼产品⽣产⼒;并且以此作为代码⾛查的标准。
FIFO同步、异步以及Verilog代码实现
FIFO同步、异步以及Verilog代码实现FIFO 很重要,之前参加的各类电⼦公司的逻辑设计的笔试⼏乎都会考到。
FIFO是英⽂First In First Out 的缩写,是⼀种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使⽤起来⾮常简单,但缺点就是只能顺序写⼊数据,顺序的读出数据, 其数据地址由内部读写指针⾃动加1完成,不能像普通存储器那样可以由地址线决定读取或写⼊某个指定的地址。
FIFO⼀般⽤于不同时钟域之间的数据传输,⽐如FIFO的⼀端是AD数据采集, 另⼀端是计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,⽽PCI总线的速度为33MHz,总线宽度32bit,其最⼤传输速率为 1056Mbps,在两个不同的时钟域间就可以采⽤FIFO来作为数据缓冲。
另外对于不同宽度的数据接⼝也可以⽤FIFO,例如单⽚机位8位数据输出,⽽ DSP可能是16位数据输⼊,在单⽚机与DSP连接时就可以使⽤FIFO来达到数据匹配的⽬的。
FIFO的分类根均FIFO⼯作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。
同步FIFO是指读时钟和写时钟为同⼀个时钟。
在时钟沿来临时同时发⽣读写操作。
异步FIFO是指读写时钟不⼀致,读写时钟是互相独⽴的。
FIFO设计的难点 FIFO设计的难点在于怎样判断FIFO的空/满状态。
为了保证数据正确的写⼊或读出,⽽不发⽣益处或读空的状态出现,必须保证FIFO在满的情况下,不 能进⾏写操作。
在空的状态下不能进⾏读操作。
怎样判断FIFO的满/空就成了FIFO设计的核⼼问题。
.........................................................................................................................................同步FIFO的Verilog代码之⼀在modlesim中验证过。
verilog状态机
基于Verilog应用2007-09-18 16:25:19 来源:电子技术应用关键字:可编程逻辑器件Verilog HDL FIFO FSM随着数字时代的到来,数字技术的应用已经渗透到了人类生活的各个方面。
数字系统的发展在很大程度上得益于器件和集成技术的发展,著名的摩尔定律(Moore's Law)的预言也在集成电路的发展过程中被印证了,数字系统的设计理念和设计方法在这过程中发生了深刻的变化。
从电子CAD、电子CAE到电子设计自动化(EDA),随着设计复杂程度的不断增加,设计的自动化程度越来越高。
目前,EDA技术作为电子设计的通用平台,逐渐向支持系统级的设计发展;数字系统的设计也从图形设计方案向硬件描述语言设计方案发展。
可编程器件在数字系统设计领域得到广泛应用,不仅缩短了系统开发周期,而且利用器件的现场可编程特性,可根据应用的要求对器件进行动态配置或编程,简单易行地完成功能的添加和修改。
在现代工业的发展中,实时测控系统得到广泛应用,这就对高速数字信号处理系统提出了更高的要求。
因为要涉及大量的设计,为了提高运算速度,应用了大量DSP器件。
数字采集系统是整个系统的核心部分之一,传统方法是应用MCU或DSP通过软件控制数据采集的模/数转换,这样必将频繁中断系统的运行从而减弱系统的数据运算,数据采集的速度也将受到限制。
因此,DSP+CPLD的方案被认为是数字信号处理系统的最优方案之一,由硬件控制模/数转换和数据存储,从而最大限度地提高系统的信号采集和处理能力。
1 系统总体方案数据采集系统是基于DSP的信号处理系统中的一部分。
框图如图1所示。
该数字信号处理系统用于随机共振理论在弱信号检测中的应用研究中。
整个系统由信号放大、信号滤波、信号采样、高速数字信号处理、与主计算机的高速数据传输接口等部分组成。
其中,信号放大是对输入信号进行调理以满足采样的要求;信号滤波是防止信号产生“混叠现象”;信号采样是完成模拟信号的数字化;高速数字信号处理是在建立随机共振模型的基础上完成各种算法;与主计算机的高速数据传输接口是满足信号检测的实时性,将DSP处理的数据传给计算机以进行进一步的处理。
Verilog语法详细解读
语法详细讲解
简单RAM建模
上述模型是可综合的,但是许多工具只产生一系列的寄存器,这一般 就需要更大的空间,从而比实际的存储器的价格更昂贵。
虽然传递给任务的参数名可以和任务内部io声明的参数名相同但是为了提高任务的模块化程度传递给任务的参数名通常是唯一的而不使用与任务内部io声明的参数名相同的参数名
语法详细讲解
强制激励
在一个过程块中,可以用两种不同的方式对信号变量或表达式进 行连续赋值。
过程连续赋值往往是不可以综合的,通常用在测试模块中。 两种方式都有各自配套的命令来停止赋值过程。 两种不同方式均不允许赋值语句间的时间控制。 assign和deassign 适用于对寄存器类型的信号(例如:RTL级上 的节点或测试模块中在多个地方被赋值的信号)进行赋值。 initial begin #10 assign top.dut.fsml.state_reg = `init_state;
存储建模
目标 学会使用Verilog进行存储建模。
学会在Verilog中进行双向口建模。
语法详细讲解
存储设备建模
存储设备建模必须注意以下两个方面的问题:
声明存储容量的大小。 提供对内容的访问权限,例如: 只读 读写 同步读写 多次读,同时进行一次写 多次同步读写,同时提供一些方法保证一致性
语法详细讲解
语法详细讲解
怎样使用双向口
使用inout关键字声明双向口。 inout [7:0] databus;