【FPGA实战篇六】四位数据选择器与D触发器、移位寄存器原理详解及功能验证
一、数据选择器
1、原理详解
-
什么是数据选择器?
数据选择器根据给定的输入地址代码,从一组输入信号中选出指定的一个送至输出端的组合逻辑电路。有时候也叫做多路选择器或者多路调制器。 -
数据选择器基本定义
在多路数据传输过程中,能够根据需要将其中任意一路选出来的电路,叫做数据选择器。
-
逻辑功能
数据选择器的逻辑功能是在地址选择信号控制下,从多路数据中选择一路数据作为输出信号。 -
分类
2选1,4选1、8选1和16选1等类型的数据选择器。
2、工作方式
结合上图,给A1A0一组信号 比如1 0 那么就相当于给了他一个2进制数字2 也就相当于选通了D2这个输入端这个时候 输出Y 输出的就是D2的信号D2是什么 Y就输出什么。
控制 | 选择的输出源 | |
---|---|---|
A1 | A0 | Y |
0 | 0 | D0 |
0 | 1 | D1 |
1 | 0 | D2 |
1 | 1 | D3 |
二、四位数据选择器功能验证
1、Verilog实现四位选择器
用Verilog编写一个简单的四位选择器
module multiplexer_s(
input clk ,
input rst_n ,
input din_a ,
input din_b ,
input din_c ,
input din_d ,
input [1:0] sel ,
output dout
);
//信号定义
reg data_dout;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
data_dout <= 2'b00;
end
else begin
case(sel)
2'b00: data_dout <= din_a ;
2'b01: data_dout <= din_b ;
2'b10: data_dout <= din_c ;
2'b11: data_dout <= din_d ;
default:data_dout <= 2'b00 ;
endcase
end
end
assign dout = data_dout;
endmodule
顶层模块
module multiplexer(
input clk ,
input rst_n ,
output dout
);
wire din_a ;
wire din_b ;
wire din_c ;
wire din_d ;
wire [1:0] sel ;
//模块例化
multiplexer_s u_multiplexer
(
.din_a (din_a ) ,
.din_b (din_b ) ,
.din_c (din_c ) ,
.din_d (din_d ) ,
.sel (sel ) ,
.dout (dout ) ,
.rst_n (rst_n ) ,
.clk (clk )
);
endmodule
2、创建工程
对于工程创建的详细步骤,可参考此篇文章:
数码管实现秒表计数
工程创建完成后,将四位数据选择器源码导入工程
将导入项目文件进行全编译
查看RTL电路图
3、更改系统内源和探针
点击quartus右上角IP Catalog或者【Tools】→【IP Catalog】
更改ip
将小窗展开,点击OK
配置source和probes的值,然后点击generate HDl…
再点击generate
生成完成后,点击close
可以在prj文件夹下看到生成的issp文件
在文件目录下找到issp.v文件
打开文件,将此文件中的该部分例化到四位选择器中
module issp (
input wire [31:0] probe, // probes.probe
output wire [31:0] source // sources.source
);
例化后各部分代码
①multiplexer.v
module multiplexer(
input clk ,
input rst_n ,
output dout
);
wire din_a ;
wire din_b ;
wire din_c ;
wire din_d ;
wire [1:0] sel ;
//模块例化
multiplexer_s u_multiplexer
(
.din_a (din_a ) ,
.din_b (din_b ) ,
.din_c (din_c ) ,
.din_d (din_d ) ,
.sel (sel ) ,
.dout (dout ) ,
.rst_n (rst_n ) ,
.clk (clk )
);
wire [31:0] probe ;
issp u_issp
(
.probe (probe ),
.source ({
sel,din_a,din_b,din_c,din_d})
);
endmodule
将设置的issp实体加入工程文件中
对整个工程进行全编译
4、逻辑分析
【Tools】→【Signal Tap Logic Analyzer】
连接到开发板,先进行烧录,确保驱动无异常
选择所使用的驱动以及下载文件,设置好采样时钟与深度
下载文件
设置时钟,点击Clock后面的三个小点,出现如示界面
选中Filter下拉框中的Design Entry(all names)。再点击list
再出现的界面中选择采样时钟
将.sof文件进行下载
选择【Tools】→【In_System Source and Probes Editor】
将.sof文件下载进去
出现如示界面,将source展开赋值,可以看到输出变化
点击运行图标,可看到【Signal Tap Logic Analyzer】中出现如下波形
点击红色方框图标,进行自往返分析
通过对source进行相应的赋值,可以观察到波形的变化。
5、功能验证
片选信号示意图
{sel,din_a,din_b,din_c,din_d}中{}方式是由高到低的,拼接不允许出现未指明位宽的变量。
根据此段代码块,验证其逻辑功能:
case(sel)
2'b00: data_dout <= din_a ;
2'b01: data_dout <= din_b ;
2'b10: data_dout <= din_c ;
2'b11: data_dout <= din_d ;
default:data_dout <= 1'b0 ;
endcase
①当片选信号sel为00时,data_out输出din_a
②当片选信号sel为01时,data_out输出din_b
③当片选信号sel为10时,data_out输出din_c
④当片选信号sel为11时,data_out输出din_d
三、D触发器
1、基本概念
- D触发器是一个具有记忆功能的,具有两个稳定状态的信息存储器件,是构成多种时序电路的最基本逻辑单元,也是数字逻辑电路中一种重要的单元电路。
- D触发器在时钟脉冲CP的前沿(正跳变0→1)发生翻转,触发器的次态取决于CP的脉冲上升沿到来之前D端的状态,即次态=D。因此,它具有置0、置1两种功能。由于在CP=1期间电路具有维持阻塞作用,所以在CP=1期间,D端的数据状态变化,不会影响触发器的输出状态。
2、工作原理
SD 和RD 接至基本RS 触发器的输入端,分别是预置和清零端,低电平有效。当SD=0且RD=1时,不论输入端D为何种状态,都会使Q=1,Q=0,即触发器置1;当SD=1且RD=0时,触发器的状态为0,SD和RD通常又称为直接置1和置0端。
工作流程
- CP=0时,与非门G3和G4封锁,其输出Q3=Q4=1,触发器的状态不变。同时,由于Q3至Q5和Q4至Q6的反馈信号将这两个门打开,因此可接收输入信号D,Q5=D,Q6=Q5非=D非;
- 当CP由0变1时触发器翻转。这时G3和G4打开,它们的输入Q3和Q4的状态由G5和G6的输出状态决定。Q3=Q5非=D非,Q4=Q6非=D。由基本RS触发器的逻辑功能可知,Q=Q3非=D;
四、D触发器功能验证
1、Verilog实现简易D触发器
D触发器模块
data_flip_flop.v
module data_flip_flop(
input clk ,//系统时钟
input rst_n ,//复位信号
input en ,//使能信号(cp)
input d ,//D触发器输入
output q ,//输出q
output q_n //输出非q
);
//信号定义
reg dout_q ;//输出定义
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
dout_q <= 0;
end
else if(en) begin
dout_q <= d;
end
else begin
dout_q <= 0;
end
end
assign q = dout_q ;
assign q_n = ~dout_q ;
endmodule
顶层模块
data_flip_flop_top.v
module data_flip_flop_top(
input clk ,
output q ,
output q_n
);
//信号定义
wire d ;
wire en ;
wire rst_n ;
//模块例化
data_flip_flop u_data_flip_flop
(
.clk ( clk ),
.rst_n ( rst_n),
.en ( en ),
.d ( d ),
.q ( q ),
.q_n ( q_n )
);
endmodule
查看有Verilog生成的RTL原理图
点击+展开,查看组成电路的结构
2、步骤略解(详细步骤雷同数据选择器)
配置ip,改名并保存在ip(知识产权)目录下
更改系统内源与探针
将生成的issp文件添加到工程中
添加后如示
将此部分代码例化到顶层模块
module issp (
input wire [7:0] probe, // probes.probe
output wire [7:0] source // sources.source
);
例化后的顶层模块源码
module data_flip_flop_top(
input clk ,
output q ,
output q_n
);
//信号定义
wire d ;
wire en ;
wire rst_n ;
wire [7:0] probe ;
//模块例化
data_flip_flop u_data_flip_flop
(
.clk ( clk ),
.rst_n ( rst_n),
.en ( en ),
.d ( d ),
.q ( q ),
.q_n ( q_n )
);
issp u_issp
(
.source ( {
rst_n,en,d} ) ,
.probe ( probe )
);
endmodule
3、逻辑分析
出GIF动图,给大家看看步骤
双击界面空白,添加信号
出现红色则代表出错,所添加的为wire型信号,需要更改
鼠标右键单击【select all】,再次鼠标右键点击【delete】
再次双击空白,添加信号
添加信号如图所示
在内源探针编辑器中,将.sof文件下载进去
在【Tap】界面,按照图示箭头一次操作
最后出现如示界面
下面,我们通过赋值验证D触发器的功能
4、功能验证
信号示意图
结果如示
五、移位寄存器
移位 寄存器可以用来寄存代码,还可以用来实现数据的串行—并行转换、数值的运算以及数据的处理等。
1、基本概念
- 移位寄存器(外文名:shift register)在数字电路中,是一种在若干相同时间脉冲下工作的以触发器为基础的器件,数据以并行或串行的方式输入到该器件中,然后每个时间脉冲依次向左或右移动一个比特,在输出端进行输出。
- 移位寄存器可分为一维和多维移位寄存器。多维移位寄存器的输入、输出的数据本身就是一些列位。
2、原理介绍
四位移位寄存器的原理图如图所示。F 0、F 1、F 2、F 3是四个边沿触发的D触发器,每个触发器的输出端Q接到右边一个触发器的输入端D。因为从时钟信号CP的上升沿加到触发器上开始到输出端新状态稳定地建立起来有一段延迟时间,所以当时钟信号同时加到四个触发器上时,每个触发器接收的都是左边一个触发器中原来的数据(F 0接收的输入数据D 1)。寄存器中的数据依次右移一位。
3、寄存器分类
- 根据移位方向,常把它分成左移寄存器、右移寄存器和双向移位寄存器三种。
- 根据移位数据的输入-输出方式,又可将它分为串行输入-串行输出、串行输入-并行输出、并行输入-串行输出和并行输入-并行输出四种电路结构。
- 此外,有些移位寄存器还具有预置数功能,可以把数据并行地置入寄存器中。
- 利用移位寄存器能进行数据运算、数据处理,实现数据的串行—并行互相转换,还可接成各种移位寄存器式计数器,如环形计数器、扭环形计数器等。
六、移位寄存器功能验证
1、Verilog实现移位寄存器
shift_reg.v
module shift_reg (
input clk ,
input rst_n ,
input [3:0] din ,
input dsr ,
input en ,
input [1:0] mode ,
output [3:0] dout ,
output one_out
);
//信号定义
reg [3:0] dout_r ;
reg one_out_r ;
//输出
always @(posedge clk or negedge rst_n) begin
if(~rst_n)begin
dout_r <= 0;
one_out_r <= 0;
end
else if(en)begin
case({
mode,dsr})
3'b000:begin
dout_r <= dout_r;
one_out_r <= 0;
end
3'b001:begin
dout_r <= dout_r;
one_out_r <= 0;
end
3'b010:begin
dout_r <= {dsr,dout_r[3:1]};
one_out_r <= dout_r[0];
end
3'b011:begin
dout_r <= {
dsr,dout_r[3:1]};
one_out_r <= dout_r[0];
end
3'b100:begin
dout_r <= {dout_r[2:0],dsr};
one_out_r <= dout_r[3];
end
3'b101:begin
dout_r <= {
dout_r[2:0],dsr};
one_out_r <= dout_r[3];
end
3'b110:begin
dout_r <= din;
one_out_r <= 0;
end
3'b111:begin
dout_r <= din;
one_out_r <= 0;
end
default:begin
dout_r <= dout_r;
one_out_r <= 0;
end
endcase
end
else begin
dout_r <= 0;
one_out_r <= 0;
end
end
assign dout = dout_r;
assign one_out = one_out_r;
endmodule
shift_reg_top.v
module shift_reg_top (
input clk,
input rst_n,
output [3:0] dout,
output one_out
);
//信号定义
wire en;
wire [3:0] din;
wire dsr;
wire mode;
//模块例化
shift_reg u_shift_reg
(
.clk (clk),
.rst_n (rst_n),
.din (din),
.dsr (dsr),
.en (en),
.mode (mode),
.dout (dout),
.one_out (one_out)
);
endmodule
查看RTL图
创建issp,并对内源以及探针进行例化
module shift_reg_top (
input clk,
input rst_n,
output [3:0] dout,
output one_out
);
//信号定义
wire en;
wire [3:0] din;
wire dsr;
wire mode;
wire [12:0] probe;
//模块例化
shift_reg u_shift_reg
(
.clk (clk),
.rst_n (rst_n),
.din (din),
.dsr (dsr),
.en (en),
.mode (mode),
.dout (dout),
.one_out (one_out)
);
issp u_issp
(
.source({
en,din,dsr,mode}),
.probe(probe)
)
endmodule
2、功能验证
①
②
③
④