#!/usr/bin/perl
|
#!/usr/bin/perl
|
################################################################
|
################################################################
|
#Theia, Ray Cast Programable graphic Processing Unit.
|
#Theia, Ray Cast Programable graphic Processing Unit.
|
#Copyright (C) 2010 Diego Valverde (diego.valverde.g@gmail.com)
|
#Copyright (C) 2010 Diego Valverde (diego.valverde.g@gmail.com)
|
#
|
#
|
#This program is free software; you can redistribute it and/or
|
#This program is free software; you can redistribute it and/or
|
#modify it under the terms of the GNU General Public License
|
#modify it under the terms of the GNU General Public License
|
#as published by the Free Software Foundation; either version 2
|
#as published by the Free Software Foundation; either version 2
|
#of the License, or (at your option) any later version.
|
#of the License, or (at your option) any later version.
|
#
|
#
|
#This program is distributed in the hope that it will be useful,
|
#This program is distributed in the hope that it will be useful,
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
#GNU General Public License for more details.
|
#GNU General Public License for more details.
|
#
|
#
|
#You should have received a copy of the GNU General Public #License
|
#You should have received a copy of the GNU General Public #License
|
#along with this program; if not, write to the Free Software
|
#along with this program; if not, write to the Free Software
|
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA #02110-1301, USA.
|
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA #02110-1301, USA.
|
################################################################
|
################################################################
|
$CodePath = $ARGV[0];
|
$CodePath = $ARGV[0];
|
$DefsPath = "aDefinitions.v";
|
$DefsPath = "aDefinitions.v";
|
|
|
|
|
print
|
print
|
"
|
"
|
---------------------------------------------------------------
|
---------------------------------------------------------------
|
|
|
_/_/_/_/_/ _/ _/
|
_/_/_/_/_/ _/ _/
|
_/ _/_/_/ _/_/ _/_/_/
|
_/ _/_/_/ _/_/ _/_/_/
|
_/ _/ _/ _/_/_/_/ _/ _/ _/
|
_/ _/ _/ _/_/_/_/ _/ _/ _/
|
_/ _/ _/ _/ _/ _/ _/
|
_/ _/ _/ _/ _/ _/ _/
|
_/ _/ _/ _/_/_/ _/ _/_/_/
|
_/ _/ _/ _/_/_/ _/ _/_/_/
|
|
|
|
|
---------------------------------------------------------------
|
---------------------------------------------------------------
|
Compiling file '$CodePath'
|
Compiling file '$CodePath'
|
|
|
|
|
";
|
";
|
|
|
$Line = 0;
|
$Line = 0;
|
%Registers;
|
%Registers;
|
%Instructions;
|
%Instructions;
|
%Labels;
|
%Labels;
|
%EntryPoints;
|
%EntryPoints;
|
@EntryKeys;
|
@EntryKeys;
|
$OutputFile = "Instructions.mem";
|
$OutputFile = "Instructions.mem";
|
open OUT, ">$OutputFile" or die "Can't open output file for R/W\n";
|
open OUT, ">$OutputFile" or die "Can't open output file for R/W\n";
|
PopulateRegistersAndInstructionSet();
|
PopulateRegistersAndInstructionSet();
|
GenerateLabels();
|
GenerateLabels();
|
ParseCode();
|
ParseCode();
|
print
|
print
|
"
|
"
|
|
|
Output file: '$OutputFile'
|
Output file: '$OutputFile'
|
|
|
** Compilation successful! **
|
** Compilation successful! **
|
---------------------------------------------------------------
|
---------------------------------------------------------------
|
";
|
";
|
close OUT;
|
close OUT;
|
exit(0);
|
exit(0);
|
|
|
|
|
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
sub PopulateRegistersAndInstructionSet()
|
sub PopulateRegistersAndInstructionSet()
|
{
|
{
|
open DEFINITIONS, $DefsPath or die "'$DefsPath' : $!\n";
|
open DEFINITIONS, $DefsPath or die "'$DefsPath' : $!\n";
|
while ()
|
while ()
|
{
|
{
|
#skip comments and empty lines
|
#skip comments and empty lines
|
next if (m/^([\s|\t]*\/\/)|^(\s*\n).*/);
|
next if (m/^([\s|\t]*\/\/)|^(\s*\n).*/);
|
|
|
if (m/`define\s*(ENTRYPOINT_ADRR_\S*)[\s|\t]+.*\'d(\d+)/)
|
if (m/`define\s*(ENTRYPOINT_ADRR_\S*)[\s|\t]+.*\'d(\d+)/)
|
{
|
{
|
push @EntryKeys, $1;
|
push @EntryKeys, $1;
|
$EntryPoints{$1}= sprintf('%08X',$2);
|
$EntryPoints{$1}= sprintf('%08X',$2);
|
|
|
next;
|
next;
|
}
|
}
|
|
|
if (m/\`define\s*([C|O]REG\_\S*)[\s|\t]+.*\'d(\d+)/ ||
|
if (m/\`define\s*([C|O]REG\_\S*)[\s|\t]+.*\'d(\d+)/ ||
|
m/\`define\s*([R|C]\d+)[\s|\t]+.*\'d(\d+)/)
|
m/\`define\s*([R|C]\d+)[\s|\t]+.*\'d(\d+)/)
|
{
|
{
|
$Registers{$1} = sprintf('%X', $2);
|
$Registers{$1} = sprintf('%X', $2);
|
next;
|
next;
|
}
|
}
|
|
|
if (m/\`define\s*(\S*)[\s|\t]+\`INSTRUCTION_OP_LENGTH\'b([0|1|\_]+)/)
|
if (m/\`define\s*(\S*)[\s|\t]+\`INSTRUCTION_OP_LENGTH\'b([0|1|\_]+)/)
|
{
|
{
|
$Instructions{$1} = $2;
|
$Instructions{$1} = $2;
|
$key = $1;
|
$key = $1;
|
#get rid of the '_' characters
|
#get rid of the '_' characters
|
$Instructions{$key} =~ s/\_//g;
|
$Instructions{$key} =~ s/\_//g;
|
#convert to hexadecimal
|
#convert to hexadecimal
|
$Instructions{$key}= sprintf('%X', oct("0b$Instructions{$key}"));
|
$Instructions{$key}= sprintf('%X', oct("0b$Instructions{$key}"));
|
next;
|
next;
|
}
|
}
|
if (m/\`define\s*(\S*)[\s|\t]+32\'d(\d+)/)
|
if (m/\`define\s*(\S*)[\s|\t]+32\'d(\d+)/)
|
{
|
{
|
$Registers{$1} = $2;
|
$Registers{$1} = $2;
|
}
|
}
|
|
|
|
|
}
|
}
|
|
|
$InstructionCount = 0;
|
$InstructionCount = 0;
|
close DEFINITIONS;
|
close DEFINITIONS;
|
#Ok, add some extra stuff
|
#Ok, add some extra stuff
|
$Registers{'VOID'} = 0;
|
$Registers{'VOID'} = 0;
|
$Registers{'RT_TRUE'} = 1;
|
$Registers{'RT_TRUE'} = 1;
|
$Registers{'RT_FALSE'} = 0;
|
$Registers{'RT_FALSE'} = 0;
|
}
|
}
|
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
sub GenerateLabels()
|
sub GenerateLabels()
|
{
|
{
|
|
|
my $IP = 0;
|
my $IP = 0;
|
open CODE, $CodePath or die "'$CodePath': $!\n";
|
open CODE, $CodePath or die "'$CodePath': $!\n";
|
while ()
|
while ()
|
{
|
{
|
#skip comments and empty lines
|
#skip comments and empty lines
|
next if (m/^([\s|\t]*\/\/)|^(\s*\n).*/);
|
next if (m/^([\s|\t]*\/\/)|^(\s*\n).*/);
|
$Line++;
|
$Line++;
|
#print "$_ &&&& $IP\n";
|
#print "$_ &&&& $IP\n";
|
|
|
if (m/^(ENTRYPOINT_ADRR_\S+)\:.*\n/)
|
if (m/^(ENTRYPOINT_ADRR_\S+)\:.*\n/)
|
|
|
{
|
{
|
#print "$1\n";
|
#print "$1\n";
|
die "Error line $Line: Entry point not defined $1\n" if (not defined $EntryPoints{$1});
|
die "Error line $Line: Entry point not defined $1\n" if (not defined $EntryPoints{$1});
|
$EntryPoints{$1} = sprintf("%06X",$IP | 0x8000);#sprintf("%08X",$Line-1 | 0x8000);
|
$EntryPoints{$1} = sprintf("%06X",$IP | 0x8000);#sprintf("%08X",$Line-1 | 0x8000);
|
print "Implemented @ 0x$EntryPoints{$1} --> $1\n";
|
print "Implemented @ 0x$EntryPoints{$1} --> $1\n";
|
next;
|
next;
|
}
|
}
|
|
|
if (m/[\s|\t]*(\S+)\:.*\n/)
|
if (m/[\s|\t]*(\S+)\:.*\n/)
|
{
|
{
|
# print "$1 " . sprintf("%08X",$InstructionCount | 0x8000) . "\n";
|
# print "$1 " . sprintf("%08X",$InstructionCount | 0x8000) . "\n";
|
$Labels{$1} = ($IP | 0x8000);#(($Line-1) | 0x8000); #sprintf("%08X",$Line-1 | 0x8000)
|
$Labels{$1} = ($IP | 0x8000);#(($Line-1) | 0x8000); #sprintf("%08X",$Line-1 | 0x8000)
|
# print "$1 = $Labels{$1}\n";
|
# print "$1 = $Labels{$1}\n";
|
next;
|
next;
|
}
|
}
|
|
|
$IP++;
|
$IP++;
|
$InstructionCount++;
|
$InstructionCount++;
|
}
|
}
|
close CODE;
|
close CODE;
|
$Line = 0;
|
$Line = 0;
|
}
|
}
|
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
sub DecodeInstruction
|
sub DecodeInstruction
|
{
|
{
|
my ($Line,$EntryAddrCount,$OP,@Tokens) = @_;
|
my ($Line,$EntryAddrCount,$OP,@Tokens) = @_;
|
my @D_Tokens;
|
my @D_Tokens;
|
if ( defined $Instructions{$OP}) { $D_OP = hex $Instructions{$OP};
|
if ( defined $Instructions{$OP}) { $D_OP = hex $Instructions{$OP};
|
} else {
|
} else {
|
die "Error Line $Line: undefined instruction '$OP'\n";
|
die "Error Line $Line: undefined instruction '$OP'\n";
|
}
|
}
|
|
|
foreach $Token (@Tokens)
|
foreach $Token (@Tokens)
|
{
|
{
|
next if ($Token eq '');
|
next if ($Token eq '');
|
if ($Token =~ m/(RT_TRUE|RT_FALSE)/)
|
if ($Token =~ m/(RT_TRUE|RT_FALSE)/)
|
{
|
{
|
push @D_Tokens,0;
|
push @D_Tokens,0;
|
push @D_Tokens,0;
|
push @D_Tokens,0;
|
push @D_Tokens,$Registers{$Token};
|
push @D_Tokens,$Registers{$Token};
|
} elsif ($Token =~ m/SWIZZLE.*/){
|
} elsif ($Token =~ m/SWIZZLE.*/){
|
push @D_Tokens,0;
|
push @D_Tokens,0;
|
push @D_Tokens,$Registers{$Token};
|
push @D_Tokens,$Registers{$Token};
|
} elsif (defined $Registers{$Token} ){
|
} elsif (defined $Registers{$Token} ){
|
|
|
push @D_Tokens, hex $Registers{$Token};
|
push @D_Tokens, hex $Registers{$Token};
|
|
|
} elsif (defined $Labels{$Token})
|
} elsif (defined $Labels{$Token})
|
{
|
{
|
# print "$Labels{$Token}\n";
|
# print "$Labels{$Token}\n";
|
push @D_Tokens, ($Labels{$Token}+$EntryAddrCount);
|
push @D_Tokens, ($Labels{$Token}+$EntryAddrCount);
|
}elsif (defined $EntryPoints{$Token}){
|
}elsif (defined $EntryPoints{$Token}){
|
|
|
push @D_Tokens,hex $EntryPoints{$Token};
|
push @D_Tokens,hex $EntryPoints{$Token};
|
} elsif ($Token =~ m/32\'h(.*)/) {
|
} elsif ($Token =~ m/32\'h(.*)/) {
|
#if this is inmmediate value of 32 bits, then insert 0 and then the value
|
#if this is inmmediate value of 32 bits, then insert 0 and then the value
|
push @D_Tokens,0;
|
push @D_Tokens,0;
|
push @D_Tokens, hex $1;
|
push @D_Tokens, hex $1;
|
} else {
|
} else {
|
die "Error Line $Line: undefined token '$Token'\n"
|
die "Error Line $Line: undefined token '$Token'\n"
|
}
|
}
|
}
|
}
|
|
|
return ($D_OP,@D_Tokens);
|
return ($D_OP,@D_Tokens);
|
}
|
}
|
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
sub ParseCode()
|
sub ParseCode()
|
{
|
{
|
|
|
my $ByteCount = ($InstructionCount+$#EntryKeys+1)*2;
|
my $ByteCount = ($InstructionCount+$#EntryKeys+1)*2;
|
print OUT "$ByteCount //Number of ioctects in file\n";
|
print OUT "$ByteCount //Number of ioctects in file\n";
|
print OUT "//--------------------------------------\n";
|
print OUT "//--------------------------------------\n";
|
print OUT "//Subroutine Entry Point Table\n";
|
print OUT "//Subroutine Entry Point Table\n";
|
|
|
my $IP = 0;
|
my $IP = 0;
|
for my $k ( @EntryKeys )
|
for my $k ( @EntryKeys )
|
{
|
{
|
my $foo = (oct("0x$EntryPoints{$k}") & 0x8000) ?
|
my $foo = (oct("0x$EntryPoints{$k}") & 0x8000) ?
|
sprintf("%08X", oct("0x$EntryPoints{$k}")+$#EntryKeys+1) :
|
sprintf("%08X", oct("0x$EntryPoints{$k}")+$#EntryKeys+1) :
|
sprintf("%08X", oct("0x$EntryPoints{$k}")) ;
|
sprintf("%08X", oct("0x$EntryPoints{$k}")) ;
|
print OUT "00000000 $foo\t//$k\n";
|
print OUT "00000000 $foo\t//$k\n";
|
|
|
$IP++;
|
$IP++;
|
}
|
}
|
|
|
print OUT "//--------------------------------------\n";
|
print OUT "//--------------------------------------\n";
|
|
|
open CODE, $CodePath or die "$CodePath: $!\n";
|
open CODE, $CodePath or die "$CodePath: $!\n";
|
while ()
|
while ()
|
{
|
{
|
$Line++;
|
$Line++;
|
#skip comments and empty lines
|
#skip comments and empty lines
|
next if (m/^([\s|\t]*\/\/)|^(\s*\n).*/);
|
next if (m/^([\s|\t]*\/\/)|^(\s*\n).*/);
|
#skip labels
|
#skip labels
|
next if (m/(\S+\:).*\n/);
|
next if (m/(\S+\:).*\n/);
|
#get rid of comments in the same line
|
#get rid of comments in the same line
|
s/\/\/.*\n/\n/g;
|
s/\/\/.*\n/\n/g;
|
|
|
my $OpcodeH,$OpcodeL;
|
my $OpcodeH,$OpcodeL;
|
($OP,$DST,$R1,$R2) = ("","","","");
|
($OP,$DST,$R1,$R2) = ("","","","");
|
#Handle OP DST R1 R2
|
#Handle OP DST R1 R2
|
if (m/^[\s|\t]*(\S+)\s+(\S+)\s*(\S*)\s*(\S*).*\n/)
|
if (m/^[\s|\t]*(\S+)\s+(\S+)\s*(\S*)\s*(\S*).*\n/)
|
{
|
{
|
($OP,$DST,$R1,$R2) = ($1,$2,$3,$4);
|
($OP,$DST,$R1,$R2) = ($1,$2,$3,$4);
|
my @D = DecodeInstruction($Line,$#EntryKeys+1,$OP,($DST,$R1,$R2) );
|
my @D = DecodeInstruction($Line,$#EntryKeys+1,$OP,($DST,$R1,$R2) );
|
|
|
|
|
$OpcodeH = ($D[0] << 16) + $D[1];
|
$OpcodeH = ($D[0] << 16) + $D[1];
|
$OpcodeL = ($D[2] << 16) + $D[3];
|
$OpcodeL = ($D[2] << 16) + $D[3];
|
} else {
|
} else {
|
die "Error: line $Line: incorrect statement '$_'\n";
|
die "Error: line $Line: incorrect statement '$_'\n";
|
}
|
}
|
|
|
printf OUT "%08X",$OpcodeH;
|
printf OUT "%08X",$OpcodeH;
|
printf OUT " %08X",$OpcodeL;
|
printf OUT " %08X",$OpcodeL;
|
print OUT "\t\t// ".sprintf("IP %06X",$IP | 0x8000) . " ($IP): $OP $DST $R1 $R2\n"; $IP++;
|
print OUT "\t\t// ".sprintf("IP %06X",$IP | 0x8000) . " ($IP): $OP $DST $R1 $R2\n"; $IP++;
|
|
|
|
|
}
|
}
|
|
|
close CLOSE;
|
close CLOSE;
|
}
|
}
|
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
|
|
|
|