第六篇 移位寄存器

实验六 移位寄存器

6.1实验目的

  1. 掌握移位寄存器的工作原理;

  2. 掌握利用移位寄存器实现串行与并行的相互转换;

  3. 掌握使用移位寄存器实现乘除法运算;

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脉冲个数DSIQ0Q1Q2Q3
第一个CLK脉冲之前D3xxxx
1D2D3xxx
2D1D2D3xx
3D0D1D2D3x
40D0D1D2D3
500D0D1D2
6000D0D1
70000D0

为了加深理解,在图6.2中画出了数据1101在寄存器中移位的波形,在经过四个时钟脉冲后,1101出现在触发器的输出端Q_3Q_2Q_1Q_0。在第八个时钟脉冲作用后,数据已从Q_3端(即串行数据输出端D_{SO})全部移出寄存器。随着时钟信号的推移,D_{SO}输出端得到1101的串行输出序列。可以看到,如果首先将4位数据并行地置入移位寄存器的四个触发器中,然后连续加入四个移位脉冲,则移位寄存器里的4位数据将从串行输出端D_{SO}依次送出,因此,该电路叫并-串转换器

image-20210630093719243

图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。

image-20210630101523866

图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}输出,电路实现左移操作。

image-20210630102106310

图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。

image-20210630104321406

图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输出)。

image-20210630105252445

图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。

image-20210630105618233

图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列出了该多功能双向移位寄存器的四种操作。

image-20210630110557264

图6.8 实现多功能双向移位寄存器的一种方案

​​

表6.2 图6.8电路的功能表

控制信号功能
S1S0
00保持
01右移
10左移
11并行输入

代码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。

image-20210630111344065

图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,所以使用两个数码管来显示运算的结果。

image-20240520165005303

图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。

image-20210630094009622

图6.11 左移(a)和右移(b)运算示例

图6.12为4位移位寄存器的框图,rst_n为异步清零信号,a为4位输入数据,进行左移1位或右移1位后,输出数据f。该框图可以表示4位左移移位寄存器,也可以表示4位右移移位寄存器,因为它们对外的接口信号都是一样的,进行左移还是右移是在内部实现的,即框图内部实现时会不同。

image-20210630094040193

图6.12 4位移位寄存器的框图

表6.3是4位移位寄存器的输入输出信号描述。

表6.3 4位移位寄存器信号描述

信号名称位宽方向功能描述
clk1-bitInput4位移位寄存器的时钟信号
rst_n1-bitInput4位移位寄存器的异步复位信号
a4-bitInput4位移位寄存器的输入信号
f4-bitOutput4位移位寄存器的输出信号

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。

    image-20210630094433063

    图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。

    image-20210630094543369

    图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节画的系统框图是一致的。

    image-20240520170238619

    图6.15 calculator模块的RTL Viewer

6.5 实验步骤

6.5.1 创建工程和代码输入
  1. 点击电脑右下角的开始菜单找到Quartus软件,双击Quartus (Quartus Prime 17.1)打开Quartus Prime软件。

  2. 点击菜单File-->New Project Wizard弹出工程创建的对话框。在弹出的对话框中点击Next。

  3. 在您的DE1-SOC 工作文件夹下创建一个lab7的文件夹,并将工程路径指向该文件夹,且工程的名称也命名calculator。如图6.16-1所示。

image-20240520145247493

图6.16-1 创建Quartus工程

image-20240520145425656

图6.16-2

image-20240520145514303

图6.17

完成创建工程后,打开后的工程Quartus Prime工程界面如图6.18所示。

image-20240520145535274

图6.18 Quartus打开的工程窗口

在lab6工程文件夹下新建名为v的文件夹。点击Quartus软件工具栏的File --> New --> Verilog HDL File,创建c6.v、c7.v文件保存到v文件夹,并依次添加代码6.7、代码6.8中的代码。

image-20240520165319356

图6.19 c6.v

image-20240520165417025

图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所示。

image-20240520165634751

图6.21 复制文件至本实验的工程路径下

点击Quartus软件工具栏的Assignments --> Settings --> Files,将前面拷贝的文件添加至本实验的Quartus工程,如图6.22所示。

image-20240520165745111

图6.22 添加文件至Quartus工程

修改calculator.v文件,参考代码6.9。

image-20240520170327952

图6.23 修改calculator.v文件

  1. 点击Quartus软件工具栏的Processing --> Start --> Start Analysis & Synthesis或点击

    image-20210603145513555

    按钮对Verilog HDL代码执行语法检查和综合。如果在该过程中提示有错误,请检查Verilog HDL代码语法,确保与上述代码块完全一致。

    image-20240520170410592

    图6.25 执行语法检查和综合

6.5.2 仿真
  1. 点击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

  1. 点击Quartus工具栏Assignments --> Settings --> EDA Tool Settings --> Simulation,设置Quartus自动调用ModelSim仿真软件,并设置test bench为calculator_tb,设置完成后如图6.26所示。

image-20240520172125103

图6.26 设置test bech为calculator_tb

  1. 其中,添加Compile test bench的具体步骤如下。

image-20240520172026817

图6.27 设置test bech的具体步骤

点击Quartus工具栏Tools --> Run Simulation Tool --> RTL Simulation启动ModelSim仿真,再点击Wave切换到仿真波形窗口,并点击Zoom Full按钮,如图6.28所示。

image-20240521142320987

图6.28 打开的初始仿真波形

点击上图左侧的Calculator_inst旁的"+"按钮,再单击选中c6_inst,将c6模块的输出信号f添加到wave中,如下图6.29所示。依此再将reg4bits_inst的输出信号q、c7模块的输出信号f和mux8x1模块的输出信号m添加到wave中。

image-20240520173148390

图6.29 添加c6、c7和mux8x1模块的输出信号

右键选中下图中的a、q(其实就是操作数b)、c6、c7和mux8x1,点击Radix-->Hexadecimal,以十六进制数显示。

image-20240520174853712

图6.30 更改十六进制显示

点击ModelSim工具栏的Simulate-->Restart,在弹出的Restart窗口,保持默认选择并点击OK按钮,然后再点击Run -All图标进行仿真。

image-20240520175018139

图6.31 开始仿真

仿真波形如下图6.32所示。

image-20240521142757841

图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。

  1. 点击Quartus菜单Assignments——Pin Planner进行引脚分配。

img

图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页。

img

image-20240517165745573

img

image-20240517165857589

image-20240521091242725

image-20240521092456466

image-20240521092534583

  1. 点击Quartus软件工具栏的Processing --> Start Compilation或点击

    image-20210603145755433

    按钮编译lab6工程,并检查是否生成calculator.sof。

    image-20240521093008816

    图6.33 编译lab6工程

  2. 连接DE1-SOC开发板到PC, 给开发板上电开机。

  3. 点击Quartus软件工具栏的Tools --> Programmer

    image-20210603150014201

    按钮打开Programmer窗口,点击Hardware Setup选择USB-Blaster设备,点击Auto Detect选择5CSEBA6器件,左键单击选中5CSEBA6器件再点击Change File,选择lab6.sof,勾选Program/configure,点击Start下载calculator.sof。

    image-20240521093339274

    图6.34 烧录lab6.sof

6.5.4 实验现象观察
  1. 拨动界面上的滑动开关,并观察实验现象:

  • 先按一次KEY0,寄存器异步复位,c6、c7模块和6位寄存器中的数据被清0,LEDR5 ~ LEDR0全部熄灭,HEX1HEX0都显示十六进制数字“0”;

    IMG_20240521_093536(1)

    图6.38 实验现象1

  • 拨动SW10 ~ SW8为“up、down、up”,SW3 ~ SW0为“down、down、up、up”,按一次KEY1LEDR5 ~ LEDR0显示为“熄灭、熄灭、熄灭、点亮、点亮、熄灭”,HEX1、HEX0分别显示十六进制数字“0”、“6”;

    即:a=(3)_{16},sel=(101)_2,计算器作乘以2运算,a*2=(6)_{16}。

    IMG_20240521_093716(1)

    图6.39 实验现象2

  • 拨动SW10 ~ SW8为“up、down、up”,SW3 ~ SW0为“up、down、down、down”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1LEDR5 ~ LEDR0显示为“熄灭、点亮、熄灭、熄灭、熄灭、熄灭”,HEX1、HEX0分别显示十六进制数字“1”、“0”;

    即:a=(8)_{16},sel=(101)_2,计算器作乘以2运算,a*2=(10)_{16}。

    IMG_20240521_135759(1)

    图6.40 实验现象3

  • 拨动SW10 ~ SW8为“up、down、up”,SW3 ~ SW0为“up、up、down、down”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1LEDR5 ~ LEDR0显示为“熄灭、点亮、点亮、熄灭、熄灭、熄灭”,HEX1、HEX0分别显示十六进制数字“1”、“8”;

    即:a=(c)_{16},sel=(101)_2,计算器作乘以2运算,a*2=(18)_{16}。

    IMG_20240521_135826(1)

    图6.41 实验现象4

  • 拨动SW10 ~ SW8为“up、up、down”,SW3 ~ SW0为“up、up、up、down”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1LEDR5 ~ LEDR0显示为“熄灭、熄灭、熄灭、点亮、点亮、点亮”,HEX1、HEX0分别显示十六进制数字“0”、“7”;

    即:a=(e)_{16},sel=(110)_2,计算器作除以2运算,a/2=(7)_{16}。

    IMG_20240521_135900(1)

    图6.42 实验现象5

  • 拨动SW10 ~ SW8为“up、up、down”,SW3 ~ SW0为“down、up、up、up”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1LEDR5 ~ LEDR0显示为“熄灭、熄灭、熄灭、熄灭、点亮、点亮”,HEX1、HEX0分别显示十六进制数字“0”、“3”;

    即:a=(7)_{16},sel=(110)_2,计算器作除以2运算,a/2=(3)_{16}。

    IMG_20240521_135916(1)

    图6.43 实验现象6

  • 拨动SW10 ~ SW8为“up、up、down”,SW3 ~ SW0为“down、up、down、down”,SW7 ~ SW4为“down、down、down、down”;按一次KEY1LEDR5 ~ LEDR0显示为“熄灭、熄灭、熄灭、熄灭、点亮、熄灭”,HEX1、HEX0分别显示十六进制数字“0”、“2”;

    即:a=(4)_{16},sel=(110)_2,计算器作除以2运算,a/2=(2)_{16}。

    IMG_20240521_135933(1)

    图6.44 实验现象7

6.6 实验小结

本章我们学习了如何使用寄存器组成移位寄存器,移位寄存器不仅可以存储数据,还可以用来实现数据的串-并转换、数据处理以及数值的运算,像我们在实验中使用移位寄存器来实现了乘以2、除以2运算。

使用移位寄存器还可以实现环形计数器和扭环形计数器,由于这不是我们本章的主旨,没有做过多的介绍,有兴趣的同学可查阅相关资料学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/677514.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QGIS 根据点图层上的点 画线生成线图层

使用节点捕捉功能 空白处鼠标右键---》勾选捕捉工具栏----》选中磁铁工具 创建线图层---》编辑模式---》点击新增线工具--》鼠标靠近点&#xff0c;会有高亮提醒&#xff0c;左键选中&#xff0c;右键结束当前线段绘制

千帆 AppBuilder 工作流编排功能直播总结

千帆 AppBuilder 工作流编排功能直播总结 ​ 上个月&#xff0c;千帆AppBuilder推出了一项引人瞩目的新功能——工作流编排。在官方直播中&#xff0c;百度产品经理不仅深入介绍了这项功能&#xff0c;而且还通过创建多个组件&#xff0c;生动展示了AppBuilder组件工作流的强大…

网络工程师---第四十六天

1、逻辑网络结构设计阶段中&#xff0c;要想实现核心层与汇聚层交换机全部互相连接&#xff0c;组网技术有哪些&#xff1f; 2、工作区子系统的通信布线规范有哪些&#xff1f; 3、综合布线中施工规范有哪些&#xff1f; 4、综合布线系统中核心机房通常包括哪些设备&#xff1f…

API商品数据接口(电商数据api)返回京东淘宝商品详情数据提高开发效率

众多品牌选择使用比价工具进行采购&#xff0c;主要是出于以下几个重要原因&#xff1a; 提高开发效率&#xff1a;电商数据采集API接口允许不同的应用程序之间高效地进行交互&#xff0c;节省了大量的人力物力成本&#xff0c;使得开发者可以将更多时间和精力集中于自身的核心…

分库分表方案

文章目录 分库分表设计思路hash取模和范围方案最终方案采用hash取模和rang范围两者相结合 分库分表设计思路 首先分库分表有两种方式&#xff0c;一种是垂直拆分&#xff0c;一种是水平拆分。 垂直拆分 垂直拆分比较简单&#xff0c;也就是本来一个数据库&#xff0c;数据量大…

小红书前端2轮面试期望22K,全程问低代码设计

一面&#xff08;通过&#xff09; 1、好&#xff0c;那我们开始把&#xff0c;先简单介绍一下自己的一个经历&#xff0c;以及自己有亮点的项目&#xff1f;balabala 2、你可以这样介绍&#xff1a;在这里边主要负责哪几个项目&#xff0c;哪些项目是比较有亮点的&#xff0…

超市管理系统设计1——基本功能设计

超市管理系统基础功能类设计 1. 概述 本设计文稿提供一个基础的超市管理系统&#xff0c;包含基本的功能设计。该系统将管理商品、顾客、员工和交易记录&#xff0c;不需要接入数据库&#xff0c;通过文件存储数据&#xff0c;并满足面向对象编程的基本要求&#xff08;继承、…

LabVIEW开发EOL功能测试系统

LabVIEW开发EOL功能测试系统 介绍了一种基于LabVIEW开发的EOL功能测试系统方案&#xff0c;涵盖软件架构、工作流程、模块化设计、低耦合性、易于修改与维护、稳定性及硬件选型。系统通过高效的CAN通信实现对电机控制器的全面测试&#xff0c;确保运行可靠并支持未来的升级需求…

媒体有入口,发稿有入口 是什么意思?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体有入口&#xff0c;发稿有入口是指在新闻媒体发稿时&#xff0c;稿件可以通过一定的路径被访问和浏览。具体来说&#xff0c;有入口的新闻稿件可以通过点击链接&#xff0c;逐步深入…

PyTorch深度学习实战(44)——基于 DETR 实现目标检测

PyTorch深度学习实战&#xff08;44&#xff09;——基于 DETR 实现目标检测 0. 前言1. Transformer1.1 Transformer 基础1.2 Transformer 架构 2. DETR2.1 DETR 架构2.2 实现 DETR 模型 3. 基于 DETR 实现目标检测3.1 数据加载与模型构建3.2 模型训练与测试 小结系列链接 0. 前…

第 10 章 动态参数(自学二刷笔记)

重要参考&#xff1a; 课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ 讲义链接:Introduction Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 10.2动态参数 参数服务器的数据被修改时&#xff0c;如果节点不重新访问&#xff0c;那么就不能获取修改后的…

MySQL的组成与三种log

MySQL由几块组成 连接器分析器优化器执行器 MySQL的三大log blog 作用&#xff1a; 用于主从同步与数据恢复 记录内容&#xff1a; 已经完成的 DML(数据操作语句)&#xff0c;主要是用于数据备份 redolog<重试日志> 作用&#xff1a; 崩溃恢复&#xff0c;用于事…

Linux - 高级IO

目录 理解五种IO模型非阻塞IO的设置多路转接之select 实现一个简易的select服务器select服务器的优缺点 多路转接之poll 实现一个简易的poll服务器poll服务器的优缺点 多路转接之epoll epoll原理epoll的优势用epoll实现一个简易的echo服务器 epoll的LT和ET工作模式 什么是LT和…

【mysql】数据报错: incorrect datetime value ‘0000-00-00 00:00:00‘ for column

一、问题原因 时间字段在导入值0000-00-00 00:00:00或者添加 NOT NULL的时间字段时&#xff0c;会往mysql添加0值&#xff0c;此时可能出现此报错。 这是因为当前的MySQL不支持datetime为0&#xff0c;在MySQL5.7版本以上&#xff0c;默认设置sql_mode模式包含NO_ZERO_DATE, N…

实验名称:组合数据类型

大家好&#xff01;欢迎收听你的月亮我的心&#xff01;我是肖老师&#xff01;好久不见&#xff01; 目录 一、实验目的&#xff1a; 二、实验环境&#xff1a; 三、实验步骤&#xff1a; 四、实验结果&#xff1a; 1.已知列表li_one[1,2,1,2,3,5,4,3,5,7,4,7,8],删除列…

解决使用Python检查本地网络中运行的Web服务器的问题

如果我们要检查本地网络中运行的 Web 服务器&#xff0c;可以使用 Python 的 socket 模块来进行网络连接测试。以下是一个简单的示例代码&#xff0c;演示如何检查本地网络中运行的 Web 服务器&#xff1a; 1、问题背景 在学习如何使用 Python 时&#xff0c;一位用户希望编写…

C#的web项目ASP.NET

添加实体类和控制器类 using System; using System.Collections.Generic; using System.Linq; using System.Web;namespace WebApplication1.Models {public class Company{public string companyCode { get; set; }public string companyName { get; set; }public string com…

开始报名!龙蜥社区系统安全 Meetup 硬核议程发布

在数字化时代&#xff0c;随着云计算、大数据和人工智能等技术的广泛应用&#xff0c;操作系统扮演着关键的角色&#xff0c;成为支撑关键业务和数据的核心基础设施。在这一背景下&#xff0c;操作系统的安全性显得尤为重要&#xff0c;它直接影响着信息系统的稳定运行和持续发…

RocketMQ---Day1

RocketMQ---Day1 1.认识MQ 火车案例&#xff1a; 人就相当于消息 进站口将消息分发给不同的候车厅&#xff08;主题&#xff09; 火车将不同候车厅的人拉走&#xff08;消费不同主题里面的数据&#xff09; MQ是一种消息中间件。 2.微服务的远程调用 1.同步调用 RPC&am…

(Arkts界面示例)ets pages Demo

Index.ets 文件 import router from ohos.routerEntry//表示该自定义组件为入口组件 Component //表示自定义组件 struct Index {//表示组件中的状态变量&#xff0c;状态变量变化会触发UI刷新State changeValue: string State submitValue: string controller: SearchContr…