#![no_main]
#![no_std]

extern crate log;
use log::debug;
use stm32h7xx_hal::{pac, prelude::*, spi};

use cortex_m;
use cortex_m::asm::nop;
use cortex_m_rt::entry;

use firmware::flash::flash_ice40_fpga;

#[path = "util/logger.rs"]
mod logger;

#[entry]
fn main() -> ! {

	let mut cp = cortex_m::Peripherals::take().unwrap();
	let dp = pac::Peripherals::take().unwrap();

	let pwr = dp.PWR.constrain();
	let vos = pwr.freeze();

	let rcc = dp.RCC.constrain();
	let ccdr = rcc
		.sys_ck(400.mhz())
		.pll1_q_ck(48.mhz())
		.pll1_r_ck(400.mhz())   // for TRACECK
		.freeze(vos, &dp.SYSCFG);

	unsafe {
		logger::enable_itm(&dp.DBGMCU, &mut cp.DCB, &mut cp.ITM);
	}
	
	let delay = cp.SYST.delay(ccdr.clocks);

	let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
	let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
	let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
	let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);

    // gpiob.pb3.into_alternate_af0().set_speed(Speed::VeryHigh);

	logger::init();
	
	debug!("Flashing configuration bitstream to iCE40 HX8K on Humpback.");

	// Using SPI_1 alternate functions (af5)
	let fpga_sck = gpiob.pb3.into_alternate_af5();
	let fpga_sdo = gpiob.pb4.into_alternate_af5();
	let fpga_sdi = gpiob.pb5.into_alternate_af5();

	// Setup SPI_SS_B and CRESET_B
	let fpga_ss = gpioa.pa4.into_push_pull_output();
	let fpga_creset = gpiof.pf3.into_open_drain_output();

	// Setup CDONE
	let fpga_cdone = gpiod.pd15.into_pull_up_input();

	// Setup SPI interface
	let fpga_cfg_spi = dp.SPI1.spi(
		(fpga_sck, fpga_sdo, fpga_sdi),
		spi::MODE_3,
		12.mhz(),
		ccdr.peripheral.SPI1,
		&ccdr.clocks,
	);

	// Pre-load the configuration bytes
	let config_data = include_bytes!("../build/top.bin");

	flash_ice40_fpga(fpga_cfg_spi, fpga_ss, fpga_creset, fpga_cdone, delay, config_data).unwrap();

	loop {
		nop();
	}
}