/* * top.v * * vim: ts=4 sw=4 * * Copyright (C) 2020-2021 Sylvain Munaut * SPDX-License-Identifier: CERN-OHL-P-2.0 */ `default_nettype none `include "boards.vh" 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 `ifdef HAS_UART // UART input wire uart_rx, output wire uart_tx, `endif `ifdef HAS_USB // USB inout wire usb_dp, inout wire usb_dn, output wire usb_pu, `endif // Clock (12M) input wire clk_in ); // Target UART baudrate localparam integer BAUDRATE = 2000000; // 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; wire clk_usb; wire rst_usb; wire bootloader; // Host interface // -------------- `ifdef HAS_UART uart2wb #( .UART_DIV($rtoi((`SYS_FREQ / BAUDRATE) + 0.5)), `elsif HAS_USB muacm2wb #( `endif .WB_N(3) ) if_I ( `ifdef HAS_UART .uart_rx (uart_rx), .uart_tx (uart_tx), `elsif HAS_USB .usb_dp (usb_dp), .usb_dn (usb_dn), .usb_pu (usb_pu), .usb_clk (clk_usb), .usb_rst (rst_usb), .bootloader (bootloader), `endif .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]; `ifdef HAS_USB SB_WARMBOOT warmboot ( .BOOT (bootloader), .S0 (1'b1), .S1 (1'b0) ); `endif // 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), .clk_usb (clk_usb), .rst_usb (rst_usb) ); endmodule