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

[复制链接]
2806|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来跨时钟域较好

这是最可靠的办法
GoldSunMonkey 发表于 2013-7-29 21:43 | 显示全部楼层
sxtz531 发表于 2013-7-29 12:45
数据量不大,每1ms最多也就传输4个8位的数据,用这种缓存的方式,会不会有点浪费资源。 ...

那就打两拍
钻研的鱼 发表于 2013-7-30 08:43 | 显示全部楼层
网上搜搜异步fifo的设计,很多经典的**和讨论。
异步fifo的设计,其实就是跨时钟域的设计,其中的空、满、将满、将空等设计,非常有讲究,仔细研究吧!
GoldSunMonkey 发表于 2013-7-30 23:59 | 显示全部楼层
钻研的鱼 发表于 2013-7-30 08:43
网上搜搜异步fifo的设计,很多经典的**和讨论。
异步fifo的设计,其实就是跨时钟域的设计,其中的空、满 ...

鱼哥,你跑哪里去了?
GoldSunMonkey 发表于 2013-7-30 23:59 | 显示全部楼层
想四你了
mhanchen 发表于 2013-7-31 21:20 | 显示全部楼层
sxtz531 发表于 2013-7-29 12:45
数据量不大,每1ms最多也就传输4个8位的数据,用这种缓存的方式,会不会有点浪费资源。 ...

你用的芯片上RAM使用很紧张吗?不紧张的话用一点其实也无所谓,还能省下一些触发器资源
 楼主| sxtz531 发表于 2013-8-4 00:11 | 显示全部楼层
mhanchen 发表于 2013-7-31 21:20
你用的芯片上RAM使用很紧张吗?不紧张的话用一点其实也无所谓,还能省下一些触发器资源 ...

片子上没有用到的RAM快,就剩一块了
mhanchen 发表于 2013-8-4 10:15 | 显示全部楼层
sxtz531 发表于 2013-8-4 00:11
片子上没有用到的RAM快,就剩一块了

其实对于你这个设计来说最好还是用RAM,因为是慢采快,用触发器同步的方法一点儿也不可靠
 楼主| sxtz531 发表于 2013-8-4 21:16 | 显示全部楼层
mhanchen 发表于 2013-8-4 10:15
其实对于你这个设计来说最好还是用RAM,因为是慢采快,用触发器同步的方法一点儿也不可靠 ...

请问下,在跨时钟域的设计中使用握手信号与使用异步FIFO相比较会怎样,一般教科书上在跨时钟域设计里都有提到,但貌似平时很少有人使用,更多的还是使用异步FIFO的方式
mhanchen 发表于 2013-8-4 21:43 | 显示全部楼层
sxtz531 发表于 2013-8-4 21:16
请问下,在跨时钟域的设计中使用握手信号与使用异步FIFO相比较会怎样,一般教科书上在跨时钟域设计里都有 ...

我觉得fifo可靠。。但是我没有比较过,找个有经验的请教一下吧
 楼主| sxtz531 发表于 2013-8-4 21:51 | 显示全部楼层
mhanchen 发表于 2013-8-4 21:43
我觉得fifo可靠。。但是我没有比较过,找个有经验的请教一下吧

了解,谢谢
廊桥拾梦 发表于 2013-8-9 12:53 | 显示全部楼层
猴哥说的对 fifo就ok
HORSE7812 发表于 2013-8-9 13:53 | 显示全部楼层
winkle.zhang 发表于 2013-9-8 12:56 | 显示全部楼层
呵呵 TQ同学的书讲了 脉冲边沿检测法 借助于存储器 专用握手信号
江宇平99999 发表于 2013-9-8 21:21 | 显示全部楼层
(1) two FF
(2) google "toggle synchronizer"
(3) async fifo / dual port ram
GoldSunMonkey 发表于 2013-9-8 23:29 | 显示全部楼层
廊桥拾梦 发表于 2013-8-9 12:53
猴哥说的对 fifo就ok

;P有人夸我了
GoldSunMonkey 发表于 2013-9-8 23:29 | 显示全部楼层
winkle.zhang 发表于 2013-9-8 12:56
呵呵 TQ同学的书讲了 脉冲边沿检测法 借助于存储器 专用握手信号

嗯嗯,好好学习一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

37

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部