写在前面,4位右移移位寄存器,顾名思义使用四个触发器级联,从一次输入到输出,只移动了3位,而不是4位。比如输入是1101,输出时为0001,而不是0000。
虚拟机:VMware -14.0.0.24051
环 境:ubuntu 18.04.1
脚 本:makefile(点击直达)
应用工具:vcs 和 verdi
文章目录
一、Overview
(1)Theory
-
行为级描述
-
结构级描述
移位寄存器可以存储数据,还可以用来实现数据的串并转换、分频,构成序列码发生器、序列码检测器等;上图是4位右移寄存器原理图,依据移位寄存器的特点,移位寄存器在时钟的控制下,可将输入数据依次往后移动,N个寄存器级联,最后输出的数据是输入数据的右移N-1
位。其中,左边的空位会被补0。其中QD是串行输出端,{QA,QB,QC,QD}可实现并行输出,如果将输出端QD接到输入端QI,则可以实现自循环移位寄存器。
(2)Demand
- 当复位信号为0时,输出端全为0;在每个时钟的上升沿时刻,输出端的4位数据向右移一位。
- 使用行为级描述和结构建模方式描述。
二、Interface
Signal Name | Width | Direction | Description |
---|---|---|---|
clk | 1 | input | System clk signal, xxMhz |
rst | 1 | input | System reset signal |
data | 1 | input | Detected data |
result | 1 | output | Detection result signal |
三、Timeing
四、Design and Functional Verification
(1)RTL
//行为级描述
//-- modified by xlinxdu, 2022/04/27
module shift(
input clk_i ,
input rst_n_i,
input data_i ,
output reg [3:0] out_o
);
reg [3:0] out_s;
always @ (posedge clk_i or negedge rst_n_i)begin
if(!rst_n_i)begin
out_s <= 4'b0;
end
else begin
out_s <= {out_s[2:0],data_i};
end
end
always @ (posedge clk_i or negedge rst_n_i)begin
if(!rst_n_i)begin
out_o <= 4'b0;
end
else begin
out_o <= (out_s >> 3);
end
end
endmodule
//结构级描述
//-- modified by xlinxdu, 2022/04/27
module shift(
input clk_i ,
input rst_n_i ,
input data_i ,
output reg [3:0] result_o,
output reg [3:0] out_o
);
reg [2:0] cnt;
reg QA,QB,QC,QD;
always @ (posedge clk_i or negedge rst_n_i)begin
if(!rst_n_i) begin
cnt <= 2'b0;
QA <= 1'b0;
QB <= 1'b0;
QC <= 1'b0;
QD <= 1'b0;
result_o <= 4'b0;
end
else begin
QA <= data_i;
QB <= QA;
QC <= QB;
QD <= QC;
result_o <= {QD,QC,QB,QA};
end
end
always @ (posedge clk_i or negedge rst_n_i)begin
if(!rst_n_i) begin
out_o <= 4'b0;
end
else begin
out_o <= {out_o[2:0],QD};
end
end
endmodule
(2)Test Bench
//行为级描述测试平台
//-- modified by xlinxdu, 2022/04/27
module tb_shift;
reg clk_i;
reg rst_n_i;
reg data_i;
// wire [3:0] result_o;
wire [3:0] out_o;
initial begin
clk_i = 0;
rst_n_i = 1;
data_i = 0;
#10 rst_n_i = 0;
#10;
rst_n_i = 1;
end
always #50 clk_i = ~clk_i;
always begin
#100 data_i = 1;
#100 data_i = 1;
#100 data_i = 0;
#100 data_i = 1;
#100;
end
shift tb_shift(
.clk_i(clk_i),
.rst_n_i(rst_n_i),
.data_i(data_i),
// .result_o(result_o),
.out_o(out_o)
);
initial begin
$fsdbDumpfile("shift.fsdb");
$fsdbDumpvars ;
$fsdbDumpMDA ;
#1000 $finish ;
end
endmodule
//结构描述测试平台
//-- modified by xlinxdu, 2022/04/27
module tb_shift;
reg clk_i;
reg rst_n_i;
reg data_i;
wire [3:0] result_o;
wire [3:0] out_o;
initial begin
clk_i = 0;
rst_n_i = 1;
data_i = 0;
#10 rst_n_i = 0;
#10;
rst_n_i = 1;
end
always #50 clk_i = ~clk_i;
always begin
#100 data_i = 1;
#100 data_i = 1;
#100 data_i = 0;
#100 data_i = 1;
#100;
end
shift tb_shift(
.clk_i(clk_i),
.rst_n_i(rst_n_i),
.data_i(data_i),
.result_o(result_o),
.out_o(out_o)
);
initial begin
$fsdbDumpfile("shift.fsdb");
$fsdbDumpvars ;
$fsdbDumpMDA ;
#1000 $finish ;
end
endmodule
五、Result
(1)行为级描述测试结果
(2)结构级描述测试结果
分析:
在行为级描述过程中,输出只与输入有关,每次只会操作就近的四位数据,之外的数据会被丢弃掉,四位内左侧补0,因为每次只有四位数据被赋值到中间变量out_s造成下一次的时候,四位以外的数据丢失了,数据不符合实际电路产生的值(bug)。
在结构级描述过程中,输出与result_o是4位寄存器的并输出端,out_o是移位后数据的输出端,其中输出的值需要看该时刻前面的完整的输入值。比如刚开始的时候,串行输入值为0110时,移位输出值为0000;串行输入值为01101时,移位输出值为0001;串行输入值为0110111时,移位输出值为0110,,依次类推,每来一个时钟,数据右移一位输出。
(3)bug分析
针对上述情况,分析产生数据丢失的是因为中间的缓存变量每次只缓存4bit数据,而在四位移位寄存器中,要保证数据不被截取掉,至少保证数据位宽为7(移动的3bit+4bit数据)。见下表:
输入 | 累计数据(4bit) | 移位后的数据(>>3) | 累计数据(7bit) | 移位后的数据(>>3) | |
---|---|---|---|---|---|
a | 000a | 0000 | 000_000a | 0000 | |
b | 00ab | 0000 | 000_00ab | 0000 | |
c | 0abc | 0000 | 000_0abc | 0000 | |
d | abcd | 000a | 000_abcd | 000a | |
e | bcde | 000b | 00a_bcde | 00ab | |
f | cdef | 000c | 0ab_cdef | 0abc | |
g | defg | 000d | abc_defg | abcd | |
h | efgh | 000h | bcd_efgh | bcde |
- 更正后的测试波形与结构描述的一一致。
作者:xlinxdu
版权:本文是作者原创,版权归作者所有。
转载:未经作者允许,禁止转载,转载必须保留此段声明,必须在文章中给出原文连接。