搜索
bottom↓
回复: 30

高手们,问一个关于Altera双口RAM使用问题

[复制链接]

出0入0汤圆

发表于 2012-12-11 15:01:58 | 显示全部楼层 |阅读模式
双口RAM可以配置成8bit进,32bit出,比如我存了16个8bit数据,RAM地址为0-15。
那么RAM内部配置成0-3地址为一个32bit数据,4-7地址为一个32bit数据,8-11地址为一个32bit数据,12-15地址为1个32bit数据。
总共就能读出4个32bit数据,这是固定的不可更改的。

现在我想要做的是一个时钟周期读出任意地址起始的连续4个字节,比如我想要读出0-3地址的4个字节,接下来又要读出1-4地址的4个字节,然后又要读出3-6地址的4个字节。
总之,一个时钟周期读出任意地址起始的连续4个字节,而不是固定的起始地址。
该怎么做?
读时钟160M。

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2012-12-11 15:05:22 | 显示全部楼层
你从地址0到12地址连续读,不就是连续的32bit数据吗,如果不行,你可以仿真看一下,这样连续从地址0读,看看是不是正确

出0入0汤圆

 楼主| 发表于 2012-12-11 15:05:45 | 显示全部楼层
可以考虑用4个RAM存同样的数据,每个RAM的读地址在起始地址的基础上依次加1,这样就同时读出4个字节了,但是这样太耗存储资源了,不可取。
有没有更好的办法?

出0入0汤圆

 楼主| 发表于 2012-12-11 15:06:58 | 显示全部楼层
chm119 发表于 2012-12-11 15:05
你从地址0到12地址连续读,不就是连续的32bit数据吗,如果不行,你可以仿真看一下,这样连续从地址0读,看 ...

能否解释清楚点?

出0入0汤圆

发表于 2012-12-11 15:14:24 | 显示全部楼层
ab8780000 发表于 2012-12-11 15:06
能否解释清楚点?

你就从0地址开始读,一直到地址12,地址加一,就相当于这个32位数据,向右移除8bit数据,从左边移入8的bit数据,这样就达到了你的要的要求了

出0入0汤圆

 楼主| 发表于 2012-12-11 16:22:35 | 显示全部楼层
chm119 发表于 2012-12-11 15:14
你就从0地址开始读,一直到地址12,地址加一,就相当于这个32位数据,向右移除8bit数据,从左边移入8的bi ...

0-15这16个地址存的是8bit数据...

出0入0汤圆

发表于 2012-12-11 18:03:27 | 显示全部楼层
4个RAM,然后在输入跟输出做一下处理
输入根据地址最后两位写到某个RAM里面
输出根据地址先把数据读出来,再拼接起来- -
比你3L的方法省点RAM,不过输出的部分应该要不少逻辑资源

出0入0汤圆

发表于 2012-12-11 19:01:23 | 显示全部楼层
Cyclone 系列使用內部雙口異步+異步使能...Quartus無法編輯
如果容量小,你可以使用內部的 le 模擬就可以了.

出350入477汤圆

发表于 2012-12-11 21:28:40 | 显示全部楼层
本帖最后由 redroof 于 2012-12-11 21:37 编辑

使用4个独立的8位双口RAM(下面叫做RAM0-RAM3)每个RAM作为实际存储区(32位)的1个字节范围
每个RAM的地址线上面带一个可选的加1电路。
为了倒换字节顺序,还需要一个32入32出的循环移位器(多路开关也行,反正完成的作用是倒换4个字节的顺序),它有4种选项:
0:原样输出
1:循环右移8位
2:循环移动16位
3:循环左移8位
4个RAM的数据线通过这个循环移位器接到最终输出
4个RAM的地址线并起来,地址最低2位作为控制位,控制每个8位RAM的地址加1是否有效,也控制循环移位器。
循环移位器的控制字就是地址最低2位。
4个地址加1电路的控制与地址低2位关系如下:
地址低2=0,所有加1无效
地址低2=1,RAM0的地址加1
地址低2=2,RAM1和RAM0的地址加1
地址低2=3,RAM0-RAM2的地址加1

基本的思路就是,在外部给定一个地址的时候,内部根据情况,给每个小RAM或者是原始地址,或者是原始地址加1。
因为,不对齐的32位,在内部存储在各个小ram中的地址可能是原始地址,也可能是原始地址加1。

如果地址加1器不能作为组合逻辑使用,或者他作为组合逻辑会拖慢系统速度,那么就用寄存器把数据缓存一个周期,变成一个流水线的RAM(收到地址后在第二个时钟才能输出数据)
如果这个端口还要写,逻辑完全是相同的,照此办理。
RAM的另外一个端口如果也有这种要求(从不对齐的地址访问32位),也可以照此办理。如果另一个端口无此要求,可以直接把数据口合并起来,地址口连在一起当普通的32位RAM

出0入0汤圆

发表于 2012-12-11 22:06:02 | 显示全部楼层
本帖最后由 Codoox 于 2012-12-11 22:10 编辑

输入输出都配置成8位,读出时连续读RAM即可,将读出的数据放到8*4=32bit的移位寄存器中,第4个周期开始从移位寄存器中拿数据,每个周期拿一次,得到数据就是0-3,1-4,2-5.。。。

出0入0汤圆

发表于 2012-12-11 22:24:42 | 显示全部楼层
不好意思,没看清楚,LZ是要一个时钟读出“任意”4Byte,也就是说要一个周期读四次RAM,160M*4的频率,够呛啊。LZ存的数也不多也就128bit,直接用LE实现吧,好操作。

出0入0汤圆

 楼主| 发表于 2012-12-12 09:21:14 | 显示全部楼层
Codoox 发表于 2012-12-11 22:24
不好意思,没看清楚,LZ是要一个时钟读出“任意”4Byte,也就是说要一个周期读四次RAM,160M*4的频率,够呛 ...

这里只是举个例子,实际上我存的是2048个Bytes

出0入0汤圆

 楼主| 发表于 2012-12-12 09:25:10 | 显示全部楼层
redroof 发表于 2012-12-11 21:28
使用4个独立的8位双口RAM(下面叫做RAM0-RAM3)每个RAM作为实际存储区(32位)的1个字节范围
每个RAM的地址 ...

非常感谢,4个RAM是可以做,但是这样做下去芯片存储资源远远不够了,用2个RAM可以考虑,大于3个RAM就不能做了。

出350入477汤圆

发表于 2012-12-12 10:04:05 | 显示全部楼层
ab8780000 发表于 2012-12-12 09:25
非常感谢,4个RAM是可以做,但是这样做下去芯片存储资源远远不够了,用2个RAM可以考虑,大于3个RAM就不能 ...

如果想从任意的8位地址开始,读32位,并且数据只存储1份,唯一的方法就是前面我说的方法。再没有其他选择。如果谁能找到比这更好的方法,欢迎告诉我!

如果只用2个独立RAM,只能做到从任意16位对齐的地址开始读一个32位。

其实FPGA片内的DPRAM数目不少啊,为了你这个功能占用4块8位的DPRAM并不夸张。上面还有人说让你存数据的时候存4份相差1个地址,这个才浪费呢^_^
如果还不够,只能换大容量的FPGA了。

出0入0汤圆

 楼主| 发表于 2012-12-12 13:14:16 | 显示全部楼层
redroof 发表于 2012-12-12 10:04
如果想从任意的8位地址开始,读32位,并且数据只存储1份,唯一的方法就是前面我说的方法。再没有其他选择 ...

非常感谢,整个设计有很多个这样的模块,所以存储器比较紧。

出350入477汤圆

发表于 2012-12-12 14:03:02 | 显示全部楼层
ab8780000 发表于 2012-12-12 13:14
非常感谢,整个设计有很多个这样的模块,所以存储器比较紧。

或许你的设计本身有问题。
通常不应该有这样的需求啊,为什么要从不对齐的任意地址读32位呢?这个数字是怎么存进去的?
正常来说,数字始终应该是对齐的,不然你存入的时候也麻烦。
大部分处理器或者禁止不对齐的访问,或者自动把不对齐的访问拆成两个总线周期。

出0入0汤圆

发表于 2012-12-12 15:52:16 | 显示全部楼层

双口RAM可以配置成8bit进,32bit出,比如我存了16个8bit数据,RAM地址为0-15。
那么RAM内部配置成0-3地址为一个32bit数据,4-7地址为一个32bit数据,8-11地址为一个32bit数据,12-15地址为1个32bit数据。
总共就能读出4个32bit数据,这是固定的不可更改的。”

对于LZ这种用法没实践过,请问LZ在读数据的时候,比如要读第一个32bit,是不是在一个CLK内输入0-3任意一个地址都能读出0-3地址的32bit数据?
如果是这样的话,大家看看这样可不可行:
用两块RAM存放相同的数据,暂且命名为RAM0、RAM1;
读取数据的时候先分析一下地址,例如要读1-4的32bit数据,就读取RAM0中的第0-3byte,RAM1中的第4-7byte,然后将RAM0的第1-3byte和RAM1的第4byte拼接成所需的32bit数据。
其他类似,以RAM0为参照,根据地址动态选择读取RAM1中的前一个或后一个32bit,与RAM0(当前地址)数据拼接得到所需数据。

不知道分析的对不对,欢迎各位拍砖!

出0入0汤圆

 楼主| 发表于 2012-12-12 16:35:03 | 显示全部楼层
Codoox 发表于 2012-12-12 15:52

双口RAM可以配置成8bit进,32bit出,比如我存了16个8bit数据,RAM地址为0-15。
那么RAM内部配置成0-3地 ...

呵呵,对的,跟我想一块去了,就是用这种方法解决的

出350入477汤圆

发表于 2012-12-12 20:36:36 | 显示全部楼层
Codoox 发表于 2012-12-12 15:52

双口RAM可以配置成8bit进,32bit出,比如我存了16个8bit数据,RAM地址为0-15。
那么RAM内部配置成0-3地 ...

这是个好方法,数据存2份,但最少也只需要2个DPRAM块。
在所需存储器小于FPGA的单个DPRAM块的时候,这个方法比我上面说的用4个8位DPRAM要节约一些。但另外一些情况比我的方法耗RAM多。
例如:
FPGA的DPRAM块,常见的尺寸是18KBit,也就是可以当作2K的8位,或者1K的16位。
假如这种特殊存储器只需要4K字节,或者更少,那么这种方法用2个DPRAM块就可以做到。用我说的方法仍然得4个DPRAM块,不论每个块有没有用满。
但如果这种存储器需要8K字节,两种方法的消耗就是一样的了,都是4块DPRAM
如果这种存储器需要大于8K字节,那么我的方法更节约,因为我的方法只存1份数据,这个方法要存2份。

出0入0汤圆

发表于 2012-12-12 20:59:43 | 显示全部楼层
redroof 发表于 2012-12-12 20:36
这是个好方法,数据存2份,但最少也只需要2个DPRAM块。
在所需存储器小于FPGA的单个DPRAM块的时候,这个 ...

兄弟,你分析的很周到,佩服!

出350入477汤圆

发表于 2012-12-13 09:24:29 | 显示全部楼层
Codoox 发表于 2012-12-12 20:59
兄弟,你分析的很周到,佩服!

其实我好久没做FPGA了。。。
我当年的流行型号还是Spartan2或者cyclone2,也不知道现在的主流型号的dpram是不是继续保持18Kbit了。
不过原理都是相同的

出0入0汤圆

 楼主| 发表于 2012-12-13 09:45:30 | 显示全部楼层
redroof 发表于 2012-12-12 20:36
这是个好方法,数据存2份,但最少也只需要2个DPRAM块。
在所需存储器小于FPGA的单个DPRAM块的时候,这个 ...

你说的方法不是也存4份数据吗?

出350入477汤圆

发表于 2012-12-13 10:04:40 | 显示全部楼层
ab8780000 发表于 2012-12-13 09:45
你说的方法不是也存4份数据吗?

我只存了1份数据哦!
把数据分成4部分存的。0,4,8字节在RAM0;1,5,9字节在RAM1;2,6,10字节在RAM2;3,7,11字节在RAM3;依次类推。但总容量是1份的容量。
只因为我分了4份,而每一份在FPGA内部都有最小容量(一个DPRAM块的大小),所以如果需要容量很小,我这个做法就不如存2份合算。
存2份最小只要2个DPRAM,存4个部分最小需要4个DPRAM。
如果需要容量大一点,我这个做法更合算。

出0入0汤圆

 楼主| 发表于 2012-12-13 10:12:50 | 显示全部楼层
redroof 发表于 2012-12-13 10:04
我只存了1份数据哦!
把数据分成4部分存的。0,4,8字节在RAM0;1,5,9字节在RAM1;2,6,10字节在RAM2 ...

高手啊,绝对的高手!佩服、你这个方法帮我省了很多M9K块,我的数据量很大的。
不做FPGA了现在在哪高就啊?

出0入0汤圆

发表于 2012-12-13 10:15:48 | 显示全部楼层
ab8780000 发表于 2012-12-11 16:22
0-15这16个地址存的是8bit数据...

你也可以做个32bit的双端RAM,在写数据之前进行处理,进行移位,将数据进行右移,在填满32bit数据之后在写进入ram,以后每次就写入就行,例如,data【31::】 <= {data1[7:0],24‘b0},头四个数据不向ram写,四个之后,每个时钟将data写一次。

出350入477汤圆

发表于 2012-12-13 10:21:25 | 显示全部楼层
chm119 发表于 2012-12-13 10:15
你也可以做个32bit的双端RAM,在写数据之前进行处理,进行移位,将数据进行右移,在填满32bit数据之后在 ...

没用的,问题在读这一端,不在写。
即使用再大的宽度,如果它读的跨越了宽度的边界,始终不能一次读出。
除非内部使用多套总线,然后拼起来。
例如我的做法使用了4套内部总线,各管1/4的存储区
Codoox 的做法使用了2套内部总线,数据在内部存了2份

出0入0汤圆

 楼主| 发表于 2012-12-13 10:23:13 | 显示全部楼层
redroof 发表于 2012-12-13 10:21
没用的,问题在读这一端,不在写。
即使用再大的宽度,如果它读的跨越了宽度的边界,始终不能一次读出。
...

是啊,不过redroof 你的做法写的时候比较费劲啊,我还是pingpong写的

出350入477汤圆

发表于 2012-12-13 10:39:18 | 显示全部楼层
ab8780000 发表于 2012-12-13 10:23
是啊,不过redroof 你的做法写的时候比较费劲啊,我还是pingpong写的

我说的只是原理,其实可以优化:
输入的地址,其实只需要1个地址加1电路
每个小RAM的地址带一个1:2切换器,或者选择原始地址,或者选择加1的地址
输出部分倒换字节顺序的的8位4:4交叉开关或者循环移位器是省不了的。你自己选择是用交叉开关还是移位器吧,我不知道哪个更省资源。
如果RAM的频率已经接近上限,你需要做流水线,增加一个流水级来做地址加1,再增加一个流水级来做输出的倒换字节顺序。
无流水的时候DPRAM是收到地址的第二个时钟输出数据,如果多带两级流水,就变成在收到地址的第四个时钟输出数据了。


出0入0汤圆

 楼主| 发表于 2012-12-13 10:54:38 | 显示全部楼层
redroof 发表于 2012-12-13 10:39
我说的只是原理,其实可以优化:
输入的地址,其实只需要1个地址加1电路
每个小RAM的地址带一个1:2切换 ...

嗯,明白了,非常感谢啊

出0入0汤圆

发表于 2012-12-13 11:06:37 | 显示全部楼层
redroof 发表于 2012-12-13 09:24
其实我好久没做FPGA了。。。
我当年的流行型号还是Spartan2或者cyclone2,也不知道现在的主流型号的dpram ...

呵呵,前辈啊!
回头一想,这个问题归根结底就是一个串转并的问题,公司做图像插补算法的时候采用了你说的这种做法,用了两片SRAM,不过时序没这么紧,一时间没想起来,呵呵。
前辈不做FPGA了,转管理了?

出0入0汤圆

 楼主| 发表于 2012-12-13 13:32:45 | 显示全部楼层
Codoox 发表于 2012-12-13 11:06
呵呵,前辈啊!
回头一想,这个问题归根结底就是一个串转并的问题,公司做图像插补算法的时候采用了你说 ...

是啊,前辈现在在做什么了?给做FPGA小弟们指明一条的出路啊
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 07:22

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表