实验六 移位寄存器
6.1实验目的
-
掌握移位寄存器的工作原理;
-
掌握利用移位寄存器实现串行与并行的相互转换;
-
掌握使用移位寄存器实现乘除法运算;
6.2 原理介绍
6.2.1 基本移位寄存器
在实验四中,我们主要介绍了寄存器的结构及功能,一个N位的寄存器可以存储N位二进制数,即寄存器具有存储数据的功能。移位寄存器(Shift Register)除了具有存储数据的功能以外,还具有移位功能。它们在同一时钟脉冲作用下,可将寄存的二进制数据依次移位,用来实现数据的串行/并行或并行/串行的转换、数值运算以及其他数据处理功能。
将若干个D触发器串接级联在一起构成的具有移位功能的寄存器叫移位寄存器。图6.1是由四个D触发器构成的一个4位移位寄存器的逻辑电路。串行二进制数据从输入端D_{SI}输入,左边触发器的输出作为右邻触发器的数据输入。
图6.1 用D触发器构成的4位移位寄存器
若将串行数据D_3D_2D_1D_0从高位(D_3)至低位(D_0)按时钟序列依次送到D_{SI}端,经过第一个时钟脉冲后,Q_0=D_3。由于跟随D_3后面的是D_2,因此经过第二个时钟脉冲后,触发器FF0的状态移入触发器FF1,而FF0转变为新的状态,即Q_1=D_3、Q_0=D_2,以此类推,可得到该移位寄存器的状态,如表6.1所示(x表示不确定状态)。由表6.1可知,经过四个时钟脉冲后,四个触发器的输出状态Q_3Q_2Q_1Q_0与输入数据D_3D_2D_1D_0相对应。此时,串行输入数据可以从并行数据输出端D_{PO}送出去。可见,数据可以串行输入并行读取,因此,该电路也叫做串-并转换器。
如果继续移位,则第七个时钟脉冲作用之后,从D_{SI}逐位输入的数据就能够从输出端D_{SO}(即Q_3端)逐位输出寄存器。可见,该电路串行输入的数据是从左向右移位的。如果将图6.1所示电路中各触发器的连接顺序调换一下,让右边触发器的输出作为左邻触发器的数据输入,则可以构成从右向左移位的寄存器。
表6.1 图6.1电路的状态表
CLK脉冲个数 | DSI | Q0 | Q1 | Q2 | Q3 |
---|---|---|---|---|---|
第一个CLK脉冲之前 | D3 | x | x | x | x |
1 | D2 | D3 | x | x | x |
2 | D1 | D2 | D3 | x | x |
3 | D0 | D1 | D2 | D3 | x |
4 | 0 | D0 | D1 | D2 | D3 |
5 | 0 | 0 | D0 | D1 | D2 |
6 | 0 | 0 | 0 | D0 | D1 |
7 | 0 | 0 | 0 | 0 | D0 |
为了加深理解,在图6.2中画出了数据1101在寄存器中移位的波形,在经过四个时钟脉冲后,1101出现在触发器的输出端Q_3Q_2Q_1Q_0。在第八个时钟脉冲作用后,数据已从Q_3端(即串行数据输出端D_{SO})全部移出寄存器。随着时钟信号的推移,D_{SO}输出端得到1101的串行输出序列。可以看到,如果首先将4位数据并行地置入移位寄存器的四个触发器中,然后连续加入四个移位脉冲,则移位寄存器里的4位数据将从串行输出端D_{SO}依次送出,因此,该电路叫并-串转换器。
图6.2 图6.1电路的时序图
我们来看如何使用Verilog HDL来实现图6.1所示的4位移位寄存器。
对于移位功能,我们可由代码6.1所示的四条语句来实现。
q[0] <= dsi; q[1] <= q[0]; q[2] <= q[1]; q[3] <= q[2]
代码6.1 4位移位寄存器移位功能的实现方法一
我们可以将上述四条语句简化,如代码6.2所示,这与代码6.1是等价的。
q[0] <= dsi; q[3:1] <= q[2:0];
代码6.2 4位移位寄存器移位功能的实现方法二
根据图6.1可以写出4位移位寄存器的Verilog HDL实现,如代码6.3所示。
module shift_reg_4bit( input clk, // 时钟信号 input clr_n, // 异步清零信号,低电平有效 input dsi, // 串行数据输入 output reg [3:0] q, // 并行数据输出 output dso // 串行数据输出 ); always@(posedge clk, negedge clr_n) begin if(~clr_n) // clk_n为0,寄存器清零 begin q <= 4'b0000; end else begin // 数据从低位触发器向高位触发器移位 q[0] <= dsi; q[3:1] <= q[2:0]; end end assign dso = q[3]; // 串行数据输出 endmodule
代码6.3 4位移位寄存器Verilog HDL实现
图6.3是代码6.3对应的4位移位寄存器的RTL Viewer。
图6.3 4位移位寄存器的RTL Viewer
6.2.2 双向移位寄存器
有时需要对移位寄存器的数据流向加以控制,实现数据的双向移动,其中一个方向称为右移,另一个方向称为左移,这种移位寄存器称为双向移位寄存器。
注:这里需要注意的是,由于国家标准规定,逻辑图中的最低有效位(LSB)到最高有效位(MSB)的电路排列顺序应从上到下,从左到右。因此定义移位寄存器中的数据从低位触发器移向高位为右移,移向低位为左移。这一点与通常计算机程序中的规定相反,后者从二进制数的自然排列考虑,将数据移向高位定义为左移,反之为右移。
图6.4是双向移位寄存器的一种方案,与普通移位寄存器的连接不同,每个触发器的输入端D连接两个不同的数据源,一个是前级的输出,用于右移操作;另外一个数后一级的输出,用于左移操作。控制信号S用来选择操作的模式,当S=0时,FF0的D_0端与右移串行输入端D_{IR}连通,FF1的D_1端与Q_0连通,FF2的D_2端与Q_1连通,FF3的D_3端与Q_3连通,在时钟脉冲CLK的作用下,D_{IR}端输入的数据将向右移位,并从右移串行输出端D_{OR}输出,电路实现右移操作;当S=1时,FF3的D_3端与左移串行输入端D_{IL}连通,FF2的D_2端与Q_3连通,FF1的D_1端与Q_2连通,FF0的D_0端与Q_1连通,在时钟脉冲CLK的作用下,D_{IL}端输入的数据将向左移位,并从左移串行输出端D_{OL}输出,电路实现左移操作。
图6.4 用D触发器构成的双向移位寄存器
由此可见,图6.4所示电路可作双向移位,当S=0时,数据向右移位;当S=1时,数据向左移位,可实现串行输入-串行输出(由D_{OR}或D_{OL}输出)、串行输入-并行输出(由Q3 \sim Q0输出)的工作方式。
代码6.4是图6.4所示的4位双向移位寄存器的Verilog HDL实现。
module bidir_shift_reg_4bit( input clk, // 时钟信号 input clr_n, // 异步清零信号,低电平有效 input dir, // 右移串行输入 input dil, // 左移串行输入 input s, // 控制信号 output reg [3:0] q, // 并行数据输出 output dor, // 右移串行输出 output dol // 左移串行输出 ); always@(posedge clk, negedge clr_n) begin if(~clr_n) // clk_n为0,寄存器清零 begin q <= 4'b0000; end else begin if(s == 1'b0) // 右移 q <= {q[2:0], dir}; else // 左移 q <= {dil, q[3:1]}; end end assign dor = q[3]; // 右移串行输出 assign dol = q[0]; // 左移串行输出 endmodule
代码6.4 4位双向移位寄存器Verilog HDL实现
图6.5是代码6.4对应的4位双向移位寄存器的RTL Viewer。
图6.5 4位双向移位寄存器的RTL Viewer
6.2.3 并行存取的移位寄存器
并行存取的移位寄存器如图6.6所示,它与双向移位寄存器的连接有些类似,但又有不同。并行存取的移位寄存器的每个触发器的输入端D也是连接两个不同的数据源,一个数据源是前级的输出,用于移位寄存器的右移操作,这与双向移位寄存器是一样的;另外一个数据来自于外部的输入,作为并行操作的一部分,这部分与双向移位寄存器不同。控制信号S用来选择操作的模式,当S=0时,电路实现右移操作;当S=1时,并行数据DI_3 \sim DI_0送到各自的寄存器进行寄存,由此便可实现并行输入(由DI_3 \sim DI_0输入)、并行输出(由Q3 \sim Q0输出)。
图6.6 4位并行存取的移位寄存器
代码6.5是图6.6所示的4位并行存取的移位寄存器的Verilog HDL实现。
module parallel_shift_reg_4bit( input clk, // 时钟信号 input clr_n, // 异步清零信号,低电平有效 input dir, // 右移串行输入 input [3:0] di, // 并行数据输入 input s, // 控制信号 output reg [3:0] q, // 并行数据输出 output dor // 右移串行输出 ); always@(posedge clk, negedge clr_n) begin if(~clr_n) // clk_n为0,寄存器清零 begin q <= 4'b0000; end else begin if(s == 1'b0) // 右移 q <= {q[2:0], dir}; else // 并行存取 q <= di; end end assign dor = q[3]; // 右移串行输出 endmodule
代码6.5 4位并行存取移位寄存器Verilog HDL实现
图6.7是代码6.5对应的4位并行存取移位寄存器的RTL Viewer。
图6.7 4位并行存取移位寄存器的RTL Viewer
6.2.4 多功能双向移位寄存器
为便于扩展逻辑功能和增加使用的灵活性,我们将并行输入、并行输出、左移、右移、保持、异步复位等功能集合到同一个电路中,组成多功能双向移位寄存器。
图6.8所示是实现一个4位的具有数据保持、右移、左移、并行输入和并行输出功能的多功能双向移位寄存器的一种电路方案。该电路主要由四个D触发器和四个四选一数据选择器构成,每个D触发器的数据输入端都插入一个四选一数据选择器MUX,并用2位的输入S1、S0控制MUX,来选择D触发器输入信号D的来源。当S1=S0=0时,选择该D触发器自身的输出Q,使D触发器保持状态不变;当S1=0、S0=1时,前一级D触发器的输出被选中,所以当时钟信号上升沿到来时,D触发器存入前一级D触发器的逻辑值,从而实现右移功能;类似地,当S1=1、S0=0时,实现左移功能;而当S1=S0=1时,选择并行输入数据DI3 \sim DI0,即实现并行输入的功能。表6.2列出了该多功能双向移位寄存器的四种操作。
图6.8 实现多功能双向移位寄存器的一种方案
表6.2 图6.8电路的功能表
控制信号 | 功能 | |
---|---|---|
S1 | S0 | |
0 | 0 | 保持 |
0 | 1 | 右移 |
1 | 0 | 左移 |
1 | 1 | 并行输入 |
代码6.6是图6.8所示的4位多功能双向的移位寄存器的Verilog HDL实现。
module multi_func_shift_reg_4bit( input clk, // 时钟信号 input clr_n, // 异步清零信号,低电平有效 input dir, // 右移串行输入 input dil, // 左移串行输入 input [3:0] di, // 并行数据输入 input [1:0] s, // 控制信号 output reg [3:0] q, // 并行数据输出 output dor, // 右移串行输出 output dol // 左移串行输出 ); always@(posedge clk, negedge clr_n) begin if(~clr_n) // clk_n为0,寄存器清零 begin q <= 4'b0000; end else begin case(s[1:0]) 2'b00: q <= q; // 保持 2'b01: q <= {q[2:0], dir}; // 右移 2'b10: q <= {dil, q[3:1]}; // 左移 2'b11: q <= di; // 并行存取 endcase end end assign dor = q[3]; // 右移串行输出 assign dol = q[0]; // 左移串行输出 endmodule
代码6.6 4位多功能双向移位寄存器Verilog HDL实现
图6.9是代码6.6对应的4位多功能双向移位寄存器的RTL Viewer。
图6.9 4位多功能双向移位寄存器的RTL Viewer
6.3 实验目标
-
使用移位寄存器来实现乘以2和除以2的运算;
-
并将乘以2和除以2的运算加入到实验五实现的计算器中,即计算器可实现与运算、或运算、异或运算、非运算、加(减)法运算、乘以2、除以2运算;
6.4 设计实现
6.4.1 设计思路
图6.10是本实验的系统框图,我们增加了如红色框所示的部分,它们分别实现乘以2、除以2的运算。使用SW3 ~ SW0作为乘法和除法的第一个操作数A,第二个操作数固定为常数2。经过乘法运算后,结果可能会超过16,所以使用两个数码管来显示运算的结果。
图6.10 实验六系统框图
我们再来看乘法、除法运算的实现。
二进制数A乘以2,这相当于在A最低有效位的右边添加一个0,或者说把A的所有位左移1位,如图6.11(a)所示。因此A乘以2可以用左移的移位寄存器来实现。
二进制数A除以2,这相当于在A最高有效位添加一个0,即把A的所有位右移1位,如图6.11(b)所示。因此A除以2可以用右移的移位寄存器来实现。
注:上文中讨论的乘法和除法,都是考虑无符号二进制数A。
图6.11 左移(a)和右移(b)运算示例
图6.12为4位移位寄存器的框图,rst_n为异步清零信号,a为4位输入数据,进行左移1位或右移1位后,输出数据f。该框图可以表示4位左移移位寄存器,也可以表示4位右移移位寄存器,因为它们对外的接口信号都是一样的,进行左移还是右移是在内部实现的,即框图内部实现时会不同。
图6.12 4位移位寄存器的框图
表6.3是4位移位寄存器的输入输出信号描述。
表6.3 4位移位寄存器信号描述
信号名称 | 位宽 | 方向 | 功能描述 |
---|---|---|---|
clk | 1-bit | Input | 4位移位寄存器的时钟信号 |
rst_n | 1-bit | Input | 4位移位寄存器的异步复位信号 |
a | 4-bit | Input | 4位移位寄存器的输入信号 |
f | 4-bit | Output | 4位移位寄存器的输出信号 |
6.4.2 代码实现
-
乘以2运算
代码6.7是乘以2运算的代码实现。
module c6( input clk, // 时钟信号 input rst_n, // 异步复位信号 input [ 3: 0] a, // 输入信号 output reg [ 4: 0] f // 输出信号 ); always@(posedge clk, negedge rst_n) begin if(~rst_n) begin f <= 5'b00000; end else begin f[4:1] <= a[3:0]; // 右移1位 f[0] <= 1'b0; // 右移1位,最低位填0 end end endmodule
代码6.7 c6.v
如下图是乘以2运算的RTL Viewer。
图6.13 乘以2运算的RTL Viewer
-
除以2运算
代码6.8是除以2运算的代码实现。
module c7( input clk, // 时钟信号 input rst_n, // 异步复位信号 input [ 3: 0] a, // 输入信号 output reg [ 3: 0] f // 输出信号 ); always@(posedge clk, negedge rst_n) begin if(~rst_n) begin f <= 4'b0000; end else begin f[2:0] <= a[3:1]; // 左移1位 f[3] <= 1'b0; // 左移1位,最高位填0 end end endmodule
代码6.8 c7.v
图6.14是除以2运算的RTL Viewer。
图6.14 除以2运算的RTL Viewer
-
计算器模块
计算器模块是在实验五实现的计算器的基础上增加了乘以2、除以2运算,需要修改calculator.v文件,其中第72行 ~ 98行为主要的修改部分,主要是添加了c6、c7模块以及与mux8x1模块之间的连接。
module calculator( input clk, // 时钟信号,50MHz input rst_n, // 异步复位信号 input en, // 寄存器使能信号 input carry_in, // 加法的进位输入 input [3:0] a, // 计算器的第一个操作数 //input [3:0] b, // 计算器的第二个操作数 input [2:0] sel, // 计算器的功能选择信号 output [5:0] ledr_out, // 寄存器的数据输出 output [6:0] hex0_out, // 七段数码管译码器的输出HEX0 output [6:0] hex1_out // 七段数码管译码器的输出HEX1 ); // 变量声明 wire [3:0] operator_a; wire [3:0] operator_b; wire operator_cin; wire [2:0] operation_s; wire [3:0] f1; wire [3:0] f2; wire [3:0] f3; wire [3:0] f4; wire [5:0] f5; wire [4:0] f6; wire [3:0] f7; wire [5:0] f; wire [5:0] g; wire [6:0] hex0dec_output; wire [6:0] hex1dec_output; // 输入信号赋值 assign operator_a = a; //assign operator_b = b; assign operator_cin = carry_in; assign operation_s = sel; // 将输入a存入寄存器中 reg4bits reg4bits_inst (.clk(clk), .rst_n(rst_n), .en(~en), .d(a), .q(operator_b)); // 与运算 c1 c1_inst( .a (operator_a), .b (operator_b), .f (f1) ); // 或运算 c2 c2_inst( .a (operator_a), .b (operator_b), .f (f2) ); // 异或运算 c3 c3_inst( .a (operator_a), .b (operator_b), .f (f3) ); // 非运算 c4 c4_inst( .a (operator_a), .f (f4) ); // 加(减)运算 c5 c5_inst ( .a (operator_a), .b (operator_b), .ci (operator_cin), .f (f5) ); // 乘以2 c6 c6_inst ( .clk (clk), .rst_n (rst_n), .a (operator_a), .f (f6) ); // 除以2 c7 c7_inst ( .clk (clk), .rst_n (rst_n), .a (operator_a), .f (f7) ); // 在f1,f2,f3,f4,f5,f6,f7七种运算结果中,选择一个运算结果f mux8x1 mux8x1_inst( .r ({2'd0, f1}), .t ({2'd0, f2}), .u ({2'd0, f3}), .v ({2'd0, f4}), .w (f5), .x ({1'd0, f6}), .y ({2'd0, f7}), .z (6'd0), .s (operation_s), .m (f) ); // 将选出的运算结果f存入寄存器中 reg6bits reg6bits_inst( .clk (clk), .rst_n (rst_n), .en (~en), .d (f), .q (g) ); // 寄存器的输出数据g输入至数码管译码器,经译码后显示至两个七段数码管上 decod7seg decod7seg_inst0( .hex (g[3:0]), .display (hex0dec_output) ); decod7seg decod7seg_inst1( .hex ({2'd0, g[5:4]}), .display (hex1dec_output) ); // 寄存器的输出数据g直接显示在LED上 assign ledr_out = g; assign hex0_out = hex0dec_output; assign hex1_out = hex1dec_output; endmodule
代码6.9 calculator.v
calculator模块的RTL Viewer如图6.15所示,可以看出和6.3.1节画的系统框图是一致的。
图6.15 calculator模块的RTL Viewer
6.5 实验步骤
6.5.1 创建工程和代码输入
-
点击电脑右下角的开始菜单找到Quartus软件,双击Quartus (Quartus Prime 17.1)打开Quartus Prime软件。
-
点击菜单File-->New Project Wizard弹出工程创建的对话框。在弹出的对话框中点击Next。
-
在您的DE1-SOC 工作文件夹下创建一个lab7的文件夹,并将工程路径指向该文件夹,且工程的名称也命名calculator。如图6.16-1所示。
图6.16-1 创建Quartus工程
图6.16-2
图6.17
完成创建工程后,打开后的工程Quartus Prime工程界面如图6.18所示。
图6.18 Quartus打开的工程窗口
在lab6工程文件夹下新建名为v的文件夹。点击Quartus软件工具栏的File --> New --> Verilog HDL File,创建c6.v、c7.v文件保存到v文件夹,并依次添加代码6.7、代码6.8中的代码。
图6.19 c6.v
图6.20 c7.v
将实验五 加法器中的c1.v、c2.v、c3.v、c4.v、c5.v、decod7seg.v、fa.v、mux2x1.v、mux8x1.v、reg6bits.v、calculator.v文件复制到本实验工程文件夹下,如图6.21所示。
图6.21 复制文件至本实验的工程路径下
点击Quartus软件工具栏的Assignments --> Settings --> Files,将前面拷贝的文件添加至本实验的Quartus工程,如图6.22所示。
图6.22 添加文件至Quartus工程
修改calculator.v文件,参考代码6.9。
图6.23 修改calculator.v文件
-
点击Quartus软件工具栏的Processing --> Start --> Start Analysis & Synthesis或点击
按钮对Verilog HDL代码执行语法检查和综合。如果在该过程中提示有错误,请检查Verilog HDL代码语法,确保与上述代码块完全一致。
图6.25 执行语法检查和综合
6.5.2 仿真
-
点击Quartus工具栏File --> New --> Verilog HDL File,点击OK,添加如下仿真代码,点击File --> Save保存,并命名为calculator_tb.v,保存在v文件夹中。
`timescale 1ns/1ns module calculator_tb(); // 产生50MHz时钟信号 reg clk; localparam PERIOD = 20; // 20ns = 50MHz initial begin clk = 1'b0; forever #(PERIOD/2) clk = ~clk; // 每隔10ns,clk翻转一次 end // 产生复位信号,用作6位寄存器的异步复位 reg rst_n; initial begin rst_n = 1'b0; #(PERIOD) rst_n = 1'b1; end // 产生计算器的操作数a、运算操作选择sel和4位寄存器的使能信号en reg [3:0] a; //reg [3:0] b; reg ci; reg [2:0] sel; reg en; initial begin #0 a = 4'd0; // b = 4'd0; ci = 1'b0; sel = 3'b000; en = 1'b0; #(PERIOD) a = 4'd3; sel = 3'b101; // a=2, 乘以2 #(PERIOD) a = 4'd8; sel = 3'b101; // a=8, 乘以2 #(PERIOD) a = 4'd12; sel = 3'b101; // a=12, 乘以2 #(2 * PERIOD) a = 4'd14; sel = 3'b110; // a=14, 除以2 #(PERIOD) a = 4'd7; sel = 3'b110; // a=7, 除以2 #(PERIOD) a = 4'd4; sel = 3'b110; // a=4, 除以2 #(3 * PERIOD) $stop(); end // 例化 calculator wire [5:0] ledr_out; wire [6:0] hex0_out; wire [6:0] hex1_out; calculator calculator_inst( .clk (clk), .rst_n (rst_n), .en (en), .carry_in (ci), .a (a), // .b (b), .sel (sel), .ledr_out (ledr_out), .hex0_out (hex0_out), .hex1_out (hex1_out) ); endmodule
代码6.11 calculator_tb.v
-
点击Quartus工具栏Assignments --> Settings --> EDA Tool Settings --> Simulation,设置Quartus自动调用ModelSim仿真软件,并设置test bench为calculator_tb,设置完成后如图6.26所示。
图6.26 设置test bech为calculator_tb
-
其中,添加Compile test bench的具体步骤如下。
图6.27 设置test bech的具体步骤
点击Quartus工具栏Tools --> Run Simulation Tool --> RTL Simulation启动ModelSim仿真,再点击Wave切换到仿真波形窗口,并点击Zoom Full按钮,如图6.28所示。
图6.28 打开的初始仿真波形
点击上图左侧的Calculator_inst旁的"+"按钮,再单击选中c6_inst,将c6模块的输出信号f添加到wave中,如下图6.29所示。依此再将reg4bits_inst的输出信号q、c7模块的输出信号f和mux8x1模块的输出信号m添加到wave中。
图6.29 添加c6、c7和mux8x1模块的输出信号
右键选中下图中的a、q(其实就是操作数b)、c6、c7和mux8x1,点击Radix-->Hexadecimal,以十六进制数显示。
图6.30 更改十六进制显示
点击ModelSim工具栏的Simulate-->Restart,在弹出的Restart窗口,保持默认选择并点击OK按钮,然后再点击Run -All图标进行仿真。
图6.31 开始仿真
仿真波形如下图6.32所示。
图6.32 calculator仿真波形
仿真波形分析
-
0 ~ 20ns,复位信号rst_n=0,c6、c7处于复位状态,ledr_out=(00)16,hex0_out=hex1_out=(1000000)2,即数码管HEX1、HEX0都显示十六进制数“0”;
-
20ns,复位信号rst_n=1,移位寄存器c6、c7恢复正常状态,a=(3)16,sel=(101)2,但此时clk上升沿还没有到来,所以ledr_out=(00)16,hex0_out=hex1_out=(1000000)2,即数码管HEX1、HEX0都显示十六进制数“0”;
-
30ns,clk上升沿到来,数据选择器选择乘以2运算的结果输出m=(06)16;
-
50ns,clk上升沿时刻,寄存器的输出ledr_out=(06)16,hex1_out=(1000000)2,hex0_out=(0000010)2,即数码管HEX1、HEX0分别显示显示十六进制数“0”、“6”;
-
同样是在50ns,clk上升沿时刻,a=(8)16,sel=(101)2,m=(10)16;
-
70ns,clk上升沿时刻,寄存器的输出ledr_out=(10)16,hex1_out=(1111001)2,hex0_out=(1000000)2,即数码管HEX1、HEX0分别显示显示十六进制数“1”、“0”;
-
同样是在70ns,clk上升沿时刻,a=(c)16,sel=(101)2,m=(18)16;
-
90ns,clk上升沿时刻,寄存器的输出ledr_out=(18)16,hex1_out=(1111001)2,hex0_out=(0000000)2,即数码管HEX1、HEX0分别显示显示十六进制数“1”、“8”;
-
100ns,sel由(101)2变为(110)2,但此时处于clk下降沿,数码管HEX1、HEX0保持不变;
-
110ns,clk上升沿时刻,a=(e)16,sel=(110)2,数据选择器选择除以2运算的结果输出m=(7)16;
-
130ns,clk上升沿时刻,寄存器的输出ledr_out=(07)16,hex1_out=(1000000)2,hex0_out=(1111000)2,即数码管HEX1、HEX0分别显示显示十六进制数“0”、“7”;
-
同样是在130ns,clk上升沿时刻,a=(7)16,sel=(110)2,m=(3)16;
-
150ns,clk上升沿时刻,寄存器的输出ledr_out=(03)16,hex1_out=(1000000)2,hex0_out=(0110000)2,即数码管HEX1、HEX0分别显示显示十六进制数“0”、“3”;
-
同样是在150ns,clk上升沿时刻,a=(4)16,sel=(110)2,m=(2)16;
-
170ns,clk上升沿时刻,寄存器的输出ledr_out=(02)16,hex1_out=(1000000)2,hex0_out=(0100100)2,即数码管HEX1、HEX0分别显示显示十六进制数“0”、“2”;
6.5.3 引脚分配、全编译与烧录
这个实验的操作数a及sel可以通过拨码开关SW0~SW3以及SW7~SW9来控制,carry_in从SW6输入。out信号分别输出到LEDR0到LEDR5,hex0_out输出到数码管0,hex1_out输出到数码管1,en和rst_n连接到按键key1和key0。
-
点击Quartus菜单Assignments——Pin Planner进行引脚分配。
图4.41
关于引脚分配信息可以查看DE1-SoC_v.5.1.3_HWrevF.revG_SystemCD\UserManual\DE1-SoC_User_manual.pdf第 22、25、26、28页或者E:\CD_Package\01-DE1-SoC\DE1-SoC_v.5.1.3_HWrevF.revG_SystemCD\Schematic\DE1-SoC.pdf的第3页。
-
点击Quartus软件工具栏的Processing --> Start Compilation或点击
按钮编译lab6工程,并检查是否生成calculator.sof。
图6.33 编译lab6工程
-
连接DE1-SOC开发板到PC, 给开发板上电开机。
-
点击Quartus软件工具栏的Tools --> Programmer或
按钮打开Programmer窗口,点击Hardware Setup选择USB-Blaster设备,点击Auto Detect选择5CSEBA6器件,左键单击选中5CSEBA6器件再点击Change File,选择lab6.sof,勾选Program/configure,点击Start下载calculator.sof。
图6.34 烧录lab6.sof
6.5.4 实验现象观察
-
拨动界面上的滑动开关,并观察实验现象:
-
先按一次KEY0,寄存器异步复位,c6、c7模块和6位寄存器中的数据被清0,LEDR5 ~ LEDR0全部熄灭,HEX1、HEX0都显示十六进制数字“0”;
图6.38 实验现象1
-
拨动SW10 ~ SW8为“up、down、up”,SW3 ~ SW0为“down、down、up、up”,按一次KEY1,LEDR5 ~ LEDR0显示为“熄灭、熄灭、熄灭、点亮、点亮、熄灭”,HEX1、HEX0分别显示十六进制数字“0”、“6”;
即:a=(3)_{16},sel=(101)_2,计算器作乘以2运算,a*2=(6)_{16}。
图6.39 实验现象2
-
拨动SW10 ~ SW8为“up、down、up”,SW3 ~ SW0为“up、down、down、down”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1,LEDR5 ~ LEDR0显示为“熄灭、点亮、熄灭、熄灭、熄灭、熄灭”,HEX1、HEX0分别显示十六进制数字“1”、“0”;
即:a=(8)_{16},sel=(101)_2,计算器作乘以2运算,a*2=(10)_{16}。
图6.40 实验现象3
-
拨动SW10 ~ SW8为“up、down、up”,SW3 ~ SW0为“up、up、down、down”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1,LEDR5 ~ LEDR0显示为“熄灭、点亮、点亮、熄灭、熄灭、熄灭”,HEX1、HEX0分别显示十六进制数字“1”、“8”;
即:a=(c)_{16},sel=(101)_2,计算器作乘以2运算,a*2=(18)_{16}。
图6.41 实验现象4
-
拨动SW10 ~ SW8为“up、up、down”,SW3 ~ SW0为“up、up、up、down”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1,LEDR5 ~ LEDR0显示为“熄灭、熄灭、熄灭、点亮、点亮、点亮”,HEX1、HEX0分别显示十六进制数字“0”、“7”;
即:a=(e)_{16},sel=(110)_2,计算器作除以2运算,a/2=(7)_{16}。
图6.42 实验现象5
-
拨动SW10 ~ SW8为“up、up、down”,SW3 ~ SW0为“down、up、up、up”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1,LEDR5 ~ LEDR0显示为“熄灭、熄灭、熄灭、熄灭、点亮、点亮”,HEX1、HEX0分别显示十六进制数字“0”、“3”;
即:a=(7)_{16},sel=(110)_2,计算器作除以2运算,a/2=(3)_{16}。
图6.43 实验现象6
-
拨动SW10 ~ SW8为“up、up、down”,SW3 ~ SW0为“down、up、down、down”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1,LEDR5 ~ LEDR0显示为“熄灭、熄灭、熄灭、熄灭、点亮、熄灭”,HEX1、HEX0分别显示十六进制数字“0”、“2”;
即:a=(4)_{16},sel=(110)_2,计算器作除以2运算,a/2=(2)_{16}。
图6.44 实验现象7
6.6 实验小结
本章我们学习了如何使用寄存器组成移位寄存器,移位寄存器不仅可以存储数据,还可以用来实现数据的串-并转换、数据处理以及数值的运算,像我们在实验中使用移位寄存器来实现了乘以2、除以2运算。
使用移位寄存器还可以实现环形计数器和扭环形计数器,由于这不是我们本章的主旨,没有做过多的介绍,有兴趣的同学可查阅相关资料学习。