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

2020-02-27 21:16发布


        有一个处理器,工作于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

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
19条回答
sxtz531
1楼-- · 2020-02-29 22:30
 精彩回答 2  元偷偷看……
廊桥拾梦
2楼-- · 2020-03-01 02:11
猴哥说的对 fifo就ok
HORSE7812
3楼-- · 2020-03-01 02:46
:)
winkle.zhang
4楼-- · 2020-03-01 03:05
呵呵 TQ同学的书讲了 脉冲边沿检测法 借助于存储器 专用握手信号
江宇平99999
5楼-- · 2020-03-01 06:47
(1) two FF
(2) google "toggle synchronizer"
(3) async fifo / dual port ram
GoldSunMonkey
6楼-- · 2020-03-01 11:11
 精彩回答 2  元偷偷看……

一周热门 更多>