diff options
Diffstat (limited to 'fpga/usrp3/lib/io_port2/pcie_dma_ctrl.v')
-rw-r--r-- | fpga/usrp3/lib/io_port2/pcie_dma_ctrl.v | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/io_port2/pcie_dma_ctrl.v b/fpga/usrp3/lib/io_port2/pcie_dma_ctrl.v new file mode 100644 index 000000000..6809939af --- /dev/null +++ b/fpga/usrp3/lib/io_port2/pcie_dma_ctrl.v @@ -0,0 +1,156 @@ +// +// Copyright 2013 Ettus Research LLC +// + + +`define BIT_WIDTH(N) (\ + N <= 2 ? 1 : \ + N <= 4 ? 2 : \ + N <= 8 ? 3 : \ + N <= 16 ? 4 : \ + N <= 32 ? 5 : \ + N <= 64 ? 6 : \ + N <= 128 ? 7 : \ + N <= 256 ? 8 : \ + N <= 512 ? 9 : \ + 10) +`define GET_REG_OFFSET(reg_addr, chan_idx) (((chan_idx * (1<<DMA_REG_GRP_W)) + reg_addr) + REG_BASE_ADDR) +`define EXTRACT_CHAN_NUM(reg_addr) regi_addr[`BIT_WIDTH(NUM_STREAMS)+DMA_REG_GRP_W-1:DMA_REG_GRP_W] + +module pcie_dma_ctrl #( + parameter NUM_STREAMS = 4, + parameter FRAME_SIZE_W = 16, + parameter REG_BASE_ADDR = 20'h00000, + parameter ENABLE_ROUTER = 0, + parameter ROUTER_SID_W = 8, + parameter ROUTER_DST_W = 2 +) ( + input clk, + input reset, + + input [63:0] regi_tdata, + input regi_tvalid, + output regi_tready, + output [63:0] rego_tdata, + output rego_tvalid, + input rego_tready, + + output reg [NUM_STREAMS-1:0] set_clear, + output [(NUM_STREAMS*FRAME_SIZE_W)-1:0] set_frame_size, + output [(NUM_STREAMS*3)-1:0] swap_lanes, + + input [NUM_STREAMS-1:0] packet_stb, + input [NUM_STREAMS-1:0] sample_stb, + input [NUM_STREAMS-1:0] stream_err, + + input [ROUTER_SID_W-1:0] rtr_sid, + output [ROUTER_DST_W-1:0] rtr_dst +); + + localparam DMA_REG_GRP_W = 4; + localparam DMA_CTRL_STATUS_REG = 4'h0; //[RW] R: Stream Error, W: Reset stream + localparam DMA_FSIZE_REG = 4'h4; //[RW] R: Frame Size, W: Frame Size + localparam DMA_SAMP_CNT_REG = 4'h8; //[RW] R: Sample Count, W: Reset Count to 0 + localparam DMA_PKT_CNT_REG = 4'hC; //[RW] R: Packet Count, W: Reset Count to 0 + + localparam DEFAULT_FSIZE = 32; + + //NOTE: Although this module supports these, the 8 and 16 bit modes will be disabled for efficiency + localparam DMA_CTRL_BUF_SIZE_8 = 2'b00; // 8-bit wide SW buffer + localparam DMA_CTRL_BUF_SIZE_16 = 2'b01; //16-bit wide SW buffer + localparam DMA_CTRL_BUF_SIZE_32 = 2'b10; //32-bit wide SW buffer + localparam DMA_CTRL_BUF_SIZE_64 = 2'b11; //64-bit wide SW buffer + + wire regi_wr, regi_rd; + wire [19:0] regi_addr; + wire [31:0] regi_payload; + wire [31:0] rego_payload; + + ioport2_msg_decode regi_decoder ( + .message(regi_tdata), .wr_request(regi_wr), .rd_request(regi_rd), + .address(regi_addr), .data(regi_payload) + ); + + ioport2_msg_encode rego_encoder ( + .rd_response(1'b1), .data(rego_payload), .message(rego_tdata) + ); + + reg [31:0] pkt_count_mem[0:NUM_STREAMS-1]; + reg [31:0] samp_count_mem[0:NUM_STREAMS-1]; + reg [FRAME_SIZE_W-1:0] frame_size_mem[0:NUM_STREAMS-1]; + reg [NUM_STREAMS-1:0] sw_buf_width_mem; + + genvar i; + generate + for (i=0; i<NUM_STREAMS; i=i+1) begin: dma_ctrl_logic_generator + //Memory -> output translations + assign set_frame_size[(FRAME_SIZE_W*(i+1))-1:(FRAME_SIZE_W*i)] = frame_size_mem[i]; + assign swap_lanes[(3*(i+1))-1:(3*i)] = { ~(sw_buf_width_mem[i]), 2'b00 }; //Optimized for only 2 modes + + //Setting registers + always @(posedge clk) begin + if (reset) begin + frame_size_mem[i] <= DEFAULT_FSIZE; + set_clear[i] <= 0; + sw_buf_width_mem[i] <= 1; + end else if (regi_tready & regi_tvalid & regi_wr) begin + if (regi_addr == `GET_REG_OFFSET(DMA_CTRL_STATUS_REG, i)) begin + set_clear[i] <= regi_payload[0]; //DMA_CTRL_STATUS_REG[0] == Clear DMA queues + sw_buf_width_mem[i] <= regi_payload[4]; //DMA_CTRL_STATUS_REG[5:4] == SW Buffer Size (See note above) + end else if (regi_addr == `GET_REG_OFFSET(DMA_FSIZE_REG, i)) begin + frame_size_mem[i] <= regi_payload[FRAME_SIZE_W-1:0]; //DMA_FSIZE_REG[14:0] == DMA Frame size + set_clear[i] <= 1; + end + end else begin + set_clear[i] <= 0; //set_clear should be "self-clearing" + end + end + + //Packet counter + always @(posedge clk) begin + if (reset | (regi_tvalid && regi_wr && (regi_addr == `GET_REG_OFFSET(DMA_PKT_CNT_REG, i)))) begin + pkt_count_mem[i] <= 0; + end else if (packet_stb[i]) begin + pkt_count_mem[i] <= pkt_count_mem[i] + 1; + end + end + + //Sample counter + always @(posedge clk) begin + if (reset | (regi_tvalid && regi_wr && (regi_addr == `GET_REG_OFFSET(DMA_SAMP_CNT_REG, i)))) begin + samp_count_mem[i] <= 0; + end else if (sample_stb[i]) begin + samp_count_mem[i] <= samp_count_mem[i] + 1; + end + end + end + endgenerate + + //Readback + assign rego_payload = + (regi_addr[DMA_REG_GRP_W-1:0] == DMA_PKT_CNT_REG) ? pkt_count_mem[`EXTRACT_CHAN_NUM(regi_addr)] : ( + (regi_addr[DMA_REG_GRP_W-1:0] == DMA_SAMP_CNT_REG) ? samp_count_mem[`EXTRACT_CHAN_NUM(regi_addr)] : ( + (regi_addr[DMA_REG_GRP_W-1:0] == DMA_FSIZE_REG) ? frame_size_mem[`EXTRACT_CHAN_NUM(regi_addr)] : ( + (regi_addr[DMA_REG_GRP_W-1:0] == DMA_CTRL_STATUS_REG) ? {31'h0, stream_err[`EXTRACT_CHAN_NUM(regi_addr)]} : ( + 32'hFFFFFFFF)))); + + assign rego_tvalid = regi_tvalid && regi_rd; + assign regi_tready = rego_tready || (regi_tvalid && regi_wr); + + //Optional router + if (ENABLE_ROUTER == 1) begin + pcie_pkt_route_specifier #( + .BASE_ADDR((1<<ROUTER_SID_W) + REG_BASE_ADDR), .ADDR_MASK(20'hFFFFF^((1<<ROUTER_SID_W)-1)), + .SID_WIDTH(ROUTER_SID_W), .DST_WIDTH(ROUTER_DST_W) + ) route_specifier ( + .clk(clk), .reset(reset), + .regi_tdata(regi_tdata), .regi_tvalid(regi_tvalid), .regi_tready(), + .local_sid(rtr_sid), .fifo_dst(rtr_dst) + ); + end + +endmodule + +`undef EXTRACT_CHAN_NUM +`undef GET_REG_OFFSET +`undef BIT_WIDTH |