/*
 * top.v
 *
 * vim: ts=4 sw=4
 *
 * Copyright (C) 2019-2020  Sylvain Munaut <tnt@246tNt.com>
 * SPDX-License-Identifier: CERN-OHL-P-2.0
 */

`default_nettype none

module top (
	// SPI
	inout  wire  [3:0] spi_io,
	output wire        spi_clk,
	output wire        spi_cs_n,

	// USB
	inout  wire        usb_dp,
	inout  wire        usb_dn,
	output wire        usb_pu,

	// Power
	input  wire        pwr_usb_n,
	input  wire        pwr_chg_n,
	output wire        pwr_off,

	// Buttons
	input  wire  [1:0] btn,

	// I2C
	inout  wire        scl,
	inout  wire        sda,

	// Speaker
	output wire        hp_p,
	output wire        hp_n,

	// LED matrix
	output wire [13:0] led_a,
	output wire  [2:0] led_c
);

	localparam integer WN = 6;
	genvar i;


	// Signals
	// -------

	// Wishbone
	wire   [15:0] wb_addr;
	wire   [31:0] wb_rdata [0:WN-1];
	wire   [31:0] wb_wdata;
	wire    [3:0] wb_wmsk;
	wire [WN-1:0] wb_cyc;
	wire          wb_we;
	wire [WN-1:0] wb_ack;

	wire [(32*WN)-1:0] wb_rdata_flat;

	// I2C
	wire       i2c_scl_oe;
	wire       i2c_scl_i;
	wire       i2c_sda_oe;
	wire       i2c_sda_i;

	// USB Core
		// Wishbone in 48 MHz domain
	wire [11:0] ub_addr;
	wire [15:0] ub_wdata;
	wire [15:0] ub_rdata;
	wire        ub_cyc;
	wire        ub_we;
	wire        ub_ack;

		// EP Buffer
	wire [ 8:0] ep_tx_addr_0;
	wire [31:0] ep_tx_data_0;
	wire        ep_tx_we_0;

	wire [ 8:0] ep_rx_addr_0;
	wire [31:0] ep_rx_data_1;
	wire        ep_rx_re_0;

	// Clock Control
	wire        wakeup;
	wire        sys_start;
	wire        sys_stop;
	wire        usb_ena;

	// Clock / Reset
	wire        clk_led;
	wire        rst_led;
	wire        clk_sys;
	wire        rst_sys;
	wire        clk_usb;
	wire        rst_usb;


	// SoC
	// ---

	soc_picorv32_base #(
		.WB_N     (WN),
		.WB_DW    (32),
		.WB_AW    (16),
		.BRAM_AW  (8), //  1k BRAM
		.SPRAM_AW (14) // 64k SPRAM
	) base_I (
		.wb_addr  (wb_addr),
		.wb_rdata (wb_rdata_flat),
		.wb_wdata (wb_wdata),
		.wb_wmsk  (wb_wmsk),
		.wb_we    (wb_we),
		.wb_cyc   (wb_cyc),
		.wb_ack   (wb_ack),
		.clk      (clk_sys),
		.rst      (rst_sys)
	);

	for (i=0; i<WN; i=i+1)
		assign wb_rdata_flat[i*32+:32] = wb_rdata[i];


	// PMU [0]
	// ---

	pmu pmu_I (
		.wb_addr   (wb_addr[15:0]),
		.wb_rdata  (wb_rdata[0]),
		.wb_wdata  (wb_wdata),
		.wb_we     (wb_we),
		.wb_cyc    (wb_cyc[0]),
		.wb_ack    (wb_ack[0]),
		.btn       (btn),
		.pwr_usb_n (pwr_usb_n),
		.pwr_chg_n (pwr_chg_n),
		.pwr_off   (pwr_off),
		.sys_start (sys_start),
		.sys_stop  (sys_stop),
		.usb_ena   (usb_ena),
		.wakeup    (wakeup),
		.clk       (clk_sys),
		.rst       (rst_sys)
	);


	// SPI [1]
	// ---

	ice40_spi_wb #(
		.N_CS(1),
		.WITH_IOB(1),
		.UNIT(0)
	) spi_I (
		.pad_mosi (spi_io[0]),
		.pad_miso (spi_io[1]),
		.pad_clk  (spi_clk),
		.pad_csn  (spi_cs_n),
		.wb_addr  (wb_addr[3:0]),
		.wb_rdata (wb_rdata[1]),
		.wb_wdata (wb_wdata),
		.wb_we    (wb_we),
		.wb_cyc   (wb_cyc[1]),
		.wb_ack   (wb_ack[1]),
		.clk      (clk_sys),
		.rst      (rst_sys)
	);

	assign spi_io[3:2] = 4'bzz;


	// I2C [2]
	// ---

	// Controller
	i2c_master_wb #(
		.DW(4),
		.TW(15),
		.CLOCK_STRETCH(1),
		.FIFO_DEPTH(0)
	) i2c_I (
		.scl_oe  (i2c_scl_oe),
		.scl_i   (i2c_scl_i),
		.sda_oe  (i2c_sda_oe),
		.sda_i   (i2c_sda_i),
		.wb_rdata(wb_rdata[2]),
		.wb_wdata(wb_wdata),
		.wb_we   (wb_we),
		.wb_cyc  (wb_cyc[2]),
		.wb_ack  (wb_ack[2]),
		.clk     (clk_sys),
		.rst     (rst_sys)
	);

	// IOBs
	SB_IO #(
		.PIN_TYPE(6'b110100),
		.PULLUP(1'b1),
		.IO_STANDARD("SB_LVCMOS")
	) i2c_iob_I[1:0] (
		.PACKAGE_PIN  ({scl, sda}),
		.INPUT_CLK    (clk_sys),
		.OUTPUT_CLK   (clk_sys),
		.OUTPUT_ENABLE({i2c_scl_oe, i2c_sda_oe}),
		.D_OUT_0      (1'b0),
		.D_IN_0       ({i2c_scl_i, i2c_sda_i})
	);


	// USB Buffer [3]
	// ----------

	soc_usb_buf_bridge usb_buf_I (
		.wb_addr      (wb_addr),
		.wb_rdata     (wb_rdata[3]),
		.wb_wdata     (wb_wdata),
		.wb_wmsk      (wb_wmsk),
		.wb_we        (wb_we),
		.wb_cyc       (wb_cyc[3]),
		.wb_ack       (wb_ack[3]),
		.ep_tx_addr_0 (ep_tx_addr_0),
		.ep_tx_data_0 (ep_tx_data_0),
		.ep_tx_we_0   (ep_tx_we_0),
		.ep_rx_addr_0 (ep_rx_addr_0),
		.ep_rx_data_1 (ep_rx_data_1),
		.ep_rx_re_0   (ep_rx_re_0),
		.clk          (clk_sys),
		.rst          (rst_sys)
	);


	// USB core [4]
	// --------

	// Cross-clock
	xclk_wb #(
		.DW(16),
		.AW(12)
	)  wb_48m_xclk_I (
		.s_addr  (wb_addr[11:0]),
		.s_wdata (wb_wdata[15:0]),
		.s_rdata (wb_rdata[4][15:0]),
		.s_cyc   (wb_cyc[4]),
		.s_ack   (wb_ack[4]),
		.s_we    (wb_we),
		.s_clk   (clk_sys),
		.m_addr  (ub_addr),
		.m_wdata (ub_wdata),
		.m_rdata (ub_rdata),
		.m_cyc   (ub_cyc),
		.m_ack   (ub_ack),
		.m_we    (ub_we),
		.m_clk   (clk_usb),
		.rst     (rst_usb)
	);

	assign wb_rdata[4][31:16] = 0;

	// Core
	usb #(
		.EPDW(32)
	) usb_I (
		.pad_dp       (usb_dp),
		.pad_dn       (usb_dn),
		.pad_pu       (usb_pu),
		.ep_tx_addr_0 (ep_tx_addr_0),
		.ep_tx_data_0 (ep_tx_data_0),
		.ep_tx_we_0   (ep_tx_we_0),
		.ep_rx_addr_0 (ep_rx_addr_0),
		.ep_rx_data_1 (ep_rx_data_1),
		.ep_rx_re_0   (ep_rx_re_0),
		.ep_clk       (clk_sys),
		.wb_addr      (ub_addr),
		.wb_rdata     (ub_rdata),
		.wb_wdata     (ub_wdata),
		.wb_we        (ub_we),
		.wb_cyc       (ub_cyc),
		.wb_ack       (ub_ack),
		.clk          (clk_usb),
		.rst          (rst_usb)
	);


	// LED matrix controller [5]
	// ---------------------

	led_ctrl led_I (
		.led_a    (led_a),
		.led_c    (led_c),
		.led_clk  (clk_led),
		.led_rst  (rst_led),
		.trig_out (wakeup),
		.wb_addr  (wb_addr[15:0]),
		.wb_rdata (wb_rdata[5]),
		.wb_wdata (wb_wdata),
		.wb_we    (wb_we),
		.wb_cyc   (wb_cyc[5]),
		.wb_ack   (wb_ack[5]),
		.wb_clk   (clk_sys),
		.wb_rst   (rst_sys)
	);


	// CRG
	// ---

`ifdef SIM
	sysmgr_sim crg_I (
`else
	sysmgr crg_I (
`endif
		.sys_start (sys_start),
		.sys_stop  (sys_stop),
		.usb_ena   (usb_ena),
		.clk_led   (clk_led),
		.rst_led   (rst_led),
		.clk_sys   (clk_sys),
		.rst_sys   (rst_sys),
		.clk_usb   (clk_usb),
		.rst_usb   (rst_usb)
	);


	// Unused
	// ------

	assign hp_p = 1'bz;
	assign hp_n = 1'bz;

endmodule // top
