//--------------------------------------------------------------------------------
//--
//-- This file is owned and controlled by Xilinx and must be used solely
//-- for design, simulation, implementation and creation of design files
//-- limited to Xilinx devices or technologies. Use with non-Xilinx
//-- devices or technologies is expressly prohibited and immediately
//-- terminates your license.
//--
//-- Xilinx products are not intended for use in life support
//-- appliances, devices, or systems. Use in such applications is
//-- expressly prohibited.
//--
//-- **************************************
//-- ** Copyright (C) 2005, Xilinx, Inc. **
//-- ** All Rights Reserved. **
//-- **************************************
//--
//--------------------------------------------------------------------------------
//-- Filename: BMD_64_RX_ENGINE.v
//--
//-- Description: 64 bit Local-Link Receive Unit.
//--
//--------------------------------------------------------------------------------
`timescale 1ns/1ns
`define BMD_64_RX_RST 8'b00000001
`define BMD_64_RX_MEM_RD32_QW1 8'b00000010
`define BMD_64_RX_MEM_RD32_WT 8'b00000100
`define BMD_64_RX_MEM_WR32_QW1 8'b00001000
`define BMD_64_RX_MEM_WR32_WT 8'b00010000
`define BMD_64_RX_CPL_QW1 8'b00100000
`define BMD_64_RX_CPLD_QW1 8'b01000000
`define BMD_64_RX_CPLD_QWN 8'b10000000
`define BMD_MEM_RD32_FMT_TYPE 7'b00_00000
`define BMD_MEM_WR32_FMT_TYPE 7'b10_00000
`define BMD_CPL_FMT_TYPE 7'b00_01010
`define BMD_CPLD_FMT_TYPE 7'b10_01010
module BMD_RX_ENGINE (
clk,
rst_n,
//Initiator reset
init_rst_i,
//Receive local link interface from PCIe core
trn_rd,
trn_rrem_n,
trn_rsof_n,
trn_reof_n,
trn_rsrc_rdy_n,
trn_rsrc_dsc_n,
trn_rdst_rdy_n,
trn_rbar_hit_n,
/*
* Memory Read data handshake with Completion
* transmit unit. Transmit unit reponds to
* req_compl assertion and responds with compl_done
* assertion when a Completion w/ data is transmitted.
*/
req_compl_o,
compl_done_i,
addr_o, // Memory Read Address
req_tc_o, // Memory Read TC
req_td_o, // Memory Read TD
req_ep_o, // Memory Read EP
req_attr_o, // Memory Read Attribute
req_len_o, // Memory Read Length (1DW)
req_rid_o, // Memory Read Requestor ID
req_tag_o, // Memory Read Tag
req_be_o, // Memory Read Byte Enables
/*
* Memory interface used to save 1 DW data received
* on Memory Write 32 TLP. Data extracted from
* inbound TLP is presented to the Endpoint memory
* unit. Endpoint memory unit reacts to wr_en_o
* assertion and asserts wr_busy_i when it is
* processing written information.
*/
wr_be_o, // Memory Write Byte Enable
wr_data_o, // Memory Write Data
wr_en_o, // Memory Write Enable
wr_busy_i, // Memory Write Busy
/*
* Completion no Data
*/
cpl_ur_found_o,
cpl_ur_tag_o,
/*
* Completion with Data
*/
cpld_data_i,
cpld_found_o,
cpld_data_size_o,
cpld_malformed_o,
cpld_data_err_o
);
//1,BMD_RX_ENGINE的设计:这个模块的作用就是接受来自PC的TLP包(trn_rd[63:0]),
//并根据不同的情况对包进行拆解,首先根据trn_rd[62:56]位判断包的类型,
//如果是32位地址读请求(BMD_MEM_RD32_FMT_TYPE),
//那么就转到32位读对应的状态(BMD_64_RX_MEM_RD32_QW1)
//如果是32位地址写请求(BMD_MEM_WR32_FMT_TYPE)
//那么久转到32位写对应的状态(BMD_64_RX_MEM_WR32_QW1)
//如果是不带数据的完成类型(BMD_CPL_FMT_TYPE)
//那么就转到完成请求对应的状态(BMD_64_RX_CPL_QW1)
//如果是带数据的完成类型(BMD_CPLD_FMT_TYPE)
//那么就转到带数据完成对应的状态(BMD_64_RX_CPLD_QW1)
//原文:https://blog.csdn.net/buyi_shizi/article/details/51244966
//版权声明:本文为博主原创文章,转载请附上博文链接!
//上面是状态机的第一次过渡
//下面看状态的第二次过渡
//在状态是BMD_MEM_RD32_FMT_QW1时
//这个时候TLP包的第二个DWORD已经传来
//从第二个DWORD中可以得到读请求的地址addr_o
//这个地址是输入到memory模块下用于读出对应地址下的数据的
//然后过渡到下一个状态(BMD_64_RX_MEM_32_WT)
//在这个状态下,RX模块会一直检测从TX返回的compl_done_i信号
//当读请求申请的对应地址下的数据由TX发送出去时
//compl_done_i信号就为1
//这个时候RX就会返回到RST状态.
//当状态是BMD_MEM_WR32_FMT_QW1时
//这个时候RX也接受到了TLP包的第二个DWORD
//从这个DWORD中可以拆分出地址(addr_o)和要写的数据(wr_data_o)
//同时在这个状态写使能值为有效(we_en_o)
//然后过渡到下一个状态(BMD_64_RX_MEM_WR32_WT)
//在这一个状态,RX会一直检测从memory模块出来的信号(wr_busy_i)是不是为0
//如果为0,说明写操作完成
//RX回到RST状态.
//当状态是BMD_64_RX_CPL_QW1的时候,
//说明这是一个不带数据的完成
//其他并没有什么操作
//当状态是BMD_64_RX_CPLD_QW1时
//说明这是一个带数据的完成
//为什么完成信号要携带数据呢
//原因就是为了检验传输的数据是否正确
//在这个状态下以及它的过渡状态中
//RX会一次检测传输到PC端的数据和设备内存的数据是否相同
//如果不相同,说明数据传输失败,
//返回失败传输信号(cpld_malformed)
//从上面的描述可以看出,BMD中的RX是不支持连续的写数据的(往设备内存写数据)
//所以往设备内存写数据的DMA操作,xapp1052是不支持的,
//那么这里发送和接收的数据到底是什么呢
//其实这里RX并不是要发送和接收存储数据
//而是发送和接收配置数据,即DMA的配置数据
input clk;
input rst_n;
input init_rst_i;
input [63:0] trn_rd;
input [7:0] trn_rrem_n;
input trn_rsof_n;
input trn_reof_n;
input trn_rsrc_rdy_n;
input trn_rsrc_dsc_n;
output trn_rdst_rdy_n;
input [6:0] trn_rbar_hit_n;
output req_compl_o;
input compl_done_i;
output [10:0] addr_o;
output [2:0] req_tc_o;
output req_td_o;
output req_ep_o;
output [1:0] req_attr_o;
output [9:0] req_len_o;
output [15:0] req_rid_o;
output [7:0] req_tag_o;
output [7:0] req_be_o;
output [7:0] wr_be_o;
output [31:0] wr_data_o;
output wr_en_o;
input wr_busy_i;
output [7:0] cpl_ur_found_o;
output [7:0] cpl_ur_tag_o;
input [31:0] cpld_data_i;
output [31:0] cpld_found_o;
output [31:0] cpld_data_size_o;
output cpld_malformed_o;
output cpld_data_err_o;
// Local wire
wire [31:0] cpld_data_i_sw = {cpld_data_i[07:00],
cpld_data_i[15:08],
cpld_data_i[23:16],
cpld_data_i[31:24]};
// Local Registers
reg [7:0] bmd_64_rx_state;
reg trn_rdst_rdy_n;
reg req_compl_o;
reg [2:0] req_tc_o;
reg req_td_o;
reg req_ep_o;
reg [1:0] req_attr_o;
reg [9:0] req_len_o;
reg [15:0] req_rid_o;
reg [7:0] req_tag_o;
reg [7:0] req_be_o;
reg [10:0] addr_o;
reg [7:0] wr_be_o;
reg [31:0] wr_data_o;
reg wr_en_o;
reg [7:0] cpl_ur_found_o;
reg [7:0] cpl_ur_tag_o;
reg [31:0] cpld_found_o;
reg [31:0] cpld_data_size_o;
reg cpld_malformed_o;
reg cpld_data_err_o;
//reg [9:0] cpld_real_size;
//reg [9:0] cpld_tlp_size;
reg [6:0] cpld_real_size;
reg [6:0] cpld_tlp_size;
reg [7:0] bmd_64_rx_state_q;
reg [63:0] trn_rd_q;
reg [7:0] trn_rrem_n_q;
reg trn_reof_n_q;
reg trn_rsrc_rdy_n_q;
always @( posedge clk ) begin
if( !rst_n ) begin
bmd_64_rx_state <= `BMD_64_RX_RST;
trn_rdst_rdy_n <= 1'b0;
req_compl_o <= 1'b0;
req_tc_o <= 2'b0;
req_td_o <= 1'b0;
req_ep_o <= 1'b0;
req_attr_o <= 2'b0;
req_len_o <= 10'b0;
req_rid_o <= 16'b0;
req_tag_o <= 8'b0;
req_be_o <= 8'b0;
addr_o <= 31'b0;
wr_be_o <= 8'b0;
wr_data_o <= 31'b0;
wr_en_o <= 1'b0;
cpl_ur_found_o <= 8'b0;
cpl_ur_tag_o <= 8'b0;
cpld_found_o <= 32'b0;
cpld_data_size_o <= 32'b0;
cpld_malformed_o <= 1'b0;
cpld_real_size <= 7'b0;
cpld_tlp_size <= 7'b0;
bmd_64_rx_state_q <= `BMD_64_RX_RST;
trn_rd_q <= 64'b0;
trn_rrem_n_q <= 8'b0;
trn_reof_n_q <= 1'b1;
trn_rsrc_rdy_n_q <= 1'b1;
end else begin
wr_en_o <= 1'b0;
req_compl_o <= 1'b0;
trn_rdst_rdy_n <= 1'b0;
if( init_rst_i ) begin
bmd_64_rx_state <= `BMD_64_RX_RST;
cpl_ur_found_o <= 8'b0;
cpl_ur_tag_o <= 8'b0;
cpld_found_o <= 32'b0;
cpld_data_size_o <= 32'b0;
cpld_malformed_o <= 1'b0;
cpld_real_size <= 7'b0;
cpld_tlp_size <= 7'b0;
bmd_64_rx_state_q <= `BMD_64_RX_RST;
trn_rd_q <= 64'b0;
trn_rrem_n_q <= 8'b0;
trn_reof_n_q <= 1'b1;
trn_rsrc_rdy_n_q <= 1'b1;
end
bmd_64_rx_state_q <= `BMD_64_RX_RST;
trn_rd_q <= 64'b0;
trn_rrem_n_q <= 8'b0;
trn_reof_n_q <= 1'b1;
trn_rsrc_rdy_n_q <= 1'b1;
case( bmd_64_rx_state )
`BMD_64_RX_RST: begin
if( (!trn_rsof_n) &&
//接收引擎接收tlp包开始信号 i
(!trn_rsrc_rdy_n) &&
//源端准备好信号 i
(!trn_rdst_rdy_n) ) begin
//目的端准备好信号 o
case (trn_rd[62:56])
`BMD_MEM_RD32_FMT_TYPE: begin
//读32位模式
if( trn_rd[41:32] == 10'b1 ) begin
req_tc_o <= trn_rd[54:52];
req_td_o <= trn_rd[47];
req_ep_o <= trn_rd[46];
req_attr_o <= trn_rd[45:44];
req_len_o <= trn_rd[41:32];
req_rid_o <= trn_rd[31:16];
req_tag_o <= trn_rd[15:08];
req_be_o <= trn_rd[07:00];
bmd_64_rx_state <= `BMD_64_RX_MEM_RD32_QW1;
end else begin
bmd_64_rx_state <= `BMD_64_RX_RST;
end
end
`BMD_MEM_WR32_FMT_TYPE : begin
//40000001 0000000f
//写32位模式
if( trn_rd[41:32] == 10'b1 ) begin
wr_be_o <= trn_rd[07:00];
bmd_64_rx_state <= `BMD_64_RX_MEM_WR32_QW1;
end else begin
bmd_64_rx_state <= `BMD_64_RX_RST;
end
end
`BMD_CPL_FMT_TYPE : begin
if( trn_rd[15:12] != 3'b000 ) begin
cpl_ur_found_o <= cpl_ur_found_o + 1'b1;
bmd_64_rx_state <= `BMD_64_RX_CPL_QW1;
end else begin
bmd_64_rx_state <= `BMD_64_RX_RST;
end
end
`BMD_CPLD_FMT_TYPE: begin
//带数据的完成类型
cpld_data_size_o <= cpld_data_size_o + trn_rd[41:32];
cpld_tlp_size <= trn_rd[38:32];
cpld_found_o <= cpld_found_o + 1'b1;
cpld_real_size <= 7'b0;
bmd_64_rx_state <= `BMD_64_RX_CPLD_QW1;
end
default: begin
bmd_64_rx_state <= `BMD_64_RX_RST;
end
endcase
end else begin
bmd_64_rx_state <= `BMD_64_RX_RST;
end
end
`BMD_64_RX_MEM_RD32_QW1: begin
//进入读32bit模式的查询与等待状态
if( (!trn_reof_n) &&
(!trn_rsrc_rdy_n) &&
(!trn_rdst_rdy_n) ) begin
addr_o <= trn_rd[63:34];
//取读地址 4字节对齐
req_compl_o <= 1'b1;
//请求完成信号置1
trn_rdst_rdy_n <= 1'b1;
bmd_64_rx_state <= `BMD_64_RX_MEM_RD32_WT;
end else begin
bmd_64_rx_state <= `BMD_64_RX_MEM_RD32_QW1;
end
end
`BMD_64_RX_MEM_RD32_WT: begin
//读32位数据模式等待态
trn_rdst_rdy_n <= 1'b1;
if( compl_done_i ) begin
//等待完成信号置1
bmd_64_rx_state <= `BMD_64_RX_RST;
end else begin
req_compl_o <= 1'b1;
trn_rdst_rdy_n <= 1'b1;
bmd_64_rx_state <= `BMD_64_RX_MEM_RD32_WT;
end
end
`BMD_64_RX_MEM_WR32_QW1: begin
if( (!trn_reof_n) &&
(!trn_rsrc_rdy_n) &&
(!trn_rdst_rdy_n) ) begin
addr_o <= trn_rd[44:34];
//从tlp包中提取地址 bit32-31忽略,4字节对齐
wr_data_o <= trn_rd[31:00];
//从tlp包中提取32bit数据
wr_en_o <= 1'b1;
trn_rdst_rdy_n <= 1'b1;
bmd_64_rx_state <= `BMD_64_RX_MEM_WR32_WT;
end else begin
bmd_64_rx_state <= `BMD_64_RX_MEM_WR32_QW1;
end
end
`BMD_64_RX_MEM_WR32_WT: begin
trn_rdst_rdy_n <= 1'b1;
//等待写忙状态位
if( !wr_busy_i ) begin
//闲,进入接收复位态
bmd_64_rx_state <= `BMD_64_RX_RST;
end else begin
//忙,维持在本状态
bmd_64_rx_state <= `BMD_64_RX_MEM_WR32_WT;
end
end
`BMD_64_RX_CPL_QW1: begin
if( (!trn_reof_n) &&
(!trn_rsrc_rdy_n) &&
(!trn_rdst_rdy_n) ) begin
cpl_ur_tag_o <= trn_rd[47:40];
bmd_64_rx_state <= `BMD_64_RX_RST;
end else begin
bmd_64_rx_state <= `BMD_64_RX_CPL_QW1;
end
end
`BMD_64_RX_CPLD_QW1: begin
bmd_64_rx_state_q <= bmd_64_rx_state;
trn_rd_q <= trn_rd;
trn_rrem_n_q <= trn_rrem_n;
trn_reof_n_q <= trn_reof_n;
trn_rsrc_rdy_n_q <= trn_rsrc_rdy_n;
if( (!trn_reof_n) &&
(!trn_rsrc_rdy_n) &&
(!trn_rdst_rdy_n) ) begin
cpld_real_size <= cpld_real_size + 1'b1;
if( cpld_tlp_size != 1'b1 ) begin
cpld_malformed_o <= 1'b1;
end
if( trn_rrem_n != 8'h00 ) begin
cpld_malformed_o <= 1'b1;
end
bmd_64_rx_state <= `BMD_64_RX_RST;
end else if( (!trn_rsrc_rdy_n) &&
(!trn_rdst_rdy_n) ) begin
cpld_real_size <= cpld_real_size + 1'b1;
bmd_64_rx_state <= `BMD_64_RX_CPLD_QWN;
end else begin
bmd_64_rx_state <= `BMD_64_RX_CPLD_QW1;
end
end
`BMD_64_RX_CPLD_QWN: begin
bmd_64_rx_state_q <= bmd_64_rx_state;
trn_rd_q <= trn_rd;
trn_rrem_n_q <= trn_rrem_n;
trn_reof_n_q <= trn_reof_n;
trn_rsrc_rdy_n_q <= trn_rsrc_rdy_n;
if( (!trn_reof_n) &&
(!trn_rsrc_rdy_n) &&
(!trn_rdst_rdy_n) ) begin
if( trn_rrem_n == 8'h0F ) begin
cpld_real_size <= cpld_real_size + 1'h1;
if( cpld_tlp_size != cpld_real_size + 1'h1 ) begin
cpld_malformed_o <= 1'b1;
end
end else begin
cpld_real_size <= cpld_real_size + 2'h2;
if( cpld_tlp_size != cpld_real_size + 2'h2 ) begin
cpld_malformed_o <= 1'b1;
end
end
bmd_64_rx_state <= `BMD_64_RX_RST;
end else if( (!trn_rsrc_rdy_n) &&
(!trn_rdst_rdy_n) ) begin
cpld_real_size <= cpld_real_size + 2'h2;
bmd_64_rx_state <= `BMD_64_RX_CPLD_QWN;
end else begin
bmd_64_rx_state <= `BMD_64_RX_CPLD_QWN;
end
end
endcase
end
end
always @( posedge clk ) begin
if( !rst_n ) begin
cpld_data_err_o <= 1'b0;
end else begin
if( init_rst_i ) begin
cpld_data_err_o <= 1'b0;
end else begin
case( bmd_64_rx_state_q )
`BMD_64_RX_CPLD_QW1: begin
if( cpld_data_err_o == 1'b0 ) begin
if( trn_rd_q[31:00] != cpld_data_i_sw ) begin
//pc端发送下来的数据与我们设置的读寄存器的值比较
cpld_data_err_o <= 1'b1;
end
end
end
`BMD_64_RX_CPLD_QWN: begin
if( !trn_reof_n_q ) begin
if( trn_rrem_n_q == 8'h0F ) begin
if( cpld_data_err_o == 1'b0 ) begin
if( trn_rd_q[63:32] != cpld_data_i_sw ) begin
cpld_data_err_o <= 1'b1;
end
end
end else if( trn_rrem_n_q == 8'h00 ) begin
if( cpld_data_err_o == 1'b0 ) begin
if( trn_rd_q != {cpld_data_i_sw, cpld_data_i_sw} ) begin
cpld_data_err_o <= 1'b1;
end
end
end else begin
//Invalid remainder
cpld_data_err_o <= 1'b1;
end
end else begin
if( cpld_data_err_o == 1'b0 ) begin
if( trn_rd_q != {cpld_data_i_sw, cpld_data_i_sw} ) begin
cpld_data_err_o <= 1'b1;
end
end
end
end
endcase
end
end
end
/*
///////////////////////////////////////////////////////////////////////
//chipscope xilinx
wire [35:0] CONTROL0;
wire [255:0] TRIG0;
my_debug_ctrl icon_debug (
.CONTROL0(CONTROL0)
);
my_debug ila_filter_debug (
.CONTROL(CONTROL0),
.CLK(clk),
.TRIG0(TRIG0)
);
assign TRIG0[0] = trn_rsof_n;
assign TRIG0[1] = trn_reof_n;
assign TRIG0[2] = trn_rsrc_rdy_n;
assign TRIG0[3] = trn_rdst_rdy_n;
assign TRIG0[4] = wr_en_o;
assign TRIG0[5] = wr_busy_i;
assign TRIG0[6] = req_compl_o;
assign TRIG0[7] = compl_done_i;
assign TRIG0[39:8] = wr_data_o[31:0];
assign TRIG0[50:40] = addr_o[10:0];
assign TRIG0[58:51] = wr_be_o[7:0];
assign TRIG0[122:59] = trn_rd[63:0];
assign TRIG0[154:123] = cpld_data_i[31:0];
*/
endmodule // BMD_64_RX_ENGINE