1.FPGA纯组合逻辑电路
二选一选择器
1. 编写HDL描述文件
module ux2( //所有的verilog都是从module开始的 module 模块名 (端口名1,端口名2)
a,
b, //端口名
sel,
out
);
//端口定义
input a;
input b; //这里只用输入 输出端口 无inout输入输出端口
input sel;
output out;
//端口功能
//assign out = (sel == 1)? b:a; //assign持续赋值语句
assign out = sel ? b:a;
endmodule
2.编写测试脚本(testbench)
`timescale 1ns/1ns //`timescale是Verilog中的预编译指令,指定位于它后边的module的时间单位和时间精度,直到遇到新的`timescale指令或者aresetall指令ms
module ux2_tb();
//定义激励源 数据类型
reg a1; //a 寄存器型(reg)
reg a2; //b的激励源
reg a3; //sel的
wire a4; //out的 连线型(wire)
ux2 ux2_0( //ux2第一次例化 第一次仿真
//端口列表
.a(a1), //加点表示例化 ()里加激励源
.b(a2),
.sel(a3),
.out(a4)
);
//verilog中有两种结构化的过程语句:initial语句和always语句
initial begin
a1=0;a2=0;a3=0;
#100;
a1=1;a2=0;a3=0;
#100;
a1=0;a2=1;a3=0;
#100;
a1=1;a2=1;a3=0;
#100;
a1=0;a2=0;a3=1;
#100;
a1=1;a2=0;a3=1;
#100;
a1=0;a2=1;a3=1;
#100;
a1=1;a2=1;a3=1;
#100
$stop;
end
endmodule
同步时序逻辑电路
计数器
时序逻辑电路是指电路任何时刻的稳态输出不仅取决于当前的输入,还与前一时刻输入形成的状态有关。这跟组合逻辑电路相反。时序逻辑拥有储存元件来储存信息,而组合逻辑则没有。
1.编写计数器HDL描述文件
module shixu_led_second(
//端口列表
Clk50M, //时钟 时序逻辑电路必须要有时钟
Rst_n, //复位 仿真时信号初始化信号初始值
led //连接LED灯
);
parameter CNT_MAX = 25'd24_999_999; //定义参数
//端口定义
input Clk50M;
input Rst_n;
output reg[3:0]led; //4个LED灯 默认为wire线性型 在always中用reg
reg [24:0]count; //寄存器类型计数 25位 计数器计数25_000_000 从0开始计数到24_999_999
/*******************端口功能 计数器 同步时序逻辑电路用always******************/
always@(posedge Clk50M or negedge Rst_n) //总是关注上升沿Clk50M或者下降沿Rst_n
if(!Rst_n) //满足复位端为低电平就清零
count <= 25'd0; //非阻塞赋值方式
else if(count == 25'd24_999_999) //判断计数器是否计满
count <= 25'd0; //25表示最大位宽 25位 25位宽 d数据进制 0数值
else
count <= count + 1'b1;
/**************** led输出******存储状态用时序逻辑*************************/
always@(posedge Clk50M or negedge Rst_n)
if(!Rst_n)
led <= 4'b1111;
else if(count == 25'd24_999_999)
led <= ~led; //两种取反 逻辑取反和按位取反
else
led <= led;
endmodule
注
d 十进制 b 二进制 h 16进制 d'128=h'80=b'10000000
led <= 4'b1111; 逻辑取反 led <= 4'b1101; 按位取反
led <= !led; led <= ~led;
led <= 0; led <= 4'b0010;
led <= !led;
led <=1;
2.编写计数器测试脚本
描述仿真时间精度timescale声明。
新建Verilog HDL File文件。
`timescale 1ns/1ns //仿真时间精度
`define clock_period 20 //周期宏定义
module shixu_led_second_tb;
reg Clk50M;
reg Rst_n; //激励源
wire [3:0]led; //输出 线性
shixu_led_second
#(
.CNT_MAX (25'd2499) //在仿真文件中定义参数
)
shixu_led_second1( //第0号模块
.Clk50M(Clk50M), //例化 端口
.Rst_n(Rst_n), //被测试模块
.led(led)
);
//产生激励信号 产生50MHZ频率的周期信号
//50MHz的方波,就是指方波的频bai率是50MHz,或者说,每秒钟范围内,有50M个方波波形。换句话说,就是大约1/50 = 0.02微秒 = 20纳秒,有一个方波
initial Clk50M = 1;
always #(`clock_period/2) Clk50M = ~Clk50M;
//复位信号
initial begin
Rst_n = 0;//复位端高电平清零 低电平计数
#(`clock_period*20+1) Rst_n=1; //上升沿后异步计数 清零后开始计数
#(`clock_period*25000000*6);
$stop;
end
endmodule
注
在仿真中shixu_led_second_tb文件为顶层,参数CNT_MAX 为2499
在编译中shixu_led_second文件为顶层,参数CNT_MAX为24_999_999
在时序仿真时不支持仿真文件shixu_led_second_tb中的参数
RTL视图
查看代码综合出来的电路结构
tools>Netlist Viewers>RTL Viewer
移位操作
4个LED灯按照流水的方式闪烁
方式1
module shixu_led_second(
//端口列表
Clk50M, //时钟 时序逻辑电路必须要有时钟
Rst_n, //复位 仿真时信号初始化信号初始值
led //连接LED灯
);
//端口定义
input Clk50M;
input Rst_n;
output [3:0]led; //4个LED灯 默认为wire线性型 在always中用reg
reg [24:0]count; //寄存器类型计数 25位 计数器计数25_000_000 从0开始计数到24_999_999
parameter CNT_MAX = 25'd24_999_999; //定义参数
// d 十进制 b 二进制 h 16进制 d'128=h'80=b'10000000
/*******************端口功能 计数器 同步时序逻辑电路用always******************/
always@(posedge Clk50M or negedge Rst_n) //总是关注上升沿Clk50M或者下降沿Rst_n 触发器
if(!Rst_n) //满足复位端为低电平就清零
count <= 25'd0; //非阻塞赋值方式
else if(count == CNT_MAX) //判断计数器是否计满
count <= 25'd0; //25表示最大位宽 25位 25位宽 d数据进制 0数值
else
count <= count + 1'b1;
reg [3:0]led_r;
always@(posedge Clk50M or negedge Rst_n)
if(!Rst_n)
led_r <= 4'b0001;
else if(count == CNT_MAX) begin //每一个 always 模块,都需要有 begin -- end 来确定起始和结束。
if(led_r == 4'b1000) //分支语句 if~else、case,每一个模块都需要 begin -- end 来确定起始和结束。
led_r <= 4'b0001; //if中一行代码可以不用begin
else
led_r <= led_r << 1;
end
else led_r <= led_r;
assign led = ~led_r; //组合逻辑输出
endmodule
方式2 :位拼接
module shixu_led_second(
//端口列表
Clk50M, //时钟 时序逻辑电路必须要有时钟
Rst_n, //复位 仿真时信号初始化信号初始值
led //连接LED灯
);
//端口定义
input Clk50M;
input Rst_n;
output [3:0]led; //4个LED灯 默认为wire线性型 在always中用reg
reg [24:0]count; //寄存器类型计数 25位 计数器计数25_000_000 从0开始计数到24_999_999
parameter CNT_MAX = 25'd24_999_999; //定义参数
// d 十进制 b 二进制 h 16进制 d'128=h'80=b'10000000
/*******************端口功能 计数器 同步时序逻辑电路用always******************/
always@(posedge Clk50M or negedge Rst_n) //总是关注上升沿Clk50M或者下降沿Rst_n 触发器
if(!Rst_n) //满足复位端为低电平就清零
count <= 25'd0; //非阻塞赋值方式
else if(count == CNT_MAX) //判断计数器是否计满
count <= 25'd0; //25表示最大位宽 25位 25位宽 d数据进制 0数值
else
count <= count + 1'b1;
/**************** led输出******存储状态用时序逻辑*************************/
always@(posedge Clk50M or negedge Rst_n)
if(!Rst_n)
led_r <= 4'b0001;
else if(count == CNT_MAX)
led_r <= {led_r[2:0],led_r[3]}; //低位移到高位,高位移到低位
else led_r <= led_r;
assign led = ~led_r; //组合逻辑输出
endmodule
4个LED灯以不同频率闪亮
module shixu_led_second(
//端口列表
Clk50M, //时钟 时序逻辑电路必须要有时钟
Rst_n, //复位 仿真时信号初始化信号初始值
led0, //连接LED灯
led1,
led2,
led3
);
//端口定义
input Clk50M;
input Rst_n;
//output [3:0]led; //4个LED灯 默认为wire线性型 在always中用reg
output reg led0;
output reg led1;
output reg led2;
output reg led3;
reg [24:0]count; //寄存器类型计数 25位 计数器计数25_000_000 从0开始计数到24_999_999
reg [24:0]count1;
reg [24:0]count2;
reg [24:0]count3;
parameter CNT_MAX = 25'd24_999_999; //定义参数 24_999_999为500ms 12,499,999为250ms 49,999,999为1s 99,999,999为2秒
parameter CNT_MAX1 = 25'd12_499_999;
parameter CNT_MAX2 = 25'd49_999_999;
parameter CNT_MAX3 = 25'd99_999_999;
// d 十进制 b 二进制 h 16进制 d'128=h'80=b'10000000
always@(posedge Clk50M or negedge Rst_n) //250ms
if(!Rst_n)
count1 <= 25'd0;
else if(count1 == CNT_MAX1)
count1 <= 25'd0;
else count1 <= count1 + 1'b1;
always@(posedge Clk50M or negedge Rst_n) //1s
if(!Rst_n)
count2 <= 25'd0;
else if(count2 == CNT_MAX2)
count2 <= 25'd0;
else count2 <= count2 + 1'b1;
always@(posedge Clk50M or negedge Rst_n) //2s
if(!Rst_n)
count3 <= 25'd0;
else if(count3 == CNT_MAX3)
count3 <= 25'd0;
else count3 <= count3 + 1'b1;
/*******************端口功能 计数器 同步时序逻辑电路用always******************/
always@(posedge Clk50M or negedge Rst_n) //总是关注上升沿Clk50M或者下降沿Rst_n 触发器 500ms
if(!Rst_n) //满足复位端为低电平就清零
count <= 25'd0; //非阻塞赋值方式
else if(count == CNT_MAX) //判断计数器是否计满
count <= 25'd0; //25表示最大位宽 25位 25位宽 d数据进制 0数值
else
count <= count + 1'b1;
/**************** led4个同时亮******存储状态用时序逻辑*************************
always@(posedge Clk50M or negedge Rst_n)
if(!Rst_n)
led <= 4'b1111;
else if(count == CNT_MAX)
led <= ~led; //两种取反 逻辑取反和按位取反
else
led <= led;
***************************************************************************/
// reg [3:0]led_r;
/*******************************流水灯写法1********************************************************
always@(posedge Clk50M or negedge Rst_n)
if(!Rst_n)
led_r <= 4'b0001;
else if(count == CNT_MAX) begin //每一个 always 模块,都需要有 begin -- end 来确定起始和结束。
if(led_r == 4'b1000) //分支语句 if~else、case,每一个模块都需要 begin -- end 来确定起始和结束。
led_r <= 4'b0001;
else
led_r <= led_r << 1;
end
else led_r <= led_r;
assign led = ~led_r; //组合逻辑输出
***********************************************************************************************/
/*****************************流水灯写法2***********************************************************
always@(posedge Clk50M or negedge Rst_n)
if(!Rst_n)
led_r <= 4'b0001;
else if(count == CNT_MAX)
led_r <= {led_r[2:0],led_r[3]}; //低位移到高位,高位移到低位
else led_r <= led_r;
assign led = ~led_r; //组合逻辑输出
******************************************************************************/
always@(posedge Clk50M or negedge Rst_n) //250ms
if(!Rst_n)
led0 <= 1'b1;
else if(count1 == CNT_MAX1)
led0 <= ~led0; //低位移到高位,高位移到低位
else led0 <= led0;
always@(posedge Clk50M or negedge Rst_n) //500ms
if(!Rst_n)
led1 <= 1'b1;
else if(count == CNT_MAX)
led1 <= ~led1; //低位移到高位,高位移到低位
else led1 <= led1;
always@(posedge Clk50M or negedge Rst_n) //1s
if(!Rst_n)
led2 <= 1'b1;
else if(count2 == CNT_MAX2)
led2 <= ~led2; //低位移到高位,高位移到低位
else led2 <= led2;
always@(posedge Clk50M or negedge Rst_n) //2s
if(!Rst_n)
led3 <= 1'b1;
else if(count3 == CNT_MAX3)
led3 <= ~led3; //低位移到高位,高位移到低位
else led3 <= led3;
endmodule