1// 2// Copyright 2013 Ettus Research LLC 3// Copyright 2018 Ettus Research, a National Instruments Company 4// 5// SPDX-License-Identifier: LGPL-3.0-or-later 6// 7 8 9`define BIT_WIDTH(N) (\ 10 N <= 2 ? 1 : \ 11 N <= 4 ? 2 : \ 12 N <= 8 ? 3 : \ 13 N <= 16 ? 4 : \ 14 N <= 32 ? 5 : \ 15 N <= 64 ? 6 : \ 16 N <= 128 ? 7 : \ 17 N <= 256 ? 8 : \ 18 N <= 512 ? 9 : \ 19 10) 20`define GET_REG_OFFSET(reg_addr, chan_idx) (((chan_idx * (1<<DMA_REG_GRP_W)) + reg_addr) + REG_BASE_ADDR) 21`define EXTRACT_CHAN_NUM(reg_addr) regi_addr[`BIT_WIDTH(NUM_STREAMS)+DMA_REG_GRP_W-1:DMA_REG_GRP_W] 22 23module pcie_dma_ctrl #( 24 parameter NUM_STREAMS = 4, 25 parameter FRAME_SIZE_W = 16, 26 parameter REG_BASE_ADDR = 20'h00000, 27 parameter ENABLE_ROUTER = 0, 28 parameter ROUTER_SID_W = 8, 29 parameter ROUTER_DST_W = 2 30) ( 31 input clk, 32 input reset, 33 34 input [63:0] regi_tdata, 35 input regi_tvalid, 36 output regi_tready, 37 output [63:0] rego_tdata, 38 output rego_tvalid, 39 input rego_tready, 40 41 output reg [NUM_STREAMS-1:0] set_enabled, 42 output reg [NUM_STREAMS-1:0] set_clear, 43 output [(NUM_STREAMS*FRAME_SIZE_W)-1:0] set_frame_size, 44 45 input [NUM_STREAMS-1:0] packet_stb, 46 input [NUM_STREAMS-1:0] sample_stb, 47 input [NUM_STREAMS-1:0] stream_busy, 48 input [NUM_STREAMS-1:0] stream_err, 49 50 input [ROUTER_SID_W-1:0] rtr_sid, 51 output [ROUTER_DST_W-1:0] rtr_dst 52); 53 54 localparam DMA_REG_GRP_W = 4; 55 localparam DMA_CTRL_STATUS_REG = 4'h0; //[RW] R: Stream Status, W: Stream Control 56 localparam DMA_FSIZE_REG = 4'h4; //[RW] R: Frame Size, W: Frame Size 57 localparam DMA_SAMP_CNT_REG = 4'h8; //[RW] R: Sample Count, W: Reset Count to 0 58 localparam DMA_PKT_CNT_REG = 4'hC; //[RW] R: Packet Count, W: Reset Count to 0 59 60 localparam DEFAULT_FSIZE = 32; 61 62 //NOTE: Although this module supports these, the 8 and 16 bit modes will be disabled for efficiency 63 localparam DMA_CTRL_BUF_SIZE_8 = 2'b00; // 8-bit wide SW buffer 64 localparam DMA_CTRL_BUF_SIZE_16 = 2'b01; //16-bit wide SW buffer 65 localparam DMA_CTRL_BUF_SIZE_32 = 2'b10; //32-bit wide SW buffer 66 localparam DMA_CTRL_BUF_SIZE_64 = 2'b11; //64-bit wide SW buffer 67 68 wire regi_wr, regi_rd; 69 wire [19:0] regi_addr; 70 wire [31:0] regi_payload; 71 wire [31:0] rego_payload; 72 73 ioport2_msg_decode regi_decoder ( 74 .message(regi_tdata), .wr_request(regi_wr), .rd_request(regi_rd), 75 .address(regi_addr), .data(regi_payload) 76 ); 77 78 ioport2_msg_encode rego_encoder ( 79 .rd_response(1'b1), .data(rego_payload), .message(rego_tdata) 80 ); 81 82 reg [31:0] pkt_count_mem[0:NUM_STREAMS-1]; 83 reg [31:0] samp_count_mem[0:NUM_STREAMS-1]; 84 reg [FRAME_SIZE_W-1:0] frame_size_mem[0:NUM_STREAMS-1]; 85 86 genvar i; 87 generate 88 for (i=0; i<NUM_STREAMS; i=i+1) begin: dma_ctrl_logic_generator 89 //Memory -> output translations 90 assign set_frame_size[(FRAME_SIZE_W*(i+1))-1:(FRAME_SIZE_W*i)] = frame_size_mem[i]; 91 92 //Setting registers 93 always @(posedge clk) begin 94 if (reset) begin 95 frame_size_mem[i] <= DEFAULT_FSIZE; 96 set_clear[i] <= 0; 97 set_enabled[i] <= 0; 98 end else if (regi_tready & regi_tvalid & regi_wr) begin 99 if (regi_addr == `GET_REG_OFFSET(DMA_CTRL_STATUS_REG, i)) begin 100 set_clear[i] <= regi_payload[0]; //DMA_CTRL_STATUS_REG[0] == Clear DMA queues 101 set_enabled[i] <= regi_payload[1]; //DMA_CTRL_STATUS_REG[1] == Enable DMA channel 102 end else if (regi_addr == `GET_REG_OFFSET(DMA_FSIZE_REG, i)) begin 103 frame_size_mem[i] <= regi_payload[FRAME_SIZE_W-1:0]; //DMA_FSIZE_REG[14:0] == DMA Frame size 104 end 105 end else begin 106 set_clear[i] <= 0; //set_clear should be "self-clearing" 107 end 108 end 109 110 //Packet counter 111 always @(posedge clk) begin 112 if (reset | (regi_tvalid && regi_wr && (regi_addr == `GET_REG_OFFSET(DMA_PKT_CNT_REG, i)))) begin 113 pkt_count_mem[i] <= 0; 114 end else if (packet_stb[i]) begin 115 pkt_count_mem[i] <= pkt_count_mem[i] + 1; 116 end 117 end 118 119 //Sample counter 120 always @(posedge clk) begin 121 if (reset | (regi_tvalid && regi_wr && (regi_addr == `GET_REG_OFFSET(DMA_SAMP_CNT_REG, i)))) begin 122 samp_count_mem[i] <= 0; 123 end else if (sample_stb[i]) begin 124 samp_count_mem[i] <= samp_count_mem[i] + 1; 125 end 126 end 127 end 128 endgenerate 129 130 //Readback 131 assign rego_payload = 132 (regi_addr[DMA_REG_GRP_W-1:0] == DMA_PKT_CNT_REG) ? pkt_count_mem[`EXTRACT_CHAN_NUM(regi_addr)] : ( 133 (regi_addr[DMA_REG_GRP_W-1:0] == DMA_SAMP_CNT_REG) ? samp_count_mem[`EXTRACT_CHAN_NUM(regi_addr)] : ( 134 (regi_addr[DMA_REG_GRP_W-1:0] == DMA_FSIZE_REG) ? frame_size_mem[`EXTRACT_CHAN_NUM(regi_addr)] : ( 135 (regi_addr[DMA_REG_GRP_W-1:0] == DMA_CTRL_STATUS_REG) ? {30'h0, stream_busy[`EXTRACT_CHAN_NUM(regi_addr)], stream_err[`EXTRACT_CHAN_NUM(regi_addr)]} : ( 136 32'hFFFFFFFF)))); 137 138 assign rego_tvalid = regi_tvalid && regi_rd; 139 assign regi_tready = rego_tready || (regi_tvalid && regi_wr); 140 141 //Optional router 142 generate if (ENABLE_ROUTER == 1) begin 143 pcie_pkt_route_specifier #( 144 .BASE_ADDR((1<<ROUTER_SID_W) + REG_BASE_ADDR), .ADDR_MASK(20'hFFFFF^((1<<ROUTER_SID_W)-1)), 145 .SID_WIDTH(ROUTER_SID_W), .DST_WIDTH(ROUTER_DST_W) 146 ) route_specifier ( 147 .clk(clk), .reset(reset), 148 .regi_tdata(regi_tdata), .regi_tvalid(regi_tvalid), .regi_tready(), 149 .local_sid(rtr_sid), .fifo_dst(rtr_dst) 150 ); 151 end endgenerate 152 153endmodule 154 155`undef EXTRACT_CHAN_NUM 156`undef GET_REG_OFFSET 157`undef BIT_WIDTH 158