流水灯与移位寄存器实验
实验内容1:流水灯
一组LED指示灯在某一时刻只有部分LED点亮,依次变换点亮的LED灯,并且不停地循环,这种效果通常称为流水灯或走马灯。
参考设计1
/****** Replace input ports with internal signals *******/
wire reset = PB[0];
wire clk = PB[1];
/************* The logic of this experiment *************/
logic [7:0]q;
always @ (posedge clk or posedge reset)
if (reset)
q <= 1;
else
q <= {q[6:0], q[7]};
/***** Internal signals assignment to output ports ******/
assign L[7:0] = q[7:0];
注:为节省篇幅,仅给出了核心逻辑。完整代码可从开源项目托管网站下载,下载方法见下载实验材料。
实验任务1
用HDL设计一个可并行装载的右移移位寄存器,并在实验系统上验证。具体要求如下。
-
设计右移移位寄存器
将右移移位寄存器设计为一个独立的模块,端口定义如下。
module RightShifter
#(parameter N = 4)
(
input wire iClk,
input wire iReset,
input wire iLoad,
input wire iEnable,
input wire iShiftIn,
input wire [N-1:0] iD,
output logic [N-1:0] oQ
);
parameter N = 4
定义了一个参数N,若上层模块实例化时未传递该参数,默认取值为4。Reset是异步复位信号,Load和Enable是同步装数和使能信号,表 1是功能表。可以看出,这些控制信号是有优先级的;只要Reset有效,就会使寄存器清零,与Load和Enable无关;当Reset无效时,如果Load有效,在时钟上升沿到来时将输入数据D保存在寄存器中,与Enable是什么电平无关;如果Reset和Load都无效但Enable=1,则寄存器内容右移一位,并且将ShiftIn移入寄存器的最高位;否则寄存器内容保持不变。这种有优先级的结构适合用“if-else if”语句描述。
Reset | Load | Enable | 功能 |
---|---|---|---|
0 |
0 |
0 |
保持不变 |
0 |
0 |
1 |
右移一位(高位移入的数据来自ShiftIn) |
0 |
1 |
X |
并行装载(保存iD输入数据) |
1 |
X |
X |
异步清零 |
ShiftIn是移入数据的端口,在上层模块实例化时将不同的数据或信号连接到ShiftIn,可以实现逻辑右移、算术右移和循环右移。
-
编写VirtualBoard模块
在VirtualBoard模块中实例化右移移位寄存器模块。可在实验系统中打开虚拟面板查看虚拟元件的序号,连接相应的端口。例 2给出了与虚拟面板一致的端口连接代码。
/****** Replace input ports with internal signals *******/
wire reset = PB[0];
wire clk = PB[1];
wire [7:0] data = S[7:0];
wire load = S[8];
wire enable = S[9];
/***** Internal signals assignment to output ports ******/
assign L[7:0] = q[7:0];
|
【思考】不改变RightShifter模块的设计,如何实现算术右移或逻辑右移。
-
验证设计
虚拟面板如图 2。除了Load和Enable各用一个开关控制外,还有8个开关提供并行装载的数据,用来设置灯的初始状态。
代码编译成功后,加载FPGA,验证表 1各项功能,如装载、右移、保持和异步复位等。
实验内容2:桶形移位
上面的设计是一个时钟移一位,如果需要移动多位,就需要多个时钟周期。但是现代计算机的移位指令,通常需要在一个时钟周期移动多位。实现多位移位的组合逻辑称作桶形移位器(barrel shifter),一般的实现方法是使用多路器阵列。图 3是一个四位的循环左移桶形移位器,由4个4选1多路器构成;DI3-0是4位输入,DO3-0是移位的输出,移位的位数由N1N0决定,一次可移位0~3位。N1N0实际是4选1多路器的选择信号,当N1N0=00时,DO3-0输出选择的是对应的DI3-0输入,即DO3-0=DI3-0,不进行移位;当N1N0=01时,DO3-1=DI2-0,即DI左移1位,而DO0=DI3,所以是循环左移1位;当N1N0=10时,DO3-2=DI1-0,DO1-0=DI3-2,循环左移2位;类似地,当N1N0=11时,循环左移3位。
由上可知,构造一个M位的桶形移位器需要M个M选1的多路器,最大可移位位数为M-1位。如果M较大,可采用分层的多路器阵列,以避免扇入数太大。
参考设计2
桶形移位器是一个组合逻辑,要实现桶形移位寄存器,还需要增加一个数据寄存器。例 3给出了一个8位的循环左移桶形移位寄存器的设计,该电路分为组合逻辑和时序逻辑两个部分,组合逻辑实现桶形移位功能,而时序逻辑就是一个并行数据寄存器,用来将移位的结果保存在寄存器中。
logic [7:0] q, shiftOut;
always_comb
case (num)
3'b000: shiftOut = q[7:0];
3'b001: shiftOut = {q[6:0],q[7]};
3'b010: shiftOut = {q[5:0],q[7:6]};
3'b011: shiftOut = {q[4:0],q[7:5]};
3'b100: shiftOut = {q[3:0],q[7:4]};
3'b101: shiftOut = {q[2:0],q[7:3]};
3'b110: shiftOut = {q[1:0],q[7:2]};
3'b111: shiftOut = {q[0],q[7:1]};
default:shiftOut = 8'hxx;
endcase
/*
循环左移桶形移位的另一种实现方法
logic [7:0] temp;
assign {shiftOut, temp} = {q,q}<<num;
*/
always @ (posedge clk or posedge reset)
if (reset)
q <= 1;
else
q <= shiftOut;
注:为节省篇幅,仅给出了核心逻辑。完整代码可从开源项目托管网站下载,下载方法见下载实验材料。
电路框图如图 4虚拟面板所示,复位时数据寄存器的初值为00000001,寄存器的输出Q连到桶形移位逻辑的数据输入DI,Num决定移位位数,DO是移位输出。如果Num大于1,DI左移Num位,当点击Clk按钮时,此前的移位输出保存到寄存器并且作为移位器新的输入,连续点击Clk,LED的视觉效果是一个跳跃的流水灯。
实验任务2
用HDL设计一个具有多种移位功能的桶形移位器,电路框图如图 5虚拟面板所示。
该桶形移位器是一个组合逻辑(不包含寄存器),可以对并行输入数据进行左移、逻辑右移、算术右移、并行传送以及输出零。Num指定移位的位数,SM0和SM1控制移位方式,具体含义见表 2。AM控制是否算术移位,若AM=1,进行算术移位,否则进行逻辑移位;只有右移受AM控制,左移始终是逻辑移位。
SM1 | SM0 | 功能 |
---|---|---|
0 |
0 |
输出零(DO=0) |
0 |
1 |
右移Num位 |
1 |
0 |
左移Num位 |
1 |
1 |
传送(DO=DI) |
例 4给出了与虚拟面板一致的端口连接代码。
/****** Replace input ports with internal signals *******/
wire [7:0] data = S[7:0];
wire [1:0] shift_mode = S[9:8];
wire [2:0] num = S[12:10];
wire arith_mode = S[13]; //0:Logic, 1:Arithmetic
/***** Internal signals assignment to output ports ******/
assign L[7:0] = shiftOut[7:0];
|