end
always@(posedge clk) begin
{cout,sum}={firsta[2:0]+firstb[2:0]+firstco,firstsum}; end endmodule
使用流水线的方法,最重要的是将未用到的数据进行存储,这样做使得流水线不同级之间相互独立,这样做大大提高了速度(除了第一次运算需要额外的两个时钟周期),但是这样的设计使用大量资源,这需要在性能和资源中进行折衷。
使用的资源:
我们从图中可以看出,流水线极大提高了触发器的使用量,是典型的以面积换取速度的例子。
小结:通过对加法器的各种设计以及编码风格,我们可以看出Verilog HDL——硬件描述语言的优势,不同的编码风格所产生的电路在速度与面积上都将产生不同的变化,要学好HDL,则需要经验的积累和对电路结构的了解,必须明白语言与电路之间的对应关系,这样,Verilog语言才能用得得心应手。 反思:Verilog的编码与FPGA内部结构、内部器件特性有着很大关系,要编写一个好的代码,学习FPGA内部结构成为必不可少的一个阶段。
4.有限状态机 时序电路由组合电路和存储电路组成,时序电路是状态依赖的,所以称为状态机。 其中Melay状态机,其状态与当前状态,输入,输出均有关系,而Moore状态机则只跟当前状态有关,一下用两个实例对其进行探讨。 (1)Melay状态机
module serial_checkout(same,din,clk,rst); input din; input clk,rst; output same; reg [2:0] status; reg same_temp; //Write down your serial which you want to check out parameter serial_number = 8'h11010011; //check the lowest bit first parameter bit1 = 1'b1; parameter bit2 = 1'b1; parameter bit3 = 1'b0; parameter bit4 = 1'b0; parameter bit5 = 1'b1; parameter bit6 = 1'b0; parameter bit7 = 1'b1; parameter bit8 = 1'b1; assign same = same_temp; always @ (posedge clk or negedge rst) if(rst == 0) begin status <= 3'b000; same_temp <= 1'b0; end else case(status) 3'b000:begin if(din==bit1) status <= 3'b001; else status <= 3'b000; end 3'b001:begin if(din==bit2) status <= 3'b010; else status <= 3'b000; end 3'b010:begin if(din==bit3) status <= 3'b011; else status <= 3'b000; end 3'b011:begin if(din==bit4)
status <= 3'b100; else status <= 3'b000; end 3'b100:begin if(din==bit5) status <= 3'b101; else status <= 3'b000; end 3'b101:begin if(din==bit6) status <= 3'b110; else status <= 3'b000; end 3'b110:begin if(din==bit7) status <= 3'b111; else status <= 3'b000; end 3'b111:begin if(din==bit8) same_temp <= 1; else status <= 3'b000; end endcase endmodule
上述是使用Melay状态机实现的序列检测模块的完整代码,每一个状态都与输入有关,当所有状态均通过时,same_temp输出1以表示检测到特定序列。
(2)Moore状态机:实现LCD1602的初始化,显示和移位输出 module LCD1602_ctrl_8data(clk,rst,lcd_data,lcd_rs,lcd_rw,lcd_en);
input clk,rst; //系统时钟与系统复位信号 output lcd_rs,lcd_rw,lcd_en; //rs命令/数据选择信号,rw读/写数据选择信号,en操作使能 output [7:0] lcd_data; //8位数据总线 //如果要求lcd_data为inout型引脚,这时候只能为wire型,需要使用reg变量驱动他 //暂时没有输入,只作演示说明 reg lcd_rs,lcd_rw,lcd_en; reg [7:0] lcd_data;
reg [3:0] stage; reg [7:0] ddram_address; reg [4:0] shift_count; reg [7:0] shift_freq; reg flag,shift_flag;
//命令参数 parameter START =4'b0000; // RS RW D7 D6 D5 D4 D3 D2 D1 D0
//指令1:清? 0 0 0 0 0 0 0 0 0 1 parameter CLEAR_SCREEN =4'b0001; //指令2:光标复位 0 0 0 0 0 0 0 0 1 0 //光标回到00h地址 parameter CURSOR_BACK =4'b0010; //指令3:置输入模式 0 0 0 0 0 0 0 1 I/D S //光标和显示模式设置-> I/D:光标移动方向,I/D=1时右移(当读写一个字符后,地址指针加1),I/D=0时左移(当读写一个字符后,地址指针减1) S:当写一个字符屏幕上所有文字是否左移(I/D=1)或者右移(I/D=0)。S=1时表示有效,S=0时则无效 parameter SETMODE =4'b0011; parameter CURSOR_MOVE_RIGHT =1; parameter CURSOR_MOVE_LEFT =0; parameter WORD_SHIFT =1; parameter WORD_NOSHIFT =0; // RS RW D7 D6 D5 D4 D3 D2 D1 D0 //指令4:显示开关控制 0 0 0 0 0 0 1 D C B //D:控制整体显示的开与关,D=1表示开显示,D=0表示关显示 //C:控制光标的开与关,C=1表示有光标,C=0表示无光标 //B:控制光标是否闪烁,B=1闪烁,B=0不闪烁;闪烁只对于当前地址指针指向的字符位有效。 parameter DISPLAY_CTRL_OFF =4'b0100; parameter DISPLAY_ON =1; parameter DISPLAY_OFF =0; parameter CURSOR_ON =1; parameter CURSOR_OFF =0; parameter CURSOR_FLASH_ON =1; parameter CURSOR_FLASH_OFF =0; // RS RW D7 D6 D5 D4 D3 D2 D1 D0 //指令5:光标或字符移动0 0 0 0 0 1 S/C R/L 0 0 //S/C:滚动对象选择:S/C=1时移动显示的文字,S/C=0时移动光标 //R/L:滚动方向选择:R/L=1时向右滚动,R/L=0 向左滚动 parameter SHIFT =4'b0101; parameter SEL_WORD =1; parameter SEL_CURSOR =0;
parameter RIGHT_SHIFT =1; parameter LEFT_SHIFT =0; // RS RW D7 D6 D5 D4 D3 D2 D1 D0 //指令6:功能设置命令 0 0 0 0 1 D/L N F 0 0 //D/L:DL=1时为8位总线(DB7-DB0有效),D/L=0?位(DB7-DB4行В? //N:N=0时为单行显示,N=1时双行显示 //F: F=0时?x7的阏字符,F=1时显示5x10的阏笾? parameter SETFUNCTION =4'b0110; parameter DATAWIDTH8 =1; parameter DATAWIDTH4 =0; parameter TWOLINE_DISPLAY =1; parameter ONELINE_DISPLAY =0; parameter FONT5x10 =1; parameter FONT5x7 =0; // RS RW D7 D6 D5 D4 D3 D2 D1 D0 //指令7:置字符发生器贮存地址 0 0 0 1 ( AGG ) //AGG:设置CGRAM地址,AGG高三位为自定义字符代码,低三位为字模数据地址(5X8),可最多定义8个字符调用自定义字符时,调?~7这8? parameter SETCGRAM =4'b0111; // RS RW D7 D6 D5 D4 D3 D2 D1 D0
//指令8:置数据存贮器地址 0 0 1 ( ADD ) //ADD:DDRAM地址 parameter SETDDRAM =4'b1000; //指令9:读忙信号(不用) parameter RESERVE =4'b1001; // RS RW D7 D6 D5 D4 D3 D2 D1 D0 //指令10:写RAM数据 1 0 ( data )
parameter WRITE_RAM =4'b1010; // RS RW D7 D6 D5 D4 D3 D2 D1 D0
1 1 (
data
//指令11:读RAM数据 ) parameter READ_RAM parameter STOP //parameter DELAY parameter DISPLAY_CTRL_ON parameter SETFUNCTION2
//时钟信号 reg [15:0] clkcnt; //分频函数 always @ (posedge clk) begin if(!rst)
=4'b1011;
=4'b1100; =4'b1101; =4'b1110; =4'b1111;