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

from torii.build                        import Attrs, Clock, Connector, Pins, Resource
from torii.build.run                    import BuildProducts
from torii.platform.resources.display   import Display7SegResource, VGAResource
from torii.platform.resources.interface import PS2Resource
from torii.platform.resources.memory    import SDCardResources, SDRAMResource
from torii.platform.resources.user      import ButtonResources, LEDResources, SwitchResources
from torii.platform.vendor.altera       import AlteraPlatform

__all__ = (
	'DE0CVPlatform',
)

class DE0CVPlatform(AlteraPlatform):
	device      = '5CEBA4' # Cyclone V 49K LEs
	package     = 'F23'    # FBGA-484
	speed       = 'C7'
	default_clk = 'clk50'

	pretty_name = 'DE0-CV'
	description = 'terasIC DE0-CV Altera Cyclone V Development Board'

	resources   = [
		Resource(
			'clk50', 0, Pins('M9', dir = 'i'),  Clock(50e6), Attrs(io_standard = '3.3-V LVTTL')
		),
		Resource(
			'clk50', 1, Pins('H13', dir = 'i'), Clock(50e6), Attrs(io_standard = '3.3-V LVTTL')
		),
		Resource(
			'clk50', 2, Pins('E10', dir = 'i'), Clock(50e6), Attrs(io_standard = '3.3-V LVTTL')
		),
		Resource(
			'clk50', 3, Pins('V15', dir = 'i'), Clock(50e6), Attrs(io_standard = '3.3-V LVTTL')
		),

		*LEDResources(
			pins = 'AA2 AA1 W2 Y3 N2 N1 U2 U1 L2 L1', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		*ButtonResources(
			pins = 'U7 W9 M7 M6', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		*SwitchResources(
			pins = 'U13 V13 T13 T12 AA15 AB15 AA14 AA13 AB13 AB12',
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		Display7SegResource(
			0,
			a = 'U21', b = 'V21', c = 'W22', d = 'W21', e = 'Y22', f = 'Y21', g = 'AA22', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		Display7SegResource(
			1,
			a = 'AA20', b = 'AB20', c = 'AA19', d = 'AA18', e = 'AB18', f = 'AA17', g = 'U22', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		Display7SegResource(
			2,
			a = 'Y19', b = 'AB17', c = 'AA10', d = 'Y14', e = 'V14', f = 'AB22', g = 'AB21', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		Display7SegResource(
			3,
			a = 'Y16', b = 'W16', c = 'Y17', d = 'V16', e = 'U17', f = 'V18', g = 'V19', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		Display7SegResource(
			4,
			a = 'U20', b = 'Y20', c = 'V20', d = 'U16', e = 'U15', f = 'Y15', g = 'P9', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		Display7SegResource(
			5,
			a = 'N9', b = 'M8', c = 'T14', d = 'P14', e = 'C1', f = 'C2', g = 'W19', invert = True,
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		VGAResource(
			0,
			r = 'A9 B10 C9 A5',
			g = 'L7 K7 J7 J8',
			b = 'B6 B7 A8 A7',
			hs = 'H8', vs = 'G8',
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		PS2Resource(
			0, # Keyboard
			clk = 'D3', dat = 'G2', attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		PS2Resource(
			1, # Mouse
			clk = 'E2', dat = 'G1', attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		*SDCardResources(
			0,
			clk = 'H11', cmd = 'B11', dat0 = 'K9', dat1 = 'D12', dat2 = 'E12', dat3 = 'C11',
			attrs = Attrs(io_standard = '3.3-V LVTTL')
		),
		SDRAMResource(
			0,
			clk = 'AB11', cke = 'R6', cs_n = 'U6', we_n = 'AB5', ras_n = 'AB6', cas_n = 'V6',
			ba = 'T7 AB7', a = 'W8 T8 U11 Y10 N6 AB10 P12 P7 P8 R5 U8 P6 R7',
			dq = 'Y9 T10 R9 Y11 R10 R11 R12 AA12 AA9 AB8 AA8 AA7 V10 V9 U10 T9', dqm = 'U12 N8',
			attrs = Attrs(io_standard = '3.3-V LVCMOS')
		),
	]
	connectors  = [
		Connector(
			'j', 1,
			'N16 B16 M16 C16 D17 K20 K21 K22 M20 M21 '
			'-   -   N21 R22 R21 T22 N20 N19 M22 P19 '
			'L22 P17 P16 M18 L18 L17 L19 K17 -   -   '
			'K19 P18 R15 R17 R16 T20 T19 T18 T17 T15 '
		),
		Connector(
			'j', 2,
			'H16 A12 H15 B12 A13 B13 C13 D13 G18 G17 '
			'-   -   H18 J18 J19 G11 H10 J11 H14 A15 '
			'J13 L8  A14 B15 C15 E14 E15 E16 -   -   '
			'F14 F15 F13 F12 G16 G15 G13 G12 J17 K16 '
		),
	]

	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:
			check_call([
				quartus_pgm, '--haltcc', '--mode', 'JTAG',
				'--operation', 'P;' + bitstream_filename
			])


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