【Verilog实战】SPI协议底层硬件接口设计和功能验证(附源码)

完整程序:点击下载
脚  本:makefile
工  具:vcs 和 verdi


路 线:



一、SPI协议

1.1 概念

SPI 协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线。和UART协议类似,都属于片外协议,但UART协议是通用的异步串行通信接口。


1.2 物理层

在这里插入图片描述

  SPI 协议使用 3 条总线及N条片选线,3 条总线分别为 SCLK、MOSI、MISO,片选线为CS,其中3条总线是多个从设备共用的,cs是每一个从机有一条。它们的作用介绍如下:


(1)CS
  全称:Chip Selection,从设备选择信号线,常称为片选信号线,也称为 NSS、SS。 SPI 协议中没有设备地址,它使用 cs 信号线来寻址,当主机要选择从设备时,把该从设备的 cs 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以SPI通讯以 cs 线置低电平为开始信号,以 cs 线被拉高作为结束信号


(2)SCLK
  全称:Serial Clock。时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,两个设备之间通讯时,通讯速率受限于低速设备。


(3)MOSI
  全称:Master Output, Slave Input。主设备输出/从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入主机发送的数据,即这条线上数据的方向为主机到从机。


(4)MISO
  全称:Master Input,Slave Output。主设备输入/从设备输出引脚。主机从这条信号线读入数据,从机的数据由这条信号线输出到主机,即在这条线上数据的方向为从机到主机。


1.3 协议层

(1)通信模式

SPI工作模式 CPOL CPHA 空闲时的SCLK电平 采样时刻
0 0 0 低电平 奇数边沿
1 0 1 低电平 偶数边沿
2 1 0 高电平 奇数边沿
3 1 1 高电平 偶数边沿

SPI 一共有四种通讯模式,它们的主要区别是总线空闲时 SCK 的时钟状态以及数据采样时刻。工作模式由“时钟极性 CPOL”和“时钟相位 CPHA”决定。

  • 时钟极性 CPOL: 表示SPI 通讯设备处于空闲状态时,SCK信号线的电平信号(即 SPI 通讯开始前、CS 线为高电平时 SCLK的状态)。CPOL=0时, SCK在空闲状态时为低电平,CPOL=1 时,则相反。
  • 时钟相位 CPHA:表示数据采样的时刻,当 CPHA=0 时,MOSI 或 MISO 数据线上的信号将会在 SCLK 时钟线的“奇数边沿”被采样。当 CPHA=1 时,数据线在 SCLK 的“偶数边沿”采样。

(2)时序

根据 SCLK 在空闲状态时的电平,分为两种情况。CPOL=0时,SCLK信号线在空闲状态为低电平;CPOL=1时,空闲状态为高电平。

在这里插入图片描述

无论 CPOL=0,还是=1,因为配置的时钟相位 CPHA=0,在图中可以看到,采样时刻都是在 SCLK 的奇数边沿。注意当 CPOL=0 的时候,时钟的奇数边沿是上升沿,而 CPOL=1 的时候,时钟的奇数边沿是下降沿。所以 SPI 的采样时刻不是由上升/下降沿决定的


在这里插入图片描述

类似地,当 CPHA=1 时,不受 CPOL 的影响,数据信号在 SCK 的偶数边沿被采样。


(3)基本通信过程
在这里插入图片描述

  • 起始和结束信号
    标号1处,CS 信号线(NNS)由高变低,是 SPI 通讯的起始信号。CS 信号线(NNS) 是每个从机各自独占的信号线,当从机在自己的片选信号线检测到起始信号后,就知道自己被主机选中了,开始准备与主机通讯。标号6处,CS 信号线(NNS) 由低变高,是 SPI 通讯的停止信号,表示本次通讯结束,从机的选中状态被取消。

  • 数据有效性
    SPI 使用 MOSI 及 MISO 信号线来传输数据,使用 SCK 信号线进行数据同步。MOSI及 MISO 数据线在 SCK 的每个时钟周期传输一位数据,且数据输入输出是同时进行的。数据传输时,MSB先行或 LSB先行并没有作硬性规定,但要保证两个 SPI 通讯设备之间使用同样的协定,一般都会采用图中的 MSB 先行模式。

  图中的2~5标号处,MOSI 及 MISO 的数据在 SCK 的上升沿期间变化输出,在 SCK的下降沿时被采样。即在 SCK的下降沿时刻,MOSI 及 MISO的数据有效,高电平时表示数据“1”,为低电平时表示数据“0”。在其它时刻,数据无效。
注意:SPI 每次数据的单位数不受限制


二、Spec

2.1 Function descripton

  上游模块实现通过SPI接口与下游进行并行数据的交互,完成了并串互转和串行数据传输与采集的工作。


2.2 Feature list

  1. 接收上一级模块并行数据,将数据按照SPI协议发送出去
  2. SCLK采用10MHz
  3. 模块工作时钟100MHz
  4. 当接收到的串行数据做串并转换,将并行数据反馈给上一级模块
  5. 规定SPI接口工作在模式0,即CPOL时钟极性为0,CPHA时钟相位为0。
  6. 低位数据LSB先行

2.3 Block Diagram

在这里插入图片描述


2.4 Interface description

Signal Name Width Direction Description
clk_i 1 input system clock,100MHz
rst_n_i 1 input system reset signal
cmd_in 12 input 输入命令,[11]: write/read;
[10:8]: addr;
[7:0]: 写数据 or 无意义
cmd_rdy 1 output 输入命令ready
cmd_vld_i 1 input 输入命令valid
sclk 1 output spi时钟,10MHz
cs 1 output spi片选
mosi 1 output spi串行数据,master发,slave收
miso 1 input spi串行数据,master收,slave发
read_vld_o 1 output 读数据valid
read_data_o 8 output 读数据

2.5 Timing

(1)Write timing
在这里插入图片描述


(2)Read Timing
在这里插入图片描述


三、Design and Verification

3.1 RTL

/*-- modified by xlinxdu, 2022/05/20
  -- clk_i : 100MHz
  -- sclk_o: 10MHz
  -- sclk  : 0(CPOL)
  -- mosi  : posedge sclk(CPHA)
  -- receive_en:receive signal
  -- cmd_in = 12bit;[11]:r/w;[10:8]:addr;[7:0]:data 
*/
module spi 
#(
  parameter CMD_RW_WIDTH    =  1,
  parameter CMD_ADDR_WIDTH  =  3,
  parameter CMD_DATA_WIDTH  =  8,
  parameter CMD_IN_WIDTH    =  CMD_RW_WIDTH + CMD_ADDR_WIDTH +
                               CMD_DATA_WIDTH,
  parameter CLK_CNT_WIDTH   =  4,
  parameter BIT_CNT_WIDTH   =  4,
  parameter DLY_CNT_WIDTH   =  2,//delay counter
  parameter DLY_CNT         =  2,//delay counter of clk
  parameter FDC             =  10
)(
//-- system signal
  input clk_i  ,
  input rst_n_i,

//-- mosi
  input       [CMD_IN_WIDTH-1:0]   cmd_in     ,
  input                            cmd_vld_i  ,
  output  reg                      cmd_rdy_o  ,
  output  reg                      sclk_o     ,
  output  reg                      cs_o       ,
  output  reg                      mosi_o     ,

//-- miso
  input                            miso_i     ,
  output  reg                      read_vld_o ,
  output  reg [CMD_DATA_WIDTH-1:0] read_data_o
);

reg [CMD_IN_WIDTH-1 :0]  cmd_in_buf ;
reg                      start_flag ;
reg [CLK_CNT_WIDTH-1:0]  clk_cnt    ;
reg [BIT_CNT_WIDTH-1:0]  bit_cnt    ;
reg [DLY_CNT_WIDTH-1:0]  dly_cnt    ;
reg                      dly_en     ;

reg [CMD_ADDR_WIDTH-1:0] rd_data_buf;

wire wr_end_flag ;
wire rd_stop_flag;
wire rd_end_flag ;

reg  receive_en  ;

/*-----------------------------------------------\
 --             updata cmd_rdy_o              --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    cmd_rdy_o <= 1'b1;
  end
  else if (cmd_vld_i) begin
    cmd_rdy_o <= 1'b0;
  end
  else if(wr_end_flag || read_vld_o) begin
    cmd_rdy_o <= 1'b1;
  end
end

/*-----------------------------------------------\
 --            updata cmd_in_buf              --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    cmd_in_buf <= {
    
    (CMD_IN_WIDTH){
    
    1'b0}};
  end
  else if (cmd_vld_i) begin
    cmd_in_buf <= cmd_in;
  end
end

/*-----------------------------------------------\
 --    Generate a flag to start the transfer  --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    start_flag <= 1'b0;
  end
  else if (cmd_vld_i) begin
    start_flag <= 1'b1;
  end
  else begin
    start_flag <= 1'b0;
  end
end

/*-----------------------------------------------\
 --                Chip Selection              --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    cs_o <= 1'b1;
  end
  else if (start_flag) begin
    cs_o <= 1'b0;
  end
  else if(dly_en && (dly_cnt == (DLY_CNT-1)))begin
    cs_o <= 1'b0;
  end
  else if(wr_end_flag || rd_stop_flag) begin
    cs_o <= 1'b1;
  end
end

/*-----------------------------------------------\
 --              Frequency divider             --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    clk_cnt <= {
    
    (CLK_CNT_WIDTH){
    
    1'b0}};
  end
  else if (clk_cnt == (FDC-1)) begin
    clk_cnt <= {
    
    (CLK_CNT_WIDTH){
    
    1'b0}};
  end
  else if(!cs_o) begin
    clk_cnt <= clk_cnt + 1'b1;
  end
end

/*-----------------------------------------------\
 --                 updata sclk                --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    sclk_o <= 1'b0;
  end
  else if(clk_cnt == (FDC/2-1)) begin
    sclk_o <= 1'b1;
  end
  else if(clk_cnt == (FDC-1)) begin
    sclk_o <= 1'b0;
  end
end

/*-----------------------------------------------\
 --  Generate of write end flag ,read stop flag
     and read end flag                         --
\-----------------------------------------------*/
assign wr_end_flag = (!cmd_in_buf[CMD_IN_WIDTH-1]) && (clk_cnt == (FDC-1) && (bit_cnt == (CMD_IN_WIDTH-1)));
assign rd_stop_flag = (cmd_in_buf[CMD_IN_WIDTH-1]) && (clk_cnt == (FDC-1) && (bit_cnt == (CMD_RW_WIDTH+CMD_ADDR_WIDTH-1)));
assign rd_end_flag = (cmd_in_buf[CMD_IN_WIDTH-1]) && (clk_cnt == (FDC-1) && (bit_cnt == (CMD_DATA_WIDTH-1)));

/*-----------------------------------------------\
 --                 bit counter                --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    bit_cnt <= {
    
    (BIT_CNT_WIDTH){
    
    1'b0}};
  end
  else if(wr_end_flag)begin
    bit_cnt <= {
    
    (BIT_CNT_WIDTH){
    
    1'b0}};
  end
  else if(!receive_en && rd_stop_flag)begin
    bit_cnt <= {
    
    (BIT_CNT_WIDTH){
    
    1'b0}}; 
  end
  else if(receive_en && rd_end_flag)begin
    bit_cnt <= {
    
    (BIT_CNT_WIDTH){
    
    1'b0}}; 
  end
  else if (!cs_o && clk_cnt == (FDC-1)) begin
    bit_cnt <= bit_cnt + 1'b1;
  end
end

/*-----------------------------------------------\
 --              updata MOSI                   --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    mosi_o <= 1'b0;
  end
  else if (!cs_o) begin
    if(!cmd_in_buf[CMD_IN_WIDTH-1])begin
      mosi_o <= cmd_in_buf[bit_cnt];
    end
    else begin
      mosi_o <= cmd_in_buf[CMD_DATA_WIDTH + bit_cnt];
    end
  end
  else begin
    mosi_o <= 1'b0;
  end
end

/*-----------------------------------------------\
 --                 delay enable               --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    dly_en <= 1'b0;
  end
  else if (rd_stop_flag) begin
    dly_en <= 1'b1;
  end
  else if(dly_cnt == (DLY_CNT-1))begin
    dly_en <= 1'b0;
  end
end

/*-----------------------------------------------\
 --                delay counter               --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    dly_cnt <= {
    
    (DLY_CNT_WIDTH){
    
    1'b0}};
  end
  else if (dly_en) begin
    dly_cnt <= dly_cnt + 1'b1;
  end
  else begin
    dly_cnt <= {
    
    (DLY_CNT_WIDTH){
    
    1'b0}};
  end
end

/*-----------------------------------------------\
 --               receive enable               --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    receive_en <= 1'b0;
  end
  else if(dly_cnt == (DLY_CNT-1)) begin
    receive_en <= 1'b1;
  end
  else if(rd_end_flag) begin
    receive_en <= 1'b0;
  end
end

/*-----------------------------------------------\
 --         updata rd_data_buf of miso         --
\-----------------------------------------------*/
always @ (posedge sclk_o or negedge rst_n_i) begin
  if (!rst_n_i) begin
    rd_data_buf <= {
    
    (CMD_DATA_WIDTH){
    
    1'b0}};
  end
  else if (receive_en) begin
    rd_data_buf[bit_cnt] <= miso_i; 
  end
end

/*-----------------------------------------------\
 --               updata read valid           --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    read_vld_o <= 1'b0;
  end
  else if (rd_end_flag) begin
    read_vld_o <= 1'b1;
  end
  else begin
    read_vld_o <= 1'b0;
  end
end

/*-----------------------------------------------\
 --              updata read_data_o            --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    read_data_o <= {
    
    (CMD_DATA_WIDTH){
    
    1'b0}};
  end
  else if (read_vld_o) begin
    read_data_o <= rd_data_buf;
  end
end


endmodule

3.2 Test bench

`timescale 1ns/1ps
module tb_spi ;
  reg        clk_i    ;
  reg        rst_n_i  ;

  reg [11:0] cmd_in   ;
  reg        cmd_vld_i;
  wire       cmd_rdy_o;
  wire       sclk_o   ;
  wire       cs_o     ;
  wire       mosi_o   ;

  reg        miso_i     ;
  wire       read_vld_o ;
  wire [7:0] read_data_o;

initial begin
  clk_i = 0;
end

always #5 clk_i = ~clk_i;

initial begin
  rst_n_i    = 1;
  cmd_vld_i  = 0;
  cmd_in = 12'b0011_0001_1001;//16'h318
  #5 rst_n_i = 0;
  #5 rst_n_i = 1;
     cmd_vld_i=1;
  #10 cmd_vld_i =0;
  cmd_in = 12'b1010_0011_0010;//16'hA32
  #1500 ;
      cmd_vld_i=1;
  #10 cmd_vld_i =0;
  
end

initial begin
  miso_i = 0;
  #1955 miso_i = 1;
  #100 miso_i = 0;
  #100 miso_i = 1;
  #100 miso_i = 0;

  #100 miso_i = 1;
  #100 miso_i = 1;
  #100 miso_i = 0;
  #100 miso_i = 1;
  
  #100;
end

spi tb_spi(
          .clk_i      (clk_i      ),
          .rst_n_i    (rst_n_i    ),
          .cmd_in     (cmd_in     ),
          .cmd_vld_i  (cmd_vld_i  ),
          .cmd_rdy_o  (cmd_rdy_o  ),
          .sclk_o     (sclk_o     ),
          .cs_o       (cs_o       ),
          .mosi_o     (mosi_o     ),
          .miso_i     (miso_i     ),
          .read_vld_o (read_vld_o ),
          .read_data_o(read_data_o)
          );

initial begin
  #4500 $finish            ;
  $fsdbDumpfile("spi.fsdb");
  $fsdbDumpvars            ;
  $fsdbDumpMDA             ;
end
endmodule

3.3 Analyse

bug1:在进行读操作时,mosi发送完读写指令+读地址(标号1阶段)后,又重复发送了一遍(标号2阶段),标号3阶段出现了不定态。

在这里插入图片描述

定位到更新mosi代码块

/*-----------------------------------------------\
 --              updata MOSI                   --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    mosi_o <= 1'b0;
  end
  else if (!cs_o) begin
    if(!cmd_in_buf[CMD_IN_WIDTH-1])begin
      mosi_o <= cmd_in_buf[bit_cnt];
    end
    else begin
      mosi_o <= cmd_in_buf[CMD_DATA_WIDTH + bit_cnt];
    end
  end
  else begin
    mosi_o <= 1'b0;
  end
end

分析:由代码块可以知道,在读操作阶段,因为不是写就会不断执行,并且出现不定态的原因是在读操作中,在cs有效阶段(cs==0),会有两次cs拉低,第一次是发送读写控制位+读地址位,此时bit_cnt计数到3(0~3);第二次拉低是因为miso要反馈一个8位的串行数据流,此时,mosi应该不输出,逻辑错误。

/*-----------------------------------------------\
 --              updata MOSI                   --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    mosi_o <= 1'b0;
  end
  else if (!cs_o) begin
    if(!cmd_in_buf[CMD_IN_WIDTH-1])begin
      mosi_o <= cmd_in_buf[bit_cnt];
    end
    else if(!receive_en)begin
      mosi_o <= cmd_in_buf[CMD_DATA_WIDTH + bit_cnt];
    end
  end
  else begin
    mosi_o <= 1'b0;
  end
end

在这里插入图片描述

更正:把读阶段的mosi触发条件改为只有非反馈数据阶段触发,即receive_en==0时触发。


bug2:在miso反馈数据阶段,cs_o片选信号被中断过,导致cs_o被中断是因为产生了一个在读操作中,发送读写控制位+读地址后才会产生的高电平信号(rd_stop_flag)。这个rd_stop_flag是用来指示在读操作中,mosi已经发送完读写控制位和读地址位。

在这里插入图片描述

定位到rd_stop_flag更新代码块

assign rd_stop_flag = (cmd_in_buf[CMD_IN_WIDTH-1]) && (clk_cnt == (FDC-1) && 
					  (bit_cnt == (CMD_RW_WIDTH+CMD_ADDR_WIDTH-1)));

更改触发条件,只在miso非反馈数据阶段触发。

assign rd_stop_flag = (cmd_in_buf[CMD_IN_WIDTH-1]) && (clk_cnt == (FDC-1) && 
					  (bit_cnt == (CMD_RW_WIDTH+CMD_ADDR_WIDTH-1)) && !receive_en);

在这里插入图片描述


bug3:读出数据缓存只有3位,而本来读出数据应该是8位

在这里插入图片描述

定位,发现是在定义的时候,用错参数

reg [CMD_ADDR_WIDTH-1:0] rd_data_buf;

更改

reg [CMD_DATA_WIDTH-1:0] rd_data_buf;

在这里插入图片描述


bug4:mosi输出延迟了一拍

在这里插入图片描述

定位到mosi更新代码块

/*-----------------------------------------------\
 --              updata MOSI                   --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    mosi_o <= 1'b0;
  end
  else if (!cs_o) begin
    if(!cmd_in_buf[CMD_IN_WIDTH-1])begin
      mosi_o <= cmd_in_buf[bit_cnt];
    end
    else if(!receive_en)begin
      mosi_o <= cmd_in_buf[CMD_DATA_WIDTH + bit_cnt];
    end
  end
  else begin
    mosi_o <= 1'b0;
  end
end

分析:由代码块可以看到,mosi的更新是在cs片选信号拉低之后,再更新,但实际应该是mosi和cs同一时刻开始更新,逻辑错误。
更改:引入一个mosi的读写使能信号rw_en,在cmd_vld_i有效时拉高,依此作为mosi输出的触发条件,即可完成与cs同步输出。
在这里插入图片描述


四、Result

4.1 Write

在这里插入图片描述

在cmd_vld_i有效时,更新待发数据缓存cmd_in_buf,拉低cmd_rdy,并且生成一个写操作开始发送标志,打开发送使能,下一个时钟周期开始传输12bit数据,低位数据先行。在发完的前一个时钟周期生成结束写操作发送标志,并且拉高cmd_rdy信号。


4.2 Read

在这里插入图片描述

读操作,在cmd_vld有效时,将待发数据写入缓存,之后开始发送读写控制位和地址位,一共4bit数据。发送结束前一周期生成rd_stop_flag信号,并开始启动延时,等待从模块反馈数据。等待时间事先已规定好,这里是两个时钟周期,并且可以配置。延时结束后,开始通过sclk采集miso反馈的数据,一共8bit,采集完成后,生成一个read_vld高电平,通过这个高电平,更新read_data_o。


4.3 Output

在这里插入图片描述

仿真时序和规定时序在两个cmd_in之后不一致,功能验证不通过

4.4 bug(补充)

补充bug1:在dly_cnt中,多记数一个,造成不必要的信号变化,定位到delay counter代码块
在这里插入图片描述

/*-----------------------------------------------\
 --                delay counter               --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    dly_cnt <= {
    
    (DLY_CNT_WIDTH){
    
    1'b0}};
  end
  else if (dly_en) begin
    dly_cnt <= dly_cnt + 1'b1;
  end
  else begin
    dly_cnt <= {
    
    (DLY_CNT_WIDTH){
    
    1'b0}};
  end
end

更改清零的优先级。

/*-----------------------------------------------\
 --                delay counter               --
\-----------------------------------------------*/
always @ (posedge clk_i or negedge rst_n_i) begin
  if (!rst_n_i) begin
    dly_cnt <= {
    
    (DLY_CNT_WIDTH){
    
    1'b0}};
  end
  else if(dly_cnt == (DLY_CNT-1)) begin
    dly_cnt <= {
    
    (DLY_CNT_WIDTH){
    
    1'b0}};
  end
  else if (dly_en) begin
    dly_cnt <= dly_cnt + 1'b1;
  end
end

在这里插入图片描述

补充bug2:在没有新的数据来时,即传输完两次后,没新的cmd_vld来临,可是模块miso还在工作,延时计数器也打开了,经过分析,cs_o被拉低了,cs_o受dly_en和dly_cnt共同影响,而影响dly_en的是rd_stop_flag信号。因此更改这几个标志信号,使其在cmd_rdy_o低电平时间段才可以产生,而不是全时间段不断产生。

/*-----------------------------------------------\
 --  Generate of write end flag ,read stop flag
     and read end flag                         --
\-----------------------------------------------*/
assign wr_end_flag  = (!cmd_in_buf[CMD_IN_WIDTH-1]) &&  (clk_cnt == (FDC-1) && (bit_cnt == (CMD_IN_WIDTH-1)));
assign rd_stop_flag = (cmd_in_buf[CMD_IN_WIDTH-1]) &&  (clk_cnt == (FDC-1) && 
                      (bit_cnt == (CMD_RW_WIDTH+CMD_ADDR_WIDTH-1)) && !receive_en);
assign rd_end_flag  = (cmd_in_buf[CMD_IN_WIDTH-1]) && (clk_cnt == (FDC-1) && (bit_cnt == (CMD_DATA_WIDTH-1)));

更改为:

/*-----------------------------------------------\
 --  Generate of write end flag ,read stop flag
     and read end flag                         --
\-----------------------------------------------*/
assign wr_end_flag  = (!cmd_in_buf[CMD_IN_WIDTH-1]) && (!cmd_rdy_o) && 
										(clk_cnt == (FDC-1) && (bit_cnt == (CMD_IN_WIDTH-1)));
assign rd_stop_flag = (cmd_in_buf[CMD_IN_WIDTH-1]) && (!cmd_rdy_o) && (clk_cnt == (FDC-1) && 
                      (bit_cnt == (CMD_RW_WIDTH+CMD_ADDR_WIDTH-1)) && !receive_en);
assign rd_end_flag  = (cmd_in_buf[CMD_IN_WIDTH-1]) && (!cmd_rdy_o) &&
									  (clk_cnt == (FDC-1) && (bit_cnt == (CMD_DATA_WIDTH-1)));

在这里插入图片描述

更改后,测试仿真时序和原来时序一致,功能验证通过。


作者:xlinxdu
版权:本文版权归作者所有
转载:未经作者允许,禁止转载,转载必须保留此段声明,必须在文章中给出原文连接。

猜你喜欢

转载自blog.csdn.net/qq_43244515/article/details/124919979
今日推荐