#!/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; }