`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Copyright Ettus Research LLC // The ZYNQ FIFO Top: // - takes read and write 32-bit addressable AXI slave // - takes read and write 64-bit addressable AXI master // - drives N input and output AXI stream FIFOs ////////////////////////////////////////////////////////////////////////////////// // Mapping: // Page0 - stream to host config // Page1 - host to stream config module zynq_fifo_top #( parameter CONFIG_BASE = 32'h40000000, parameter PAGE_WIDTH = 16, //in bytes, must fit widths below parameter H2S_STREAMS_WIDTH = 2, parameter H2S_CMDFIFO_DEPTH = 4, parameter S2H_STREAMS_WIDTH = 2, parameter S2H_CMDFIFO_DEPTH = 4, parameter PROT = 3'b010 //data, non-secure, unpriv ) ( input clk, input rst, //------------------------------------------------------------------ // AXI slave addressable signals - control //------------------------------------------------------------------ //control write signals - slave input [31:0] CTL_AXI_AWADDR, input CTL_AXI_AWVALID, output CTL_AXI_AWREADY, input [31:0] CTL_AXI_WDATA, input [3:0] CTL_AXI_WSTRB, input CTL_AXI_WVALID, output CTL_AXI_WREADY, output [1:0] CTL_AXI_BRESP, output CTL_AXI_BVALID, input CTL_AXI_BREADY, //control read signals - slave input [31:0] CTL_AXI_ARADDR, input CTL_AXI_ARVALID, output CTL_AXI_ARREADY, output [31:0] CTL_AXI_RDATA, output [1:0] CTL_AXI_RRESP, output CTL_AXI_RVALID, input CTL_AXI_RREADY, //------------------------------------------------------------------ // AXI master addressable signals - DDR access //------------------------------------------------------------------ //memory write signals - master output [31:0] DDR_AXI_AWADDR, output [2:0] DDR_AXI_AWPROT, output DDR_AXI_AWVALID, input DDR_AXI_AWREADY, output [63:0] DDR_AXI_WDATA, output [7:0] DDR_AXI_WSTRB, output DDR_AXI_WVALID, input DDR_AXI_WREADY, input [1:0] DDR_AXI_BRESP, input DDR_AXI_BVALID, output DDR_AXI_BREADY, output [7:0] DDR_AXI_AWLEN, output [2:0] DDR_AXI_AWSIZE, output [1:0] DDR_AXI_AWBURST, output [3:0] DDR_AXI_AWCACHE, output DDR_AXI_WLAST, //memory read signals - master output [31:0] DDR_AXI_ARADDR, output [2:0] DDR_AXI_ARPROT, output DDR_AXI_ARVALID, input DDR_AXI_ARREADY, input [63:0] DDR_AXI_RDATA, input [1:0] DDR_AXI_RRESP, input DDR_AXI_RVALID, output DDR_AXI_RREADY, input DDR_AXI_RLAST, output [3:0] DDR_AXI_ARCACHE, output [7:0] DDR_AXI_ARLEN, output [1:0] DDR_AXI_ARBURST, output [2:0] DDR_AXI_ARSIZE, //------------------------------------------------------------------ // AXI streams host to stream //------------------------------------------------------------------ output [63:0] h2s_tdata, output h2s_tlast, output h2s_tvalid, input h2s_tready, //------------------------------------------------------------------ // AXI streams stream to host //------------------------------------------------------------------ input [63:0] s2h_tdata, input s2h_tlast, input s2h_tvalid, output s2h_tready, output event_irq, output [31:0] debug ); //////////////////////////////////////////////////////////////////////// ///////////////////////////// Begin R T L ////////////////////////////// //////////////////////////////////////////////////////////////////////// //interrupt wires wire h2s_irq, s2h_irq; assign event_irq = h2s_irq | s2h_irq; wire [31:0] set_addr, set_data; wire [31:0] rb_addr, rb_data; wire [31:0] rb_data_s2h, rb_data_h2s; wire set_stb, set_stb_s2h, set_stb_h2s; wire rb_stb, rb_stb_s2h, rb_stb_h2s; wire [1:0] set_page = set_addr[PAGE_WIDTH+1:PAGE_WIDTH]; wire [1:0] rb_page = rb_addr[PAGE_WIDTH+1:PAGE_WIDTH]; //each arbiter gets 1 page assign set_stb_s2h = set_stb && (set_page == 2'h0); assign set_stb_h2s = set_stb && (set_page == 2'h1); assign rb_stb_s2h = rb_stb && (rb_page == 2'h0); assign rb_stb_h2s = rb_stb && (rb_page == 2'h1); assign rb_data = (rb_page == 2'h0)? rb_data_s2h : rb_data_h2s; //------------------------------------------------------------------ // configuration slaves //------------------------------------------------------------------ zf_slave_settings #(.CONFIG_BASE(CONFIG_BASE)) zf_slave_settings ( .clk(clk), .rst(rst), .AXI_AWADDR(CTL_AXI_AWADDR), .AXI_AWVALID(CTL_AXI_AWVALID), .AXI_AWREADY(CTL_AXI_AWREADY), .AXI_WDATA(CTL_AXI_WDATA), .AXI_WSTRB(CTL_AXI_WSTRB), .AXI_WVALID(CTL_AXI_WVALID), .AXI_WREADY(CTL_AXI_WREADY), .AXI_BRESP(CTL_AXI_BRESP), .AXI_BVALID(CTL_AXI_BVALID), .AXI_BREADY(CTL_AXI_BREADY), .addr(set_addr), .data(set_data), .strobe(set_stb), .debug() ); zf_slave_readback #(.CONFIG_BASE(CONFIG_BASE)) zf_slave_readback ( .clk(clk), .rst(rst), .AXI_ARADDR(CTL_AXI_ARADDR), .AXI_ARVALID(CTL_AXI_ARVALID), .AXI_ARREADY(CTL_AXI_ARREADY), .AXI_RDATA(CTL_AXI_RDATA), .AXI_RRESP(CTL_AXI_RRESP), .AXI_RVALID(CTL_AXI_RVALID), .AXI_RREADY(CTL_AXI_RREADY), .addr(rb_addr), .data(rb_data), .strobe(rb_stb), .debug() ); //------------------------------------------------------------------ // fifo to ddr //------------------------------------------------------------------ wire [71:0] s2h_cmd_tdata; wire [7:0] s2h_sts_tdata; wire s2h_cmd_tvalid, s2h_cmd_tready; wire s2h_sts_tvalid, s2h_sts_tready; assign s2h_irq = s2h_sts_tvalid; //lookup destination wire [63:0] s2h_tdata_i0; wire s2h_tready_i0, s2h_tvalid_i0, s2h_tlast_i0; wire [S2H_STREAMS_WIDTH-1:0] which_stream_s2h; cvita_dest_lookup #(.DEST_WIDTH(S2H_STREAMS_WIDTH)) s2h_dest_gen ( .clk(clk), .rst(rst), .set_stb(set_stb && (set_page == 2'h2)), .set_addr(set_addr[9:2]), .set_data(set_data), .i_tdata(s2h_tdata), .i_tlast(s2h_tlast), .i_tvalid(s2h_tvalid), .i_tready(s2h_tready), .o_tdata(s2h_tdata_i0), .o_tlast(s2h_tlast_i0), .o_tvalid(s2h_tvalid_i0), .o_tready(s2h_tready_i0), .o_tdest(which_stream_s2h) ); //only active in cycles between command and tlast //this prevents bullshit consumption after tlast reg s2h_active; always @(posedge clk) begin if (rst) s2h_active <= 0; else if (s2h_cmd_tvalid && s2h_cmd_tready) s2h_active <= 1; else if (s2h_tready_i0 && s2h_tvalid_i0 && s2h_tlast_i0) s2h_active <= 0; end //cut fifo comms when not in active state wire [63:0] s2h_tdata_i1; wire s2h_tready_i1, s2h_tvalid_i1, s2h_tlast_i1; assign s2h_tdata_i1 = s2h_tdata_i0; assign s2h_tlast_i1 = s2h_tlast_i0; assign s2h_tvalid_i1 = s2h_tvalid_i0 && s2h_active; assign s2h_tready_i0 = s2h_tready_i1 && s2h_active; wire [31:0] s2h_arbiter_debug; zf_arbiter #( .STREAMS_WIDTH(H2S_STREAMS_WIDTH), .CMDFIFO_DEPTH(H2S_CMDFIFO_DEPTH), .PAGE_WIDTH(PAGE_WIDTH) ) s2h_arbiter ( .clk(clk), .rst(rst), .set_addr(set_addr), .set_data(set_data), .set_stb(set_stb_s2h), .rb_addr(rb_addr), .rb_data(rb_data_s2h), .rb_stb(rb_stb_s2h), .cmd_tdata(s2h_cmd_tdata), .cmd_tvalid(s2h_cmd_tvalid), .cmd_tready(s2h_cmd_tready), .sts_tdata(s2h_sts_tdata), .sts_tvalid(s2h_sts_tvalid), .sts_tready(s2h_sts_tready), .ext_stream(which_stream_s2h), .stream_valid(s2h_tvalid_i0), .debug(s2h_arbiter_debug) ); //------------------------------------------------------------------ // ddr to fifo //------------------------------------------------------------------ wire [71:0] h2s_cmd_tdata; wire [7:0] h2s_sts_tdata; wire h2s_cmd_tvalid, h2s_cmd_tready; wire h2s_sts_tvalid, h2s_sts_tready; assign h2s_irq = h2s_sts_tvalid; //simple round robin implementation for checking available packets reg [H2S_STREAMS_WIDTH-1:0] which_stream_h2s; always @(posedge clk) if (rst) which_stream_h2s <= 0; else which_stream_h2s <= which_stream_h2s + 1'b1; wire [31:0] h2s_arbiter_debug; zf_arbiter #( .STREAMS_WIDTH(S2H_STREAMS_WIDTH), .CMDFIFO_DEPTH(S2H_CMDFIFO_DEPTH), .PAGE_WIDTH(PAGE_WIDTH) ) h2s_arbiter ( .clk(clk), .rst(rst), .set_addr(set_addr), .set_data(set_data), .set_stb(set_stb_h2s), .rb_addr(rb_addr), .rb_data(rb_data_h2s), .rb_stb(rb_stb_h2s), .cmd_tdata(h2s_cmd_tdata), .cmd_tvalid(h2s_cmd_tvalid), .cmd_tready(h2s_cmd_tready), .sts_tdata(h2s_sts_tdata), .sts_tvalid(h2s_sts_tvalid), .sts_tready(h2s_sts_tready), .ext_stream(which_stream_h2s), .stream_valid(1'b1), .debug(h2s_arbiter_debug) ); //------------------------------------------------------------------ // axi_datamover //------------------------------------------------------------------ wire reset_dm = rst; axi_datamover_v3_00_a axi_datamover ( //host to stream reset stuff .m_axi_mm2s_aclk(clk), .m_axi_mm2s_aresetn(!reset_dm), .mm2s_halt(1'b0), .mm2s_halt_cmplt(), .mm2s_err(), //host to stream command .m_axis_mm2s_cmdsts_aclk(clk), .m_axis_mm2s_cmdsts_aresetn(!reset_dm), .s_axis_mm2s_cmd_tvalid(h2s_cmd_tvalid), .s_axis_mm2s_cmd_tready(h2s_cmd_tready), .s_axis_mm2s_cmd_tdata(h2s_cmd_tdata), //host to stream status .m_axis_mm2s_sts_tvalid(h2s_sts_tvalid), .m_axis_mm2s_sts_tready(h2s_sts_tready), .m_axis_mm2s_sts_tdata(h2s_sts_tdata), .m_axis_mm2s_sts_tkeep(), .m_axis_mm2s_sts_tlast(), //store and forward - always can post .mm2s_allow_addr_req(1'b1), .mm2s_addr_req_posted(), .mm2s_rd_xfer_cmplt(), //HP RD connection to DDR .m_axi_mm2s_arid(), .m_axi_mm2s_araddr(DDR_AXI_ARADDR), .m_axi_mm2s_arlen(DDR_AXI_ARLEN), .m_axi_mm2s_arsize(DDR_AXI_ARSIZE), .m_axi_mm2s_arburst(DDR_AXI_ARBURST), .m_axi_mm2s_arprot(DDR_AXI_ARPROT), .m_axi_mm2s_arcache(DDR_AXI_ARCACHE), .m_axi_mm2s_arvalid(DDR_AXI_ARVALID), .m_axi_mm2s_arready(DDR_AXI_ARREADY), .m_axi_mm2s_rdata(DDR_AXI_RDATA), .m_axi_mm2s_rresp(DDR_AXI_RRESP), .m_axi_mm2s_rlast(DDR_AXI_RLAST), .m_axi_mm2s_rvalid(DDR_AXI_RVALID), .m_axi_mm2s_rready(DDR_AXI_RREADY), //AXI host to stream connection .m_axis_mm2s_tdata({h2s_tdata[31:0], h2s_tdata[63:32]}), .m_axis_mm2s_tkeep(), //dont care .m_axis_mm2s_tlast(h2s_tlast), .m_axis_mm2s_tvalid(h2s_tvalid), .m_axis_mm2s_tready(h2s_tready), //unused debug .mm2s_dbg_sel(4'b0), .mm2s_dbg_data(), //stream to host reset stuff .m_axi_s2mm_aclk(clk), .m_axi_s2mm_aresetn(!reset_dm), .s2mm_halt(1'b0), .s2mm_halt_cmplt(), .s2mm_err(), //stream to host command .m_axis_s2mm_cmdsts_awclk(clk), .m_axis_s2mm_cmdsts_aresetn(!reset_dm), .s_axis_s2mm_cmd_tvalid(s2h_cmd_tvalid), .s_axis_s2mm_cmd_tready(s2h_cmd_tready), .s_axis_s2mm_cmd_tdata(s2h_cmd_tdata), //stream to host status .m_axis_s2mm_sts_tvalid(s2h_sts_tvalid), .m_axis_s2mm_sts_tready(s2h_sts_tready), .m_axis_s2mm_sts_tdata(s2h_sts_tdata), .m_axis_s2mm_sts_tkeep(), .m_axis_s2mm_sts_tlast(), //store and forward - always can post .s2mm_allow_addr_req(1'b1), .s2mm_addr_req_posted(), .s2mm_wr_xfer_cmplt(), .s2mm_ld_nxt_len(), .s2mm_wr_len(), //HP WR connection to DDR .m_axi_s2mm_awid(), .m_axi_s2mm_awaddr(DDR_AXI_AWADDR), .m_axi_s2mm_awlen(DDR_AXI_AWLEN), .m_axi_s2mm_awsize(DDR_AXI_AWSIZE), .m_axi_s2mm_awburst(DDR_AXI_AWBURST), .m_axi_s2mm_awprot(DDR_AXI_AWPROT), .m_axi_s2mm_awcache(DDR_AXI_AWCACHE), .m_axi_s2mm_awvalid(DDR_AXI_AWVALID), .m_axi_s2mm_awready(DDR_AXI_AWREADY), .m_axi_s2mm_wdata(DDR_AXI_WDATA), .m_axi_s2mm_wstrb(DDR_AXI_WSTRB), .m_axi_s2mm_wlast(DDR_AXI_WLAST), .m_axi_s2mm_wvalid(DDR_AXI_WVALID), .m_axi_s2mm_wready(DDR_AXI_WREADY), .m_axi_s2mm_bresp(DDR_AXI_BRESP), .m_axi_s2mm_bvalid(DDR_AXI_BVALID), .m_axi_s2mm_bready(DDR_AXI_BREADY), //AXI stream to host connection .s_axis_s2mm_tdata({s2h_tdata_i1[31:0], s2h_tdata_i1[63:32]}), .s_axis_s2mm_tkeep(8'hff), //all bytes valid .s_axis_s2mm_tlast(s2h_tlast_i1), .s_axis_s2mm_tvalid(s2h_tvalid_i1), .s_axis_s2mm_tready(s2h_tready_i1), //unused debug .s2mm_dbg_sel(4'b0), .s2mm_dbg_data() ); //------------------------------------------------------------------ // chipscope debugs //------------------------------------------------------------------ wire [35:0] CONTROL; wire [255:0] DATA; wire [7:0] TRIG; chipscope_icon chipscope_icon(.CONTROL0(CONTROL)); chipscope_ila chipscope_ila ( .CONTROL(CONTROL), .CLK(clk), .DATA(DATA), .TRIG0(TRIG) ); assign DATA[255:256-64] = {set_addr, set_data}; assign DATA[79:76] = which_stream_s2h; assign DATA[75:72] = {1'b0, s2h_tlast, s2h_tvalid, s2h_tready}; assign DATA[71:68] = {1'b0, s2h_tlast_i0, s2h_tvalid_i0, s2h_tready_i0}; assign DATA[67:64] = {1'b0, s2h_tlast_i1, s2h_tvalid_i1, s2h_tready_i1}; assign DATA[63:0] = s2h_tdata_i1; assign TRIG = { set_stb, s2h_tlast_i0, s2h_tvalid_i0, s2h_tready_i0, (set_stb && (set_page == 2'h2)), s2h_tlast_i1, s2h_tvalid_i1, s2h_tready_i1 }; endmodule //zynq_fifo_top