可以发现这里非常重要的一个资源就是MUX,Spartan3E称为wide multiplexer。 在一个Slice中,下半部分只提供F5MUX,也就是用于构造LUT5的MUX。
而在上半部分中则没有F5MUX,因为一个slice刚好两个LUT4,有一个F5MUX就够了。 但是上半部分提供了一个FiMUX,这个i可以是6、7、8。
这样,上半部的FiMUX就为扩展更大规模的LUT-i提供了物质基础。
如果要细究一下哪些slice提供F6/7/8 MUX,可以这样来归纳。 一个CLB中的下面两个slice,只能提供F6MUX。
上面的两个slice中,SliceM提供F7MUX,SliceL提供F8MUX。
另外,LUT作为4比特逻辑能够实现2:1MUX功能,因此借助wide MUX可以实现更高阶的MUX。
最后重点关注一下F5MUX中提高性能的一个细节。
F5MUX的选通输出,如果要构造LUT-6,就可以直接将输出绕回本Slice的F6MUX。 为此,F5MUX特意创建了两个输出口,一个输出到CLB外,一个则利用本地反馈电路快速绕回到FiMUX进行级联。
进位与算术逻辑
这是Slice结构部分的高阶知识。
Slice的主角是LUT,他有个缺陷,就是比较适合完成普通的逻辑设计,也就是单比特输出的运算。
但是在设计中,大量用到算术逻辑,最常见的就是乘法和加法,这些运算的特点就是多个输出。
比如带进位的1比特加法运算,结果有两个比特,一个是部分和,一个是进位。
如果用LUT来实现的话,这么一个简单的运算都至少需要两个LUT来完成,非常浪费。 为了避免这种浪费,Xilinx想出了妙计,就是在Slice中添加几个简单的XOR和AND门。 这些门数量极少,但是画龙点睛,把算术逻辑激活了。
比如上面的单比特加法,只使用一个LUT,然后搭配简单的几个门就搞定了,大大节省资源。
我们看以参考经典的图12和图20、21,我们发现,支持算术逻辑的单元并不多。 在slice的上下两侧各有这样一套资源。
每套资源都是一个三元组:{AND、XOR、CYMUX}。
结合图20、21,我们可以领悟到,这些资源其实就是为了实现“部分和”运算和“部分积”运算而实现的。
从而构造出一个完整的、高效的算术逻辑运算通道。
对于加法和乘法,产生部分和以及部分积是在横向完成的,并且没有积累,所以时序上没有问题。
但是进位链由于具有累积效应,因此必须有专门的针对性设计。
我们可以看到Spartan3E里面就有这样的一条进位链自下往上,通过一堆级联的MUX快速
输出。
这个就是Xilinx的进位链优化电路。 赞!
存储单元
存储单元是通用的设计,可以配置成为FF,也可以配置成为Latch。 关于两者的差异,请自己查阅手册。
基本上存储单元的输入数据来自两个部分: 1. LUT组合逻辑输出; 2. 旁路数据
一个存储单元有12个输入输出口,当然配置在不同的类型下,会使用到不同的接口。 D-Q 是输入输出数据信号,我给他列成一对; C-CE 是时钟和时钟使能,也是一对;
G-GE 是配置为latch时的门和门使能信号,又是一对;
S-R 是同步set/reset信号,两者取反,所以等效于一个信号;
PRE-CLR 是异步set/reset信号,两者取反,所以等效于一个信号; SR-REV 和S-R以及PRE-CLR是一个系列,只不过他们是CLB的输入信号,在Slice内部,他们化身成了S-R以及PRE-CLR。
注意SR是一个通用用法,你可以通过SRLOW和SRHIGH属性来将其设置为SET用途还是Reset用途。
提一下REV,这个信号和SR同时作用,当他有效时,set/reset的值就取反。 感觉很全面,不过又感觉好无聊,尽整一些没用的东西。
分布式存储 Distributed RAM
一个SliceM LUT 存储16位数据 (RAM 16)。
通过多个LUT的组合,可以对宽度和深度进行扩展,比如 16x4,32x2,64x1。
要提高地址空间就需要有地址线的扩展,LUT4只接收4位地址,扩展的地址由BX、BY两个旁路信号提供。
有了这两个信号,地址就是6位的,深度就是64。
写操作是同步的,也就是和写时钟(SliceM的CLK)同步。 读操作则是异步的,随时反映当前读地址的内容。
接下来重点研究一下SliceM如何构造dual port RAM。这个非常巧妙。 建议大家对照图12、23进行研究。
注意SliceM中上面的LUT可以同时读写,而下面的是只读的。
这和dual port的定义有关,dual port是一侧只读、一侧只写,所以有一个LUT完全可以只读,来减小控制逻辑。
由于在逻辑上只有一个存储空间,所以两块LUT的内容必须一致。
这就要求所以写操作必须同时反映到两个LUT,要完成这一点,必须令写使能、写地址、写数据同时反映到两个LUT。
观察图12的两个LUT的WS (写使能)、WG-WF (写地址)、D1 (写数据) 的级联关系就明白了。
好了,到此我们保证了写操作的正确性和两块LUT的内容一致性。 那么读操作怎么完成呢?
我们观察到,除了WG-WF,还有一个名为A[4:1]的地址总线。 这个地址总线独立于写地址总线,从而确保了独立的读操作。 然后读出的数据由LUT的D端输出。
作为Dualport RAM使用的时候,读数据从下端LUT的D口输出。
最后,介绍一个使用注意: 1. INIT属性用于初始化RAM;
2. 如果只要ROM功能,则SliceL也可以提供;
3. 全局写使能信号GWE在配置阶段关闭,可以防止对RAM初始值的干扰;
总之,通过上面的内容我们明白了,SliceM和SliceL在存储支持上的最大区别: - SliceL只能支持读功能,比如 ROM - SliceM则支持读写以及DualPort实现,因此在读写地址独立和输入数据通道等方面做了增强
移位寄存器 - 构造
Slice-M的LUT有个优势,就是可以构造16位的移位寄存器。 由于一个SliceM内有两个LUT,所以可以级联构造32位寄存器。
进一步,一个CLB内有上下两个SliceM,可以构造64位的移位寄存器。 事实上,以此类推,多个CLB可以进一步构造更长的移位寄存器。
- 例化
要使用移位寄存器可以使用SRL16 (Shift Register LUT 16 bit),他有很多变种,可以构造出多种形式的近似的移位寄存器。
他的输出有两个,一个是可寻址的输出,这是可变长度的移位寄存器的输出。
另外一个名为MC15,是LUT中的最后一个比特,用于多个移位寄存器级联时使用。 因为级联的上级SR总是从最后一个比特连到下一个SR。 移位寄存器有原语,好像是SSRL16,大家可以试用一下。 在Xilinx的技术文档中可以找到更多的SR形式。
- 不包括FF
很多人疑惑,SR中是否有FF存在,其实图25清楚的回答了这个问题。 可以看到SR是完全由SliceM的LUT实现的,FF不在其内。 当然可以在SR之外和FF连接,构造更长的SR。
Block RAM 概览
在spartan3E系列中,每个FPGA基本有4-36个BRAM。
每个这样的BRAM都是DualPort的、可配置的18Kbit存储器。 为什么是18Kbit呢,可以这样记忆,16K做数据,2K做校验位。
当然你一定要放18K数据也是可以的,但是涉及初衷肯定是考虑了校验位的需要。
所以以后如果使用小的内存就用我们前面讲过的Slice(LUT)分布式RAM。 如果要大块的,就不要麻烦了,直接例化BRAM。
BRAM有几种主要的可配置项:
- 初始值(比如可以放启动软件代码)
- 端口aspect ratio,这个我会在后面介绍,简单讲就是输入输出数据长度的不对称配置 - 写状态下的数据输出模式 - 单端口双端口配置
BRAM的片上位置
BRAM和乘法器相邻,两者一起以1~2纵列的形式放在FPGA内部。 根据FPGA的大小,有些只有1列,有些有2列。
每个BRAM都和一个18x18的乘法器相邻。
BRAM的A口上端16位和乘法器A口上端16位共享。 BRAM的B口上端16位和乘法器B口上端16位共享。 不知道这样做的目的是什么,请大家补充
BRAM的端口结构
BRAM被配置为双端口结构。
每个端口都有其独立的数据、控制、时钟总线。
根据这个特点,一个BRAM可以有四种基本的读写数据通路: - 只从A端口读和写 - 只从B端口读和写 - A写B读 - B写A读
通过原语调用BRAM
BRAM的调用原语有两种,一种是当做dual port 调用,一种是当做single port 调用。
当dual port 调用时,使用原语 RAMB16_S[wa]_S[wb],例如
- RAMB16_S9_S18:双端口RAM,A端口宽度为9,B端口宽度为18