移位寄存器的 IP核调取及应用

六眼飞鱼酱① 提交于 2019-11-29 13:20:25

写在前面的话

做很多图像算法的时候我们经常需要用到模板运算(如sobel图像边缘检测、中值滤波、均值滤波等等),处理这些问题的时候,我们可以借助altera提供的移位寄存器IP核来简化我们的设计,从而提高设计效率。本节,梦翼师兄和大家一起学习这个适合用于模板运算的移位寄存器IP核的用法。

 

功能要求

 

假设数据在一个ROM中以如下图所示的方式存放,列加行的值作为该数的地址(如e的地址就是8+1=9)。

 

address

0

1

2

3

4

5

6

7

0

a

d

g

j

m

p

aa

bb

8

b

e

h

k

n

q

dd

cc

16

c

f

i

l

o

r

ee

ff

24

s

t

u

v

w

rr

gg

hh

……

y

z

uu

vv

ww

qq

ii

jj

 

在图像处理领域,要实现Sobel或者均值滤波等算法,则需要按照3*3矩阵的格式提取数据,如下图所示:(现在想要每次取出3列数据为一组,如第一列数据:a、b、c 第二列数据:d、e、f 第三列数据:g、h、i)

解决方案:在这儿我想给大家介绍一个叫做Shift_register的 IP核来实现这种功能,而且还有很重要的一点就是我们可以利用这种方法来实现流水线操作,我们暂且就将其看做是移位寄存的“FIFO”吧。

如果我们将该IP核配置成如下图所示的两个“FIFO”,那么我们从ROM中取数的原理就可以用下图表示:

有两个“FIFO”,长度都是8。ROM中的数据从in端口输入,每次地址加一。

用一个计数器cnt作为ROM的地址线,cnt每增加1,ROM就会输出新的数据并通过in[7:0]端口进入shift_register,同时shift_register中的所有数据就会同步向前移位一次,当计数到16时:

 

 

 

下一个时钟到来时候开始同时取值shiftout0、shiftout1、shiftout2

操作步骤

首先建立一个深度为256,字节位宽为8,初始值为0255ROM IP核(参考:5.2)。

接下来设置移位寄存器的IP核:

在右侧的IP核搜索的编辑区,键入shift,在菜单栏中找到并双击【Shift register】

 选择语言类型为Verilog,并命名,然后点击【OK】

设置位宽8bit,设置有2个“fifo”,每个“fifo”的深度为8。然后点击【NEXT

   

选择shift_reg_inst.v,点击【Finish】

顶层架构设计

 

模块功能介绍

模块名

功能描述

counter

给出rom的地址,以及移位寄存器的输出使能

rom

Rom IP核,负责提供源数据

shift_register

输出一定形式的数据

shift_reg

连接各子模块

端口和内部连线描述


顶层模块端口介绍

端口名

端口说明

clk

系统时钟输入

Rst_n

系统复位

shiftout0

数据输出

Shiftout1

数据输出

Shiftout2

数据输出

系统内部连线介绍

连线名

连线说明

shift_en

输出使能信号

cnt

给rom的地址信号

in

rom提供的初始数据

代码解释


Counter模块代码

/****************************************************          

 *   Engineer      :   梦翼师兄

 *   QQ             :   761664056

 *   The module function:给出了rom的地址,以及移位寄存器的输出使能*****************************************************/

00  module counter (

01                          clk,        //系统时钟输入

02                          rst_n,  //系统复位

03                          cnt,        //rom地址

04                          shift_en //输出使能信号

05                      );

06      //模块输入

07      input clk;//系统时钟输入

08      input rst_n;//系统复位

09      //模块输出

10      output reg [7:0] cnt;//rom地址

11      output reg shift_en;//输出使能信号

12

13      always @ (posedge clk or negedge rst_n)

14          begin

15              if (!rst_n)         //复位清零

16                  begin

17                      cnt <= 0;

18                      shift_en <= 0;

19                  end

20              else

21                  begin

22                      if (cnt >= 16)      //cnt计数为16的时候表示shift_register中的两个fifo值已经移入

23                          begin

24                              cnt <= cnt+1;

25                              shift_en <= 1;

26                          end

27                      else

28                          cnt <= cnt + 1;

29                  end

30          end

31

32

33  endmodule 

Shift_register模块代码

/****************************************************          

 *   Engineer      :   梦翼师兄

 *   QQ             :   761664056

 *   E_mail        :   zxopenwjf@126.com

 *   The module function:进行移位输出 *****************************************************/

00 module shift_register (

01 clk, //系统时钟

02 rst_n, //系统复位

03 in,  //rom给出的数据

04 shiftout0, //输出数据

05 shiftout1, //输出数据

06 shiftout2, //输出数据

07 shift_en //出使能

08 );

09 //系统输入

10 input clk; //系统时钟

11 input rst_n;//系统复位

12 input [7:0] in;//rom给出的数据

13 input shift_en;//出使能

14 //系统输出

15 output [7:0] shiftout0; //输出数据

16 output [7:0] shiftout1;//输出数据

17 output [7:0] shiftout2;//输出数据

18 //定义中间连线

19 wire [15:0] taps;

20

21 assign shiftout0 = shift_en ? in : 0 ;//shift_en为真值时,shiftout0 = in

22 assign shiftout1 = shift_en ? taps [7:0] : 0 ;//shift_en为真值时,shiftout1 = taps [7:0]

23 assign shiftout2 = shift_en ? taps [15:8] : 0 ;//shift_en为真值时,shiftout2 = taps [15:8]

24 //调用IP

25 my_shift my_shift_inst (

26 .clock ( clk ), //系统时钟

27 .shiftin ( in ), //rom给出的数据

28 .shiftout (), //shiftouttaps中的数据一样,所以只用一个

29 .taps ( taps )

30    );

31

32 endmodule

顶层连接

/****************************************************          

 *   Engineer      :   梦翼师兄

 *   QQ             :   761664056

 

 *   The module function:顶层连接*****************************************************/

00  module shift_reg ( 

01                          clk,    //系统时钟输入

02                          rst_n,  //系统复位

03                          shiftout0, //输出有效数据

04                          shiftout1, //输出有效数据

05                          shiftout2  //输出有效数据

06                      );

07      //系统输入

08      input clk;  //系统时钟输入

09      input rst_n;//系统复位  

10      //系统输出

11      output [7:0] shiftout0; //输出有效数据

12      output [7:0] shiftout1; //输出有效数据

13      output [7:0] shiftout2; //输出有效数据

14      //定义中间连线

15      wire [7:0] cnt; //rom的地址

16      wire [7:0] in;  //rom中的数据

17      wire shift_en;  //输出使能

18      //调用rom

19      my_rom  my_rom_inst (

20                                  .address ( cnt ), //rom的地址

21                                  .clock ( clk ), //时钟

22                                  .q (in )                //rom的输出数据

23                              );

24      //实例化counter

25      counter counter (

26                                  .clk(clk),      //系统时钟输入

27                                  .rst_n(rst_n),//系统复位

28                                  .cnt(cnt),  //rom的地址

29                                  .shift_en(shift_en)//输出使能

30                              ); 

31      //实例化shift_register

32      shift_register  shift_register (

33                                    .clk(clk),      //系统时钟输入

34                                    .rst_n(rst_n), //系统复位

3                                     .in(in),        //移位寄存器的输入数据

36                                    .shift_en(shift_en), //输出使能

37                                    .shiftout0(shiftout0), //输出有效数据

38                                    .shiftout1(shiftout1), //输出有效数据

39                                    .shiftout2(shiftout2)   //输出有效数据

40                                 );

41

42  endmodule 

编写完可综合代码之后,查看RTL视图如下:

 

RTL视图可以看出,代码综合以后的结果和我们设计的系统框图一致,说明顶层模块级联关系正确,接下来编写测试代码如下:

/****************************************************          

 *   Engineer      :   梦翼师兄

 *   QQ             :   761664056

 *   The module function :shift_reg 的仿真测试:*****************************************************/

00 `timescale 1ns/1ps  //时间单位和精度定义

01

02 module shift_reg_tb;

03 //系统输入

04 reg clk; //系统时钟输入

05 reg rst_n;//系统复位

06 //系统输出

07 wire [7:0] shiftout0; //输出有效数据

08 wire [7:0] shiftout1; //输出有效数据

09 wire [7:0] shiftout2; //输出有效数据

10

11 initial begin

12 clk = 1;

13 rst_n = 0;

14 # 200.1

15 rst_n = 1;

16 end

17

18 always # 10 clk = ~clk; //50M的时钟

19

20 shift_reg shift_reg ( 

21 .clk(clk),    //系统时钟输入

22 .rst_n(rst_n),  //系统复位

23 .shiftout0(shiftout0), //输出有效数据

24 .shiftout1(shiftout1), //输出有效数据

25          .shiftout2(shiftout2)  //输出有效数据

26 );

27

28 endmodule

仿真分析

shift_en拉高以后,shiftout0shiftout1shiftout2,就输出了预想的值,证明我们的设计正确。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!