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结构来看主要可以分为如下几个部分:
上行数据的通道从端(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、通道从端接口时序
当valid为高时,表示要写入数据。如果该时钟周期ready为高,则表示已经将数据写入;如果该时钟周期ready为低,则需要等到ready为高的时钟周期才可以将数据写入。
2、整形器接口时序
整形器发送数据是按照数据包的形式发送的,可以选择数据包的长度有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、控制寄存器接口时序
在控制寄存器接口上,需要在每一个时钟解析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进行仿真
首先将这4个设计文件导入到创建好的Project里面
要注意设计文件的路径名不能有中文名
2. 编译设计文件
3. 仿真tb文件
在work库里面找到编译好的tb文件,右键进行仿真
4. 添加信号波形
选中dut中所有in、out端口信号,右键add ware
命令窗口执行“run 1us”
分析波形
当ch0_data_i要发送数据的时候,波形由x变成了00c00000,同时ch0_valid_i信号由x变成了1,代表发送数据有效,ch0_ready_o也拉高,代表已经准备好接受数据。
当把数据送进入之后,ch0_margin_o信号的值由20变成1f,是因为当送入一个数据之后fifo的余量减少了一个。
当mcdt_data_o把数据送出的时候,fifo余量就会加1,从1f又变成了20。
整体来看显示通道1发送数据,再是通道2发送数据,最后是通道3发送数据。
分析设计文件代码
时钟5ns一翻转,也就是时钟周期是10ns
// clock generation
initial begin
clk <= 0;
forever begin
#5 clk <= !clk;
end
end
1
2
3
4
5
6
7
复位信号在仿真开始10ns时置0,等待10个时钟周期后,也就是在10ns+100ns=110ns时置1。
// reset trigger
initial begin
#10 rstn <= 0;
repeat(10) @(posedge clk);
rstn <= 1;
end
1
2
3
4
5
6
然后开始发送数据,通道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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
在下一拍的时候,会将ch0_valid_i置0,所以从波形上看,相邻的数据之间valid拉低,有一个无效的数据,处于idle的状态。
当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)
);
————————————————
版权声明:本文为CSDN博主「煎丶包」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39794062/article/details/113402057