微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > verilog代码奇怪的问题求助!

verilog代码奇怪的问题求助!

时间:10-02 整理:3721RD 点击:
/*************************************************************
说明:这里的数据位宽需要根据ddr2中的参数设置和fifo的例化得到
**************************************************************/

module data_flow(  
      input
sys_rst_n,

      input
phy_clk,       //ddr2时钟 双fifo读出时钟 和upp fifo写入时钟
      //双fifo操作接口
      input
fifo1_full,    //fifo的空满信号
      input
fifo2_full,
      input
fifo1_empty,
      input
fifo2_empty,
      output reg
rd_req1,   //fifo的读请求
      output reg
rd_req2,
      input[1:0] fifo_status,    //双fifo的当前状态指示
      input[63:0] q_fifo1,  //fifo的数据输出 需要与wr_burst_data对接
      input[63:0] q_fifo2,
      //ddr2侧的接口
      input  burst_finish,       //突发读写完成信号 由读写的各自完成信号相与而来
      input  wr_burst_data_req,  //写数据有效标志 说明已经进入了写操作中
      input  rd_burst_data_valid,//读数据有效 说明不冲突 进入了读操作
      output reg wr_burst_req,      //读写请求操作
      output reg rd_burst_req,
      output reg[63:0] wr_burst_data, //ddr2写入的数据64位  与ddr2模块对接
      input [63:0] rd_burst_data,  //从ddr2中读出数据 给upp的fifo 与data_in对接
      output reg[23:0] wr_burst_addr, //对ddr2的读写地址进行操作
      output reg[23:0] rd_burst_addr,
      output reg[9:0]  wr_burst_len,  //对ddr2的读写数据长度进行操作
      output reg[9:0]  rd_burst_len,
      input  local_init_done,     //ddr2初始化完成信号
      //定时器信号
      output reg start_timer,         //当ddr2中的数据达到一定量时 启动定时器
      input start_upp,            //输入1  定时器完成10ms定时 启动upp传输
     //upp的fifo写请求信号
      output reg wr_req,              //upp中的fifo 写请求
      output reg[63:0] data_in
                 );

  
  
//双fifo中状态定义
parameter fifo_idle= 2'd0,
          fifo_write1  = 2'd1,
fifo_wr1_rd2 = 2'd2,
fifo_rd1_wr2 = 2'd3;
  
  
parameter  DDR2_IDLE = 2'd0,
           READ_DDR2 = 2'd1,
           FIFO1_WRITE_DDR2  = 2'd2,
  FIFO2_WRITE_DDR2  = 2'd3;
reg[1:0] state;        //当前状态 寄存器
reg[1:0] next_state;   //下一个状态寄存器

reg[15:0] wr_cnt = 16'd0;
reg[15:0] rd_cnt = 16'd0;

/*************************************************************
   驱动源:phy_clk(DDR2控制器提供给用户的读写同步时钟)
描述:ddr2控制器初始化完成后才进行其他操作,状态才能转移
     初始化未完成,或是复位有效,则进入空闲状态
  每个时钟周期都会将下一个状态转给当前状态
**************************************************************/
always@(posedge phy_clk)
begin
if( (~local_init_done) || (!sys_rst_n) || (fifo_status == fifo_idle) || (fifo_status == fifo_write1) )
      begin

  state <= DDR2_IDLE;
end
else

   begin
     state <= next_state;  //下一个状态赋给当前状态
end
end
/*************************************************************
   驱动源:状态改变,根据always中的输入变量来改变
描述:  一旦此模块中的输入变量改变便被执行一次
语法说明:always@(*)敏感变量由综合器根据always里面的输入变量自动添加,不用自己考虑
         如果没有@,那就是不会满足特定条件才执行,而是执行完一次后立马执行下一次,一直重复执行
**************************************************************/
always@(*)
begin
case(state)         //初始化完成后由空闲状态转到读状态
DDR2_IDLE:
   begin  //当在空闲时 如有读状态且fifo为满时转到读fifo写ddr2状态
   if( (fifo_status == fifo_rd1_wr2) && fifo1_full )   //监控双fifo那边的状态
   begin
  rd_req1 <= 1'b1;         //读请求立即为1,一旦上升沿来到便出来一个数据
        next_state <= FIFO1_WRITE_DDR2;
end
   else if( (fifo_status == fifo_wr1_rd2) && fifo2_full )
   begin
  rd_req2 <= 1'b1;
     next_state <= FIFO2_WRITE_DDR2;
end

else if( start_upp )          //start_upp 前5ms为0,后5ms为1
   next_state <= READ_DDR2;   //每隔10ms时,状态换为读
   else
   next_state <= next_state;
end

  
FIFO1_WRITE_DDR2:
      
   begin

  if( burst_finish & fifo1_empty )  //写完64个数据同时fifo1读空有效
     begin
     next_state <= DDR2_IDLE;    //写完跳到空闲,同时读1停止
     rd_req1 <= 1'b0;
  
     end
  else
        next_state <= FIFO1_WRITE_DDR2;   //否则状态保持不变
   end

FIFO2_WRITE_DDR2:
   begin
   if( burst_finish & fifo2_empty )  //写完64个数据同时fifo1读空有效
     begin
     next_state <= DDR2_IDLE;    //写完跳到空闲,同时读2停止
     rd_req2 <= 1'b0;   
  
     end
   else
        next_state <= FIFO2_WRITE_DDR2;   //否则状态保持不变
end

READ_DDR2:
           begin
  
if(burst_finish)
  begin

next_state <= DDR2_IDLE;   //读ddr2到fifo中 128个地址后 转为空闲
//wr_req <= 1'b0;
//同时写uppfifo请求无效
  end
else
next_state <= READ_DDR2;
  end
default:  
next_state <= DDR2_IDLE;
endcase
end
reg a;
wire fifo1_finish;
wire fifo2_finish;
assign fifo1_finish = ( state == FIFO1_WRITE_DDR2 && next_state == DDR2_IDLE );
assign fifo2_finish = ( state == FIFO2_WRITE_DDR2 && next_state == DDR2_IDLE );
/*************************************************************
   驱动源:phy_clk
描述:对地址进行操作,每读完一次地址加128,写完一次地址加64,乒乓操作完成3次后启动定时器,不关闭
     ddr2相当于一个缓冲,始终对地址0-768操作
**************************************************************/
always@( posedge phy_clk )
  begin
    if( fifo1_finish )   
   begin
  a <= 1'b1;
  wr_burst_addr <= wr_burst_addr + 24'd64;
      end        
else if( fifo2_finish )
    begin
   wr_burst_addr <= wr_burst_addr + 24'd64;
a <= 1'b0;
end

else if( wr_burst_addr >= 24'd768 )
wr_burst_addr <= 24'd0;                   //写地址清零,如此循环

else if( wr_burst_addr >= 24'd384 )          //当存完384个内存单元后启动定时器,一旦启动就不停,除了复位时
start_timer <= 1'b1;                      //开启定时器 不开启后不关闭
else
wr_burst_addr <= wr_burst_addr;
  end

always@( posedge phy_clk )
   begin
   if( state == READ_DDR2 && next_state == DDR2_IDLE )
      rd_burst_addr <= rd_burst_addr + 24'd128;
   else if( rd_burst_addr >= 24'd768 )
   rd_burst_addr <= 24'd0;                //读地址清零,如此循环
else
   rd_burst_addr <= rd_burst_addr;

end

/*************************************************************
   驱动源:phy_clk(DDR2控制器提供的读写同步时钟)
描述:提供写请求信号   wr_burst_req
        写数据长度       wr_burst_len
     同时准备接收写数据准备好有效位 wr_burst_data_req
     ddr2控制器的写请求要操作两次,但是在顶层不用管  
  写之前给个写请求信号就好
说明:下边的可以合并,有个bug,如果wr_burst_data_req不能立即为1,也就是读写有冲突的时候
      数据会丢失?有数据0出现  不过在这里应用不会存在冲突的情况
**************************************************************/
always@(posedge phy_clk)
begin
if(next_state == FIFO1_WRITE_DDR2 && state != FIFO1_WRITE_DDR2) //由非读状态马上要转到读状态时的处理
begin
wr_burst_req <= 1'b1;     //突发写请求有效  写请求置1
wr_burst_len <= 10'd64;  //突发写数据长度128
wr_cnt <= 16'd0;          //写数据个数清零 准备写数据         
//rd_req1 <= 1'b1;

wr_burst_data <= q_fifo1;  //fifo与ddr2对接
end
else if(next_state == FIFO2_WRITE_DDR2 && state != FIFO2_WRITE_DDR2)
   begin
   wr_burst_req <= 1'b1;     //突发写请求有效  写请求置1
wr_burst_len <= 10'd64;   //突发写数据长度128
wr_cnt <= 16'd0;          //写数据个数清零 准备写数据         
//rd_req2 <= 1'b1;
   wr_burst_data <= q_fifo2;
end
else if( wr_burst_data_req && ( state == FIFO1_WRITE_DDR2 ) )   //上边的请求信号有效后下一个时钟周期  写请求有效 说明没有读写冲突 进入写状态 开始写
begin
   //rd_req1 <= 1'b1;
wr_burst_data <= q_fifo1;
wr_burst_req <= 1'b0;     //写数据请求置1后  写请求清零开始写数据
wr_burst_len <= 10'd64;
wr_cnt <= wr_cnt + 16'd1;  //同时写计数器加1  用来作为写入数据的值 cnt=0被读入
end
else if( wr_burst_data_req && ( state == FIFO2_WRITE_DDR2 ) )   //上边的请求信号有效后下一个时钟周期  写请求有效 说明没有读写冲突 进入写状态 开始写
begin
   //rd_req2 <= 1'b1;          //如果DDR2有应答的话,读请求有效 否则读请求无效
wr_burst_data <= q_fifo2;
wr_burst_req <= 1'b0;     //写数据请求置1后  写请求清零开始写数据
wr_burst_len <= 10'd64;
wr_cnt <= wr_cnt + 16'd1;  //同时写计数器加1  用来作为写入数据的值 cnt=0被读入
end

else                             //否则的话保持之前状态
begin
   //rd_req1 <= 1'b0;
//rd_req2 <= 1'b0;
wr_burst_data <= 64'd0;
wr_burst_req <= wr_burst_req;
wr_burst_len <= 10'd64;
wr_cnt <= wr_cnt;
end
end

/*************************************************************
   驱动源:phy_clk(DDR2控制器提供的读写同步时钟)
描述:提供读请求信号rd_burst_req
     即将读取的数据长度rd_burst_len  
  同时准备接收读数据准备好有效位 rd_burst_data_valid  
**************************************************************/
always@(posedge phy_clk)
begin
if(next_state == READ_DDR2 && state != READ_DDR2)//由非读状态装换为读状态
begin
rd_burst_req <= 1'b1;      //读请求置一
rd_burst_len <= 10'd128;   //读数据长度
rd_cnt <= 16'd1;           //读数据寄存器
end
else if(rd_burst_data_valid )   //读数据有效的时候将读请求清零  
begin
   wr_req <= 1'b1;           //写fifo
rd_burst_req <= 1'b0;
rd_burst_len <= 10'd128;
rd_cnt <= rd_cnt + 16'd1;  //读数据计数器加1
data_in <= rd_burst_data;  //ddr2的数据写入fifo
end
else if(burst_finish)            //会多写一个数据 不过fifo有写保护 ?
   wr_req <= 1'b0;  
else                             //若是读数据无效则保持状态
begin
rd_burst_req <= rd_burst_req;
rd_burst_len <= 10'd128;
rd_cnt <= rd_cnt;
end
end
endmodule

问题描述:红色代码部分仿真的时候可以进入,a <= 1'b1;也执行了,但是 后边的加法 wr_burst_addr <= wr_burst_addr + 24'd64;始终不能执行,郁闷啊!求大神指点!

这段代码是前端一个异步双fifo乒乓操作,并将数据放到DDR2中,需要的时候再从DDR2中读出,通过UPP传给dsp

你这个ALWAYS块写的就很奇葩,显然没写过工程代码,你要是用VERDI的话很容易就能查出问题,先把你的ELSE分支顺序调整好,判断 wr_burst_addr 的分支放在做加法的前面!



   谢谢指点哈!我把代码调整为:
always@( posedge phy_clk )
  begin
  
if( wr_burst_addr >= 24'd768 )
wr_burst_addr <= 24'd0;                   //写地址清零,如此循环

else if( wr_burst_addr >= 24'd384 )           //当存完384个内存单元后启动定时器,一旦启动就不停,除了复位时
start_timer <= 1'b1;  
         else if( state == FIFO1_WRITE_DDR2 && next_state == DDR2_IDLE )     
  wr_burst_addr <= wr_burst_addr + 24'd64;      
else if( state == FIFO2_WRITE_DDR2 && next_state == DDR2_IDLE )   
  wr_burst_addr <= wr_burst_addr + 24'd64;               
else
  wr_burst_addr <= wr_burst_addr;
  end
我只想将DDR2的0-768的地址空间 用来当缓存   改完后还是一样的    state == FIFO1_WRITE_DDR2 && next_state == DDR2_IDLE 这个条件的确是满足了   但是下边的代码没有执行



   问题解决了:reg[23:0] wr_burst_addr = 24'd0;                    reg[23:0] rd_burst_addr = 24'd0;  这里需要赋给初始值就可以了,谢谢指点!

用时序逻辑产生fifo1_finish和fifo2_finish。

学习了!

学习学习

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top