当前位置:   article > 正文

【PCIE】基于PCIE4C的数据传输(一)——PC访问FPGA_pcie rq rc

pcie rq rc

FPGA设计

PCIE4C

  PCIE4C是Ultrascale+系列开始引入的硬核,它是PCIE4硬核的延续,在功能上增加了对PCIe4.0协议的支持,由于PCIe报文采用高速串行传输,到达FPGA后首先经过GT转换为低速并行数据,之后由PCIE4C进行进一步处理,得到便于用户使用的AXI-Stream形式的报文。
为了便于使用,Xilinx将GT与PCIE4C打包为一个IP核Ultrascale FPGAs Transceivers Wizard(产品手册),在将FPGA作为终端设备的基本配置下,IP核的主要接口如下:
在这里插入图片描述
  各接口对应功能可从产品手册中看到,主要接口为cq、cc、rq、rc四个接口。其中cq、cc为主机(PC机)请求、从机(FPGA)响应接口,PC机将读/写地址报文通过cq接口通过握手方式发送到FPGA,FPGA将读地址对应的数据内容/写地址完成报文通过cc接口通过握手方式发送给PC机。rq、rc为从机(FPGA)请求、主机(PC机)响应接口,FPGA将读/写地址报文通过rq接口通过握手方式发送到PC机,PC机将读地址对应的数据内容/写地址完成报文通过cc接口通过握手方式发送给FPGA。
在这里插入图片描述
  对于PC主动传输过程,CPU将需要读地址/写地址及数据告知FPGA,由FPGA被动进行响应处理,主要用到cq、cc两个接口。

cq接口

  cq接口具有的信号及传输方向如图所示。需要注意的是,不同于标准PCIe报文格式,PCIE4C将部分PCIe报文头字段(描述符)放入tuser字段中。
在这里插入图片描述
  同时,PCIE4C将剩余的PCIe报文头字段留在第一个传输tdata的前几个字节中,对于内存、IO、原子操作类型的PCIe报文,tdata头个传输字段划分如下图所示。
在这里插入图片描述
  各字段解释可从产品手册找到。
  对于128bit位宽AXIS流接口、DWORD对齐模式,一次写内存请求操作对应波形类似下图。
在这里插入图片描述
  对于128bit位宽AXIS流接口,一次读内存请求操作对应波形类似下图。
在这里插入图片描述

cc接口

  cc通道的接口信号如下图,当每次cq写请求操作结束后,FPGA侧需要通过cc接口返回写成功或写失败响应。
在这里插入图片描述
  响应的每第一次传输的tdata的前几字节都被视为PCIe头字段(描述符),如下图
在这里插入图片描述
  各字段解释可从产品手册找到。
  对于128bit位宽AXIS流接口、DWORD对齐模式,一次读内存响应操作对应波形类似下图。

在这里插入图片描述

代码

1. 读写请求处理模块

  这里列出negative_process.sv的状态机代码,这里PCIE4C例化了四个功能设备,每个功能设备具有独立的ram区域,这里的状态机代码负责对PC机传入的对应功能设备ram的读写操作进行处理。

    always @(*) begin
        case (cs)
        0: begin
            if (m_axis_cq_tvalid & m_axis_cq_tready) begin
                if (m_axis_cq_tlast) begin
                    ns = 4;
                end
                else begin
                    ns = 1;
                end
            end
            else begin
                ns = 0;
            end
        end
        1: begin // must have header
            if (m_axis_cq_tvalid & m_axis_cq_tready) begin
                if (m_axis_cq_tlast) begin
                    ns = 3;
                end
                else begin
                    ns = 2;
                end
            end        
            else begin
                ns = 1;
            end    
        end
        2: begin
            if (m_axis_cq_tvalid & m_axis_cq_tlast & m_axis_cq_tready) begin
                ns = 3;
            end        
            else begin
                ns = 2;
            end   
        end
        3: begin // last_packet's frame
            if (m_axis_cq_tvalid & m_axis_cq_tready) begin
                if (m_axis_cq_tlast) begin
                    ns = 4;
                end
                else begin
                    ns = 1;
                end
            end
            else begin
                ns = 0;
            end
            // ns = 0;
        end
        4: begin // require cpl finish
            ns = 5;
        end
        5: begin
            if (usr_first_be_used_rr & cpl_ready) begin
                ns = 0;
            end
            else begin
                ns = 5;
            end
        end
        default: begin
            ns = 0;
        end
        endcase
    end
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
2. 读写响应处理模块

  这里列出positive_process.sv的状态机代码,它通过监听negative_process.sv模块进行操作类型,如果出现读写操作则返回对应响应包。

    always @(*) begin
        case (cs)
        0: begin
            // if (dma_enable) begin
            ns = 1;
            // end
            // else begin
            //     ns = 0;
            // end
        end
        1: begin
            ns = 2;
        end
        2: begin
            if (dma_fetch) begin
                ns = 7;
            end
            else begin
                ns = 1;
            end
        end
        7: begin    // delay wait fetch data from ram
            if (s_axis_rq_tready[0]) begin
                ns = 8;
            end
            else begin
                ns = 7;
            end
        end
        8: begin    // delay
            if (s_axis_rq_tready[0]) begin
                ns = 3;
            end
            else begin
                ns = 8;
            end
        end
        3: begin
            if (s_axis_rq_tvalid && s_axis_rq_tready[0]) begin
                if (dma_trans_direction) begin
                    ns = 4;
                end
                else begin
                    ns = 5;
                end
            end
            else begin
                ns = 3;
            end
        end
        4: begin // wr
            if (s_axis_rq_tvalid && s_axis_rq_tready[0] & s_axis_rq_tlast) begin
                ns = 6;
            end
            else begin
                ns = 4;
            end
        end
        5: begin // rd cpl
            if (~cpl_start & cpl_done & last_trans_flag_r) begin
                ns = 6;
            end
            else begin
                ns = 5;
            end
        end
        6: begin // write finish flag
            if (irq_ready) begin
                ns = 0;
            end
            else begin
                ns = 6;
            end
        end
        default: begin
            ns = 0;
        end
        endcase
    end
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
3. ram模块

  由于每次读取和写入ram的过程可能会同时对ram相邻两个地址的数据进行操作,为了降低读取和写入ram数据的延时,这里使用了两个ram并联的方式,即偶数地址、奇数地址数据分别存在两块ram中。当遇到对ram相邻两个地址数据的操作时,能够从两块ram同时取数并截取得到返回结果。核心代码如下

`timescale 1ns / 1ps
//
// Company: 
// Engineer: wjh776a68
// 
// Create Date: 09/13/2023 02:45:50 PM
// Design Name: 
// Module Name: ram_ctrl
// Project Name: 
// Target Devices: xcvu37p
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ram_ctrl #(
    parameter RAM_DEPTH = 1024,
    parameter BYTEADDR_WIDTH = $clog2(RAM_DEPTH * 32 / 8),
    parameter ADDR_WIDTH = $clog2(RAM_DEPTH / 4)
) (
    input  wire clk,

    output reg [127:0]                 ram_douta,
    output reg [127:0]                 ram_doutb,
    input  wire [BYTEADDR_WIDTH - 1:0] ram_byteaddra,
    input  wire [BYTEADDR_WIDTH - 1:0] ram_byteaddrb,
    input  wire [127:0]                ram_dina,
    input  wire [127:0]                ram_dinb,
    input  wire [15:0]                 ram_wea,
    input  wire [15:0]                 ram_web,
    input  wire                        ram_ena,
    input  wire                        ram_enb
);

    wire [127:0]            ram_lo_douta, ram_hi_douta;
    wire [127:0]            ram_lo_doutb, ram_hi_doutb;
    reg  [ADDR_WIDTH - 1:0] ram_lo_addra, ram_hi_addra;
    reg  [ADDR_WIDTH - 1:0] ram_lo_addrb, ram_hi_addrb;
    reg  [127:0]            ram_lo_dina, ram_hi_dina;
    reg  [127:0]            ram_lo_dinb, ram_hi_dinb;
    reg  [15:0]             ram_lo_wea, ram_hi_wea;
    reg  [15:0]             ram_lo_web, ram_hi_web;

    reg [BYTEADDR_WIDTH - 1:0] ram_byteaddra_r, ram_byteaddra_rr;
    reg [BYTEADDR_WIDTH - 1:0] ram_byteaddrb_r, ram_byteaddrb_rr;

    always @(posedge clk) begin
        if (ram_ena) begin
            ram_byteaddra_r <= ram_byteaddra;
            ram_byteaddra_rr <= ram_byteaddra_r;
        end
    end

    always @(posedge clk) begin
        case (ram_byteaddra_rr[4 : 0]) 
        5'b00000: begin
            ram_douta <= ram_lo_douta; 
        end
        5'b10000: begin
            ram_douta <= ram_hi_douta; 
        end
        5'b00001: begin
            ram_douta <= {ram_hi_douta[0 +: 1 * 8], ram_lo_douta[1 * 8 +: 15 * 8]}; 
        end
        5'b00010: begin
            ram_douta <= {ram_hi_douta[0 +: 2 * 8], ram_lo_douta[2 * 8 +: 14 * 8]}; 
        end
        。。。
        5'b01111: begin
            ram_douta <= {ram_hi_douta[0 +: 15 * 8], ram_lo_douta[15 * 8 +: 1 * 8]}; 
        end
        5'b10001: begin
            ram_douta <= {ram_lo_douta[0 +: 1 * 8], ram_hi_douta[1 * 8 +: 15 * 8]}; 
        end
        5'b10010: begin
            ram_douta <= {ram_lo_douta[0 +: 2 * 8], ram_hi_douta[2 * 8 +: 14 * 8]}; 
        end
        。。。
        5'b11111: begin
            ram_douta <= {ram_lo_douta[0 +: 15 * 8], ram_hi_douta[15 * 8 +: 1 * 8]}; 
        end
        endcase
    end

    always @(posedge clk) begin
        if (ram_enb) begin
            ram_byteaddrb_r  <= ram_byteaddrb;
            ram_byteaddrb_rr <= ram_byteaddrb_r;
        end
    end

    always @(posedge clk) begin
        case (ram_byteaddrb_rr[4 : 0]) 
        5'b00000: begin
            ram_doutb <= ram_lo_doutb; 
        end
        5'b10000: begin
            ram_doutb <= ram_hi_doutb; 
        end
        5'b00001: begin
            ram_doutb <= {ram_hi_doutb[0 +: 1 * 8], ram_lo_doutb[1 * 8 +: 15 * 8]}; 
        end
        5'b00010: begin
            ram_doutb <= {ram_hi_doutb[0 +: 2 * 8], ram_lo_doutb[2 * 8 +: 14 * 8]}; 
        end
        。。。
        5'b01111: begin
            ram_doutb <= {ram_hi_doutb[0 +: 15 * 8], ram_lo_doutb[15 * 8 +: 1 * 8]}; 
        end
        5'b10001: begin
            ram_doutb <= {ram_lo_doutb[0 +: 1 * 8], ram_hi_doutb[1 * 8 +: 15 * 8]}; 
        end
        5'b10010: begin
            ram_doutb <= {ram_lo_doutb[0 +: 2 * 8], ram_hi_doutb[2 * 8 +: 14 * 8]}; 
        end
        。。。
        5'b11111: begin
            ram_doutb <= {ram_lo_doutb[0 +: 15 * 8], ram_hi_doutb[15 * 8 +: 1 * 8]}; 
        end
        endcase
    end

    always @(*) begin
        case (ram_byteaddra[4])
        1'b0: begin
            ram_lo_addra <= ram_byteaddra[BYTEADDR_WIDTH - 1 : 5];
            ram_hi_addra <= ram_byteaddra[BYTEADDR_WIDTH - 1 : 5];
        end
        1'b1: begin
            ram_lo_addra <= ram_byteaddra[BYTEADDR_WIDTH - 1 : 5] + 1;
            ram_hi_addra <= ram_byteaddra[BYTEADDR_WIDTH - 1 : 5];
        end
        endcase 
        

        case (ram_byteaddra[4 : 0]) 
        5'b00000: begin
            ram_lo_wea <= ram_wea;
            ram_hi_wea <= 0;
            ram_lo_dina <= ram_dina;
            ram_hi_dina <= 0;
        end
        5'b10000: begin
            ram_lo_wea <= 0;
            ram_hi_wea <= ram_wea;
            ram_lo_dina <= 0;
            ram_hi_dina <= ram_dina;
        end
        5'b00001: begin
            ram_lo_wea <= {ram_wea[0 +: 15], 1'b0};
            ram_hi_wea <= {15'b0, ram_wea[15 +: 1]};
            ram_lo_dina <= {ram_dina[0 +: 15 * 8], {1{8'bx}}};
            ram_hi_dina <= {{15{8'bx}}, ram_dina[15 * 8 +: 1 * 8]};
        end
        5'b00010: begin
            ram_lo_wea <= {ram_wea[0 +: 14], 2'b0};
            ram_hi_wea <= {14'b0, ram_wea[14 +: 2]};
            ram_lo_dina <= {ram_dina[0 +: 14 * 8], {2{8'bx}}};
            ram_hi_dina <= {{14{8'bx}}, ram_dina[14 * 8 +: 2 * 8]};
        end
        。。。
        5'b01111: begin
            ram_lo_wea <= {ram_wea[0 +: 1], 15'b0};
            ram_hi_wea <= {1'b0, ram_wea[1 +: 15]};
            ram_lo_dina <= {ram_dina[0 +: 1 * 8], {15{8'bx}}};
            ram_hi_dina <= {{1{8'bx}}, ram_dina[1 * 8 +: 15 * 8]};
        end
        5'b10001: begin
            ram_hi_wea <= {ram_wea[0 +: 15], 1'b0};
            ram_lo_wea <= {15'b0, ram_wea[15 +: 1]};
            ram_hi_dina <= {ram_dina[0 +: 15 * 8], {1{8'bx}}};
            ram_lo_dina <= {{15{8'bx}}, ram_dina[15 * 8 +: 1 * 8]};
        end
        5'b10010: begin
            ram_hi_wea <= {ram_wea[0 +: 14], 2'b0};
            ram_lo_wea <= {14'b0, ram_wea[14 +: 2]};
            ram_hi_dina <= {ram_dina[0 +: 14 * 8], {2{8'bx}}};
            ram_lo_dina <= {{14{8'bx}}, ram_dina[14 * 8 +: 2 * 8]};
        end
        。。。
        5'b11111: begin
            ram_hi_wea <= {ram_wea[0 +: 1], 15'b0};
            ram_lo_wea <= {1'b0, ram_wea[1 +: 15]};
            ram_hi_dina <= {ram_dina[0 +: 1 * 8], {15{8'bx}}};
            ram_lo_dina <= {{1{8'bx}}, ram_dina[1 * 8 +: 15 * 8]};
        end
        endcase
    end



    always @(*) begin
        case (ram_byteaddrb[4])
        1'b0: begin
            ram_lo_addrb <= ram_byteaddrb[BYTEADDR_WIDTH - 1 : 5];
            ram_hi_addrb <= ram_byteaddrb[BYTEADDR_WIDTH - 1 : 5];
        end
        1'b1: begin
            ram_lo_addrb <= ram_byteaddrb[BYTEADDR_WIDTH - 1 : 5] + 1;
            ram_hi_addrb <= ram_byteaddrb[BYTEADDR_WIDTH - 1 : 5];
        end
        endcase 
        

        case (ram_byteaddrb[4 : 0]) 
        5'b00000: begin
            ram_lo_web <= ram_web;
            ram_hi_web <= 0;
            ram_lo_dinb <= ram_dinb;
            ram_hi_dinb <= 0;
        end
        5'b10000: begin
            ram_lo_web <= 0;
            ram_hi_web <= ram_web;
            ram_lo_dinb <= 0;
            ram_hi_dinb <= ram_dinb;
        end
        5'b00001: begin
            ram_lo_web <= {ram_web[0 +: 15], 1'b0};
            ram_hi_web <= {15'b0, ram_web[15 +: 1]};
            ram_lo_dinb <= {ram_dinb[0 +: 15 * 8], {1{8'bx}}};
            ram_hi_dinb <= {{15{8'bx}}, ram_dinb[15 * 8 +: 1 * 8]};
        end
        5'b00010: begin
            ram_lo_web <= {ram_web[0 +: 14], 2'b0};
            ram_hi_web <= {14'b0, ram_web[14 +: 2]};
            ram_lo_dinb <= {ram_dinb[0 +: 14 * 8], {2{8'bx}}};
            ram_hi_dinb <= {{14{8'bx}}, ram_dinb[14 * 8 +: 2 * 8]};
        end
        。。。
        5'b01111: begin
            ram_lo_web <= {ram_web[0 +: 1], 15'b0};
            ram_hi_web <= {1'b0, ram_web[1 +: 15]};
            ram_lo_dinb <= {ram_dinb[0 +: 1 * 8], {15{8'bx}}};
            ram_hi_dinb <= {{1{8'bx}}, ram_dinb[1 * 8 +: 15 * 8]};
        end
        5'b10001: begin
            ram_hi_web <= {ram_web[0 +: 15], 1'b0};
            ram_lo_web <= {15'b0, ram_web[15 +: 1]};
            ram_hi_dinb <= {ram_dinb[0 +: 15 * 8], {1{8'bx}}};
            ram_lo_dinb <= {{15{8'bx}}, ram_dinb[15 * 8 +: 1 * 8]};
        end
        5'b10010: begin
            ram_hi_web <= {ram_web[0 +: 14], 2'b0};
            ram_lo_web <= {14'b0, ram_web[14 +: 2]};
            ram_hi_dinb <= {ram_dinb[0 +: 14 * 8], {2{8'bx}}};
            ram_lo_dinb <= {{14{8'bx}}, ram_dinb[14 * 8 +: 2 * 8]};
        end
        。。。
        5'b11111: begin
            ram_hi_web <= {ram_web[0 +: 1], 15'b0};
            ram_lo_web <= {1'b0, ram_web[1 +: 15]};
            ram_hi_dinb <= {ram_dinb[0 +: 1 * 8], {15{8'bx}}};
            ram_lo_dinb <= {{1{8'bx}}, ram_dinb[1 * 8 +: 15 * 8]};
        end
        endcase
    end



    ram #(
        .RAM_DEPTH(RAM_DEPTH)
    ) ram_lo_inst (
        .clk(clk),

        .ram_douta(ram_lo_douta),
        .ram_doutb(ram_lo_doutb),
        .ram_addra(ram_lo_addra),
        .ram_addrb(ram_lo_addrb),
        .ram_dina(ram_lo_dina),
        .ram_dinb(ram_lo_dinb),
        .ram_wea(ram_lo_wea),
        .ram_web(ram_lo_web),
        .ram_ena(ram_ena),
        .ram_enb(ram_enb)
    );

    ram #(
        .RAM_DEPTH(RAM_DEPTH)
    ) ram_hi_inst (
        .clk(clk),

        .ram_douta(ram_hi_douta),
        .ram_doutb(ram_hi_doutb),
        .ram_addra(ram_hi_addra),
        .ram_addrb(ram_hi_addrb),
        .ram_dina(ram_hi_dina),
        .ram_dinb(ram_hi_dinb),
        .ram_wea(ram_hi_wea),
        .ram_web(ram_hi_web),
        .ram_ena(ram_ena),
        .ram_enb(ram_enb)
    );
endmodule
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
仿真

  这里PCIe仿真利用Alex Forencich编写的cocotb pcie仿真库进行,核心代码如下。

    tb = TB(dut)

    await tb.init()

    mem = tb.rc.mem_pool.alloc_region(16*1024*1024)
    mem_base = mem.get_absolute_address(0)

    dev = tb.rc.find_device(tb.dev.functions[0].pcie_id)

    dev_pf0_bar0 = dev.bar_window[0]
    dev_pf0_bar2 = dev.bar_window[2]

    tb.log.info("Test memory write to BAR 2")

    test_data = b'\x11\x22\x33\x44'
    await dev_pf0_bar2.write(0, test_data)

    await Timer(100, 'ns')

    tb.log.info("Test memory read from BAR 2")

    val = await dev_pf0_bar2.read(0, len(test_data), timeout=1000)
    tb.log.info("Read data: %s", val)
    assert val == test_data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

PC驱动设计

  由于系统为RHEL,因此驱动基于linux内核进行开发,对于主机而言,PCIe与PCI设备的驱动代码基本一致。kernel官网PCI设备开发教程
  进行读写测试的核心代码如下:

        if (bar32 != NULL) {
            printk("bar status: %d %d", bar_baseaddress, bar_length);
            printk("write %x to %p", bar32_rc, bar32);
            for (i = 0; i < 8; i+=4) {
                iowrite32(bar32_rc, (u32*)bar32 + i);
            }
            printk("try read from mmio");
            for (i = 0; i < 8; i++) {
                bar32_rc = ioread32((u32*)bar32 + i);
                printk("read %p value: %08x ", (u32*)bar32 + i, bar32_rc);
            }
            printk("\n");
            printk("test 32 wrrd pass, then test 64 wrrd\n");
        }
        else {
            printk("cannot map bar");
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

工程文件

  完整工程于同名公众号回复PCIE4C_PC获取。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/972910
推荐阅读
相关标签
  

闽ICP备14008679号