#!/usr/bin/perl

# Syntaxe particulière de l'assembleur perl pour motorola 68HC11 : 
# ----------------------------------------------------------------
#	1)	notation hexa. des addresses précédée de "0h" ou "#0h"	
#	2)	notation en minuscule pour les fonct.
#	3)	tjs laisser un espace après ":" 
#		pour les lignes du type"nom_boucle: fonct"
#	4)	mode DIR (8bits) inclu dans mode EXT (16bits) 

# Definition des variables

$i=0;
$j=0;
$k=0;
$x=0;
$ind=0;

# Initialisation du logiciel

print "Fichier en assembleur .asm (sans l'extension) : ";
chop($fich_in=<STDIN>);
print "Le fichier de sortie hexadécimal sera : $fich_in.hex\n";
print "Le fichier de sortie binaire sera : $fich_in.bin\n";

# Routine principale

$fich_out="$fich_in";

open (DATA,"<$fich_in.asm");
open (OUT,">$fich_in.tmp");

@tab=<DATA>;
$x=scalar(@tab);

#########################################################################
# Mise en mémoire des labels de boucle                                  #
#				(1ere passe)                            #
#########################################################################

while ($i<$x+1) 
{
@boucle = split(/\s+/,@tab[$i]);
	if (@boucle[0]=~/./ and @boucle[0]!~/;/) {
			$boucleb=substr @boucle[0],0,(length @boucle[0])-1;
			push @boucleb,$boucleb;
			}
$i++;
}
$i=0;

#########################################################################
# Crétion d'un fichier hex. avec repérage des appels de boucles par n°  #
#				(2ieme passe)                           #
#########################################################################

while ($i<$x+1)
{

#
# Mise en mémoire de l'addresse du label des boucles 
####################################################

@boucle = split(/\s+/,@tab[$i]);
	if (@boucle[0]=~/./ and @boucle[0]!~/;/) {
			push @ind,$ind;
			$j++;
			push @j,$j;
			}
#
# traitement des lignes du type "fonct #0haddr" (mode IMM)
##########################################################

if (@tab[$i]=~/#0h/ and @tab[$i]!~/,[x,y]/i) {
	@mot = split(/\s+/,@tab[$i]);
	foreach $motb (@mot) {
		if ($motb=~/;/) {goto CONT;}
		if ($motb!~/#0h/ and $motb=~/./ and $motb!~/:/) {
				&opcode_IMM;
				print OUT "$opcode_IMM"; $ind++;
			}
		if ($motb=~/^#0h/) { 
			$addr=substr $motb,3;
			$addr1=substr $addr,0,2;
			$addr2=substr $addr,2,4; 
			chomp($addr1);
			chomp($addr2);
			print OUT " \U$addr1 "; $ind++; 
			if ($addr2=~/./) {
				print OUT "\U$addr2 "; $ind++;}
			}
	}
}

#
# traitement des lignes du type "fonct 0haddr" (mode EXT et DIR)
################################################################

if (@tab[$i]=~/0h/ and @tab[$i]!~/,[x,y]/i and @tab[$i]!~/#/) {
	@mot = split(/\s+/,@tab[$i]);
	foreach $motb (@mot) {
		if ($motb=~/;/) {goto CONT;}
		if ($motb!~/0h/ and $motb=~/./ and $motb!~/:/) {
				&opcode_EXT;
				print OUT "$opcode_EXT"; $ind++;
			}
		if ($motb=~/^0h/) { 
			$addr=substr $motb,2;
			$addr1=substr $addr,0,2;
			$addr2=substr $addr,2,4; 
			chomp($addr1);
			chomp($addr2);
			print OUT " \U$addr1 "; $ind++; 
			if ($addr2=~/./) {
				print OUT "\U$addr2 "; $ind++;}
			}
	}
}

#
# traitement des lignes du type "fonct 0haddr,x" (mode IND)
###########################################################

if (@tab[$i]=~/,[x,y]/i and @tab[$i]=~/0h/ and @tab[$i]!~/,[x,y],/i) { 
	@mot = split(/\s+/,@tab[$i]);
	foreach $motb (@mot) {
		if ($motb=~/;/) {goto CONT;}
		if ($motb!~/0h/ and $motb=~/./ and $motb!~/:/) {
			&opcode_IND; 
			print OUT "$opcode_IND"; $ind++;
		}
                if ($motb=~/0h/) {
                        $addr=substr $motb,2;
                        $addr1=substr $addr,0,2;
			$addr2=substr $addr,2,4; 
			chomp($addr1);
			chomp($addr2);
			print OUT " \U$addr1 "; $ind++;
                        }
	}
}

#
# traitement des lignes du type "fonct 0haddr1,x,#0haddr2" (mode IND)
#####################################################################

if (@tab[$i]=~/,[x,y],#0h/i) { 
	@mot = split(/\s+/,@tab[$i]);
	foreach $motb (@mot) {
		if ($motb=~/;/) {goto CONT;}
		if ($motb!~/0h/ and $motb=~/./ and $motb!~/:/) {
			&opcode_IND; 
			print OUT "$opcode_IND"; $ind++;
		}
                if ($motb=~/0h*/) {
                        $addr=substr $motb,2,10;
                        $addr1=substr $addr,0,2;
			$addr2=substr $addr,8;
                        chomp($addr1);
                        chomp($addr2);
                        print OUT " \U$addr1 "; $ind++;
			print OUT "\U$addr2 "; $ind++;
                        }
		$k=0;
		foreach $boucleb (@boucleb) {
		if ($motb=~/$boucleb$/) { print OUT "-",$k+1," ";$ind++;}
		$k++;
			}
		}
}

#
# traitement des lignes du type "fonct mot" (mode REL et mode INH)
##################################################################

if (@tab[$i]!~/0h/ and @tab[$i]!~/,[x,y]/i) { 
	@mot = split(/\s+/,@tab[$i]);
	$test=0;
	$test2=0;
	foreach $motb (@mot) {
		if ($motb=~/;/) {goto CONT2;}
		if ($motb=~/./) {$test2++;}
	}
	CONT2:
	foreach $motb (@mot) {
		if ($motb=~/;/) {goto CONT;}
		if ($motb=~/./ and $motb!~/:/ and $test==O) {
				$test=1;
				if ($test2>1) {
			&opcode_REL; print OUT "$opcode_REL "; $ind++;}
				else { 
			&opcode_INH; print OUT "$opcode_INH "; $ind++;}
		}
		$k=0;
		foreach $boucleb (@boucleb) {
		if ($motb=~/$boucleb$/) { print OUT " -",$k+1," ";$ind++;}
		$k++;
		}
	}
}

CONT:
$i++;
}

close OUT;
close DATA;

############################################################################
# Ecriture du code hex final (remplacement des addr. des appels de boucle) #
#				(3ieme passe)                              #
############################################################################

$i=0;
$k=1;
open (DATA,"<$fich_in.tmp");
open (OUT,">$fich_out.hex");

@hex=<DATA>;
@hexbis = split(/\s+/,@hex[0]);
$x=scalar(@hexbis);

if ($j!="0") {
	printf OUT "FF ";
	while ($i<$x+1) {
		foreach $k (@j) {
			if (@hexbis[$i]=="-$k") {
				@hexbis[$i]="";
				if ($i>@ind[$k-1]) { 
				printf OUT "\U%x",255-$i+@ind[$k-1];}
				if ($i<@ind[$k-1]) {
				printf OUT "\U%x",@ind[$k-1]-$i-1;}
				} 
			}
	printf OUT "@hexbis[$i] ";
	$i++;
	}
}

close OUT;
close DATA;

$i=0;
$j=0;

###########################################################################
# Binarisation du code hexadécimal                                        #
#				(4ieme passe)                             #
###########################################################################

open (DATA,"<$fich_out.hex");
open (OUT,">$fich_out.bin");

@tab=<DATA>;
$x=scalar(@tab);

while ($i<$x+1) {
        chomp(@tab[$i]);
        @tab2=split / /,@tab[$i];
        $i++;
        push @tab3,@tab2;
}

$x=scalar(@tab3);

$i=0;
$bin="";

while ($i<$x) {
$val=hex @tab3[$i];
$bin=pack 'C',$val;
print OUT $bin;
$i++;

close OUT;
close DATA;

}

#
# Effacement du fichier temporaire $fich_in.tmp
###############################################################

system ("rm $fich_in.tmp");


#
# Base de donnée des fonctions du microcontroleur 68HC11 (F1)
#

sub opcode_IMM
{
%map = ("adca","89","adcb","C9","adda","8B","addb","CB","addd","C3","anda","84","andb","C4","bita","85","bitb","C5","cmpa","81","cmpb","C1","cpd","83","cpx","8C","cpy","8C","eora","88","eorb","C8","ldab","C6","ldaa","86","ldd","CC","lds","8E","ldx","CE","ldy","CE","oraa","8A","orab","CA","sbca","82","sbcb","C2","suba","80","subb","C0","subd","83");
$opcode_IMM=$map{$motb};
chomp($opcode_IMM);
}

sub opcode_IND
{
%map = ("adca","A9","adcb","E9","adda","AB","addb","EB","addd","E3","anda","A4","andb","E4","asl","68","asr","67","bclr","1D","bita","A5","bitb","E5","brclr","1F","brset","1E","bset","1C","clr","6F","cmpa","A1","cmpb","E1","com","63","cpd","A3","cpx","AC","cpy","AC","dec","6A","eora","A8","eorb","E8","inc","6C","jmp","6E","jsr","AD","ldab","E6","ldaa","A6","ldd","EC","lds","AE","ldx","EE","ldy","EE","lsl","68","lsr","64","neg","60","oraa","AA","orab","EA","rol","69","ror","66","sbca","A2","sbcb","E2","staa","A7","stab","E7","std","ED","sts","AF","stx","EF","sty","EF","suba","A0","subb","E0","subd","A3","tst","6D");
$opcode_IND=$map{$motb};
chomp($opcode_IND);
}

sub opcode_REL
{
%map = ("brn","21","bra","20","bne","26","beq","27","bsr","8D","bpl","2A","bcs","25","bcc","24","bge","2C","bgt","2E","bhi","22","bhs","24","ble","2F","blo","25","bls","23","blt","2D","bmi","2B","bvc","28","bvs","29");
$opcode_REL=$map{$motb};
chomp($opcode_REL);
}

sub opcode_INH
{
%map = ("rts","39","inca","4C","iny","08","wai","3E","xgdx","8F","xgdy","8F","aba","1B","abx","3A","aby","3A","asla","48","aslb","58","asld","05","asra","47","asrb","57","cba","11","clc","0C","cli","0E","clra","4F","clrb","5F","clv","OA","coma","43","comb","53","daa","19","deca","4A","decb","5A","des","34","dex","09","dey","09","fdiv","03","idiv","02","incb","5C","ins","31","inx","08","lsla","48","lslb","58","lsld","05","lsra","44","lsrb","54","lsrd","04","mul","3D","nega","40","negb","50","nop","01","psha","36","pshb","37","pshx","3C","pshy","3C","pula","32","pulb","33","pulx","38","puly","38","rola","49","rolb","59","rora","46","rorb","56","rti","3B","sba","10","sec","0D","sei","0F","sev","0B","stop","CF","swi","3F","tab","16","tap","06","tba","17","test","00","tpa","07","tsta","4D","tstb","5D","tsx","30","tsy","30","txs","35","tys","35");
$opcode_INH=$map{$motb};
chomp($opcode_INH);
}

sub opcode_EXT
{
%map = ("adca","B9","adcb","F9","adda","BB","addb","FB","addd","F3","anda","B4","andb","F4","asl","78","asr","77","bita","B5","bitb","F5","clr","7F","cmpa","B1","cmpb","F1","com","73","cpd","B3","cpx","BC","cpy","BC","dec","7A","eora","B8","eorb","F8","inc","7C","jmp","7E","jsr","BD","ldab","F6","ldaa","B6","ldd","FC","lds","BE","ldx","FE","ldy","FE","lsl","78","lsr","74","neg","70","oraa","BA","orab","FA","rol","79","ror","76","sbca","B2","sbcb","F2","staa","B7","stab","F7","std","FD","sts","BF","stx","FF","sty","FF","suba","B0","subb","F0","subd","B3","tst","7D");
$opcode_EXT=$map{$motb};
chomp($opcode_EXT);
}

sub opcode_DIR
{
%map = ("a","a");
$opcode_DIR=$map{$motb};
chomp($opcode_DIR);
}