/* Copyright 2007-2013, Unpublished Work of Technologic Systems
 * All Rights Reserved.
 *
 * THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL,
 * PROPRIETARY AND TRADE SECRET INFORMATION OF TECHNOLOGIC SYSTEMS.
 * ACCESS TO THIS WORK IS RESTRICTED TO (I) TECHNOLOGIC SYSTEMS 
 * EMPLOYEES WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE
 * OF THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN TECHNOLOGIC
 * SYSTEMS WHO HAVE ENTERED INTO APPROPRIATE LICENSE AGREEMENTS.  NO
 * PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED, COPIED, 
 * DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, 
 * EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, TRANSFORMED, ADAPTED
 * IN ANY FORM OR BY ANY MEANS, MANUAL, MECHANICAL, CHEMICAL, 
 * ELECTRICAL, ELECTRONIC, OPTICAL, BIOLOGICAL, OR OTHERWISE WITHOUT
 * THE PRIOR WRITTEN PERMISSION AND CONSENT OF TECHNOLOGIC SYSTEMS.
 * ANY USE OR EXPLOITATION OF THIS WORK WITHOUT THE PRIOR WRITTEN
 * CONSENT OF TECHNOLOGIC SYSTEMS COULD SUBJECT THE PERPETRATOR TO
 * CRIMINAL AND CIVIL LIABILITY.
 */
/* Modules:
 * Syscon -- DIO, LED, etc
 * CAN
 * XUARTs
 * touchscreen controller
 * external bus interface
 * SPI core
 * ADC core
 */
module ts4740_top(

  inout [15:0] smc_d_pad,
  input smc_clk_pad,
  input smc_cs1n_pad,
  input smc_llan_pad,
  input smc_luan_pad,
  input smc_be1n_pad,
  input smc_be2n_pad,
  input smc_wen_pad,
  input smc_rdn_pad,
  output smc_irq_pad,
  inout smc_rdy_pad,

  input fpga_25mhz_pad,
  output en_usb_5v_pad,
  output en_lcd_3v_pad,
  output en_avdd_otgn_pad,
  output sd_powern_pad,
  output reset_d_pad,
  output reset_clk_pad,
  input fpga_resetn_pad,
  input low_voltn_pad,
  output reboot_pad,
  output off_bd_resetn_pad,
  inout fpga_int1_pad,
  inout fpga_int2_pad,

  output flash_csn_pad,
  inout flash_clk_pad,
  inout flash_mosi_pad,
  inout flash_miso_pad,
  inout flash_holdn_pad,
  inout flash_wpn_pad,

  inout [15:0] mux_ad_pad,
  inout bus_alen_pad,
  inout bus_dir_pad,
  inout bus_csn_pad,
  inout bus_bhen_pad,
  inout bus_waitn_pad,

  inout uart0_txd_pad,
  inout uart0_rxd_pad,
  inout uart1_txd_pad,
  inout uart1_rxd_pad,
  inout uart2_txd_pad,
  inout uart2_rxd_pad,
  inout uart3_txd_pad,
  inout uart3_rxd_pad,
  inout uart4_txd_pad,
  inout uart4_rxd_pad,
  inout uart5_txd_pad,
  inout uart5_rxd_pad,

  inout spi_clk_pad,
  inout spi_miso_pad,
  inout spi_mosi_pad,
  inout spi_frm_pad,

  inout [30:0] dio_pad,
  output red_led_pad,
  output green_led_pad,

  inout sd_d0_pad,
  inout sd_d1_pad,
  inout sd_d2_pad,
  inout sd_d3_pad,
  inout sd_cmd_pad,
  output sd_clk_pad,

  output sd_act_ledn_pad,
  output fault_sd_ledn_pad,
  output fault_emmc_ledn_pad,

  inout [7:0] emmc_d_pad,
  output emmc_clk_pad,
  inout emmc_cmd_pad,
  output emmc_sci_clk_pad,
  output emmc_mosi_pad,
  input emmc_miso_pad,
  output emmc_resetn_pad,
  output emmc_pdn_pad,

  inout [23:0] lcd_d_pad,
  inout lcd_clk_pad,
  inout lcd_vsync_pad,
  inout lcd_pwm_pad,
  inout lcd_hsync_pad,
  inout lcd_de_pad
);

parameter xuart_opt = 1'b1;
parameter can_opt = 1'b1;
parameter can2_opt = 1'b0;
parameter touchscreen_opt = 1'b1;
parameter spi_opt = 1'b1;
parameter blockram_opt = 1'b1;
parameter sdcard_opt = 1'b1;
parameter lm32_opt = 1'b1;

// It won't build all the way if outputs are unassigned.
assign fpga_int1_pad = 1'b0;
assign fpga_int2_pad = 1'b0;

assign fault_sd_ledn_pad = 1'b1;
assign fault_emmc_ledn_pad = 1'b1;

/****************************************************************************
 * TS-4700 boilerplate
 ****************************************************************************/

// XXX 62.4MHz domain should arguably have its own synch reset

// XXX need to modify boilerplate
wire pll_100mhz, pll_24mhz, pll_75mhz, lock, wb62_clk;
reg [15:0] rst_counter = 16'd0;
reg rstn = 1'b0;
reg lock_q;
always @(posedge pll_100mhz) begin
  lock_q <= lock && fpga_resetn_pad;
  if (lock_q) rst_counter <= rst_counter + 1'b1;
  else begin
    rst_counter <= 16'd0;
    rstn <= 1'b0;
  end
  if (rst_counter[15]) rstn <= 1'b1;
end
wire wb_rst = !rstn;

pll1 clkgen1(
  .CLK_IN1(fpga_25mhz_pad),
  .CLK_OUT1(pll_100mhz),
  .CLK_OUT2(pll_24mhz),
  .CLK_OUT3(pll_75mhz), // 75MHz is not currently used
  .RESET(!low_voltn_pad),
  .LOCKED(lock)
);

assign en_usb_5v_pad = 1'b1;
assign en_lcd_3v_pad = 1'b1;
assign en_avdd_otgn_pad = 1'b0;
assign reset_clk_pad = 1'b1;
assign reset_d_pad = 1'b1;
assign off_bd_resetn_pad = 1'b1;

reg [6:0] count_1mhz;
reg [31:0] usecs;
always @(posedge pll_100mhz or posedge wb_rst) begin
  if (wb_rst) begin
    count_1mhz <= 7'd0;
    usecs <= 32'd0;
  end else begin
    count_1mhz <= count_1mhz + 1;
    if (count_1mhz == 7'd99) begin
      count_1mhz <= 7'd0;
      usecs <= usecs + 1;
    end
  end
end

reg [2:0] count_12mhz; // actually 12.5 MHz
assign mfp_51_pad = count_12mhz[2];
always @(posedge pll_100mhz or posedge wb_rst) begin
  if (wb_rst) count_12mhz <= 3'd0;
  else count_12mhz <= count_12mhz + 1'b1;
end

/****************************************************************************
 * Wishbone wires
 ****************************************************************************/

/* Note that most buses are 16 bits wide but some are 32.  This happened
 * because we have a mixture of 8, 16, and 32 bit devices.
 */

// Main 100MHz wishbone, controlled by ARM9 and LM32:
// (Used for Syscon, MUXBUS, ADC, SD, SPI, NOR flash, LM32 RAM)
// Most slaves are 16 bit but the bus must be 32 bit.
wire cpuwbm_cyc_o, cpuwbm_stb_o, cpuwbm_we_o;
wire [31:0] cpuwbm32_dat_o;
wire [31:0] cpuwbm32_adr_o;
wire [3:0] cpuwbm32_sel_o;
reg [31:0] cpuwbm_dat_i;
reg cpuwbm_ack_i;
wire upper16 = cpuwbm32_sel_o[2] | cpuwbm32_sel_o[3];
wire [15:0] cpuwbm_dat_o = upper16 ? cpuwbm32_dat_o[31:16] :
                                     cpuwbm32_dat_o[15:0];
wire [31:0] cpuwbm_adr_o = {cpuwbm32_adr_o[31:2], upper16, 1'b0};
wire [1:0] cpuwbm_sel_o = upper16 ? cpuwbm32_sel_o[3:2] :
                                    cpuwbm32_sel_o[1:0];

// Low latency 16 bit wishbone at 62.4MHz, inaccessible to LM32:
// (Used for CAN, XUART, XUART blockram, and touch controller)
wire cpuwbm62_cyc_o, cpuwbm62_stb_o, cpuwbm62_we_o;
wire [15:0] cpuwbm62_dat_o;
wire [31:0] cpuwbm62_adr_o;
wire [14:0] ts4740_decodes = cpuwbm62_adr_o[31:17];
wire [1:0] cpuwbm62_sel_o;
reg [15:0] cpuwbm62_dat_i;
reg cpuwbm62_ack_i;

// 100MHz 16 bit wishbone from synchronous bridge, arbitrates for cpuwbm*
wire cpuwbm100_cyc_o, cpuwbm100_stb_o, cpuwbm100_we_o;
wire [15:0] cpuwbm100_dat_o;
wire [31:0] cpuwbm100_adr_o;
wire [1:0] cpuwbm100_sel_o;
wire [3:0] cpuwbm100_sel32_o = cpuwbm100_adr_o[1] ?
  {cpuwbm100_sel_o, 2'b00} : {2'b00, cpuwbm100_sel_o};
wire [31:0] cpuwbm100_dat32_i;
wire [15:0] cpuwbm100_dat_i = cpuwbm100_adr_o[1] ? 
  cpuwbm100_dat32_i[31:16] : cpuwbm100_dat32_i[15:0];
wire cpuwbm100_ack_i;

// DMA buses from DMA cores to SMC bridge slave interfaces:
wire [15:0] cpuwbs0_dat_i, cpuwbs0_dat_o;
wire cpuwbs0_cyc_i, cpuwbs0_stb_i, cpuwbs0_we_i, cpuwbs0_ack_o;
wire [2:0] cpuwbs0_cti_i;
wire [1:0] cpuwbs0_bte_i;

wire [15:0] cpuwbs1_dat_i, cpuwbs1_dat_o;
wire cpuwbs1_cyc_i, cpuwbs1_stb_i, cpuwbs1_we_i, cpuwbs1_ack_o;
wire [2:0] cpuwbs1_cti_i;
wire [1:0] cpuwbs1_bte_i;

wire [15:0] cpuwbs2_dat_i, cpuwbs2_dat_o;
wire cpuwbs2_cyc_i, cpuwbs2_stb_i, cpuwbs2_we_i, cpuwbs2_ack_o;
wire [2:0] cpuwbs2_cti_i;
wire [1:0] cpuwbs2_bte_i;

wire [15:0] cpuwbs3_dat_i, cpuwbs3_dat_o;
wire cpuwbs3_cyc_i, cpuwbs3_stb_i, cpuwbs3_we_i, cpuwbs3_ack_o;
wire [2:0] cpuwbs3_cti_i;
wire [1:0] cpuwbs3_bte_i;

// Buses from general purpose DMA masters to main arbiter:
// (This is a 16 bit bus so that 16 bit cores work.) (XXX it is?)
wire [31:0] dmawbm2_adr_o;
wire [31:0] dmawbm2_dat_o;
wire [31:0] dmawbm2_dat_i;
wire dmawbm2_cyc_o, dmawbm2_stb_o, dmawbm2_we_o, dmawbm2_ack_i;
wire [3:0] dmawbm2_sel_o;

wire [31:0] dmawbm3_adr_o;
wire [31:0] dmawbm3_dat_o;
wire [31:0] dmawbm3_dat_i;
wire dmawbm3_cyc_o, dmawbm3_stb_o, dmawbm3_we_o, dmawbm3_ack_i;
wire [3:0] dmawbm3_sel_o;

// This is the LM32 I-bus.  It goes straight to program memory.
wire lmiwbm_cyc_o, lmiwbm_stb_o, lmiwbm_we_o;
wire [31:0] lmiwbm_adr_o;
wire [31:0] lmiwbm_dat_o;
wire [3:0] lmiwbm_sel_o;
wire [31:0] lmiwbm_dat_i;
wire lmiwbm_ack_i;

// This is the LM32 data bus.  On these wires it is a 32 bit big endian bus.
wire lmdwbm_cyc_o, lmdwbm_stb_o, lmdwbm_we_o;
wire [31:0] lmdwbm_adr_o;
wire [31:0] lmdwbm_dat_o;
wire [3:0] lmdwbm_sel_o;
reg [31:0] lmdwbm_dat_i;
wire lmdwbm_ack_i;

// Remap base of LM32 address space to LM32 RAM:
wire [31:0] lmdwbm_adr_remapped = lmdwbm_adr_o[31] ?
  lmdwbm_adr_o : {16'h0001, lmdwbm_adr_o[15:0]};

/* This block of code messes with the endianness of the LM32 data bus. This is
 * a scary thing to do, and it only works because all LM32 code knows the
 * register width and the endianness of everything it is talking to.  The LM32
 * sees RAM at base 0 and hardware at the base addresses below.
 *
 * The base addresses are:
 * 0x80000000: This bus is fully endian swapped.  It can talk to 8 bit
 *             hardware, or 32 bit hardware that has its bytes in the wrong
 *             order.
 * 0x90000000: This passes the bus straight through.  It is big endian as per
 *             the wishbone spec.  It can talk to 32 bit LE hardware if you 
 *             only do 32 bit transactions.
 * 0xa0000000: This bus is mixed endian, for the purpose of connecting to 16
 *             bit LE hardware.
 */
reg [31:0] lmd2_dat_o;
reg [3:0] lmd2_sel_o;
wire [31:0] lmd2_dat_i;
always @(*) begin
  if (lmdwbm_adr_o[28]) begin // do nothing
    lmdwbm_dat_i = lmd2_dat_i;
    lmd2_dat_o = lmdwbm_dat_o;
    lmd2_sel_o = lmdwbm_sel_o;
  end
  else if (lmdwbm_adr_o[29]) begin // 16 bit endian swap
    lmdwbm_dat_i = {
      lmd2_dat_i[15:8],
      lmd2_dat_i[7:0],
      lmd2_dat_i[31:24],
      lmd2_dat_i[23:16]
    };
    lmd2_dat_o = {
      lmdwbm_dat_o[15:8],
      lmdwbm_dat_o[7:0],
      lmdwbm_dat_o[31:24],
      lmdwbm_dat_o[23:16]
    };
    lmd2_sel_o = {
      lmdwbm_sel_o[1],
      lmdwbm_sel_o[0],
      lmdwbm_sel_o[3],
      lmdwbm_sel_o[2]
    };
  end else begin // full endian swap
    lmdwbm_dat_i = {
      lmd2_dat_i[7:0],
      lmd2_dat_i[15:8],
      lmd2_dat_i[23:16],
      lmd2_dat_i[31:24]
    };
    lmd2_dat_o = {
      lmdwbm_dat_o[7:0],
      lmdwbm_dat_o[15:8],
      lmdwbm_dat_o[23:16],
      lmdwbm_dat_o[31:24]
    };
    lmd2_sel_o = {
      lmdwbm_sel_o[0],
      lmdwbm_sel_o[1],
      lmdwbm_sel_o[2],
      lmdwbm_sel_o[3]
    };
  end
end

// Bus just to connect the main arbiter to the main buffer:
wire bufwbm_cyc_o, bufwbm_stb_o, bufwbm_we_o;
wire [31:0] bufwbm_adr_o;
wire [31:0] bufwbm_dat_o;
wire [3:0] bufwbm_sel_o;
wire [31:0] bufwbm_dat_i;
wire bufwbm_ack_i;

wb_arbiter main_arbiter(
  .wb_clk_i(pll_100mhz),

  .wbowner_dat_o(bufwbm_dat_o),
  .wbowner_dat_i(bufwbm_dat_i),
  .wbowner_adr_o(bufwbm_adr_o),
  .wbowner_cyc_o(bufwbm_cyc_o),
  .wbowner_stb_o(bufwbm_stb_o),
  .wbowner_we_o(bufwbm_we_o),
  .wbowner_ack_i(bufwbm_ack_i),
  .wbowner_sel_o(bufwbm_sel_o),

  .wb1_adr_i(cpuwbm100_adr_o),
  .wb1_dat_i({cpuwbm100_dat_o, cpuwbm100_dat_o}),
  .wb1_dat_o(cpuwbm100_dat32_i),
  .wb1_cyc_i(cpuwbm100_cyc_o),
  .wb1_stb_i(cpuwbm100_stb_o),
  .wb1_we_i(cpuwbm100_we_o),
  .wb1_ack_o(cpuwbm100_ack_i),
  .wb1_sel_i(cpuwbm100_sel32_o),

  .wb2_cyc_i(lmdwbm_cyc_o),
  .wb2_stb_i(lmdwbm_stb_o),
  .wb2_we_i(lmdwbm_we_o),
  .wb2_adr_i(lmdwbm_adr_remapped),
  .wb2_dat_i(lmd2_dat_o),
  .wb2_sel_i(lmd2_sel_o),
  .wb2_dat_o(lmd2_dat_i),
  .wb2_ack_o(lmdwbm_ack_i),

  .wb3_cyc_i(dmawbm2_cyc_o),
  .wb3_stb_i(dmawbm2_stb_o),
  .wb3_we_i(dmawbm2_we_o),
  .wb3_dat_o(dmawbm2_dat_i),
  .wb3_dat_i(dmawbm2_dat_o),
  .wb3_ack_o(dmawbm2_ack_i),
  .wb3_adr_i(dmawbm2_adr_o),
  .wb3_sel_i(dmawbm2_sel_o),

  .wb4_cyc_i(dmawbm3_cyc_o),
  .wb4_stb_i(dmawbm3_stb_o),
  .wb4_we_i(dmawbm3_we_o),
  .wb4_dat_o(dmawbm3_dat_i),
  .wb4_dat_i(dmawbm3_dat_o),
  .wb4_ack_o(dmawbm3_ack_i),
  .wb4_adr_i(dmawbm3_adr_o),
  .wb4_sel_i(dmawbm3_sel_o)
);

wb_buf main_buf(
  .wb_clk_i(pll_100mhz),
  .wb_rst_i(wb_rst),

  .wbs_cyc_i(bufwbm_cyc_o),
  .wbs_stb_i(bufwbm_stb_o),
  .wbs_we_i(bufwbm_we_o),
  .wbs_dat_o(bufwbm_dat_i),
  .wbs_dat_i(bufwbm_dat_o),
  .wbs_ack_o(bufwbm_ack_i),
  .wbs_adr_i(bufwbm_adr_o),
  .wbs_sel_i(bufwbm_sel_o),

  .wbm_dat_o(cpuwbm32_dat_o),
  .wbm_dat_i(cpuwbm_dat_i),
  .wbm_adr_o(cpuwbm32_adr_o),
  .wbm_cyc_o(cpuwbm_cyc_o),
  .wbm_stb_o(cpuwbm_stb_o),
  .wbm_we_o(cpuwbm_we_o),
  .wbm_ack_i(cpuwbm_ack_i),
  .wbm_sel_o(cpuwbm32_sel_o)
);

/****************************************************************************
 * CPU bridge 
 ****************************************************************************/

wire smc_irq;
assign smc_irq_pad = smc_irq;

wire [15:0] data_o;
wire data_oe;
assign smc_d_pad = data_oe ? data_o : 16'hzzzz;

wire [3:0] wr_fifo_empty;
mvsmcbridge cpu_bridge(
  .wb_rst_i(wb_rst),
  .wbm_clk_i(smc_clk_pad),
  .sync_i(1'b1), // SMC bus is always in sync mode.
  .wbm_clk_o(wb62_clk),
  .wbm_cyc_o(cpuwbm62_cyc_o),
  .wbm_stb_o(cpuwbm62_stb_o),
  .wbm_dat_o(cpuwbm62_dat_o),
  .wbm_adr_o(cpuwbm62_adr_o),
  .wbm_we_o(cpuwbm62_we_o),
  .wbm_dat_i(cpuwbm62_dat_i),
  .wbm_ack_i(cpuwbm62_ack_i),
  .wbm_sel_o(cpuwbm62_sel_o),  

  /* WBM2 is at 100Mhz */
  .wbm2_en_i(ts4740_decodes[13]), // decode 13 = all 100MHz slaves
  .wbm2_clk_i(pll_100mhz),
  .wbm2_cyc_o(cpuwbm100_cyc_o),
  .wbm2_stb_o(cpuwbm100_stb_o),
  .wbm2_we_o(cpuwbm100_we_o),
  .wbm2_dat_o(cpuwbm100_dat_o),
  .wbm2_adr_o(cpuwbm100_adr_o),
  .wbm2_sel_o(cpuwbm100_sel_o),
  .wbm2_ack_i(cpuwbm100_ack_i),
  .wbm2_dat_i(cpuwbm100_dat_i),

  /* For satisfying read bursts */
  .wbs_clk_i(pll_100mhz),

  .wbs0_cyc_i(cpuwbs0_cyc_i),
  .wbs0_stb_i(cpuwbs0_stb_i),
  .wbs0_we_i(cpuwbs0_we_i),
  .wbs0_dat_i(cpuwbs0_dat_i),
  .wbs0_dat_o(cpuwbs0_dat_o),
  .wbs0_cti_i(cpuwbs0_cti_i),
  .wbs0_bte_i(cpuwbs0_bte_i),
  .wbs0_ack_o(cpuwbs0_ack_o),

  .wbs1_cyc_i(cpuwbs1_cyc_i),
  .wbs1_stb_i(cpuwbs1_stb_i),
  .wbs1_we_i(cpuwbs1_we_i),
  .wbs1_dat_i(cpuwbs1_dat_i),
  .wbs1_dat_o(cpuwbs1_dat_o),
  .wbs1_cti_i(cpuwbs1_cti_i),
  .wbs1_bte_i(cpuwbs1_bte_i),
  .wbs1_ack_o(cpuwbs1_ack_o),

  .wbs2_cyc_i(cpuwbs2_cyc_i),
  .wbs2_stb_i(cpuwbs2_stb_i),
  .wbs2_we_i(cpuwbs2_we_i),
  .wbs2_dat_i(cpuwbs2_dat_i),
  .wbs2_dat_o(cpuwbs2_dat_o),
  .wbs2_cti_i(cpuwbs2_cti_i),
  .wbs2_bte_i(cpuwbs2_bte_i),
  .wbs2_ack_o(cpuwbs2_ack_o),

  .wbs3_cyc_i(cpuwbs3_cyc_i),
  .wbs3_stb_i(cpuwbs3_stb_i),
  .wbs3_we_i(cpuwbs3_we_i),
  .wbs3_dat_i(cpuwbs3_dat_i),
  .wbs3_dat_o(cpuwbs3_dat_o),
  .wbs3_cti_i(cpuwbs3_cti_i),
  .wbs3_bte_i(cpuwbs3_bte_i),
  .wbs3_ack_o(cpuwbs3_ack_o),

  .smc_be1n_i(smc_be1n_pad),
  .smc_be2n_i(smc_be2n_pad),
  .smc_dat_i(smc_d_pad),
  .smc_dat_o(data_o),
  .smc_dat_oe_o(data_oe),
  .smc_rdn_i(smc_rdn_pad),
  .smc_wrn_i(smc_wen_pad),
  .smc_cs1n_i(smc_cs1n_pad),
  .smc_advn_i(smc_luan_pad & smc_llan_pad),
  //.smc_advn_i(smc_luan_pad), // XXX this should work, try it
  .smc_waitn_o(smc_rdy_pad),
  //.smc_clk_i(smc_clk_pad),

  .wr_fifo_empty_o(wr_fifo_empty)
);


/****************************************************************************
 * Lattice Mico32 processor
 ****************************************************************************/

wire lm32_rst;

lm32_top mico32(
  .clk_i(pll_100mhz && lm32_opt),
  .rst_i(lm32_rst || !lm32_opt),
  .interrupt_n(32'hffffffff),

  .I_DAT_I({
    lmiwbm_dat_i[7:0],
    lmiwbm_dat_i[15:8],
    lmiwbm_dat_i[23:16],
    lmiwbm_dat_i[31:24]
  }),
  .I_ACK_I(lmiwbm_ack_i),

  .D_DAT_I(lmdwbm_dat_i),
  .D_ACK_I(lmdwbm_ack_i),

  .I_DAT_O({
    lmiwbm_dat_o[7:0],
    lmiwbm_dat_o[15:8],
    lmiwbm_dat_o[23:16],
    lmiwbm_dat_o[31:24]
  }),
  .I_ADR_O(lmiwbm_adr_o),
  .I_CYC_O(lmiwbm_cyc_o),
  .I_SEL_O({
    lmiwbm_sel_o[0],
    lmiwbm_sel_o[1],
    lmiwbm_sel_o[2],
    lmiwbm_sel_o[3]
  }),
  .I_STB_O(lmiwbm_stb_o),
  .I_WE_O(lmiwbm_we_o),

  .D_DAT_O(lmdwbm_dat_o),
  .D_ADR_O(lmdwbm_adr_o),
  .D_CYC_O(lmdwbm_cyc_o),
  .D_SEL_O(lmdwbm_sel_o),
  .D_STB_O(lmdwbm_stb_o),
  .D_WE_O(lmdwbm_we_o)
);

/****************************************************************************
 * SD card + DMA core
 ****************************************************************************/
wire sd_power, sd_busy, dmawbs0_ack_o;
wire sdwbs1_ack_o, sdwbs2_ack_o;
wire [7:0] sd_clk;
wire [31:0] sdwbs1_dat_o;
wire [31:0] sdwbs2_dat_o;
wire [31:0] dmawbs0_dat_o;
wire sdwbs1_ack, sdwbs2_ack;
reg sdwbs1_en, sdwbs2_en, dmawbs0_en;
wire [31:0] dmawbm0_adr_o, dmawbm0_dat_o;
wire dmawbm0_cyc_o, dmawbm0_stb_o, dmawbm0_we_o;
wire [3:0] dmawbm0_sel_o;
wire [2:0] dmawbm0_cti_o;
wire [1:0] dmawbm0_bte_o;

wire [2:0] sd_lun;
wire [3:0] sd_dat_o, sd_dat_oe, sd_dat_i;
wire sd_cmd_o, sd_cmd_oe, sd_cmd_i;
/* This currently doesn't work, probably for analog or timing reasons.
assign sd_dat_i = sd_lun[0] ? emmc_d_pad[3:0] : 
  {sd_d3_pad, sd_d2_pad, sd_d1_pad, sd_d0_pad};
assign sd_cmd_i = sd_lun[0] ? emmc_cmd_pad : sd_cmd_pad;
*/
assign sd_dat_i = {sd_d3_pad, sd_d2_pad, sd_d1_pad, sd_d0_pad};
assign sd_cmd_i = sd_cmd_pad;
assign sd_cmd_pad = sd_cmd_oe ? sd_cmd_o : 1'bz;
assign sd_d0_pad = sd_dat_oe[0] ? sd_dat_o[0] : 1'bz;
assign sd_d1_pad = sd_dat_oe[1] ? sd_dat_o[1] : 1'bz;
assign sd_d2_pad = sd_dat_oe[2] ? sd_dat_o[2] : 1'bz;
assign sd_d3_pad = sd_dat_oe[3] ? sd_dat_o[3] : 1'bz;
assign sd_powern_pad = 1'b0;
assign sd_clk_pad = sd_clk[0];

/*
assign emmc_d_pad[7:4] = 4'bzzzz;
assign emmc_d_pad[0] = sd_dat_oe[0] ? sd_dat_o[0] : 1'bz;
assign emmc_d_pad[1] = sd_dat_oe[1] ? sd_dat_o[1] : 1'bz;
assign emmc_d_pad[2] = sd_dat_oe[2] ? sd_dat_o[2] : 1'bz;
assign emmc_d_pad[3] = sd_dat_oe[3] ? sd_dat_o[3] : 1'bz;
assign emmc_pdn_pad = 1'b1;
assign emmc_clk_pad = sd_clk[1];
assign emmc_sci_clk_pad = 1'b0;
assign emmc_mosi_pad = 1'b0;
assign emmc_resetn_pad = 1'b1;
assign emmc_cmd_pad = sd_cmd_oe ? sd_cmd_o : 1'bz;
*/

assign emmc_d_pad = 8'd0;
assign emmc_pdn_pad = 1'b0;
assign emmc_clk_pad = 1'b0;
assign emmc_sci_clk_pad = 1'b0;
assign emmc_mosi_pad = 1'b0;
assign emmc_resetn_pad = 1'b0;
assign emmc_cmd_pad = 1'b0;

assign sd_act_ledn_pad = wr_fifo_empty[0];
//ts_sdcore #(.multicard(1'b1)) sdcardcore(
ts_sdcore #(.multicard(1'b0)) sdcardcore(
  .wb_rst_i(wb_rst),
  .wb_clk_i(pll_100mhz & sdcard_opt),

  .wb1_adr_i(cpuwbm32_adr_o),
  .wb1_cyc_i(cpuwbm_cyc_o && sdwbs1_en),
  .wb1_stb_i(cpuwbm_stb_o && sdwbs1_en),
  .wb1_dat_o(sdwbs1_dat_o),
  .wb1_we_i(cpuwbm_we_o),
  .wb1_dat_i(cpuwbm32_dat_o),
  .wb1_ack_o(sdwbs1_ack_o),
  .wb1_sel_i(cpuwbm32_sel_o),
  .wb1_bte_i(2'b00),
  .wb1_cti_i(3'b000),

  /* Connection to DMA core */
  .wb2_adr_i(32'h4),
  .wb2_cyc_i(dmawbm0_cyc_o),
  .wb2_stb_i(dmawbm0_stb_o),
  .wb2_dat_o(sdwbs2_dat_o),
  .wb2_we_i(dmawbm0_we_o),
  .wb2_dat_i(dmawbm0_dat_o),
  .wb2_ack_o(sdwbs2_ack_o),
  .wb2_sel_i(4'b0011),
  .wb2_bte_i(dmawbm0_bte_o),
  .wb2_cti_i(dmawbm0_cti_o),

  /* Binary netlist cannot instantiate unless all inputs are driven */
  .wb3_adr_i(32'h0),
  .wb3_cyc_i(1'b0),
  .wb3_stb_i(1'b0),
  //.wb3_dat_o(sdwbs2_dat_o),
  .wb3_we_i(1'b0),
  .wb3_dat_i(32'h0),
  //.wb3_ack_o(sdwbs2_ack_o),
  .wb3_sel_i(4'b0011),
  .wb3_bte_i(2'b00),
  .wb3_cti_i(3'b000),

  .wb4_adr_i(32'h0),
  .wb4_cyc_i(1'b0),
  .wb4_stb_i(1'b0),
  //.wb4_dat_o(sdwbs2_dat_o),
  .wb4_we_i(1'b0),
  .wb4_dat_i(32'h0),
  //.wb4_ack_o(sdwbs2_ack_o),
  .wb4_sel_i(4'b0011),
  .wb4_bte_i(2'b00),
  .wb4_cti_i(3'b000),

  .sd_cmd_i(sd_cmd_i),
  .sd_cmd_o(sd_cmd_o),
  .sd_cmd_oe_o(sd_cmd_oe),
  .sd_dat_i(sd_dat_i),
  .sd_dat_o(sd_dat_o),
  .sd_dat_oe_o(sd_dat_oe),
  .sd_clk_o(sd_clk),

  .sd_wprot_i(8'b00000000),
  //.sd_detect_i(8'b00000011),
  .sd_detect_i(8'b00000001),
  .sd_power_o(sd_power),
  .sd_lun_o(sd_lun),
  .sd_busy_o(sd_busy)
);

wire dmawbm1_dack, dmawbm2_dack;
wb_dma dmacore0(
  .wb_clk_i(pll_100mhz),
  .wb_rst_i(wb_rst),

  /* wbs gets connected to 100Mhz CPU wishbone */
  .wbs_cyc_i(cpuwbm_cyc_o && dmawbs0_en),
  .wbs_stb_i(cpuwbm_stb_o && dmawbs0_en),
  .wbs_we_i(cpuwbm_we_o),
  .wbs_adr_i(cpuwbm32_adr_o),
  .wbs_dat_o(dmawbs0_dat_o),
  .wbs_ack_o(dmawbs0_ack_o),
  .wbs_dat_i(cpuwbm32_dat_o),
  .wbs_sel_i(cpuwbm32_sel_o),

  /* wbm1 gets connected to the SMC burst fifo wbs */
  .wbm1_cyc_o(cpuwbs0_cyc_i),
  .wbm1_stb_o(cpuwbs0_stb_i),
  //.wbm1_adr_o(cpuwbs0_adr_i),
  .wbm1_dat_o(cpuwbs0_dat_i),
  .wbm1_dat_i(cpuwbs0_dat_o),
  .wbm1_we_o(cpuwbs0_we_i),
  .wbm1_ack_i(cpuwbs0_ack_o),
  .wbm1_cti_o(cpuwbs0_cti_i),
  .wbm1_bte_o(cpuwbs0_bte_i),
  .wbm1_drq_i(1'b1), /* SMC fifo is always ready */
  .wbm1_dack_o(dmawbm1_dack),

  /* wbm2 gets connected to the SD card core */
  .wbm2_cyc_o(dmawbm0_cyc_o),
  .wbm2_stb_o(dmawbm0_stb_o),
  .wbm2_adr_o(dmawbm0_adr_o),
  .wbm2_dat_o(dmawbm0_dat_o),
  .wbm2_dat_i(sdwbs2_dat_o[15:0]),
  .wbm2_we_o(dmawbm0_we_o),
  .wbm2_ack_i(sdwbs2_ack_o),
  .wbm2_cti_o(dmawbm0_cti_o),
  .wbm2_bte_o(dmawbm0_bte_o),
  .wbm2_drq_i(1'b1),
  .wbm2_dack_o(dmawbm2_dack)
);

/****************************************************************************
 * SYSCON
 ****************************************************************************/

wire en_can, en_can2, en_spi, en_bbclk, en_adc, en_touch;
wire [5:0] en_txen;
wire [15:0] bus_config;

wire reboot;
assign reboot_pad = reboot; 

wire [102:0] dio;
wire [102:0] dio_oe;
wire [102:0] dio_in;
reg [15:0] fpga_irqs;
wire green_led, red_led;
assign green_led_pad = green_led ? 1'b0 : 1'b1;
assign red_led_pad = red_led ? 1'b0 : 1'b1;
reg sd_busy_q, dmawbm1_dack_q, dmawbm2_dack_q;
always @(posedge pll_100mhz) begin
  sd_busy_q <= sd_busy;
  dmawbm1_dack_q <= dmawbm1_dack;
  dmawbm2_dack_q <= dmawbm2_dack;
end
reg scwbs_en;
wire scwbs_ack_o;
wire [15:0] scwbs_dat_o;
syscon sysconcore(
  .wb_clk_i(pll_100mhz),
  .wb_rst_i(wb_rst),

  .wb_cyc_i(cpuwbm_cyc_o && scwbs_en),
  .wb_stb_i(cpuwbm_stb_o && scwbs_en),
  .wb_we_i(cpuwbm_we_o),
  .wb_adr_i(cpuwbm_adr_o),
  .wb_dat_i(cpuwbm_dat_o),
  .wb_sel_i(cpuwbm_sel_o),
  .wb_dat_o(scwbs_dat_o),
  .wb_ack_o(scwbs_ack_o),

  .dio_o(dio),
  .dio_oe_o(dio_oe),
  .dio_i(dio_in),
  .usec_i(usecs),

  .bus_config_o(bus_config),
  .en_can_o(en_can),
  .en_can2_o(en_can2),
  .en_spi_o(en_spi),
  .en_bbclk_o(en_bbclk),
  .en_txen_o(en_txen),
  .en_touch_o(en_touch),
  .red_led_o(red_led),
  .green_led_o(green_led),
  .reboot_o(reboot),
  .irqs_i(fpga_irqs),
  .irq_o(smc_irq),
  .lm32_rst_o(lm32_rst),
  .sd_busy_i(sd_busy_q),
  .dma_idle_i(dmawbm1_dack_q && dmawbm2_dack_q)
);

/****************************************************************************
 * 8 KByte WISHBONE blockram for XUART core
 ****************************************************************************/

wire [31:0] sramwbs1_dat;
wire [15:0] sramwbs1_dat16 =
  cpuwbm62_adr_o[1] ? sramwbs1_dat[31:16] : sramwbs1_dat[15:0];
wire [3:0] cpu62wbm32_sel_o =
  cpuwbm62_adr_o[1] ? {cpuwbm62_sel_o, 2'b00} : {2'b00, cpuwbm62_sel_o};
wire sramwbs1_ack_o;
reg sramwbs1_en;

wire xuartwbm_cyc_o, xuartwbm_stb_o, xuartwbm_we_o, xuartwbm_ack_i;
wire [15:0] xuartwbm_adr_o, xuartwbm_dat_o, xuartwbm_dat_i;
wire [31:0] xuartwbm_dat32_i;
wire [3:0] xuartwbm_sel_o;
assign xuartwbm_dat_i = xuartwbm_adr_o[1] ?
  xuartwbm_dat32_i[31:16] : xuartwbm_dat32_i[15:0];

blockram_8kbyte sramcore1(
  .wb_clk_i(wb62_clk),
  .wb_rst_i(wb_rst),
  .wb1_cyc_i(cpuwbm62_cyc_o && sramwbs1_en),
  .wb1_stb_i(cpuwbm62_stb_o && sramwbs1_en),
  .wb1_we_i(cpuwbm62_we_o),
  .wb1_dat_i({cpuwbm62_dat_o, cpuwbm62_dat_o}),
  .wb1_dat_o(sramwbs1_dat),
  .wb1_ack_o(sramwbs1_ack_o),
  .wb1_adr_i({cpuwbm62_adr_o[31:2], 2'b00}),
  .wb1_sel_i(cpu62wbm32_sel_o),

  .wb2_cyc_i(xuartwbm_cyc_o),
  .wb2_stb_i(xuartwbm_stb_o),
  .wb2_adr_i(xuartwbm_adr_o),
  .wb2_dat_i({xuartwbm_dat_o, xuartwbm_dat_o}),
  .wb2_sel_i(xuartwbm_sel_o),
  .wb2_we_i(xuartwbm_we_o),
  .wb2_ack_o(xuartwbm_ack_i),
  .wb2_dat_o(xuartwbm_dat32_i)

);

/****************************************************************************
 * XUART core
 ****************************************************************************/

wire xuartwbs_ack;
wire xuartwbs_ack_o = xuartwbs_ack | !xuart_opt;
reg xuwbs_en;
wire [15:0] xuartwbs_dat_o;
reg [7:0] xuart_rx;
wire [7:0] xuart_active;
wire [7:0] xuart_cts = 8'hff;
wire [7:0] xuart_txen, xuart_tx;
reg [7:0] xuart_txen_q, xuart_tx_q;
reg [7:0] xuart_rx_q, xuart_cts_q;
wire xuart_irq;
wire xwbm_cyc_o, xwbm_stb_o, xwbm_we_o, xwbm_ack_i;
wire [15:0] xwbm_adr_o, xwbm_dat_o, xwbm_dat_i;
wire [3:0] xwbm_sel32_o = xwbm_adr_o[1] ? 4'b1100 : 4'b0011;
wire [31:0] xwbm_dat32_i;
wire [3:0] xwbm_sel_o;
always @(posedge wb62_clk or posedge wb_rst) begin
  if (wb_rst) begin
    xuart_rx_q <= 8'hff;
    xuart_cts_q <= 8'hff;
    xuart_tx_q <= 8'hff;
    xuart_txen_q <= 8'hff;
  end else begin
    xuart_rx_q <= xuart_rx;
    xuart_cts_q <= xuart_cts;
    xuart_tx_q <= xuart_tx;
    xuart_txen_q <= xuart_txen;
  end
end
wb_buf xubuf(
  .wb_clk_i(wb62_clk),
  .wb_rst_i(wb_rst),

  .wbs_cyc_i(xwbm_cyc_o),
  .wbs_stb_i(xwbm_stb_o),
  .wbs_we_i(xwbm_we_o),
  .wbs_dat_o(xwbm_dat_i),
  .wbs_dat_i(xwbm_dat_o),
  .wbs_ack_o(xwbm_ack_i),
  .wbs_adr_i(xwbm_adr_o),
  .wbs_sel_i(xwbm_sel32_o),

  .wbm_adr_o(xuartwbm_adr_o),
  .wbm_cyc_o(xuartwbm_cyc_o),
  .wbm_stb_o(xuartwbm_stb_o),
  .wbm_we_o(xuartwbm_we_o),
  .wbm_dat_o(xuartwbm_dat_o),
  .wbm_ack_i(xuartwbm_ack_i),
  .wbm_sel_o(xuartwbm_sel_o),
  .wbm_dat_i(xuartwbm_dat_i)
);
ts_xuart tsxuartcore(
  .wb_clk_i(wb62_clk & xuart_opt),
  .wb_rst_i(wb_rst | !xuart_opt),

  .wbm_cyc_o(xwbm_cyc_o),
  .wbm_stb_o(xwbm_stb_o),
  .wbm_we_o(xwbm_we_o),
  .wbm_ack_i(xwbm_ack_i),
  .wbm_adr_o(xwbm_adr_o),
  .wbm_dat_i(xwbm_dat_i),
  .wbm_dat_o(xwbm_dat_o),

  .wbs_cyc_i(cpuwbm62_cyc_o && xuwbs_en),
  .wbs_stb_i(cpuwbm62_stb_o && xuwbs_en),
  .wbs_we_i(cpuwbm62_we_o),
  .wbs_adr_i(cpuwbm62_adr_o),
  .wbs_dat_i(cpuwbm62_dat_o),
  .wbs_dat_o(xuartwbs_dat_o),
  .wbs_ack_o(xuartwbs_ack),

  .baudclk_i(pll_100mhz),
  .cts_i(xuart_cts_q),
  .rx_i(xuart_rx_q),
  .tx_o(xuart_tx),
  .txen_o(xuart_txen),
  .active_o(xuart_active),
  .irq_o(xuart_irq),
  //.uart_disable_i(can_opt ? 8'hf0 : 8'h80)
  .uart_disable_i(8'h80)
);

/****************************************************************************
 * Touchscreen core
 ****************************************************************************/

reg tswbs_en;
wire [15:0] tswbs_dat_o;
wire tswbs_ack;
wire tswbs_ack_o = tswbs_ack | !touchscreen_opt;
wire touch_mosi, touch_clk, touch_csn; // CS# is open drain for some reason
touchscreen ts(
  .wb_clk_i(wb62_clk & touchscreen_opt),
  .wb_rst_i(wb_rst | !touchscreen_opt),
  .wb_cyc_i(cpuwbm62_cyc_o && tswbs_en),
  .wb_stb_i(cpuwbm62_stb_o && tswbs_en),
  .wb_we_i(cpuwbm62_we_o),
  .wb_adr_i(cpuwbm62_adr_o),
  .wb_dat_i(cpuwbm62_dat_o),
  .wb_dat_o(tswbs_dat_o),
  .wb_ack_o(tswbs_ack),

  .spi_miso_i(mux_ad_pad[13]),
  .spi_mosi_o(touch_mosi),
  .spi_clk_o(touch_clk),
  .ad7843_csn_o(touch_csn),
  .ad7843_penirqn_i(mux_ad_pad[11])
);

/****************************************************************************
 * CAN core
 ****************************************************************************/

reg canwbs_en;
wire canwbs_ack;
wire canwbs_ack_o = canwbs_ack | !can_opt;
wire can_tx, can_irqn;
wire [7:0] canwbs_dat_i;
assign canwbs_dat_i = cpuwbm62_sel_o[0] ? cpuwbm62_dat_o[7:0] :
                                          cpuwbm62_dat_o[15:8];
wire [7:0] canwbs_dat8_o;
wire [15:0] canwbs_dat_o = {canwbs_dat8_o, canwbs_dat8_o};
wire [7:0] canwbs_adr_i;
assign canwbs_adr_i[7:1] = cpuwbm62_adr_o[7:1];
assign canwbs_adr_i[0] = !cpuwbm62_sel_o[0];

can_top cancore(
  .wb_clk_i(wb62_clk && can_opt),
  .wb_rst_i(wb_rst | !can_opt),
  .wb_cyc_i(cpuwbm62_cyc_o && canwbs_en),
  .wb_stb_i(cpuwbm62_stb_o && canwbs_en),
  .wb_we_i(cpuwbm62_we_o),
  .wb_dat_i(canwbs_dat_i),
  .wb_dat_o(canwbs_dat8_o),
  .wb_adr_i(canwbs_adr_i),
  .wb_ack_o(canwbs_ack),

  .clk_i(pll_24mhz && can_opt),
  .rx_i(dio_pad[16]),
  .tx_o(can_tx),
  .irq_on(can_irqn)
  //.bus_off_on()
);


/****************************************************************************
 * Second CAN core
 ****************************************************************************/

reg can2wbs_en;
wire can2wbs_ack;
wire can2wbs_ack_o = can2wbs_ack | !can2_opt;
wire can2_tx, can2_irqn;
wire [7:0] can2wbs_dat8_o;
wire [15:0] can2wbs_dat_o = {can2wbs_dat8_o, can2wbs_dat8_o};

can_top can2core(
  .wb_clk_i(wb62_clk && can2_opt),
  .wb_rst_i(wb_rst | !can2_opt),
  .wb_cyc_i(cpuwbm62_cyc_o && can2wbs_en),
  .wb_stb_i(cpuwbm62_stb_o && can2wbs_en),
  .wb_we_i(cpuwbm62_we_o),
  .wb_dat_i(canwbs_dat_i),
  .wb_dat_o(can2wbs_dat8_o),
  .wb_adr_i(canwbs_adr_i),
  .wb_ack_o(can2wbs_ack),

  .clk_i(pll_24mhz && can2_opt),
  .rx_i(dio_pad[11]),
  .tx_o(can2_tx),
  .irq_on(can2_irqn)
  //.bus_off_on()
);


/****************************************************************************
 * SPI core
 ****************************************************************************/

reg spiwbs_en;
wire [15:0] spiwbs_dat_o;
wire spiwbs_ack;
wire spiwbs_ack_o = spiwbs_ack | !spi_opt;
wire scken;
wire [3:0] spi_csn;
reg [3:0] spi_csn_q;
always @(posedge pll_100mhz or posedge wb_rst) begin
  if (wb_rst) spi_csn_q <= 4'hf;
  else spi_csn_q <= spi_csn;
end
wire [3:0] spi_si = {4{spi_miso_pad}};
wire spi_sck, hispeed, spi_clk;
wire spi_so;
wb_spi spicore(
  .wb_rst_i(wb_rst | !spi_opt),
  .wb_clk_i(pll_100mhz & spi_opt),
  .wb_cyc_i(cpuwbm_cyc_o && spiwbs_en),
  .wb_stb_i(cpuwbm_stb_o && spiwbs_en),
  .wb_dat_o(spiwbs_dat_o),
  .wb_dat_i(cpuwbm_dat_o),
  .wb_adr_i(cpuwbm_adr_o),
  .wb_we_i(cpuwbm_we_o),
  .wb_ack_o(spiwbs_ack),
  .wb_sel_i(cpuwbm_sel_o),

  .scken_o(scken),
  .so_o(spi_so),
  .si_i(spi_si),
  .csn_o(spi_csn),
  .sck_o(spi_sck),
  .hispeed_o(hispeed)
);

/****************************************************************************
 * ADC core (MCP3428)
 ****************************************************************************/

reg adcwbs_en;
wire [15:0] adcwbs_dat_o;
wire adcwbs_ack_o;
wire adc_scl, adc_sda, an_sel;
wire [1:0] an_sel_sel;

wb_mcp3428 adc(
  .wb_rst_i(wb_rst),
  .wb_clk_i(pll_100mhz),
  .wb_cyc_i(cpuwbm_cyc_o && adcwbs_en),
  .wb_stb_i(cpuwbm_stb_o && adcwbs_en),
  .wb_dat_o(adcwbs_dat_o),
  .wb_dat_i(cpuwbm_dat_o),
  .wb_adr_i(cpuwbm_adr_o),
  .wb_we_i(cpuwbm_we_o),
  .wb_ack_o(adcwbs_ack_o),
  .wb_sel_i(cpuwbm_sel_o),

  .scl_o(adc_scl),
  .sda_o(adc_sda),
  .sda_i(dio_pad[6]),
  .an_sel_o(an_sel),
  .an_sel_sel_o(an_sel_sel),
  .active_o(en_adc)
);


/****************************************************************************
 * External address-data bus
 ****************************************************************************/

reg buswbs_en;
wire [15:0] buswbs_dat_o;
wire buswbs_ack_o;

wire [15:0] mux_dat;
wire bus_oe, bus_csn, bus_dir, bus_ale, bus_bhen;

isamuxbus_bridge muxbus(
  .wb_clk_i(pll_100mhz),
  .wb_rst_i(wb_rst),
  .wb_cyc_i(cpuwbm_cyc_o && buswbs_en),
  .wb_stb_i(cpuwbm_stb_o && buswbs_en),
  .wb_dat_o(buswbs_dat_o),
  .wb_dat_i(cpuwbm_dat_o),
  .wb_adr_i({1'b0, cpuwbm_adr_o[14:0]}),
  .wb_we_i(cpuwbm_we_o),
  .wb_ack_o(buswbs_ack_o),
  .wb_sel_i(cpuwbm_sel_o),

  .bus_config_i(bus_config),
  .cs_8bit_i(!smc_cs1n_pad), // This will be NG with DMA possible

  .csn_o(bus_csn),
  .dir_o(bus_dir),
  .ale_o(bus_ale),
  .bhen_o(bus_bhen),
  .waitn_i(bus_waitn_pad),
  .mux_i(mux_ad_pad[15:0]),
  .mux_o(mux_dat),
  .mux_oe_o(bus_oe)
);

/****************************************************************************
 * SPI NOR flash controller with DMA channel
 ****************************************************************************/

reg norwbs_en;
wire norwbs_ack_o;
wire [15:0] norwbs_dat_o;

wire [3:0] spi_di, spi_do, spi_oe, spi_do_dly;
assign flash_mosi_pad = spi_oe[0] ? spi_do[0] : 1'bz;
assign flash_miso_pad = spi_oe[1] ? spi_do[1] : 1'bz;
assign flash_wpn_pad = spi_oe[2] ? spi_do[2] : 1'bz;
assign flash_holdn_pad = spi_oe[3] ? spi_do[3] : 1'bz;
assign spi_di[0] = flash_mosi_pad;
assign spi_di[1] = flash_miso_pad;
assign spi_di[2] = flash_wpn_pad;
assign spi_di[3] = flash_holdn_pad;

wire spiwbm_cyc_o, spiwbm_stb_o, spiwbm_we_o, spiwbm_ack_i;
wire [15:0] spiwbm_adr_o, spiwbm_dat_o, spiwbm_dat_i;
wire [1:0] spiwbm_sel_o;

// SPI core-specific streaming addresses:
assign spiwbm_adr_o = spiwbm_we_o ? 32'h00000308 : 32'h0000030a;

wb_spi2 norflashcore(
  .wb_rst_i(wb_rst),
  .wb_clk_i(pll_100mhz),

  .wb1_cyc_i(cpuwbm_cyc_o && norwbs_en),
  .wb1_stb_i(cpuwbm_stb_o && norwbs_en),
  .wb1_dat_o(norwbs_dat_o),
  .wb1_dat_i(cpuwbm_dat_o),
  .wb1_adr_i(cpuwbm_adr_o),
  .wb1_we_i(cpuwbm_we_o),
  .wb1_ack_o(norwbs_ack_o),
  .wb1_sel_i(cpuwbm_sel_o),

  .wb2_cyc_i(spiwbm_cyc_o),
  .wb2_stb_i(spiwbm_stb_o),
  .wb2_dat_o(spiwbm_dat_i),
  .wb2_dat_i(spiwbm_dat_o),
  .wb2_adr_i(spiwbm_adr_o),
  .wb2_we_i(spiwbm_we_o),
  .wb2_ack_o(spiwbm_ack_i),
  .wb2_sel_i(2'b11),

  .sck_o(flash_clk_pad),
  .d_o(spi_do),
  .d_oe_o(spi_oe),
  .d_i(spi_di),
  .csn_o(flash_csn_pad)
);

reg dmawbs1_en;
wire dmawbs1_ack_o;
wire [31:0] dmawbs1_dat_o;

wb_dma dmacore1(
  .wb_clk_i(pll_100mhz),
  .wb_rst_i(wb_rst),

  /* wbs gets connected to 100Mhz CPU wishbone */
  .wbs_cyc_i(cpuwbm_cyc_o && dmawbs1_en),
  .wbs_stb_i(cpuwbm_stb_o && dmawbs1_en),
  .wbs_we_i(cpuwbm_we_o),
  .wbs_adr_i(cpuwbm32_adr_o),
  .wbs_dat_o(dmawbs1_dat_o),
  .wbs_ack_o(dmawbs1_ack_o),
  .wbs_dat_i(cpuwbm32_dat_o),
  .wbs_sel_i(cpuwbm32_sel_o),

  /* wbm1 gets connected to the SMC burst fifo wbs */
  .wbm1_cyc_o(cpuwbs1_cyc_i),
  .wbm1_stb_o(cpuwbs1_stb_i),
  .wbm1_dat_o(cpuwbs1_dat_i),
  .wbm1_dat_i(cpuwbs1_dat_o),
  .wbm1_we_o(cpuwbs1_we_i),
  .wbm1_ack_i(cpuwbs1_ack_o),
  .wbm1_cti_o(cpuwbs1_cti_i),
  .wbm1_bte_o(cpuwbs1_bte_i),
  .wbm1_drq_i(1'b1), /* SMC fifo is always ready */

  /* wbm2 gets connected to the SPI flash core */
  .wbm2_cyc_o(spiwbm_cyc_o),
  .wbm2_stb_o(spiwbm_stb_o),
  //.wbm2_adr_o(spiwbm_adr_o),
  .wbm2_dat_o(spiwbm_dat_o),
  .wbm2_dat_i(spiwbm_dat_o),
  .wbm2_we_o(spiwbm_we_o),
  .wbm2_ack_i(spiwbm_ack_o),
  //.wbm2_cti_o(spiwbm_cti_o),
  //.wbm2_bte_o(spiwbm_bte_o),
  .wbm2_drq_i(1'b1),
  .wbm2_dack_o(spiwbm_dack)
);


/****************************************************************************
 * 32KB RAM for soft processor
 ****************************************************************************/

reg lmramwbs_en;
wire lmramwbs_ack_o;
wire [31:0] lmramwbs_dat_o;

wb_dpram_32kbyte lm32ram (
  .wb_clk_i(pll_100mhz),
  .wb_rst_i(wb_rst),

  .wb1_cyc_i(cpuwbm_cyc_o && lmramwbs_en),
  .wb1_stb_i(cpuwbm_stb_o && lmramwbs_en),
  .wb1_adr_i(cpuwbm32_adr_o),
  .wb1_dat_i(cpuwbm32_dat_o),
  .wb1_dat_o(lmramwbs_dat_o),
  .wb1_we_i(cpuwbm_we_o),
  .wb1_ack_o(lmramwbs_ack_o),
  .wb1_sel_i(cpuwbm32_sel_o),

  .wb2_cyc_i(lmiwbm_cyc_o),
  .wb2_stb_i(lmiwbm_stb_o),
  .wb2_we_i(lmiwbm_we_o),
  .wb2_adr_i(lmiwbm_adr_o),
  .wb2_dat_i(lmiwbm_dat_o),
  .wb2_sel_i(lmiwbm_sel_o),
  .wb2_dat_o(lmiwbm_dat_i),
  .wb2_ack_o(lmiwbm_ack_i)
);

/****************************************************************************
 * General purpose DMA cores
 ****************************************************************************/

reg dmawbs2_en;
wire dmawbs2_ack_o;
wire [31:0] dmawbs2_dat_o;

reg dmawbs3_en;
wire dmawbs3_ack_o;
wire [31:0] dmawbs3_dat_o;

// These DMA masters have access to all 100MHz wishbone slaves.
wb_dma dmacore2(
  .wb_clk_i(pll_100mhz),
  .wb_rst_i(wb_rst),

  /* wbs gets connected to 100Mhz CPU wishbone */
  .wbs_cyc_i(cpuwbm_cyc_o && dmawbs2_en),
  .wbs_stb_i(cpuwbm_stb_o && dmawbs2_en),
  .wbs_we_i(cpuwbm_we_o),
  .wbs_adr_i(cpuwbm32_adr_o),
  .wbs_dat_o(dmawbs2_dat_o),
  .wbs_ack_o(dmawbs2_ack_o),
  .wbs_dat_i(cpuwbm32_dat_o),
  .wbs_sel_i(cpuwbm32_sel_o),

  /* wbm1 gets connected to the SMC burst fifo wbs */
  .wbm1_cyc_o(cpuwbs2_cyc_i),
  .wbm1_stb_o(cpuwbs2_stb_i),
  .wbm1_dat_o(cpuwbs2_dat_i),
  .wbm1_dat_i(cpuwbs2_dat_o),
  .wbm1_we_o(cpuwbs2_we_i),
  .wbm1_ack_i(cpuwbs2_ack_o),
  .wbm1_cti_o(cpuwbs2_cti_i),
  .wbm1_bte_o(cpuwbs2_bte_i),
  .wbm1_drq_i(1'b1), /* SMC fifo is always ready */

  /* wbm2 gets connected to the main arbiter */
  .wbm2_cyc_o(dmawbm2_cyc_o),
  .wbm2_stb_o(dmawbm2_stb_o),
  .wbm2_adr_o(dmawbm2_adr_o),
  .wbm2_sel_o(dmawbm2_sel_o),
  .wbm2_dat_o(dmawbm2_dat_o),
  .wbm2_dat_i(dmawbm2_dat_i),
  .wbm2_we_o(dmawbm2_we_o),
  .wbm2_ack_i(dmawbm2_ack_i),
  .wbm2_drq_i(1'b1)
);

wb_dma dmacore3(
  .wb_clk_i(pll_100mhz),
  .wb_rst_i(wb_rst),

  /* wbs gets connected to 100Mhz CPU wishbone */
  .wbs_cyc_i(cpuwbm_cyc_o && dmawbs3_en),
  .wbs_stb_i(cpuwbm_stb_o && dmawbs3_en),
  .wbs_we_i(cpuwbm_we_o),
  .wbs_adr_i(cpuwbm32_adr_o),
  .wbs_dat_o(dmawbs3_dat_o),
  .wbs_ack_o(dmawbs3_ack_o),
  .wbs_dat_i(cpuwbm32_dat_o),
  .wbs_sel_i(cpuwbm32_sel_o),

  /* wbm1 gets connected to the SMC burst fifo wbs */
  .wbm1_cyc_o(cpuwbs3_cyc_i),
  .wbm1_stb_o(cpuwbs3_stb_i),
  .wbm1_dat_o(cpuwbs3_dat_i),
  .wbm1_dat_i(cpuwbs3_dat_o),
  .wbm1_we_o(cpuwbs3_we_i),
  .wbm1_ack_i(cpuwbs3_ack_o),
  .wbm1_cti_o(cpuwbs3_cti_i),
  .wbm1_bte_o(cpuwbs3_bte_i),
  .wbm1_drq_i(1'b1), /* SMC fifo is always ready */

  /* wbm2 gets connected to the main arbiter */
  .wbm2_cyc_o(dmawbm3_cyc_o),
  .wbm2_stb_o(dmawbm3_stb_o),
  .wbm2_adr_o(dmawbm3_adr_o),
  .wbm2_sel_o(dmawbm3_sel_o),
  .wbm2_dat_o(dmawbm3_dat_o),
  .wbm2_dat_i(dmawbm3_dat_i),
  .wbm2_we_o(dmawbm3_we_o),
  .wbm2_ack_i(dmawbm3_ack_i),
  .wbm2_drq_i(1'b1)
);


/****************************************************************************
 * DIO multiplexing
 ****************************************************************************/

reg [102:0] dio_reg, pad_o, pad_oe;

assign dio_pad[16:0] = dio_reg[16:0];
assign spi_frm_pad = dio_reg[17];
assign spi_mosi_pad = dio_reg[18];
assign spi_miso_pad = dio_reg[19];
assign spi_clk_pad = dio_reg[20];
assign bus_waitn_pad = dio_reg[22];
assign bus_bhen_pad = dio_reg[23];
assign bus_csn_pad = dio_reg[24];
assign bus_dir_pad = dio_reg[25];
assign bus_alen_pad = dio_reg[26];
assign mux_ad_pad[7:0] = dio_reg[42:35];
assign mux_ad_pad[15:8] = dio_reg[34:27];
assign uart0_txd_pad = dio_reg[48];
assign uart0_rxd_pad = dio_reg[49];
assign uart1_txd_pad = dio_reg[50];
assign uart1_rxd_pad = dio_reg[51];
assign uart2_txd_pad = dio_reg[52];
assign uart2_rxd_pad = dio_reg[53];
assign uart3_txd_pad = dio_reg[54];
assign uart3_rxd_pad = dio_reg[55];
assign uart4_txd_pad = dio_reg[56];
assign uart4_rxd_pad = dio_reg[57];
assign uart5_txd_pad = dio_reg[58];
assign uart5_rxd_pad = dio_reg[59];
// It's better for backward compatibility if DIO 30:17 are not DIO 30:17.
assign dio_pad[30:17] = dio_reg[73:60];
assign lcd_d_pad[23:0] = dio_reg[97:74];
assign lcd_clk_pad = dio_reg[98];
assign lcd_hsync_pad = dio_reg[99];
assign lcd_vsync_pad = dio_reg[100];
assign lcd_de_pad = dio_reg[101];
assign lcd_pwm_pad = dio_reg[102];

assign dio_in[102] = lcd_pwm_pad;
assign dio_in[101] = lcd_de_pad;
assign dio_in[100] = lcd_vsync_pad;
assign dio_in[99] = lcd_hsync_pad;
assign dio_in[98] = lcd_clk_pad;
assign dio_in[97:74] = lcd_d_pad[23:0];
assign dio_in[73:60] = dio_pad[30:17];
assign dio_in[59:48] = {
  uart5_rxd_pad,
  uart5_txd_pad,
  uart4_rxd_pad,
  uart4_txd_pad,
  uart3_rxd_pad,
  uart3_txd_pad,
  uart2_rxd_pad,
  uart2_txd_pad,
  uart1_rxd_pad,
  uart1_txd_pad,
  uart0_rxd_pad,
  uart0_txd_pad
};
assign dio_in[42:27] = {mux_ad_pad[7:0], mux_ad_pad[15:8]};
assign dio_in[26:22] = {
  bus_alen_pad,
  bus_dir_pad,
  bus_csn_pad,
  bus_bhen_pad,
  bus_waitn_pad
};
assign dio_in[20:17] = {
  spi_clk_pad,
  spi_miso_pad,
  spi_mosi_pad,
  spi_frm_pad
};
assign dio_in[16:0] = dio_pad[16:0];

integer i;

always @(*) begin
  for (i = 0; i <= 102; i = i + 1) begin
    dio_reg[i] = pad_oe[i] ? pad_o[i] : 1'bz;
  end
end

always @(*) begin
  pad_o = dio;
  pad_oe = dio_oe;

  fpga_irqs = 16'h0000;
  /* irq0: XUART
   * irq1: CAN
   * irq2: 2nd CAN
   * irq3: PC/104 irq 5
   * irq4: PC/104 irq 6
   * irq5: PC/104 irq 7
   * irq6-15 reserved
   * These 16 irqs will be remapped to Linux irqs by the kernel.
   */

  /* Primary CAN port overrides dio 15 and 16 */
  if (en_can) begin
    pad_o[15] = can_tx;
    pad_oe[16:15] = 2'b01;
    fpga_irqs[1] = !can_irqn;
  end

  /* Secondary CAN port overrides dio 10 and 11 */
  if (en_can2) begin
    pad_o[10] = can2_tx;
    pad_oe[11:10] = 2'b01;
    fpga_irqs[2] = !can2_irqn;
  end

  /* SPI core overrides DIO 17-20 */
  if (en_spi) begin
    pad_o[17] = spi_csn[0];
    pad_o[18] = spi_so;
    pad_o[20] = spi_sck;
    pad_oe[20:17] = 4'b1011;
  end

  /* ADC core overrides DIO 6 and 7.  It may also override DIO 8 or DIO 29 */
  if (en_adc) begin
    pad_o[7:6] = 2'b00;
    pad_oe[7] = !adc_scl;
    pad_oe[6] = !adc_sda;
    if (an_sel_sel == 2'b01) begin
      pad_o[8] = an_sel;
      pad_oe[8] = 1'b1;
    end else if (an_sel_sel == 2'b10) begin
      pad_o[29] = an_sel;
      pad_oe[29] = 1'b1;
    end
  end

  /* touchscreen overrides DIO 30 to 34 */
  if (en_touch) begin
    pad_o[34] = touch_clk;
    pad_o[33] = touch_mosi;
    pad_o[31] = 1'b0;
    pad_oe[31] = !touch_csn;
    pad_oe[30] = 1'b0;
    pad_oe[34:32] = 3'b110;
  end

  /* external bus overrides DIO 22-42 */
  if (bus_config[0]) begin // config bit 0 = bus enable
    pad_o[23] = bus_bhen;
    pad_o[24] = bus_csn;
    pad_o[25] = bus_dir;
    pad_o[26] = !bus_ale;
    pad_oe[26:22] = 5'b11110;
    pad_o[42:35] = mux_dat[7:0];
    pad_o[34:27] = mux_dat[15:8];
    pad_oe[42:27] = bus_oe ? 16'hffff : 16'h0000;
    fpga_irqs[5:3] = dio_pad[2:0];
    pad_oe[2:0] = 3'b000;
  end

  /* WARNING: UART numbering is all off by one. */
  if (xuart_active[7:0] != 8'h00) fpga_irqs[0] = xuart_irq;
  xuart_rx = 8'hff;

  xuart_rx[0] = uart0_rxd_pad;
  if (xuart_active[0]) begin
    pad_o[48] = xuart_tx_q[0];
    pad_oe[49:48] = 2'b01;
    if (en_txen[0]) begin
      pad_o[12] = xuart_txen_q[0];
      pad_oe[12] = 1'b1;
    end
  end

  xuart_rx[1] = uart1_rxd_pad;
  if (xuart_active[1]) begin
    pad_o[50] = xuart_tx_q[1];
    pad_oe[51:50] = 2'b01;
    if (en_txen[1]) begin
      pad_o[8] = xuart_txen_q[1];
      pad_oe[8] = 1'b1;
    end
  end

  xuart_rx[2] = uart2_rxd_pad;
  if (xuart_active[2]) begin
    pad_o[52] = xuart_tx_q[2];
    pad_oe[53:52] = 2'b01;
    if (en_txen[2]) begin
      pad_o[10] = xuart_txen_q[2];
      pad_oe[10] = 1'b1;
    end
  end

  xuart_rx[3] = uart3_rxd_pad;
  if (xuart_active[3]) begin
    pad_o[54] = xuart_tx_q[3];
    pad_oe[55:54] = 2'b01;
    if (en_txen[3]) begin
      pad_o[13] = xuart_txen_q[3];
      pad_oe[13] = 1'b1;
    end
  end

  xuart_rx[4] = uart4_rxd_pad;
  if (xuart_active[4]) begin
    pad_o[56] = xuart_tx_q[4];
    pad_oe[57:56] = 2'b01;
    if (en_txen[4]) begin
      pad_o[14] = xuart_txen_q[4];
      pad_oe[14] = 1'b1;
    end
  end

  xuart_rx[5] = uart5_rxd_pad;
  if (xuart_active[5]) begin
    pad_o[58] = xuart_tx_q[5];
    pad_oe[59:58] = 2'b01;
    if (en_txen[5]) begin
      pad_o[7] = xuart_txen_q[5];
      pad_oe[7] = 1'b1;
    end
  end

  xuart_rx[6] = dio_pad[13];

  if (en_bbclk) begin
    pad_o[3] = count_12mhz[2];
    pad_oe[3] = 1'b1;
  end

end

/****************************************************************************
 * Master address decode
 ****************************************************************************/

reg [7:0] base_100;

/*
64 KB FPGA address space:
start   stop    usage
-----   ----    -----
0x8000  0xFFFF  external bus access
0x5400          XUART IO registers
0x5000          touchscreen core
0x4F00          2nd CAN core
0x4E00          DMA controller
0x4D00          SD core
0x4C00          CAN core
0x4800          SPI core
0x4400          ADC core (MCP3428)
0x4000          syscon registers
0x0000  0x3FFF  16KB blockram access

*/
always @(*) begin
  
  sramwbs1_en = ts4740_decodes[0];
  //sramwbs2_en = 1'b0;
  buswbs_en = 1'b0;
  xuwbs_en = ts4740_decodes[2];
  tswbs_en = ts4740_decodes[3];
  canwbs_en = ts4740_decodes[4];
  can2wbs_en = ts4740_decodes[10];
  spiwbs_en = 1'b0;
  adcwbs_en = 1'b0;
  scwbs_en = 1'b0;
  lmramwbs_en = 1'b0;
  sdwbs1_en = 1'b0;
  dmawbs0_en = 1'b0;
  dmawbs1_en = 1'b0;
  dmawbs2_en = 1'b0;
  dmawbs3_en = 1'b0;
  norwbs_en = 1'b0;

  cpuwbm62_dat_i = 16'hxxxx;
  cpuwbm62_ack_i = cpuwbm62_cyc_o && cpuwbm62_stb_o;

  // 100MHz cores will not use decodes in LM32 design.

  if (ts4740_decodes[0]) begin
    cpuwbm62_dat_i = sramwbs1_dat16;
    cpuwbm62_ack_i = sramwbs1_ack_o;
  end else if (ts4740_decodes[2]) begin
    cpuwbm62_dat_i = xuartwbs_dat_o;
    cpuwbm62_ack_i = xuartwbs_ack_o;
  end else if (ts4740_decodes[3]) begin
    cpuwbm62_dat_i = tswbs_dat_o;
    cpuwbm62_ack_i = tswbs_ack_o;
  end else if (ts4740_decodes[4] && can_opt) begin
    cpuwbm62_dat_i = canwbs_dat_o;
    cpuwbm62_ack_i = canwbs_ack_o;
  end else if (ts4740_decodes[10] && can2_opt) begin
    cpuwbm62_dat_i = can2wbs_dat_o;
    cpuwbm62_ack_i = can2wbs_ack_o;
  end 

  cpuwbm_dat_i = 32'hxxxxxxxx;
  cpuwbm_ack_i = cpuwbm_cyc_o && cpuwbm_stb_o;
  
  base_100 = cpuwbm_adr_o[15:8];

  if (cpuwbm_adr_o[16]) begin
    lmramwbs_en = 1'b1;
    cpuwbm_dat_i = lmramwbs_dat_o;
    cpuwbm_ack_i = lmramwbs_ack_o;
  end else if (cpuwbm_adr_o[15]) begin
    buswbs_en = 1'b1;
    cpuwbm_dat_i = {buswbs_dat_o, buswbs_dat_o};
    cpuwbm_ack_i = buswbs_ack_o;
  end else if (base_100 == 8'h40) begin
    scwbs_en = 1'b1;
    cpuwbm_dat_i = {scwbs_dat_o, scwbs_dat_o};
    cpuwbm_ack_i = scwbs_ack_o;
  end else if (base_100 == 8'h44) begin
    adcwbs_en = 1'b1;
    cpuwbm_dat_i = {adcwbs_dat_o, adcwbs_dat_o};
    cpuwbm_ack_i = adcwbs_ack_o;
  end else if (base_100 == 8'h48) begin
    spiwbs_en = 1'b1;
    cpuwbm_dat_i = {spiwbs_dat_o, spiwbs_dat_o};
    cpuwbm_ack_i = spiwbs_ack_o;
  end else if (base_100 == 8'h4d) begin
    sdwbs1_en = 1'b1;
    cpuwbm_dat_i = sdwbs1_dat_o;
    cpuwbm_ack_i = sdwbs1_ack_o;
  end else if (cpuwbm_adr_o[15:4] == 12'h4e0) begin
    dmawbs0_en = 1'b1;
    cpuwbm_dat_i = dmawbs0_dat_o;
    cpuwbm_ack_i = dmawbs0_ack_o;
  end else if (cpuwbm_adr_o[15:4] == 12'h4e4) begin
    dmawbs1_en = 1'b1;
    cpuwbm_dat_i = dmawbs1_dat_o;
    cpuwbm_ack_i = dmawbs1_ack_o;
  end else if (cpuwbm_adr_o[15:4] == 12'h4e8) begin
    dmawbs2_en = 1'b1;
    cpuwbm_dat_i = dmawbs2_dat_o;
    cpuwbm_ack_i = dmawbs2_ack_o;
  end else if (cpuwbm_adr_o[15:4] == 12'h4ec) begin
    dmawbs3_en = 1'b1;
    cpuwbm_dat_i = dmawbs3_dat_o;
    cpuwbm_ack_i = dmawbs3_ack_o;
  end else if (base_100 == 8'h58) begin
    norwbs_en = 1'b1;
    cpuwbm_dat_i = {norwbs_dat_o, norwbs_dat_o};
    cpuwbm_ack_i = norwbs_ack_o;
  end

end

endmodule




