MCDF实验——Lab0

MCDF实验

  • 一、MCDF功能描述
  • 二、设计结构
  • 三、接口描述
    • 1、系统信号接口
    • 2、通道从端接口
    • 3、整形器接口
    • 4、控制寄存器接口
  • 四、接口时序
    • 1、通道从端接口时序
    • 2、整形器接口时序
    • 3、控制寄存器接口时序
  • 五、寄存器描述
    • 1、地址0x00 通道1控制寄存器 32bits 读写寄存器
    • 2、地址0x04 通道2控制寄存器 32bits 读写寄存器
    • 3、地址0x08 通道3控制寄存器 32bits 读写寄存器
    • 4、地址0x10 通道1状态寄存器 32bits 只读寄存器
    • 5、地址0x14 通道2状态寄存器 32bits 只读寄存器
    • 6、地址0x18 通道3状态寄存器 32bits 只读寄存器
  • 六、使用Questasim进行仿真

一、MCDF功能描述

该设计我们称之为多通道数据整形器(MCDF,multi-channel data formatter),它可以将上行(uplink)多个通道数据经过内部的FIFO,最终以数据包(data packet)的形式送出。
由于上行数据和下行数据的接口协议不同,我们也将在后面的接口描述和时序部分进一步讲解。此外,多通道数据整形器也有寄存器的读写接口,可以支持更多的控制功能。

二、设计结构

MCDF实验——Lab0_第1张图片
从上图的MCDF结构来看主要可以分为如下几个部分:

  • 上行数据的通道从端(Channel Slave),负责接收上行数据,并且存储到其FIFO中。
  • 仲裁器(Arbiter)可以选择从不同的FIFO中读取数据,进而将数据进一步传送至整形器(formatter)。
  • 整形器(Formatter)将数据按照一定的接口时序送出至下行接收端。
  • 控制寄存器(Control Registers)有专用的寄存器读写接口,负责接收命令并且对MCDF的功能做出修改。

三、接口描述

1、系统信号接口

  • CLK(0):时钟信号。
  • RSTN(0):复位信号,低位有效。

2、通道从端接口

  • CHx_DATA(31:0):通道数据输入。
  • CHx_VALID(0):通道数据有效标志信号,高位有效。
  • CHx_READY(0):通道数据接收信号,高位表示接收成功。

3、整形器接口

  • FMT_CHID(1:0):整形数据包的通道ID号。
  • FMT_LENGTH(4:0):整形数据包长度信号。
  • FMT_REQ(0):整形数据包发送请求。
  • FMT_GRANT(0):整形数据包被允许发送的接受标示。
  • FMT_DATA(31:0):数据输出端口。
  • FMT_START(0):数据包起始标示。
  • FMT_END(0):数据包结束标示。

4、控制寄存器接口

  • CMD(1:0):寄存器读写命令。
  • CMD_ADDR(7:0):寄存器地址。
  • CMD_DATA_IN(31:0):寄存器写入数据。
  • CMD_DATA_OUT(31:0):寄存器读出数据。

四、接口时序

1、通道从端接口时序

MCDF实验——Lab0_第2张图片
当valid为高时,表示要写入数据。如果该时钟周期ready为高,则表示已经将数据写入;如果该时钟周期ready为低,则需要等到ready为高的时钟周期才可以将数据写入。

2、整形器接口时序

MCDF实验——Lab0_第3张图片

  • 整形器发送数据是按照数据包的形式发送的,可以选择数据包的长度有4、8、16和32。整形器必须完整发送某一个通道的数据包后,才可以转而准备发送下一个数据包,在发送数据包期间,fmt_chid和fmt_length应该保持不变,直到数据包发送完毕。
  • 在整形器准备发送数据包时,首先应该将fmt_req置为高,同时等待接收端的fmt_grant。当fmt_grant变为高时,应该在下一个周期将fmt_req置为低。fmt_start也必须在接收到fmt_grant高有效的下一个时钟被置为高,且需要维持一个时钟周期。在fmt_start被置为高有效的同一个周期,数据也开始传送,数据之间不允许有空闲周期,即应该连续发送数据,直到发送完最后一个数据时,fmt_end也应当被置为高并保持一个时钟周期。
  • 相邻的数据包之间应该至少有一个时钟周期的空闲,即fmt_end从高位被拉低以后,至少需要经过一个时钟周期,fmt_req才可以被再次置为高。

3、控制寄存器接口时序

MCDF实验——Lab0_第4张图片
在控制寄存器接口上,需要在每一个时钟解析cmd。当cmd为写指令时,需要把数据cmd_data_in写入到cmd_addr对应的寄存器中;当cmd为读指令时,即需要从cmd_addr对应的寄存器中读取数据,并在下一个周期,将数据驱动至cmd_data_out接口。

五、寄存器描述

1、地址0x00 通道1控制寄存器 32bits 读写寄存器

  • bit(0):通道使能信号。1为打开,0位关闭。复位值为1。 bit(2:1):优先级。0为最高,3为最低。复位值为3。
  • bit(5:3):数据包长度,解码对应表为, 0对应长度4,1对应长度8,2对应长度16,3对应长度32,其它数值(4-7)均暂时对应长度32。复位值为0。
  • bit(31:6):保留位,无法写入。复位值为0。

2、地址0x04 通道2控制寄存器 32bits 读写寄存器

同通道1控制寄存器描述。

3、地址0x08 通道3控制寄存器 32bits 读写寄存器

同通道1控制寄存器描述。

4、地址0x10 通道1状态寄存器 32bits 只读寄存器

  • bit(7:0):上行数据从端FIFO的可写余量,同FIFO的数据余量保持同步变化。复位值为FIFO的深度数。
  • bit(31:8):保留位,复位值为0。

5、地址0x14 通道2状态寄存器 32bits 只读寄存器

同通道1状态寄存器描述。

6、地址0x18 通道3状态寄存器 32bits 只读寄存器

同通道1状态寄存器描述。

六、使用Questasim进行仿真

  1. 首先将这4个设计文件导入到创建好的Project里面

要注意设计文件的路径名不能有中文名
MCDF实验——Lab0_第5张图片
2. 编译设计文件
MCDF实验——Lab0_第6张图片
3. 仿真tb文件
在work库里面找到编译好的tb文件,右键进行仿真
MCDF实验——Lab0_第7张图片
MCDF实验——Lab0_第8张图片
4. 添加信号波形
选中dut中所有in、out端口信号,右键add ware
MCDF实验——Lab0_第9张图片
命令窗口执行“run 1us”
MCDF实验——Lab0_第10张图片

MCDF实验——Lab0_第11张图片

分析波形
当ch0_data_i要发送数据的时候,波形由x变成了00c00000,同时ch0_valid_i信号由x变成了1,代表发送数据有效,ch0_ready_o也拉高,代表已经准备好接受数据。
MCDF实验——Lab0_第12张图片
当把数据送进入之后,ch0_margin_o信号的值由20变成1f,是因为当送入一个数据之后fifo的余量减少了一个。
MCDF实验——Lab0_第13张图片

MCDF实验——Lab0_第14张图片
当mcdt_data_o把数据送出的时候,fifo余量就会加1,从1f又变成了20。
MCDF实验——Lab0_第15张图片
整体来看显示通道1发送数据,再是通道2发送数据,最后是通道3发送数据。
MCDF实验——Lab0_第16张图片
分析设计文件代码

时钟5ns一翻转,也就是时钟周期是10ns

// clock generation
initial begin 
  clk <= 0;
  forever begin
    #5 clk <= !clk;
  end
end

复位信号在仿真开始10ns时置0,等待10个时钟周期后,也就是在10ns+100ns=110ns时置1。

// reset trigger
initial begin 
  #10 rstn <= 0;
  repeat(10) @(posedge clk);
  rstn <= 1;
end

MCDF实验——Lab0_第17张图片
MCDF实验——Lab0_第18张图片

然后开始发送数据,通道1先发送。等待复位信号拉高时,再等待5个时钟周期,即第6个周期的上升沿才开始发送数据。也就是说110ns+5*10ns+5ns=165ns时发送数据。此时ch0_valid_i置1,同时把数据写入进去。

// data test
initial begin 
  @(posedge rstn);
  repeat(5) @(posedge clk);
  // channel 0 test
  chnl_write(0, 'h00C0_0000);
  chnl_write(0, 'h00C0_0001);
  chnl_write(0, 'h00C0_0002);
  chnl_write(0, 'h00C0_0003);
  chnl_write(0, 'h00C0_0004);
  chnl_write(0, 'h00C0_0005);
  chnl_write(0, 'h00C0_0006);
  chnl_write(0, 'h00C0_0007);
  chnl_write(0, 'h00C0_0008);
  chnl_write(0, 'h00C0_0009);
// channel write task
task chnl_write(input reg[1:0] id, input reg[31:0] data); 
  case(id)
    0: begin
      @(posedge clk);
      ch0_valid <= 1;
      ch0_data <= data;
      @(posedge clk);
      ch0_valid <= 0;
      ch0_data <= 0;
    end
    1: begin
      @(posedge clk);
      ch1_valid <= 1;
      ch1_data <= data;
      @(posedge clk);
      ch1_valid <= 0;
      ch1_data <= 0;
    end
    2: begin
      @(posedge clk);
      ch2_valid <= 1;
      ch2_data <= data;
      @(posedge clk);
      ch2_valid <= 0;
      ch2_data <= 0;
    end
    default: $error("channel id %0d is invalid", id);
  endcase
endtask


MCDF实验——Lab0_第19张图片
在下一拍的时候,会将ch0_valid_i置0,所以从波形上看,相邻的数据之间valid拉低,有一个无效的数据,处于idle的状态。
MCDF实验——Lab0_第20张图片

当ch0_valid被赋值以后,接下来就会对dut待测设计的输入做操作了。

mcdt dut(
   .clk_i(clk)
  ,.rstn_i(rstn)
  ,.ch0_data_i(ch0_data)
  ,.ch0_valid_i(ch0_valid)
  ,.ch0_ready_o(ch0_ready)
  ,.ch0_margin_o(ch0_margin)
  ,.ch1_data_i(ch1_data)
  ,.ch1_valid_i(ch1_valid)
  ,.ch1_ready_o(ch1_ready)
  ,.ch1_margin_o(ch1_margin)
  ,.ch2_data_i(ch2_data)
  ,.ch2_valid_i(ch2_valid)
  ,.ch2_ready_o(ch2_ready)
  ,.ch2_margin_o(ch2_margin)
  ,.mcdt_data_o(mcdt_data)
  ,.mcdt_val_o(mcdt_val)
  ,.mcdt_id_o(mcdt_id)
);

你可能感兴趣的:(芯片验证,systemverilog,verilog,芯片)