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

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

# argument evaluation
my $infile  = shift;
my $outfile = shift;
if(!$infile || !$outfile) {
	say "Usage: bsp2arch.pl <infile> <outfile>";
	say "\tinfile:  Epiphany Platform Description";
	say "\toutfile: DOL Architecture Specification";
	say "\tUse \'-\' for standard input/output.";
	exit 1;
}

# parse input xml file
my $input = XMLin($infile, ForceArray => '1', KeyAttr => ['chips']);

# output content
my @processors;
my @memories;
my @hw_channels;

# per-core definitions
foreach my $chips ($input->{'chips'}->[0]->{'chip'}) {
	foreach my $chip (@$chips) {
		$chip->{'id'} =~ /\((\d+),(\d+)\)/;
		my @origin    = ($1, $2);
		my $version   = $chip->{'version'};

		foreach my $row (1..$chip->{'rows'}) {
			foreach my $col (1..$chip->{'cols'}) {
				my $newrow  = $origin[0] + $row - 1;
				my $newcol  = $origin[1] + $col - 1;
				my $memsize = $chip->{'core_memory_size'};
				$memsize = "0x8000" unless($memsize);

				# eCore
				push @processors, {
					'name' => "core_${newrow}_${newcol}",
					'type' => 'RISC',
					'configuration' => [
						{ 'name'  => 'version',
						  'value' => $version },
					],
				};

				# eCore local memory
				push @memories, {
					'name' => "mem_${newrow}_${newcol}",
					'type' => 'RAM',
					'configuration' => [
						{ 'name'  => 'size',
						  'value' => $memsize },
					],
				};

				# eCore register file
				push @memories, {
					'name' => "regs_${newrow}_${newcol}",
					'type' => 'REG',
					'configuration' => [
						{ 'name'  => 'size',
						  'value' => '0x7FF' },
					],
				}
			}
		}
	}
}

# ARM host processor
push @processors, {
	'name' => 'arm_0',
	'type' => 'RISC',
	'configuration' => [
		{ 'name'  => 'cores',
		  'value' => '2' },
	]
};

# external memory
foreach my $banks ($input->{'external_memory'}->[0]->{'bank'}) {
	my $counter = 0;
	foreach my $bank (@$banks) {
		# DOL doesn't need to know the epiphany-internal address
		next if($bank->{'name'} eq 'EPIPHANY_DRAM');

		if($bank->{'name'} eq 'EXTERNAL_DRAM') {
			push @memories, {
				'name' => "emem_${counter}",
				'type' => 'DXM',
				'configuration' => [
					{ 'name'  => 'size',
					  'value' => $bank->{'size'} },
					{ 'name'  => 'start',
					  'value' => $bank->{'start'} }
				]
			};
			next;
			say "Warning: Unknown Extmem $bank->{'name'}!";
		}
	}
}

# TODO: add hw_channels data

# generate XML output
my $output = {
	'architecture' => {
		'xmlns' => "http://www.tik.ee.ethz.ch/~shapes/schema/ARCHITECTURE",
		'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
		'xsi:schemaLocation' => 'http://www.tik.ee.ethz.ch/~shapes/schema/ARCHITECTURE http://www.tik.ee.ethz.ch/~shapes/schema/architecture.xsd',
		'name' => 'Adapteva Parallella Architecture',

		'processor' => \@processors,
		'memory' => \@memories,
		'hw_channel' => \@hw_channels,
	},
};
my $outxml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".
		XMLout($output, KeyAttr => [], KeepRoot => 1);

# save XML output
if($outfile eq '-') {
	print $outxml;
	exit 0;
} else {
	open (FH, ">$outfile");
	print FH $outxml;
	close (FH);
}

