前言
移位寄存器(Shift Register)是一种数字电路组件,广泛用于计算机和电子系统中。它主要用于在数字电路中存储和移动数据。移位寄存器可以在其内部存储多个二进制位,并通过串行或并行方式将数据移位(即向左或向右移动)到寄存器的不同位置。做很多图像算法时,经常需要用到模板运算,如Sobel图像边缘检测、中值滤波、均值滤波的处理这些问题时,可以借用Altera提供的移位寄存器ip核来简化设计,提高设计效率。
正文
一、移位寄存器
1.项目需求
假设图像数据在一个rom中。比如下图所示排放,行加列的值作为该数据的地址。
在图像处理邻域,要实现Sobel或者均值滤波等算法,需要按照3*3矩形的格式提取数据。
2.技术介绍
这里可以使用Shift_register的ip核来实现功能
In[7:0]是从rom中读出的数据,用一个计数器作为rom的地址,每次地址加1,将移位寄存器比作“fifo”在计数器记到16时,in[7:0]当前数据为地址16的数据此时在Shiftout0[7:0]输出该数据,在Shiftout1[7:0]输出地址为8的数据,Shiftout2[7:0]输出地址为0的数据。在后续计数会依次输出1、9、17地址上的数据,直到扫描完整个rom。
ip核调用参考上图数据,选择shift register(RAM-based)
设置位宽8位,需要2个taps,并勾选生成inst文件。
3.顶层架构
counter模块产生rom地址,en在计数器记到16后拉高,shift_register中调用ip核Shift_register,对rom的数据进行移位并输出,计数器16之前shift_register的输出未定,故此时en拉低,16之后输出稳定,en使能。
4.端口描述
clk | 系统时钟 |
rst_n | 复位按键(低电平有效) |
shiftout0[7:0] | 地址16、17、18...数据 |
shiftout1[7:0] | 地址8、9、10...数据 |
shiftout2[7:0] | 地址0、1、2、3...数据 |
二、代码验证
counter模块:产生rom地址数据,计数16时en拉高。
module counter(
input clk,
input rst_n,
output reg [7:0]cnt,//rom地址
output reg shift_en//Shift_register使能信号
);
always @(posedge clk,negedge rst_n)
begin
if(rst_n == 0)
begin
cnt <= 8'd0;
shift_en <= 1'b0;
end
else
begin
if(cnt >= 16)//地址>16时Shift_register开始输出
begin
cnt <= cnt + 8'd1;
shift_en <= 1'b1;
end
else
cnt <= cnt + 8'd1;
end
end
endmodule
shift_register模块:调用ip核Shift_register进行数据处理。
module shift_register(
input clk,
input rst_n,
input [7:0]in,
input shift_en,
output [7:0]shifout1,
output [7:0]shifout2,
output [7:0]shifout3
);
wire [15:0]taps;
assign shifout1 = shift_en?in :8'd0;//16、17、18...地址数据
assign shifout2 = shift_en?taps[ 7:0]:8'd0;//8、9、10...地址数据
assign shifout3 = shift_en?taps[15:8]:8'd0;//0、1、2...地址数据
my_shift my_shift_inst (
.clock ( clk ),
.shiftin ( in ),
.shiftout ( ),
.taps ( taps )
);
endmodule
shift_reg模块:顶层连线
module shift_reg(
input clk,
input rst_n,
output [7:0]shiftout1,
output [7:0]shiftout2,
output [7:0]shiftout3
);
wire [7:0]cnt;
wire [7:0]in;
wire shift_en;
my_rom my_rom_inst (
.address ( cnt ),
.clock ( clk ),
.q ( in )
);
counter counter_inst(
.clk(clk),
.rst_n(rst_n),
.cnt(cnt),
.shift_en(shift_en)
);
shift_register shift_register_inst(
.clk(clk),
.rst_n(rst_n),
.in(in),
.shift_en(shift_en),
.shifout1(shiftout1),
.shifout2(shiftout2),
.shifout3(shiftout3)
);
endmodule
仿真模块
`timescale 1ns/1ps
module shift_reg_tb;
reg clk;
reg rst_n;
wire [7:0]shiftout1;
wire [7:0]shiftout2;
wire [7:0]shiftout3;
shift_reg shift_reg_inst(
.clk(clk),
.rst_n(rst_n),
.shiftout1(shiftout1),
.shiftout2(shiftout2),
.shiftout3(shiftout3)
);
initial clk = 1;
always #10 clk = ~clk;
initial begin
rst_n = 0;
#20
rst_n = 1;
#1000
$stop;
end
endmodule
三、仿真验证
运行modelsim进行仿真,可以看到有数据产生,对照rom的mif文件,产生数据正确,调出其他模块信号进行观察。
可以看到在cnt=16的时钟上升沿,en拉高,Shift_register开始输出。