#!/usr/bin/perl -w
use strict;
use v5.010;

use XML::Simple qw(:strict);
use Data::Dumper;

my $infile  = shift;
my $outfile = shift;
my $data;

# supported chips
my $chips = {
	'E16G301' => {
		'cores' => [4, 4],
		'sram'  => '0x8000',
	},
	'E64G401' => {
		'cores' => [8, 8],
		'sram'  => '0x8000',
	},
};

# parse arguments
if(!$infile || !$outfile) {
	say "Usage: hdf2arch <infile> <outfile>";
	say "\tinfile:  Epiphany HDF file";
	say "\toutfile: DOL XML file";
	say "\tSpecify '-' to use standard input/output";
	exit 1;
}

# parse HDF file
my $num_chips;		# number of chips in system
my @chiplist;		# information about current chip
my $chipnum = -1;	# current chip
my $num_emems;		# number of emems in system
my @ememlist;		# information about current emem
my $ememnum  = -1;	# current emem
open (FH, "<$infile") or die("Can't open $infile.");
while(<FH>) {
	next if /\/\/.*/;	# skip comment lines

	# globals - ignore them for now
	#$data->{'version'} = $1 if(/^PLATFORM_VERSION\s+(\S+)\s*$/);
	#$data->{'regbase'} = $1 if(/^ESYS_REGS_BASE\s+(\S+)\s*$/);


	# number of chips
	if(/^NUM_CHIPS\s+(\S+)\s*$/) {
		if(!$num_chips) {
			$num_chips = $1;
		} else {
			say STDERR "Warning: multiple 'NUM_CHIPS' entries!";
		}
	}

	# per-chip information
	if(/^CHIP\s+(\S+)\s*$/) {
		my $id = $1;
		if($chips->{$id}) {
			$chipnum++;
			$chiplist[$chipnum]->{'id'} = $id;
			$chiplist[$chipnum]->{'rows'} =
				$chips->{$id}->{'cores'}->[0];
			$chiplist[$chipnum]->{'cols'} =
				$chips->{$id}->{'cores'}->[1];
			$chiplist[$chipnum]->{'sram'} = $chips->{$id}->{'sram'};
		} else {
			say STDERR "Warning: unknown CHIP '$id' - ignoring!";
			next;
		}
	}
	$chiplist[$chipnum]->{'row'} = $1 if(/^CHIP_ROW\s+(\S+)\s*$/);
	$chiplist[$chipnum]->{'col'} = $1 if(/^CHIP_COL\s+(\S+)\s*$/);

	# number of emems
	if(/^NUM_EXT_MEMS\s+(\S+)\s*$/) {
		if(!$num_emems) {
			$num_emems = $1;
		} else {
			say STDERR "Warning: multiple 'NUM_EXT_EMEM' entries!";
		}
	}


	# per-emem information
	if(/^EMEM\s+(\S+)\s*$/) {
		my $id = $1;
		if($id eq 'ext-DRAM') {
			$ememnum++;
			$ememlist[$ememnum]->{'id'} = $id;
		} else {
			say STDERR "Warning: unknown EMEM '$id' - ignoring!";
			next;
		}
	}
	$ememlist[$ememnum]->{'base'} = $1 if(/^EMEM_BASE_ADDRESS\s+(\S+)\s*$/);
	$ememlist[$ememnum]->{'epi'}  = $1 if(/^EMEM_EPI_BASE\s+(\S+)\s*$/);
	$ememlist[$ememnum]->{'size'} = $1 if(/^EMEM_SIZE\s+(\S+)\s*$/);
	$ememlist[$ememnum]->{'type'} = $1 if(/^EMEM_TYPE\s+(\S+)\s*$/);
}

# some simple consistency checks
if($num_chips != scalar @chiplist) {
	say STDERR "Warning: NUM_CHIPS does not match the number of CHIPs!";
}
if($num_emems != scalar @ememlist) {
	say STDERR "Warning: NUM_EXT_MEMS does not match the number of EMEMs!";
}

# generate output data
$data->{'processor'} = [];
$data->{'memory'}    = [];

# host processor, epiphany cores and their memories
push $data->{'processor'}, {
	'name' => 'arm_0',
	'type' => 'RISC',
	'configuration' => [
		{ 'name'  => 'cores',
		  'value' => '2' },
	],
};

for my $chip(@chiplist) {
	for my $row (0..$chip->{'rows'}-1) {
		for my $col (0..$chip->{'cols'}-1) {
			my $r = $chip->{'row'} + $row;
			my $c = $chip->{'col'} + $col;
			push $data->{'processor'}, {
				'name' => "core_${r}_${c}",
				'type' => 'RISC',
				'configuration' => [
					{ 'name'  => 'type',
					  'value' => $chip->{'id'}, },
				],
			};

			push $data->{'memory'}, {
				'name' => "mem_${r}_${c}",
				'type' => 'RAM',
				'configuration' => [
					{ 'name'  => 'size',
					  'value' => $chip->{'sram'}, },
				],
			};
		}
	}
}

# external memories
for my $idx(0..(scalar @ememlist-1)) {
	push $data->{'memory'}, {
		'name' => "shm_$idx",
		'type' => "RAM",
		'configuration' => [
			{ 'name'  => 'size',
			  'value' => $ememlist[$idx]->{'size'} },
			{ 'name'  => 'type',
			  'value' => $ememlist[$idx]->{'type'} },
			{ 'name'  => 'base',
			  'value' => $ememlist[$idx]->{'base'} },
			{ 'name'  => 'epibase',
			  'value' => $ememlist[$idx]->{'epi'} },
		],
	};
}

#say Dumper $data;

# write data in xml format
$data->{'name'} = 'Adapteva Parallella Architecture';
$data->{'xmlns'} = 'http://www.tik.ee.ethz.ch/~shapes/schema/ARCHITECTURE';
$data->{'xmlns:xsi'} = 'http://www.w3.org/2001/XMLSchema-instance';
$data->{'xsi:schemaLocation'} = 'http://www.tik.ee.ethz.ch/~shapes/schema/ARCHITECTURE http://www.tik.ee.ethz.ch/~shapes/schema/architecture.xsd';
my $outxml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".
		XMLout({'architecture' => $data},
			KeyAttr => [],
			KeepRoot => 1);

if($outfile eq '-') {
	say $outxml;
	exit 0;
} else {
	open (FH, ">$outfile");
	say FH $outxml;
	close (FH);
}
