打印
[FPGA]

跨时钟域的代码如何写更好

[复制链接]
2020|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sxtz531|  楼主 | 2013-7-28 22:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

        有一个处理器,工作于100MHz,一个FPGA工作于50MHz(或者更低),处理器要对FPGA进行简单的控制,两者需要有数据读写通信。处理器有一个读写状态的判断信号,平时为高电平,当进行数据端口的通信时,如果读到该状态标志为低电平时,便结束数据端口上的读写操作,否则一直保持,直到发生超时错误。
        我写了一个处理器和FPGA之间的接口代码,功能可以实现,但不知道有什么不妥之处,或是还有什么更好的方式。

module Interface(
                 input           clk_i,
                 input           reset_i,
                 input           read_frm_cpu_i,                 //处理器输出读信号,低有效
                 input           write_frm_cpu_i,                //处理器输出写信号,低有效
                 input           cs_frm_cpu_i,                    //处理器输出片选信号,低有效
                 input[7:0]      data_frm_cpu_i,              //处理器输出数据信号
                 input[2:0]      addr_frm_cpu_i,              //处理器输出地址信号
                 output reg      read_to_module_o,        //FPGA使用的读信号,低有效
                 output reg      write_to_module_o,       //FPGA使用的写信号,低有效
                 output[7:0] reg data_to_module_o,     //FPGA使用的数据信号
                 output[2:0] reg addr_to_module_o,    //FPGA使用的地址信号
                 output      reg ready_o                         //FPGA对处理器反馈信号,一个FPGA周期的低电片,处理器     
                 );                                                          //收到这个低电片后,会撤销掉保持的读、写状态            

                reg       read_latch;
                reg       write_latch;
                reg[7:0]  data_latch;
                reg[2:0]  addr_latch;
                reg       ready_d1;
                reg       ready_d2;
                reg       ready_d3;
                reg       ready_d4;

                always @(reset_i or read_frm_cpu_i or cs_frm_cpu_i)
                begin
                   if(reset_i)
                   begin
                      read_latch <= 1'b1;
                   end
                   else if(!cs_frm_cpu_i)
                   begin
                      read_latch <= read_frm_cpu_i;
                   end
                   else
                   begin
                       read_latch <= 1'b1;
                   end
                end

                always @(reset_i or write_frm_cpu_i or cs_frm_cpu_i)
                begin
                   if(reset_i)
                   begin
                      write_latch <= 1'b1;
                   end
                   else if(!cs_frm_cpu_i)
                   begin
                      write_latch <= write_frm_cpu_i;
                   end
                   else
                   begin
                       write_latch <= 1'b1;
                   end
                end

                always @(reset_i or data_frm_cpu_i or cs_frm_cpu_i)
                begin
                   if(reset_i)
                   begin
                      data_latch <= 8'b0;
                   end
                   else if(!cs_frm_cpu_i)
                   begin
                      data_latch <= data_frm_cpu_i;
                   end
                   else
                   begin
                       data_latch <= 8'b0;
                   end
                end

                always @(reset_i or addr_frm_cpu_i or cs_frm_cpu_i)
                begin
                   if(reset_i)
                   begin
                      addr_latch <= 8'b0;
                   end
                   else if(!cs_frm_cpu_i)
                   begin
                      addr_latch <= addr_frm_cpu_i;
                   end
                   else
                   begin
                       addr_latch <= 8'b0;
                   end
                end

                always @(posedge clk_i or posedge reset_i)
                begin
                   if(reset_i)
                   begin
                      read_to_module_o  <= 1'b1;
                      write_to_module_o <= 1'b1;
                      data_to_module_o  <= 8'b0;
                      addr_to_module_o  <= 8'b0;
                   end
                   else
                   begin
                      read_to_module_o  <= read_latch;
                      write_to_module_o <= write_latch;
                      data_to_module_o  <= data_latch;
                      addr_to_module_o  <= addr_latch;
                   end
                end

                always @(posedge clk_i or posedge reset_i)
                begin
                   if(reset_i)
                   begin
                      ready_d1 <= 1'b1;
                      ready_d2 <= 1'b1;
                      ready_d3 <= 1'b1;
                      ready_d4 <= 1'b1;
                   end
                   else
                   begin
                      ready_d1 <= read_latch && write_latch;
                      ready_d2 <= ready_d1;
                      ready_d3 <= ready_d2;
                      ready_d4 <= ready_d3;
                   end
                end

                always @(posedge clk_i or posedge reset_i)
                begin
                   if(reset_i)
                   begin
                      ready_o <= 1'b1;
                   end
                   else
                   begin
                      ready_o <= (!ready_d4) || ready_d3;
                   end
                end
endmodule

相关帖子

沙发
Backkom80| | 2013-7-29 08:16 | 只看该作者
用fifo或双口RAM来跨时钟域较好

使用特权

评论回复
板凳
sxtz531|  楼主 | 2013-7-29 12:45 | 只看该作者
Backkom80 发表于 2013-7-29 08:16
用fifo或双口RAM来跨时钟域较好

数据量不大,每1ms最多也就传输4个8位的数据,用这种缓存的方式,会不会有点浪费资源。

使用特权

评论回复
地板
GoldSunMonkey| | 2013-7-29 21:43 | 只看该作者
Backkom80 发表于 2013-7-29 08:16
用fifo或双口RAM来跨时钟域较好

这是最可靠的办法

使用特权

评论回复
5
GoldSunMonkey| | 2013-7-29 21:43 | 只看该作者
sxtz531 发表于 2013-7-29 12:45
数据量不大,每1ms最多也就传输4个8位的数据,用这种缓存的方式,会不会有点浪费资源。 ...

那就打两拍

使用特权

评论回复
6
钻研的鱼| | 2013-7-30 08:43 | 只看该作者
网上搜搜异步fifo的设计,很多经典的**和讨论。
异步fifo的设计,其实就是跨时钟域的设计,其中的空、满、将满、将空等设计,非常有讲究,仔细研究吧!

使用特权

评论回复
7
GoldSunMonkey| | 2013-7-30 23:59 | 只看该作者
钻研的鱼 发表于 2013-7-30 08:43
网上搜搜异步fifo的设计,很多经典的**和讨论。
异步fifo的设计,其实就是跨时钟域的设计,其中的空、满 ...

鱼哥,你跑哪里去了?

使用特权

评论回复
8
GoldSunMonkey| | 2013-7-30 23:59 | 只看该作者
想四你了

使用特权

评论回复
9
mhanchen| | 2013-7-31 21:20 | 只看该作者
sxtz531 发表于 2013-7-29 12:45
数据量不大,每1ms最多也就传输4个8位的数据,用这种缓存的方式,会不会有点浪费资源。 ...

你用的芯片上RAM使用很紧张吗?不紧张的话用一点其实也无所谓,还能省下一些触发器资源

使用特权

评论回复
10
sxtz531|  楼主 | 2013-8-4 00:11 | 只看该作者
mhanchen 发表于 2013-7-31 21:20
你用的芯片上RAM使用很紧张吗?不紧张的话用一点其实也无所谓,还能省下一些触发器资源 ...

片子上没有用到的RAM快,就剩一块了

使用特权

评论回复
11
mhanchen| | 2013-8-4 10:15 | 只看该作者
sxtz531 发表于 2013-8-4 00:11
片子上没有用到的RAM快,就剩一块了

其实对于你这个设计来说最好还是用RAM,因为是慢采快,用触发器同步的方法一点儿也不可靠

使用特权

评论回复
12
sxtz531|  楼主 | 2013-8-4 21:16 | 只看该作者
mhanchen 发表于 2013-8-4 10:15
其实对于你这个设计来说最好还是用RAM,因为是慢采快,用触发器同步的方法一点儿也不可靠 ...

请问下,在跨时钟域的设计中使用握手信号与使用异步FIFO相比较会怎样,一般教科书上在跨时钟域设计里都有提到,但貌似平时很少有人使用,更多的还是使用异步FIFO的方式

使用特权

评论回复
13
mhanchen| | 2013-8-4 21:43 | 只看该作者
sxtz531 发表于 2013-8-4 21:16
请问下,在跨时钟域的设计中使用握手信号与使用异步FIFO相比较会怎样,一般教科书上在跨时钟域设计里都有 ...

我觉得fifo可靠。。但是我没有比较过,找个有经验的请教一下吧

使用特权

评论回复
14
sxtz531|  楼主 | 2013-8-4 21:51 | 只看该作者
mhanchen 发表于 2013-8-4 21:43
我觉得fifo可靠。。但是我没有比较过,找个有经验的请教一下吧

了解,谢谢

使用特权

评论回复
15
廊桥拾梦| | 2013-8-9 12:53 | 只看该作者
猴哥说的对 fifo就ok

使用特权

评论回复
16
HORSE7812| | 2013-8-9 13:53 | 只看该作者
:)

使用特权

评论回复
17
winkle.zhang| | 2013-9-8 12:56 | 只看该作者
呵呵 TQ同学的书讲了 脉冲边沿检测法 借助于存储器 专用握手信号

使用特权

评论回复
18
江宇平99999| | 2013-9-8 21:21 | 只看该作者
(1) two FF
(2) google "toggle synchronizer"
(3) async fifo / dual port ram

使用特权

评论回复
19
GoldSunMonkey| | 2013-9-8 23:29 | 只看该作者
廊桥拾梦 发表于 2013-8-9 12:53
猴哥说的对 fifo就ok

;P有人夸我了

使用特权

评论回复
20
GoldSunMonkey| | 2013-9-8 23:29 | 只看该作者
winkle.zhang 发表于 2013-9-8 12:56
呵呵 TQ同学的书讲了 脉冲边沿检测法 借助于存储器 专用握手信号

嗯嗯,好好学习一下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

37

帖子

0

粉丝