# SPDX-License-Identifier: BSD-2-Clause

from torii.build                        import Attrs, Clock, Connector, Pins, Resource, Subsignal
from torii.build.run                    import BuildProducts
from torii.platform.resources.interface import SPIResource, UARTResource
from torii.platform.resources.user      import ButtonResources, LEDResources, SwitchResources
from torii.platform.vendor.altera       import AlteraPlatform

__all__ = (
	'DE10NanoPlatform',
)

# The MiSTer platform is built around the DE10-Nano; if you update one you should update the other.
class DE10NanoPlatform(AlteraPlatform):
	device      = '5CSEBA6' # Cyclone V 110K LEs
	package     = 'U23'     # UBGA-484
	speed       = 'I7'
	default_clk = 'clk50'

	pretty_name = 'DE10-Nano'
	description = 'terasIC DE10-Nano Altera Cyclone V Development Board'

	resources   = [
		Resource(
			'clk50', 0, Pins('V11', dir = 'i'), Clock(50e6), Attrs(io_standard = '3.3-V LVTTL')
		),
		Resource(
			'clk50', 1, Pins('Y13', dir = 'i'), Clock(50e6), Attrs(io_standard = '3.3-V LVTTL')
		),
		Resource(
			'clk50', 2, Pins('E11', dir = 'i'), Clock(50e6), Attrs(io_standard = '3.3-V LVTTL')
		),
		*LEDResources(
			pins = 'W15 AA24 V16 V15 AF26 AE26 Y16 AA23',
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		*ButtonResources(
			pins = 'AH17 AH16', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		*SwitchResources(
			pins = 'Y24 W24 W21 W20',
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		# Arduino header
		UARTResource(
			0,
			rx = 'AG13', tx = 'AF13',
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		# LTC2308 analogue-to-digital converter
		SPIResource(
			0,
			cs_n = 'U9', clk = 'V10', copi = 'AC4', cipo = 'AD4',
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		# ADV7513 HDMI transmitter
		# Note this has a lot of input formats for tx_d, but this defaults to RGB24
		Resource(
			'adv7513', 0,
			Subsignal('tx_d_r', Pins('AD12 AE12 W8 Y8 AD11 AD10 AE11 Y5', dir = 'o')),
			Subsignal('tx_d_g', Pins('AF10 Y4 AE9 AB4 AE7 AF6 AF8 AF5', dir = 'o')),
			Subsignal('tx_d_b', Pins('AE4 AH2 AH4 AH5 AH6 AG6 AF9 AE8', dir = 'o')),
			Subsignal('tx_clk', Pins('AG5', dir = 'o')),
			Subsignal('tx_de', Pins('AD19', dir = 'o')),
			Subsignal('tx_hs', Pins('T8', dir = 'o')),
			Subsignal('tx_vs', Pins('V13', dir = 'o')),
			Subsignal('tx_int', Pins('AF11', dir = 'i')),
			Subsignal('i2s0', Pins('T13', dir = 'o')),
			Subsignal('mclk', Pins('U11', dir = 'o')),
			Subsignal('lrclk', Pins('T11', dir = 'o')),
			Subsignal('sclk', Pins('T12', dir = 'o')),
			Subsignal('scl', Pins('U10', dir = 'io')),
			Subsignal('sda', Pins('AA4', dir = 'io')),
			Attrs(io_standard = '3.3-V LVTTL')
		),
	]
	connectors  = [
		# Located on the top of the board, above the chip.
		Connector(
			'gpio', 0,
			'V12  E8   W12  D11  D8   AH13 AF7  AH14 AF4  AH3  '
			'-    -    AD5  AG14 AE23 AE6  AD23 AE24 D12  AD20 '
			'C12  AD17 AC23 AC22 Y19  AB23 AA19 W11  -    -    '
			'AA18 W14  Y18  Y17  AB25 AB26 Y11  AA26 AA13 AA11 '
		),
		# Located on the bottom of the board.
		Connector(
			'gpio', 1,
			'Y15  AC24 AA15 AD26 AG28 AF28 AE25 AF27 AG26 AH27 '
			'-    -    AG25 AH26 AH24 AF25 AG23 AF23 AG24 AH22 '
			'AH21 AG21 AH23 AA20 AF22 AE22 AG20 AF21 -    -    '
			'AG19 AH19 AG18 AH18 AF18 AF20 AG15 AE20 AE19 AE17 '
		),
		Connector(
			'arduino', 0,
			'AG13 AF13 AG10 AG9  U14  U13  AG8  AH8  '
			'AF17 AE15 AF15 AG16 AH11 AH12 AH9  AG11 '
			'AH7  -    -    -    -    -    -    -    '
		),
	]

	def toolchain_program(self, products: BuildProducts, name: str) -> None:
		from os         import environ
		from subprocess import check_call

		quartus_pgm = environ.get('QUARTUS_PGM', 'quartus_pgm')
		with products.extract(f'{name}.sof') as bitstream_filename:
			# The @2 selects the second device in the JTAG chain, because this chip
			# puts the ARM cores first.
			check_call([
				quartus_pgm, '--haltcc', '--mode', 'JTAG',
				'--operation', 'P;' + bitstream_filename + '@2'
			])


if __name__ == '__main__':
	from ...test.blinky import Blinky
	DE10NanoPlatform().build(Blinky(), do_program = True)
