0


基于FPGA的SRIOIP例程及仿真实现

一、IP****创建及相关介绍

    首先创建一个工程,选择相应的FPGA器件,在左边选择IP Catalog来创建SRIO IP核,现在使用的是V4.1版本的IP核,双击进入SRIO 进行设置;

    设置IP时有两种模式可以选择,一种是Advance模式,一种是Basic模式,在Advance模式下可以对几个相关事务的传输进行设置,相关IP设置根据自己需求参考pg007文档的p129 - p146(IDLE模式设置:IDLE1模式下仅支持单个lane线速率不大于5Gbps,若要使用6.25Gbps线速率,必须使用IDLE2模式);

Component Device ID:这个参数是复位以后Base Device ID CSR寄存器的复位值。

Transmitter Controlled:选中这个选项以后,RapidIO核会首先尝试用transmitter-controlled实现流控,但如果接收方不支持的话那么会自动切换为receiver-controlled。transmitter-controlled流控可以利用接收buffer的状态和水印最小化重试条件。receiver-controlled流控会随意的发包并使用重试协议。

Receiver Controlled:选中这个选项以后,RapidIO核仅能用receiver-controlled实现流控,在这种模式中,receiver-controlled流控会随意的发包并使用重试协议。

Local Configuration Space Base Address:本地配置空间基地址,选中这个选项后,RapidIO会检查I/O事务的高地址位,如果地址匹配,那么会把事务发给维护端口。由于手册没有提供一种机制去关闭LCSBA,所以在这种情况下系统的行为是未定义的。

** **IDLE Mode Support:空闲模式(IDLE Mode)的选择与传输速率有关,空闲序列1(IDLE1)仅仅支持每通道线速率小于5.5Gbps的情况,选择空闲序列1时,RapidIO使用的控制符号为短控制符号。空闲序列2(IDLE2)支持每通道线速率大于5.5Gbps的情况,6.25Gbps的线速率必须选择空闲序列2,空闲序列2提供了一些附加的功能,比如链路宽度,链路优先级信息以及一些用于改善均衡器性能,提高数据恢复率的随机数。当IDLE1和IDLE2均被选中时,每通道线速率仅支持小于等于5.5Gbps的情况。

Port General Control CSR:Host选项表明RapidIO设备是主设备,这个选项不影响核的功能。Master Enable选项用来控制是否允许RapidiO核发起请求事务,如果未选中,RapidIO核只能发起响应事务而不能发起请求事务。Discovered选项表明RapidIO核能被处理器定位,这个选项不影响核的功能。

二、例程生成

    生成IP后,等待IP综合设计完成,完成后选中IP右键单击,选择Open IP Example Design后再选择生成例程放置位置就生成例程了。

    下面是生成的SRIO IP的例程,下面一共生成了8个子模块,其中选中的那两个模块中的代码与我们设计使用相关,分别是srio_request_gen_srio_gen2_0(请求模块)和srio_response_gen_srio_gen2_0(响应模块)。

    根据生成的例程进行仿真调试,下图则是仿真文件,其中srio_example_top_primary是发送请求包,srio_example_top_mirror则是接收请求包,发送对应事务响应包,两个模块的txp0与rxp0相连形成外部回环;

srio_example_top_srio_gen2_0  srio_example_top_primary

     (.sys_clkp                (sys_clkp),

      .sys_clkn                (sys_clkn),

      .sys_rst                 (sys_rst),

      .srio_rxn0               (srio_rxn0),

      .srio_rxp0               (srio_rxp0),

      .srio_txn0               (srio_txn0),

      .srio_txp0               (srio_txp0),

      .sim_train_en            (1'b1),

      .led0                    (led0_primary));

srio_example_top_srio_gen2_0   srio_example_top_mirror

     (.sys_clkp                (sys_clkp),

      .sys_clkn                (sys_clkn),

      .sys_rst                 (sys_rst),

      // cross over serial data lines here

      .srio_rxn0               (srio_txn0),

      .srio_rxp0               (srio_txp0),

      .srio_txn0               (srio_rxn0),

      .srio_txp0               (srio_rxp0),

      .sim_train_en            (1'b1),

      .led0                    (led0_mirror));
    打开仿真,创建仿真过程时间较长(2分钟左右),

    主要将srio_request_gen_srio_gen2_0和srio_response_gen_srio_gen2_0两个模块添加到仿真窗口进行查看,可以看到发送的请求事务,接收的请求事务,发送的响应事务,接收的响应事务;

三、仿真分析

3.1、接收MAINTENANCE READ REQUEST请求

    仿真可以看到srio_response_gen_srio_gen2_0(响应模块)接收的第一个数据包头val_treq_tdata=64’h0080_2030_0000_0004(16进制数),根据解析出来的ftype=4’b1000和ttype=4’h0000对照pg007文档中p73页表格中支持的事务处理类型和相应的端口可以判断出接收到的请求包是维护读请求事务,指定一个维护读请求,不需要响应,因此vla_tresp_tvalid=0;

3.2、发送SWRITE****请求

    仿真后面可以看到srio_request_gen_srio_gen2_0(请求模块)在tvalid拉高时发送的数据包有效,发送的数据包头val_ireq_tdata=64’h0060_20fc_d000_0600(16进制数), 发送的两个数据分别是0和64’h0101_0101_0101_0101,数据类型是ftype=4’b0110和ttype=0(SWRITE),地址是36'hC_D000_0600,包头对应instruction_list.vh头文件中的流写事务,根据HELLO包格式虽然发送地址是36'hC_D000_0600,但只有34位地址有效;在数据发送完成后tlast拉高;

3.2、接收SWRITE****请求

    在发送模块发送992ns时接收模块接收到了请求包,srio_response_gen_srio_gen2_0(响应模块)接收到的数据包头val_treq_tdata=64’h0060_2000_d000_0600(16进制数),ftype=4’b0110和ttype=0(SWRITE事务),接收到的地址是36'h0_D000_0600,根据HELLO包格式地址只有34位有效,所以满足格式要求接收到了正确包头,数据可以看到在tvalid有效期间也是0和64’h0101_0101_0101_0101,tlast拉高表示一次数据包接收完成;与发送的数据包一致;

3.3、发送NWRITE_R****请求

    当第一个事务的数据包发送完成后发送下一个数据包事务,可以看到下一个事务发送的数据包头val_ireq_tdata=64’h2555_2050_0455_0002,发送数据是64’hafaf_afaf_afaf_afaf,ftype=4’b0101和ttype=4’b0101(NWRITE_R),发送地址是36'h0_0455_0002,对应instruction_list.vh头文件中带响应的写事务;

3.4、接收NWRITE_R****请求,发送响应

    在发送请求一段时间后可以看到srio_response_gen_srio_gen2_0(响应模块)接收到的数据包头val_treq_tdata=64’h2555_2050_0455_0002,接收数据是64’hafaf_afaf_afaf_afaf,ftype=4’b0101和ttype=4’b0101(NWRITE_R事务),接收地址是36'h0_0455_0002,和发送的请求包一致,该事务会产生响应;在一段时间过后可以看到val_tresp_tvalid拉高一个周期,发送的响应包val_tresp_tdata=64’h25d0_4000_0000_0000,不带数据;

3.5、发送NREAD****请求

    圈红的是下一次发送的读数据请求包,可以看到发送的数据包头是val_ireq_tdata=64’h4b24_23f0_0000_2600,ftype=4’b0010和ttype=4’b0100(NREADs),发送地址是36'h0_0000_2600,通过发送的数据和头文件进行对照发现本次发送的事务是读事务,读事务请求只有包头,不包含数据;

3.6、接收NREAD****请求

    在发送一段时间请求包后srio_response_gen_srio_gen2_0(响应模块)接收到的数据包头val_treq_tdata=64’h4b24_23f0_0000_2600,接收的数据类型ftype=4’b0010和ttype=4’b0100(NREADs),接收地址是36'h0_0000_2600,接收到的size=8’h3f,和发送的请求包一致,接收到读数据事务后根据数据类型接收模块会返回一个响应包和一串数据;

3.7、发送NREAD响应

    在接收模块srio_response_gen_srio_gen2_0(响应模块)接收到读事务一段时候后产生响应包val_tresp_tdata=64’h4bd8_4000_0000_0000,并将数据0一起打包,因为接收到的size=8’h3f,所以需要发送的数据个数是64个字节,数据位宽是64位发送(8个字节),则需要发送8个周期的数据,log_clk是62.5M的时钟,8个周期则是128ns的数据;


3.8、接收NREAD****响应

    在响应包发送一段时间后在srio_request_gen_srio_gen2_0(请求模块)中收到了响应包包头和数据,响应包包头val_iresp_tdata=64’h4bd8_4000_0000_0000,跟在包头后面的是数据0,可以看到接收响应包包头和数据总共花费了9个周期,和我们响应模块发送的响应包头和数据一致;

    在响应和数据接收到后大致的事务传输流程就很清楚了,这儿只对流写事务、带响应的写事务和读事务进行了仿真时序的分析,其他几个事务也是同样的传输方式,如果感兴趣可以根据头文件和仿真继续往后面分析,如果例程代码中有不清楚的地方可私信。

四、自定义事物传输设计*

4.1****、自定义设计

    通过用户接口来自定义数据的传输,回环仿真来观测发送和接收的数据正否正确,主要还是在srio_request_gen_srio_gen2_0和srio_response_gen_srio_gen2_0模块中进行控制,在两个模块中分别创建了两个fifo来用于数据存储,request_fifo用来存储发送的写事务类型数据,rx_request_fifo用来存储接收的读数据事务类型数据,response_fifo用来存储接收的写事务类型数据,tx_response_fifo用来存储发送的读数据事务类型数据,由于SRIO传输一次数据包最多256个字节,所以fifo深度不用太大。根据设置不同的事务类型、地址和数据传输量来控制几种事务的传输,以下仿真就是自定义的收发控制时序;

4.2、单个NWRITE****包收发流程

    下面设计的是一次发送一个NWRITE(写)事务,事务类型、读取地址、数据量通过自己设置。首先将数据写入request_fifo当中,通过srio_request_gen_srio_gen2_0(请求模块)发送一个带数据的写事务请求包,数据包头val_ireq_tdata=64’h0054_2ff0_0000_0100,发送的数据为2、4、6......;可以看到通过srio_response_gen_srio_gen2_0(响应模块)接收到的数据包val_treq_tdata=64’h0054_2ff0_0000_0100与请求模块发送出来的包头一致,并且包头后面跟的数据是2、4、6......与发送数据一致;由于接受的是NWRITE,因此没有响应;

4.3、单个NWRITE_R****包收发流程

    下面设计的是一次发送一个NWRITE_R(带响应的写)事务。首先将数据写入request_fifo当中,通过srio_request_gen_srio_gen2_0(请求模块)发送一个带响应的写事务请求包,数据包头val_ireq_tdata=64’h0055_2ff0_0000_0200,发送的数据为2、4、6......;可以看到通过srio_response_gen_srio_gen2_0(响应模块)接收到的数据包val_treq_tdata=64’h0055_2ff0_0000_0200与请求模块发送出来的包头一致,并且包头后面跟的数据是2、4、6......与发送数据一致;由于接受的是NWRITE_R,发送的响应包包头val_tresp_tdata=64’h00d0_4000_0000_0000;请求模块接收的响应包val_iresp_tdata=64’h00d0_4000_0000_0000与发送的响应包一致;

4.4、单个NREAD****包收发流程

    下面设计的是一次发送一个NREAD(读)事务。首先是将需要读回来的数据写入tx_response_fifo当中,通过srio_request_gen_srio_gen2_0(请求模块)发送一个读事务请求包,数据包头val_ireq_tdata=64’h0024_2ff0_0000_0100;可以看到通过srio_response_gen_srio_gen2_0(响应模块)接收到的数据包val_treq_tdata=64’h0024_2ff0_0000_0100与请求模块发送出来的包头一致;因为是NREAD事务,所以会将响应模块中tx_response_fifo中的数据发送出去,响应包包头val_tresp_tdata=64’h00d8_4000_0000_0000,后面的数据是我存入fifo中的1、2、3......,该数据可以根据自己项目需求写入;在一段时间过后在请求模块中接收到响应包包头val_iresp_tdata=64’h00d8_4000_0000_0000与想响应模块发送的包头一致,后面的数据也是1、2、3.......,将读到的数据存入fifo,根据自己需求随时可以读出;

4.5、多个NWRITE****包收发流程

    下面设计的是一次发送多个NWRITE(写)事务。首先将数据写入request_fifo当中,设置发送事务个数参数(本次设置的是10个),通过srio_request_gen_srio_gen2_0(请求模块)发送多个带数据的写事务请求包,数据包头val_ireq_tdata=64’h0054_2ff0_0000_0100,发送的数据为2、4、6......;可以看到通过srio_response_gen_srio_gen2_0(响应模块)接收到的数据包val_treq_tdata=64’h0054_2ff0_0000_0100与请求模块发送出来的包头一致,事务个数也一致(10个),并且包头后面跟的数据是2、4、6......与发送数据一致;由于接受的是NWRITE,因此没有响应;

4.6、多个NWRITE_R****包收发流程

    下面设计的是一次发送多个NWRITE_R(带响应的写)事务。首先将数据写入request_fifo当中,设置发送事务个数参数(本次设置的是5个),通过srio_request_gen_srio_gen2_0(请求模块)发送多个带响应的写事务请求包,数据包头val_ireq_tdata=64’h0055_2ff0_0000_0200,发送的数据为2、4、6......;可以看到通过srio_response_gen_srio_gen2_0(响应模块)接收到的数据包val_treq_tdata=64’h0055_2ff0_0000_0200与请求模块发送出来的包头一致,事务个数也一致(5个),并且包头后面跟的数据是2、4、6......与发送数据一致;由于接受的是NWRITE_R,发送了五个响应包包头val_tresp_tdata=64’h00d0_4000_0000_0000;请求模块接收的响应包val_iresp_tdata=64’h00d0_4000_0000_0000与发送的响应包一致,响应包个数也是5个;

4.7、多个NREAD****包收发流程

    下面设计的是一次发送多个NREAD(读)事务。首先是将需要读回来的数据写入tx_response_fifo当中,设置发送事务个数参数(本次设置的是4个),通过srio_request_gen_srio_gen2_0(请求模块)发送多个读事务请求包,数据包头val_ireq_tdata=64’h0024_2ff0_0000_0100;可以看到通过srio_response_gen_srio_gen2_0(响应模块)接收到的数据包val_treq_tdata=64’h0024_2ff0_0000_0100与请求模块发送出来的包头一致,事务个数也一致(4个);因为是NREAD事务,所以会将响应模块中tx_response_fifo中的数据发送出去,响应包包头val_tresp_tdata=64’h00d8_4000_0000_0000,也是4个,后面的数据是我存入fifo中的1、2、3......,该数据可以根据自己项目需求写入;在一段时间过后在请求模块中接收到响应包包头val_iresp_tdata=64’h00d8_4000_0000_0000与想响应模块发送的包头一致,事务个数也一致(4个),后面的数据也是1、2、3.......,将读到的数据存入fifo,根据自己需求随时可以读出;

    **注意:**对于小于8个字节的传输,应该满足上图中size和addr的组合,其他组合无效,地址和大小用于确定传输的字节通道(size +1确定了传输的字节个数,addr确定了对应Byte Lane的字节位置,TKEEP总线必须绑定到所有总线)。
标签: 5G fpga开发 vim

本文转载自: https://blog.csdn.net/weixin_50835177/article/details/128842126
版权归原作者 逾越TAO 所有, 如有侵权,请联系我们删除。

“基于FPGA的SRIOIP例程及仿真实现”的评论:

还没有评论