SimpleProcessorCore/scripts/asm.pl

398 lines
7.5 KiB
Perl
Executable File

#!/usr/bin/perl
#
# Small assembler for the Simple Processor Core
#
my $nr_instr_bytes = 4;
my $nr_opcode_bits = 6;
my $nr_reg_bits = 5;
my $startaddr = -1;
# mnemonnic to opcode conversion
my %opcodes = (
'shl' => 0x00,
'shr' => 0x01,
'sto' => 0x02,
'loa' => 0x03,
'add' => 0x04,
'sub' => 0x05,
'addc' => 0x06,
'subc' => 0x07,
'or' => 0x08,
'and' => 0x09,
'xor' => 0x0A,
'not' => 0x0B,
'jpz' => 0x0C,
'jpc' => 0x0D,
'jmp' => 0x0E,
'lui' => 0x0F,
'jmc' => 0x10,
'ret' => 0x11,
'hlt' => 0x3F
);
#---------------------------------------------------------------------------
# main program
#---------------------------------------------------------------------------
my $filename = $ARGV[0];
my %labels;
# check if file exists
if ( !-e $filename ) {
die("file does not exist\n");
}
open my $src, "<" . $filename;
my $addr = $startaddr;
my $lines = 0;
my @instructions;
my $valid;
while ( my $line = <$src> ) {
$line =~ /^(\S+)\s(.*)$/;
my $INSTR = $1;
my $REST = $2;
$addr++;
$lines++;
my $opc = $opcodes{"$INSTR"};
my $label = "";
$opc = $opc << 26;
$valid = 1;
if ( $INSTR eq "shl" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for shl in line $lines\n");
}
}
elsif ( $INSTR eq "shr" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for shr in line $lines\n");
}
}
elsif ( $INSTR eq "sto" ) {
if ( $REST =~ /^\$(.*),(.*)$/ ) {
my $dst = $1;
$dst =~ s/\s//g;
$dst = $dst << 16;
$opc = $opc | $dst;
my $imm = $2;
$imm =~ s/\s//g;
$opc = $opc | $imm;
}
else {
die("ASM: wrong number of parameters for sto in line $lines\n")
;
}
}
elsif ( $INSTR eq "loa" ) {
if ( $REST =~ /^\$(.*),(.*)$/ ) {
my $dst = $1;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
my $imm = $2;
$imm =~ s/\s//g;
$opc = $opc | $imm;
}
else {
die("ASM: wrong number of parameters for sto in line $lines\n")
;
}
}
elsif ( $INSTR eq "add" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for add in line $lines\n");
}
}
elsif ( $INSTR eq "sub" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for sub in line $lines\n");
}
}
elsif ( $INSTR eq "addc" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for addc in line $lines\n");
}
}
elsif ( $INSTR eq "subc" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for subc in line $lines\n");
}
}
elsif ( $INSTR eq "or" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for or in line $lines\n");
}
}
elsif ( $INSTR eq "and" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for and in line $lines\n");
}
}
elsif ( $INSTR eq "xor" ) {
if ( $REST =~ /^[\s\$]+(.*),[\s\$]+(.*),[\s\$]+(.*)$/ ) {
my $dst = $1;
my $op1 = $2;
my $op2 = $3;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
$op1 =~ s/\s//g;
$op1 = $op1 << 16;
$opc = $opc | $op1;
$op2 =~ s/\s//g;
$op2 = $op2 << 11;
$opc = $opc | $op2;
}
else {
die("ASM: wrong number of parameters for xor in line $lines\n");
}
}
elsif ( $INSTR eq "not" ) {
if ( $REST =~ /^[\s\$]+(.*)$/ ) {
my $dst = $1;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
}
else {
die("ASM: wrong number of parameters for add in line $lines\n");
}
}
elsif ( $INSTR eq "jpz" ) {
$label = $REST;
}
elsif ( $INSTR eq "jpc" ) {
$label = $REST;
}
elsif ( $INSTR eq "jmc" ) {
$label = $REST;
my $dst = 31;
$dst = $dst << 21;
$opc = $opc | $dst;
}
elsif ( $INSTR eq "jmp" ) {
$label = $REST;
}
elsif ( $INSTR eq "hlt" ) {
}
elsif ( $INSTR eq "lui" ) {
if ( $REST =~ /^\$(.*),(.*)$/ ) {
my $dst = $1;
$dst =~ s/\s//g;
$dst = $dst << 21;
$opc = $opc | $dst;
my $imm = $2;
$imm =~ s/\s//g;
$opc = $opc | $imm;
}
else {
die("ASM: wrong number of parameters for lui in line $lines\n")
;
}
}
elsif ( $INSTR eq "ret" ) {
my $op1=31;
$op1 = $op1 << 16;
$opc = $opc | $op1;
}
elsif ( $INSTR =~ /^(.*):$/ ) {
$labels{$1} = $addr;
$addr--;
$valid = 0;
}
else {
$addr--;
$valid = 0;
}
if ( $valid == 1 ) {
$line =~ s/\n//;
my $instruction = {};
$instruction->{addr} = $addr;
$instruction->{opc} = $opc;
$instruction->{comment} = $line;
$instruction->{label} = $label;
if ($line =~/jmc/) {
print "-" .$instruction->{label}."-\n";
}
push( @instructions, $instruction );
}
}
close $src;
# correct labels
for my $i (@instructions) {
if ( $i->{label} =~ /\S+/ ) {
for my $l ( keys %labels ) {
if ( $i->{label} eq $l ) {
$i->{opc} = $i->{opc} | $labels{$l};
}
}
}
}
for my $i (@instructions) {
if ($ARGV[1] eq "-vhdl") {
printf("%4s \t => B\"%.32b\", --%s\n ",$i->{addr}, $i->{opc}, $i->{comment});
}
elsif($ARGV[1] eq "-raw") {
printf("%.32b\n",$i->{opc});
}else {
printf( "%4s %.32b #%s\n", $i->{addr}, $i->{opc}, $i->{comment} );
}
}