LUT与移位寄存器

LUT表是最基本的逻辑单元,入门书籍必有的内容,基本原理这里不说了。

一般的,有SLICEM和SLICEL两种,M代表存储,L代表逻辑,好记吧。

L的功能M也能实现,M比L更复杂,所以我们直接去看SLICEM。

图上面时直接从工具里面截的,这里面包括了:

6位读地址输入(A1-A6)

8位写地址输入(WA1-WA7)

写时钟(CLK)

写使能(WEN)

数据输入(DI1)

数据输出(O6)

移位寄存器输出(MC31)

除此之外,由于DI2输入线和O5输出的存在,这片LUT还可以被配置为32-depth,2-bit-data-wide的RAM。

为什么写是8位,读是6位呢?有疑惑就看datasheet或者user guide啊,翻出UG474,里面有张图,看了就明白了:

拿一个SLICEM的四个LUT搭一个256的单口RAM,看到了吧,写地址8位直接用,读地址用6位,然后高两bit,一个给F7MUX,一个给F8MUX,相当于做了两级二选一。

还有一个重点要说的是移位寄存器,移位寄存器用的最多的地方就是做delay 了。

下面是简单的两段代码:

always @(posedge clk )begin

shift_r <= {shift_r[62:0],rxp} ;

end

always @(posedge clk )begin

txp <= shift_r[63];

end

大概的意思就是将rxp输入延迟64个时钟周期,然后输出。在很多文档里面都说过了,LUT单元是可以直接生成移位寄存器的,当然必须是SLICEM里面的LUT的,我们看看最后生成的结果是啥样的:

有点不好看啊,我俩简单解释一下:

1.红线代表LTU读地址输入,读地址代表了移位寄存器输出的位数,写31就是延迟32位,可见所有的地址都被连接在一个高电平上,5h11111=31,一般情况下,是A[5:1]表征地址,A[0]固定为高

2.青色是时钟,这对于SLICEL来说是没有的,因为有了时钟,才可能同步操作;

3.蓝色是需要移位的数据,程序里面的rxp,直接输入到了LUT-B的数据DI1口

4.黄色从LUT-B的MC31输出的结果,一个LUT可以作为32位的移位寄存器,因为需要移位64次, 所以需要两个LUT级联才能完成完整的移位结果

5.白色是最后的输出,注意是从O6输出的,即级联之后64位移位后的结果,再过一级FF之后,就是txp 。

这种写法比较简单直观,也有一些同学想要规范,那我们调用一下官方的原语试试:

SRL16E #(

.INIT(16'h0000), // Initial contents of shift register

.IS_CLK_INVERTED(1'b0) // Optional inversion for CLK

)

SRL16E_inst (

.Q(SRL10_r), // 1-bit output: SRL Data

.CE(1), // 1-bit input: Clock enable

.CLK(clk), // 1-bit input: Clock

.D(rxp ), // 1-bit input: SRL Data

// Depth Selection inputs: A0-A3 select SRL depth

.A0(0),

.A1(1),

.A2(0),

.A3(1) //0x1010= 10

);

这是一个经典的16位寄存器的小模块,看看布线后成啥样:

1.红线代表LTU读地址输入,读地址代表了移位寄存器输出,一般情况下,是A[5:1]表征地址,但是我们看到黄色线代表的数据激怒的是DI2,也就是用了两个5输入LUT中的一个,所以真实的地址是4‘h1010 = 10,也就是移位10+1次,A[0]固定为高

2.青色是时钟;

3.黄色是输入,rxp ,注意是从DI2口输入的

4.白色是最后的输出,注意是从O6输出的,即10位移位后的结果,也就是SRL10_r。

7系列因为LUT表地址位增加,因此还支持32位移位的原语,我们来看看:

SRLC32E #(

.INIT(32'h00000000), // Initial contents of shift register

.IS_CLK_INVERTED(1'b0) // Optional inversion for CLK

)

SRLC32E_inst (

.Q(SRL20_r), // 1-bit output: SRL Data

.Q31(SRL31_r), // 1-bit output: SRL Cascade Data

.A(5'd20), // 5-bit input: Selects SRL depth

.CE(1), // 1-bit input: Clock enable

.CLK(clk), // 1-bit input: Clock

.D(rxp ) // 1-bit input: SRL Data

);

看看会是怎样布线的:

1.红线代表LTU读地址输入,读地址代表了移位寄存器输出,一般情况下,是A[5:1]表征地址,是5‘h10100 = 20,也就是移位20次,A[0]固定为高

2.青色是时钟;

3.黄色是输入,rxp ,注意是从DI1口输入的

4.白色时最后的输出,注意是从O6输出的,即20+1位移位后的结果,也就是SRL20_r。

5.咖啡色是32位移位后的结果,也就是SRL31_r

这个移位跟信号实际delay的关系,还要看个仿真才能看明白:

图要放大看,rxp_r信号delay了11个时钟节拍(计数器从750到761)得到信号SRL10_r,delay了21个时钟节拍得到了信号SRL20_r,delay了32个时钟节拍得到信号SRL31_r。

也就是delay的时钟节拍N,与配置的LUT地址A之间的关系为:

N = A + 1

说了这么多,总结一下。

注意了,知识点来了:

1.LUT作为移位寄存器配置时,要注意,delay的时钟节拍和LUT地址配置之间的关系!

2.LUT资源分两种(准确来说应该是SLICE分两种),M和L的区别要记得,同时也能看出作为SLICEM功能还是很多的,如果全拿来作分布式RAM太浪费了,当需要的RAM比较大的时候,可以考虑使用BlockRam。

3.写代码时能想到FPGA这些小结构的组成,将代码与结构契合度更紧密一些,无论是资源使用还是时序,都能得到非常明显地改善!

发布了38 篇原创文章 · 获赞 73 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/woshiyuzhoushizhe/article/details/98208130