#!/usr/bin/perl
print "Assembler for SISC 0.13 written by George Ho (kyho\@csie.nctu.edu.tw).\n\n";
if($ARGV[0] eq ''|| $ARGV[1] eq '')
{
print "usage:siscasm.pl \n";
exit;
}
if (! -e $ARGV[0])
{
print "Input file doesn't exist!\n";
exit;
}
@all_inst=("LOAD","LDI","STORE","MOVE","ADD","FADD","OR","AND","XOR",
"ROTR","BR","HALT","NOP","GETC","PUTC","GETI","PUTI","GETS","PUTS",
"CMP","JLT","JEQ","JGT","CALL","RET");
@all_direc=("ORG","DB","END");
%num_param=("LOAD"=>2,"LDI"=>2,"STORE"=>2,"MOVE"=>2,"ADD"=>3,
"FADD"=>3,"OR"=>3,"AND"=>3,"XOR"=>3,"ROTR"=>2,"BR"=>2,"HALT"=>0,
"NOP"=>0,"GETC"=>0,"PUTC"=>0,"GETI"=>0,"PUTI"=>0,"GETS"=>1,"PUTS"=>1,
"CMP"=>2,"JLT"=>1,"JEQ"=>1,"JGT"=>1,"CALL"=>1,"RET"=>0);
%inst_class=("LOAD"=>1,"LDI"=>1,"STORE"=>1,"MOVE"=>3,"ADD"=>2,
"FADD"=>2,"OR"=>2,"AND"=>2,"XOR"=>2,"ROTR"=>4,"BR"=>1,"HALT"=>5,
"NOP"=>5,"GETC"=>5,"PUTC"=>5,"GETI"=>5,"PUTI"=>5,"GETS"=>6,"PUTS"=>6,
"CMP"=>3,"JLT"=>7,"JEQ"=>7,"JGT"=>7,"CALL"=>7,"RET"=>5);
%inst_code=("LOAD"=>"1","LDI"=>"2","STORE"=>"3","MOVE"=>"40","ADD"=>"5",
"FADD"=>"6","OR"=>"7","AND"=>"8","XOR"=>"9","ROTR"=>"A","BR"=>"B","HALT"=>"C000",
"NOP"=>"0000","GETC"=>"D000","PUTC"=>"D100","GETI"=>"D200","PUTI"=>"D300",
"GETS"=>"D5","PUTS"=>"D6","CMP"=>"F0","JLT"=>"F1","JEQ"=>"F2","JGT"=>"F3","CALL"=>"E2","RET"=>"E300");
open (IN,$ARGV[0]);
$pc=0; #program counter
%symtab=();
#pass 1
local($temp,@ops,@tmparr,$n);
while()
{
chop;
$temp=$_;
print "{$temp}";
$temp=~s/;.+//g; #delete comments
$temp=~s/\s+$//; #delete ending spaces
if($temp !~/^\s+/) #no leading space -> label or comment
{
if($temp=~/:\s*$/) #ending with ':'
{
$temp=~s/\s//g; #delete space
$temp=~s/://; #delete ':'
$symtab{$temp}=$pc;
next;
}
elsif($temp =~/^;/) #comment
{
next;
}
else
{
if ($temp !~/\s*/)
{
print "warning:$temp !!! Please make blanks in front of commands !!!\n";
}
}
}
else #instructions or directives or comment
{
if($temp=~/^\s+;/) #comment but has leading spaces MODIFIED BY MIGI
{
next;
}
$temp=~s/^\s+//; #delete leading spaces
print "->$temp\n";
#
# MODIFIED BY MIGI
#
@ops=split(' ',$temp); #seperate into opcode and operands
if(&is_inst($ops[0]))
{
$pc+=2;
@tmparr=split(/,/,$ops[1]);
$n=@tmparr;
if($num_param{uc($ops[0])} != $n)
{
print "$temp: $ops[0] must have $num_param{uc($ops[0])} parameters!!\n";
exit;
}
next;
}
if(&is_direc($ops[0]))
{
if(uc($ops[0]) eq "ORG") #change the pc
{
# $pc=ord(pack("H",$ops[1]));
$pc=hex($ops[1]);
print "$temp: the PC is now set to $pc.\n";
next;
}
if(uc($ops[0]) eq "DB") #define bytes
{
@tmparr=split(/,/,$ops[1]);
$n=@tmparr;
$pc+=$n;
}
if(uc($ops[0]) eq "END") #end of the program
{
break; #jump to pass 2
}
}
}
}
print "\n------------\n";
foreach (%symtab)
{
print "$_, ";
}
print "\n------------\n";
#pass 2
close(IN);
open (IN,$ARGV[0]);
open (OUT,">$ARGV[1]");
$pc=0;
while()
{
chop;
$org_line = $_;
$org_line =~ s/\t+/ /g; #change TAB to SPACE
$temp=$org_line;
$temp=~s/;.+//g; #delete ending comments
$temp=~s/\s+$//; #delete ending spaces
if($temp !~/^\s+/) #label or comment -> skip
{
print OUT " ; $org_line\n";
next;
}
else #instructions or directives or comments
{
if($temp=~/^\s+;/) #comment but has leading spaces MODIFIED BY MIGI
{
next;
}
$temp=~s/^\s+//; #delete leading spaces
@ops=split(' ',$temp); #seperate into opcode and operands
if(&is_inst($ops[0]))
{
@tmparr=split(/,/,$ops[1]);
print OUT &process_inst($ops[0],@tmparr)," ;$org_line","\n";
$pc+=2;
next;
}
elsif(&is_direc($ops[0]))
{
if(uc($ops[0]) eq "ORG")
{
# $tmp_pc=ord(pack("H",$ops[1]));
$tmp_pc=hex($ops[1]);
if ($pc > $tmp_pc)
{
print "ORG is too small!!";
exit;
}
for ($i=$pc; $i < $tmp_pc; $i+=2)
{
print OUT "0000\n";
}
$pc = $tmp_pc;
#------------------- ADDED BY MIGI --------------
# print "$temp: the PC is now set to $pc.\n";
next;
}
if(uc($ops[0]) eq "DB")
{
@tmparr=split(/,/,$ops[1]);
$n=@tmparr;
$pc+=$n;
for($i=0;$i<$n;$i++)
{
print OUT $tmparr[$i];
print OUT "\n" if $i%2==1;
}
next;
}
if(uc($ops[0]) eq "END") #end of the program
{
break;
}
}
else
{
print "I don't know: $temp\n";
}
}
}
close(IN);
close(OUT);
print "Last PC = $pc.\n";
sub is_inst
{
local($i,$len);
$len=@all_inst;
for($i=0;$i<$len;$i++)
{
if(@_[0]=~/^$all_inst[$i]$/i)
{
return 1;
}
}
return 0;
}
sub is_direc
{
local($i,$len);
$len=@all_direc;
for($i=0;$i<$len;$i++)
{
if(@_[0]=~/^$all_direc[$i]$/i)
{
return 1;
}
}
return 0;
}
sub process_inst #@_[0]==opcode,@_[1]...=operands
{
local($type,$i,$temp,$convtmp,$offset);
$temp="";
$convtmp="";
$type=$inst_class{uc(@_[0])};
if($type==0)
{
print "@_[0]:No type zero!!!\n";
exit;
}
if($type==1)
{
$temp=$inst_code{uc(@_[0])};
$temp.=reg_conv(@_[1]);
$convtmp=@_[2];
if($convtmp =~/^[0-9A-F][0-9A-F]$/)
{
$temp.=$convtmp;
return $temp;
}
elsif($convtmp =~/^[0-9a-f][0-9a-f]$/)
{
$temp.=$convtmp;
return $temp;
}
else
{
if(@_[2]=~/^@/) #using $pc
{
if(@_[2]=~/[+-]/) #using offset
{
$offset=(split(/[+-]/,@_[2]))[1];
if(@_[2]=~/\+/)
{
$temp.=sprintf("%02X",$pc+$offset);
return $temp;
}
else
{
$temp.=sprintf("%02X",$pc-$offset);
return $temp;
}
}
$temp.=sprintf("%02X",$pc);
return $temp;
}
if( !exists($symtab{@_[2]})) # label not found
{
if(@_[2]=~/[+-]/) #using offset
{
$offset=(split(/[+-]/,@_[2]))[1];
$convtmp=(split(/[+-]/,@_[2]))[0];
if( !exists($symtab{$convtmp})) #still not found
{
print "Label ",$convtmp," is not found!!\n";
exit;
}
if(@_[2]=~/\+/)
{
$temp.=sprintf("%02X",$symtab{$convtmp}+$offset);
return $temp;
}
else
{
$temp.=sprintf("%02X",$symtab{$convtmp}-$offset);
return $temp;
}
}
print "Label ",@_[2]," is not found!!\n";
exit;
}
else #Label found
{
$temp.=sprintf("%02X",$symtab{@_[2]});
return $temp;
}
}
}
if($type==2)
{
$temp=$inst_code{uc(@_[0])};
$temp.=reg_conv(@_[1]);
$temp.=reg_conv(@_[2]);
$temp.=reg_conv(@_[3]);
return $temp;
}
if($type==3)
{
$temp=$inst_code{uc(@_[0])};
$temp.=reg_conv(@_[1]);
$temp.=reg_conv(@_[2]);
return $temp;
}
if($type==4)
{
$temp=$inst_code{uc(@_[0])};
$temp.=reg_conv(@_[1]);
if(@_[2]>7 || @_[2]==0)
{
print "X must be less than 8 in ROTR !!!\n";
exit;
}
$temp.=sprintf("%02X",@_[2]);
return $temp;
}
if($type==5)
{
$temp=$inst_code{uc(@_[0])};
return $temp;
}
if($type==6)
{
$temp=$inst_code{uc(@_[0])};
$convtmp=@_[1];
if($convtmp =~/^[0-9A-F][0-9A-F]$/)
{
$temp.=$convtmp;
return $temp;
}
else
{
if( !exists($symtab{@_[1]} )) # label not found
{
print "Label ",@_[1]," is not found!!\n";
exit;
}
else
{
$temp.=sprintf("%02X",$symtab{@_[1]});
return $temp;
}
}
}
if($type==7) #almost the same as type 6
{
$temp=$inst_code{uc(@_[0])};
$convtmp=@_[1];
local($data);
if($convtmp =~/^[0-9A-F][0-9A-F]$/)
{
$data=$convtmp;
}
else
{
if( !exists($symtab{@_[1]} )) # label not found
{
print "Label ",@_[1]," is not found!!\n";
exit;
}
else
{
$data=sprintf("%02X",$symtab{@_[1]});
}
}
if (hex($data)>=256)
{
$temp=sprintf("%02X",hex($temp)+int(hex($data)/256)*4);
$data=~s/^.//; #remove first letter
}
$temp.=$data;
}
}
sub reg_conv
{
local($temp,$t);
$temp=@_[0];
# if($temp=~/r[0-9]/i || $temp=~/r1[0-5]/i)
if($temp=~/r[0-9a-f]/i || $temp=~/r[0-9A-F]/i)
{
$temp=~s/^r//i;
}
else
{
print "Error: pc=$pc !!! unknown register !!!\n";
exit;
}
# return sprintf("%X",$temp);
return $temp;
}