/* * top.v * * vim: ts=4 sw=4 * * Copyright (C) 2020 Sylvain Munaut * All rights reserved. * * BSD 3-clause, see LICENSE.bsd * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ `default_nettype none module top ( // SPI `ifdef MEM_spi inout wire [3:0] spi_io, output wire spi_sck, output wire [1:0] spi_cs_n, `endif // HyperRAM `ifdef MEM_hyperram inout wire [7:0] hram_dq, inout wire hram_rwds, output wire hram_ck, output wire [3:0] hram_cs_n, output wire hram_rst_n, `endif // HDMI pads `ifdef VIDEO_4bpp output wire [ 3:0] hdmi_data, `endif `ifdef VIDEO_12bpp output wire [11:0] hdmi_data, `endif `ifndef VIDEO_none output wire hdmi_hsync, output wire hdmi_vsync, output wire hdmi_de, output wire hdmi_clk, `endif // UART input wire uart_rx, output wire uart_tx, // Clock (12M) input wire clk_in ); // Signals // ------- // Control wire [31:0] aux_csr; wire dma_run; // Wishbone interface reg [31:0] wb_wdata; wire [95:0] wb_rdata; reg [15:0] wb_addr; reg wb_we; reg [ 2:0] wb_cyc; wire [ 2:0] wb_ack; // Memory interface wire [31:0] mi_addr; wire [ 6:0] mi_len; wire mi_rw; wire mi_valid; wire mi_ready; wire [31:0] mi_wdata; wire mi_wack; wire mi_wlast; wire [31:0] mi_rdata; wire mi_rstb; wire mi_rlast; // Memory interface - Memory Tester wire [31:0] mi0_addr; wire [ 6:0] mi0_len; wire mi0_rw; wire mi0_valid; wire mi0_ready; wire [31:0] mi0_wdata; wire mi0_wack; wire mi0_wlast; wire [31:0] mi0_rdata; wire mi0_rstb; wire mi0_rlast; // Memory interface - Video DMA wire [31:0] mi1_addr; wire [ 6:0] mi1_len; wire mi1_rw; wire mi1_valid; wire mi1_ready; wire [31:0] mi1_wdata; wire mi1_wack; wire mi1_wlast; wire [31:0] mi1_rdata; wire mi1_rstb; wire mi1_rlast; // Clock / Reset wire [3:0] clk_rd_delay; wire clk_1x; wire clk_2x; wire clk_4x; wire clk_rd; wire sync_4x; wire sync_rd; wire rst; // Host interface // -------------- uart2wb #( .WB_N(3) ) if_I ( .uart_rx(uart_rx), .uart_tx(uart_tx), .uart_div(8'd16), .wb_wdata(wb_wdata), .wb_rdata(wb_rdata), .wb_addr(wb_addr), .wb_we(wb_we), .wb_cyc(wb_cyc), .wb_ack(wb_ack), .aux_csr(aux_csr), .clk(clk_1x), .rst(rst) ); assign dma_run = aux_csr[0]; // QSPI Controller // --------------- `ifdef MEM_spi // Config localparam integer PHY_SPEED = 4; localparam integer PL = (4 * PHY_SPEED) - 1; localparam integer CL = PHY_SPEED - 1; // Signals wire [PL:0] phy_io_i; wire [PL:0] phy_io_o; wire [ 3:0] phy_io_oe; wire [CL:0] phy_clk_o; wire [ 1:0] phy_cs_o; // Controller qpi_memctrl #( .CMD_READ(16'hEBEB), .CMD_WRITE(16'h0202), .DUMMY_CLK(6), .PAUSE_CLK(8), .FIFO_DEPTH(1), .N_CS(2), .PHY_SPEED(PHY_SPEED), .PHY_WIDTH(1), .PHY_DELAY((PHY_SPEED == 1) ? 2 : ((PHY_SPEED == 2) ? 3 : 4)) ) memctrl_I ( .phy_io_i(phy_io_i), .phy_io_o(phy_io_o), .phy_io_oe(phy_io_oe), .phy_clk_o(phy_clk_o), .phy_cs_o(phy_cs_o), .mi_addr_cs(mi_addr[31:30]), .mi_addr({mi_addr[21:0], 2'b00 }), /* 32 bits aligned */ .mi_len(mi_len), .mi_rw(mi_rw), .mi_valid(mi_valid), .mi_ready(mi_ready), .mi_wdata(mi_wdata), .mi_wack(mi_wack), .mi_wlast(mi_wlast), .mi_rdata(mi_rdata), .mi_rstb(mi_rstb), .mi_rlast(mi_rlast), .wb_wdata(wb_wdata), .wb_rdata(wb_rdata[31:0]), .wb_addr(wb_addr[4:0]), .wb_we(wb_we), .wb_cyc(wb_cyc[0]), .wb_ack(wb_ack[0]), .clk(clk_1x), .rst(rst) ); // PHY generate if (PHY_SPEED == 1) qpi_phy_ice40_1x #( .N_CS(2), .WITH_CLK(1), .NEG_IN(0) ) phy_I ( .pad_io(spi_io), .pad_clk(spi_sck), .pad_cs_n(spi_cs_n), .phy_io_i(phy_io_i), .phy_io_o(phy_io_o), .phy_io_oe(phy_io_oe), .phy_clk_o(phy_clk_o), .phy_cs_o(phy_cs_o), .clk(clk_1x) ); else if (PHY_SPEED == 2) qpi_phy_ice40_2x #( .N_CS(2), .WITH_CLK(1), ) phy_I ( .pad_io(spi_io), .pad_clk(spi_sck), .pad_cs_n(spi_cs_n), .phy_io_i(phy_io_i), .phy_io_o(phy_io_o), .phy_io_oe(phy_io_oe), .phy_clk_o(phy_clk_o), .phy_cs_o(phy_cs_o), .clk_1x(clk_1x), .clk_2x(clk_2x) ); else if (PHY_SPEED == 4) qpi_phy_ice40_4x #( .N_CS(2), .WITH_CLK(1), ) phy_I ( .pad_io(spi_io), .pad_clk(spi_sck), .pad_cs_n(spi_cs_n), .phy_io_i(phy_io_i), .phy_io_o(phy_io_o), .phy_io_oe(phy_io_oe), .phy_clk_o(phy_clk_o), .phy_cs_o(phy_cs_o), .clk_1x(clk_1x), .clk_4x(clk_4x), .clk_sync(sync_4x) ); endgenerate assign clk_rd_delay = 4'h0; `endif // HyperRAM Controller // ------------------- `ifdef MEM_hyperram // Signals wire [ 1:0] phy_ck_en; wire [ 3:0] phy_rwds_in; wire [ 3:0] phy_rwds_out; wire [ 1:0] phy_rwds_oe; wire [31:0] phy_dq_in; wire [31:0] phy_dq_out; wire [ 1:0] phy_dq_oe; wire [ 3:0] phy_cs_n; wire phy_rst_n; wire [ 7:0] phy_cfg_wdata; wire [ 7:0] phy_cfg_rdata; wire phy_cfg_stb; // Controller hbus_memctrl hram_ctrl_I ( .phy_ck_en(phy_ck_en), .phy_rwds_in(phy_rwds_in), .phy_rwds_out(phy_rwds_out), .phy_rwds_oe(phy_rwds_oe), .phy_dq_in(phy_dq_in), .phy_dq_out(phy_dq_out), .phy_dq_oe(phy_dq_oe), .phy_cs_n(phy_cs_n), .phy_rst_n(phy_rst_n), .phy_cfg_wdata(phy_cfg_wdata), .phy_cfg_rdata(phy_cfg_rdata), .phy_cfg_stb(phy_cfg_stb), .mi_addr_cs(mi_addr[31:30]), .mi_addr({1'b0, mi_addr[29:0], 1'b0}), /* 32b aligned */ .mi_len(mi_len), .mi_rw(mi_rw), .mi_linear(1'b0), .mi_valid(mi_valid), .mi_ready(mi_ready), .mi_wdata(mi_wdata), .mi_wmsk(4'h0), .mi_wack(mi_wack), .mi_rdata(mi_rdata), .mi_rstb(mi_rstb), .wb_wdata(wb_wdata), .wb_rdata(wb_rdata[31:0]), .wb_addr(wb_addr[3:0]), .wb_we(wb_we), .wb_cyc(wb_cyc[0]), .wb_ack(wb_ack[0]), .clk(clk_1x), .rst(rst) ); // PHY hbus_phy_ice40 hram_phy_I ( .hbus_dq(hram_dq), .hbus_rwds(hram_rwds), .hbus_ck(hram_ck), .hbus_cs_n(hram_cs_n), .hbus_rst_n(hram_rst_n), .phy_ck_en(phy_ck_en), .phy_rwds_in(phy_rwds_in), .phy_rwds_out(phy_rwds_out), .phy_rwds_oe(phy_rwds_oe), .phy_dq_in(phy_dq_in), .phy_dq_out(phy_dq_out), .phy_dq_oe(phy_dq_oe), .phy_cs_n(phy_cs_n), .phy_rst_n(phy_rst_n), .phy_cfg_wdata(phy_cfg_wdata), .phy_cfg_rdata(phy_cfg_rdata), .phy_cfg_stb(phy_cfg_stb), .clk_rd_delay(clk_rd_delay), .clk_1x(clk_1x), .clk_4x(clk_4x), .clk_rd(clk_rd), .sync_4x(sync_4x), .sync_rd(sync_rd) ); `endif // Memory tester // ------------- memtest #( .ADDR_WIDTH(32) ) memtest_I ( .mi_addr(mi0_addr), .mi_len(mi0_len), .mi_rw(mi0_rw), .mi_valid(mi0_valid), .mi_ready(mi0_ready), .mi_wdata(mi0_wdata), .mi_wack(mi0_wack), .mi_rdata(mi0_rdata), .mi_rstb(mi0_rstb), .wb_wdata(wb_wdata), .wb_rdata(wb_rdata[63:32]), .wb_addr(wb_addr[8:0]), .wb_we(wb_we), .wb_cyc(wb_cyc[1]), .wb_ack(wb_ack[1]), .clk(clk_1x), .rst(rst) ); // Memory Mux // ---------- assign mi_addr = dma_run ? mi1_addr : mi0_addr; assign mi_len = dma_run ? mi1_len : mi0_len; assign mi_rw = dma_run ? mi1_rw : mi0_rw; assign mi_valid = dma_run ? mi1_valid : mi0_valid; assign mi0_ready = mi_ready & ~dma_run; assign mi1_ready = mi_ready & dma_run; assign mi_wdata = dma_run ? mi1_wdata : mi0_wdata; assign mi0_wack = mi_wack & ~dma_run; assign mi0_wlast = mi_wlast; assign mi1_wack = mi_wack & dma_run; assign mi1_wlast = mi_wlast; assign mi0_rdata = mi_rdata; assign mi0_rstb = mi_rstb & ~dma_run; assign mi0_rlast = mi_rlast; assign mi1_rdata = mi_rdata; assign mi1_rstb = mi_rstb & dma_run; assign mi1_rlast = mi_rlast; // HDMI output // ----------- `ifndef VIDEO_none hdmi_out #( `ifdef VIDEO_4bpp .DW(4) `endif `ifdef VIDEO_12bpp .DW(12) `endif ) hdmi_I ( .hdmi_data(hdmi_data), .hdmi_hsync(hdmi_hsync), .hdmi_vsync(hdmi_vsync), .hdmi_de(hdmi_de), .hdmi_clk(hdmi_clk), .wb_wdata(wb_wdata), .wb_rdata(wb_rdata[95:64]), .wb_addr(wb_addr[6:0]), .wb_we(wb_we), .wb_cyc(wb_cyc[2]), .wb_ack(wb_ack[2]), .mi_addr(mi1_addr), .mi_len(mi1_len), .mi_rw(mi1_rw), .mi_valid(mi1_valid), .mi_ready(mi1_ready), .mi_wdata(mi1_wdata), .mi_wack(mi1_wack), .mi_rdata(mi1_rdata), .mi_rstb(mi1_rstb), .clk_1x(clk_1x), .clk_4x(clk_4x), .sync_4x(sync_4x), .rst(rst) ); `else // Dummy wishbone assign wb_ack[2] = wb_cyc[2]; assign wb_rdata[95:64] = 32'h00000000; // Dummy mem-if assign mi1_addr = 32'hxxxxxxxx; assign mi1_len = 7'hxx; assign mi1_rw = 1'bx; assign mi1_valid = 1'b0; assign mi1_wdata = 32'hxxxxxxxx; `endif // Clock / Reset // ------------- sysmgr sysmgr_I ( .delay(clk_rd_delay), .clk_in(clk_in), .clk_1x(clk_1x), .clk_2x(clk_2x), .clk_4x(clk_4x), .clk_rd(clk_rd), .sync_4x(sync_4x), .sync_rd(sync_rd), .rst(rst) ); endmodule