⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 risc8_asm.pl

📁 这是一篇关于8位RISC CPU设计的文章
💻 PL
📖 第 1 页 / 共 2 页
字号:
#! /usr/local/bin/perl5 
#-------------------------------------------------------------------------------
#
#          (C) COPYRIGHT 2000 S.Aravindhan 
#
# This program is free software; you can redistribute it and/or
# modify it provided this header is preserved on all copies.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# 
# Author   : S.Aravindhan
# File     : risc8_asm.pl
# Abstract : Assemble for risc8 processor.
#
# History:
# ============================================================================
# 02/06/2000  arvind   1.0      Initial Release
# ============================================================================

 printf("Risc8 Assembler Version 1.0\n");

 $usage = "
 Usage: risc8_asm.pl -f asm_file_name[.asm]  <-cpp> <-i directory>\n ";
 
 $Examples = "Examples:
   risc8_asm.pl -h 
   risc8_asm.pl -f math
   risc8_asm.pl -f math.asm
   risc8_asm.pl -f math -cpp 
   risc8_asm.pl -f math -cpp -i ../include_files \n";

 $error1 = "
 Usage: Missing assembly file \n";
 $error2 = "
 Usage: Missing include directory \n";

 #----------------------------
 # Parse the arguments 
 #----------------------------
 if($ARGV[0] =~ /-h|-help/i || $#ARGV > 4)
   { die ($usage.$Examples);}

 $mem_init_value = "xx";
 $invoke_preprocessor = 0; 
 $found_include = 0;
 $found_asm = 0;
 $k = 0;
 while($k <= $#ARGV) {
   if($ARGV[$k] eq "-f") {
     if($#ARGV < ($k +1)) { die ($error1.$usage.$Examples);}
     $asm1 = $ARGV[$k +1 ]; $k=$k+2; $found_asm = 1;}
   elsif($ARGV[$k] eq "-cpp") {
     $invoke_preprocessor = 1; $k = $k +1; }
   elsif($ARGV[$k] eq "-i") {
     if($#ARGV < ($k +1)) { die ($error2.$usage.$Examples);}
     $include_dir = $ARGV[$k +1 ]; $k=$k+2; $found_include = 1;}
   else { die ($usage.$Examples);}
   }
 if($found_asm == 0) {die ($error1.$usage.$Examples);}

 $asm = $asm1;   # strip .asm, if specified
 $asm =~ s/\.asm$//g;   # strip .asm, if specified
 $asm_file = $asm . '.asm';
 $lst_file = $asm . '.lst';
 $hex_file = $asm . '.hex';
 $mem_file = $asm . '.mem';
 $tmp_file = $asm . '.tmppp';

 if($invoke_preprocessor == 1) {
    $asm_file = $asm1 . "_cpped";
   if($found_include == 0) {
     system("cpp -i $asm1 -o  $asm_file");}
   else { system("cpp -i $asm1 -I $include_dir -o $asm_file"); }
   } 

 # Open the Files
 open (ASM_F, "$asm_file")  or die ("Can't open $asm_file: $!\n");
 open (MEM_F, ">$mem_file") or die ("Can't open $mem_file: $!\n");
 open (TMP_F, ">$tmp_file") or die ("Can't open $tmp_file: $!\n");
 open (HEX_F, ">$hex_file") or die ("Can't open $hex_file: $!\n");
 #open (LST_F, ">$lst_file") or die ("Can't open $lst_file: $!\n");

 #----------------------------------------------------------
 # hash table to group instructions according to operands 
 #----------------------------------------------------------
 %opcode_type = (
   # Type 1: OP Rn
   "add" => 1, "adc" => 1, "sub" => 1, "sbc" => 1, "inc" => 1, "dec" => 1, 
   "cmp" => 1, "and" => 1, "or"  => 1, "xor" => 1, "not" => 1, "shl" => 1, 
   "shr" => 1, "subr" => 1, "psh" => 1, "pop" => 1, "umul" => 1, "udiv" => "1",

   # Type 2: OP An
   "ldr" =>  2, "str" =>  2, "inca" => 2, "deca" => 2, "jmp" =>  2,

   # Type 3: OP 
   "ret" =>  3, "ror" =>  3, "rorc" => 3, "asr" =>  3, "nop" => "3",
   "rdps" => "3", "wrps" => "3",

   # Type 4: OP xx  yy 
   "mov" => 4,
  
   # Type 5: OP An #offset8 
   "ldo" => 5, "sto" => 5,

   # Type 6: OP Rn #imm8 
   "ldi" => 6,

   # Type 7: OP CON #offset8 
   "jmpr" => 7,
  
   # Type 8: OP CON #addr16 
   "jmpa" => 8, "jmps" => 8,
  
   # Type 9: OP Rn #addr16 
   "lda" => 9, "sta" => 9,

   # Type 10: Special assembler directives
   "end" => 10, "org" => 10, "dcb" => 10, "dmem" => 10, "define" => 10, 
   
   # Type 11: Pseudo instructions
   "pmov" => 11,

   );
 
 #----------------------------------------------------
 # Hash table for the nemonics to opcode translation 
 #----------------------------------------------------
 %opcode_value = (
   # Type 1: OP Rn
   "add" => "00000", "adc" => "00001", "sub" => "00010", "sbc" => "00011", 
   "inc" => "00100", "dec" => "00101", "cmp" => "00110", "and" => "01000", 
   "or"  => "01001", "xor" => "01010", "not" => "01011", "shl" => "01100", 
   "shr" => "01101", "udiv" => "01110", "psh" => "10010", "pop" => "10011", 
   "umul" => "11000", "subr" => "00111",

   # Type 2: OP An
   "ldr"  => "101000", "str" =>  "101001", "inca" => "101100", 
   "deca" => "101101", "jmp" =>  "101110",
    
   # Type 3: OP 
   "ret" => "10111100", "ror" => "10111101", "rorc" => "10111110", 
   "asr" => "10111111", "rdps" => "01111001", "wrps"  => "01111000",
   "nop" => "01111010",

   # Type 4: OP xx  yy 
   "mov_R0_Rn"  => "10000",  "mov_Rn_R0"  => "10001",
   "mov_sp_An"  => "101010", "mov_An_sp"  => "101011",
  
   # Type 5: OP An #offset8 
   "ldo" => "110010", "sto" => "110011",

   # Type 6: OP Rn #imm8 
   "ldi" => "11010",

   # Type 7: OP CON #offset8 
   "jmpr" => "11011",
  
   # Type 8: OP CON #addr16 
   "jmpa" => "11100", "jmps" => "11101",
  
   # Type 9: OP Rn #addr16 
   "lda" => "11110", "sta" => "11111",
   );

 #---------------------------------------
 # Hash table for register translation 
 #----------------------------------------
 %reg_map = (
   "r0" => "000", "r1" => "001", "r2" => "010", "r3" => "011", 
   "r4" => "100", "r5" => "101", "r6" => "110", "r7" => "111",
   "a0" => "00",  "a1" => "01",  "a2" => "10",  "a3" => "11",
   );

 #------------------------------------------
 # Hash table for jmp condition translation 
 #-------------------------------------------
 %condition_map = (
   "eq" => "000", "ne" => "001", "gt" => "010", "lt" => "011",
   "cs" => "100", "cc" => "101", "ns" => "110", "al" => "111",
   );

 #------------------------------------------
 # Hash table for binary to hex translation 
 #------------------------------------------
 %bin2_hex = (
   "0000" => "0", "0001" => "1", "0010" => "2", "0011" => "3",
   "0100" => "4", "0101" => "5", "0110" => "6", "0111" => "7",
   "1000" => "8", "1001" => "9", "1010" => "a", "1011" => "b",
   "1100" => "c", "1101" => "d", "1110" => "e", "1111" => "f",
   );

 #-------------------------------------------------------------------
 # First pass: Parse the assembly file and generate a temp. file 
 #-------------------------------------------------------------------
 $error = 0;
 $address = 0;
 $line_no = 0;

 while ($line = <ASM_F>)
   {
   chop $line;
   $line_o = $line;        # save the original line
   $line =~ s/;.*//;       # strip the comments 
   $line_org = $line;
   $line =~ tr/A-Z/a-z/;   # convert to lowercase
   $line_no = $line_no + 1;

   $opcode = "";
   $start = 0; 
   @word = split " ", $line; 
   if($#word == -1) {next;} # empty line
  
   # process the defines 
   for($i=0; $i <= $#word; $i = $i+1) {
     if($valid_subs{$word[$i]} == 1) { #print $word[$i], $subs_value{$word[$i]};
       $word[$i] = $subs_value{$word[$i]};
       }
     } 

   # check for label
   if($word[0] =~ /:$/) { 
     $label = $word[0];
     $label =~ s/://g;
     $addr_label{$label} = $address; 
     $valid_label{$label} = 1; 
     #printf("LAB= %x %x\n", $addr_label{$label}, $address);
     if($#word == 0) { next;}
     else {$start = 1;}
     if($opcode_type{$word[$start]} < 1 and $opcode_type{$word[$start]} > 9) {
       printf("Error: Syntax error \"%s\" at line %d: %s\n", $word[$start],
                                                        $line_no, $line_o);
       $error = $error + 1;
       }
     }

   # else it should match a key word
   if($opcode_type{$word[$start]} == 0) {
     printf("Error: Syntax error \"%s\" at line %d: %s\n", $word[0], $line_no,
                                                                      $line_o);
     $error = $error + 1;
     }

   #----------------
   # Type 1: Op Rn
   #----------------
   elsif($opcode_type{$word[$start]} == 1) {
     check_argument_count($#word, ($start+1));
     check_data_register($word[$start+1]);
     $opcode = $opcode_value{$word[$start]} . $reg_map{$word[$start+1]};
     printf TMP_F ("opcode=%s\n", $opcode);
     $address = $address + 1;
     }

   #----------------
   # Type 2; OP An
   #----------------
   elsif($opcode_type{$word[$start]} == 2) {
     check_argument_count($#word, ($start+1));
     check_address_register($word[$start+1]);
     $opcode = $opcode_value{$word[$start]} . $reg_map{$word[$start+1]};
     printf TMP_F ("opcode=%s\n", $opcode);
     $address = $address + 1;
     }

   #----------------
   # Type 3; OP 
   #----------------
   elsif($opcode_type{$word[$start]} == 3) {
     check_argument_count($#word, $start);
     $opcode = $opcode_value{$word[$start]};
     printf TMP_F ("opcode=%s\n", $opcode);
     $address = $address + 1;
     }

   #--------------------------------------------------------------------------
   # Type 4; Mov ; Special case, since MOV doesn't produce one unique opcode
   #--------------------------------------------------------------------------
   elsif($opcode_type{$word[$start]} == 4) {
     check_argument_count($#word, ($start+2));
     check_mov_registers($word[$start+1]);
     check_mov_registers($word[$start+2]);
     if($word[$start+1] eq "sp") {                              # mov sp An
       check_address_register($word[$start+2]);
       $opcode = $opcode_value{mov_sp_An} . $reg_map{$word[$start+2]};
       }
     elsif($word[$start+1] =~ /^(a0|a1|a2|a3)$/) {                 # mov An sp
       if($word[$start+2] ne "sp") {
         printf("Error: Invalid move argument \"%s\" at line %d: %s\n", 
                               $word[$start+2], $line_no, $line_o);
         $error = $error + 1;
         }
       else { $opcode = $opcode_value{mov_An_sp} . $reg_map{$word[$start+1]};}
       }
     elsif(($word[$start+1] =~ /^(r0|r1|r2|r3|r4|r5|r6|r7)$/) and  # mov Rn, R0 
           ($word[$start+2] eq "r0")) {
       $opcode = $opcode_value{"mov_Rn_R0"} . $reg_map{$word[$start+1]};
       }
     elsif(($word[$start+2] =~ /^(r0|r1|r2|r3|r4|r5|r6|r7)$/) and  # mov R0 Rn 
           ($word[$start+1] eq "r0")) {
       $opcode = $opcode_value{"mov_R0_Rn"} . $reg_map{$word[$start+2]};
       }
     else {
       printf("Error: Invalid mov arguments at line %d: %s\n", 
                                           $line_no, $line_o);
       $error = $error + 1;
       }
     printf TMP_F ("opcode=%s\n", $opcode);
     $address = $address + 1;
     }

   #--------------------------
   # Type 5;  OP An #offset8
   #--------------------------
   elsif($opcode_type{$word[$start]} == 5) {
     check_argument_count($#word, ($start+2));
     check_address_register($word[$start+1]);
     $opcode = $opcode_value{$word[$start]} . $reg_map{$word[$start+1]};
     printf TMP_F ("opcode=%s\n", $opcode);
     ($status, $off) = extract_byte($word[$start+2]);
     if($status == 0) { printf  TMP_F ("byte=%x\n", $off); }
     else {  $error = $error + 1;
       printf("Error: Invalid argument \"%s\" at line %d\n", $off, $line_no);}
     $address = $address + 2;
     }

   #-----------------------
   # Type 6;  OP Rn #imm8
   #-----------------------
   elsif($opcode_type{$word[$start]} == 6) {
     check_argument_count($#word, ($start+2));
     check_data_register($word[$start+1]);
     $opcode = $opcode_value{$word[$start]} . $reg_map{$word[$start+1]};
     printf TMP_F ("opcode=%s\n", $opcode);
     ($status, $imm) = extract_byte($word[$start+2]);
     if($status == 0) {printf  TMP_F ("byte=%x\n", $imm);}
     else { $error = $error + 1; 
       printf("Error: Invalid ldi argument \"%s\" at line %d\n", $imm, $line_no);}
     #elsif($status == 2) {
     # printf TMP_F ("b_label=%s#4#%d#5#%d\n", $imm, $line_no, ($address + 1));}
     $address = $address + 2;
     }

   #---------------------------
   # Type 7;  OP Con #offset8
   #---------------------------
   elsif($opcode_type{$word[$start]} == 7) {
     check_argument_count($#word, ($start+2));
     check_condition($word[$start+1]);
     $opcode = $opcode_value{$word[$start]} . $condition_map{$word[$start+1]};
     printf TMP_F ("opcode=%s\n", $opcode);
     ($status, $off) = extract_byte($word[$start+2]);
     if($status == 0) { printf  TMP_F ("byte=%x\n", $off);}
     elsif($status == 2) {
       printf  TMP_F ("b_label=%s#4#%d#5#%d\n", $off,$line_no, ($address + 1));}
     $address = $address + 2;
     }

   #--------------------------
   # Type 8;  OP Con #addr16
   #--------------------------
   elsif($opcode_type{$word[$start]} == 8) {
     check_argument_count($#word, ($start+2));
     check_condition($word[$start+1]);
     $opcode = $opcode_value{$word[$start]} . $condition_map{$word[$start+1]};
     printf TMP_F ("opcode=%s\n", $opcode);
     ($status, $off) = extract_word($word[$start+2]);
     if($status == 0) { printf  TMP_F ("word=%x\n", $off);}
     elsif($status == 2) { 
       printf  TMP_F ("w_label=%s#4#%d#5#%d\n", $off,$line_no, ($address + 2));}
     $address = $address + 3;
     }

   #--------------------------
   # Type 9;  OP Rn #addr16
   #--------------------------
   elsif($opcode_type{$word[$start]} == 9) {
     check_argument_count($#word, ($start+2));
     check_data_register($word[$start+1]);
     $opcode = $opcode_value{$word[$start]} . $reg_map{$word[$start+1]};
     printf TMP_F ("opcode=%s\n", $opcode);
     ($status, $off) = extract_word($word[$start+2]);
     if($status == 0) { printf  TMP_F ("word=%x\n", $off);}
     elsif($status == 2) { 
       printf  TMP_F ("w_label=%s#4#%d#5#%d\n", $off,$line_no, ($address + 2));}
     $address = $address + 3;
     }

   #-----------------------------------
   # Type 10: assembler directives
   #-----------------------------------
   elsif($opcode_type{$word[0]} == 10) {
     if($word[$start] eq "org") {                          # org
       check_argument_count($#word, 1);
       $address = extract_addr($word[1]);
       printf  TMP_F ("@%x\n", $address);
       } 
     elsif($word[$start] eq "end") {last;}
     elsif($word[$start] eq "define") {                    # define
       check_argument_count($#word, 2);
       $subs_value{$word[$start+1]} = $word[$start+2]; 
       $valid_subs{$word[$start+1]} = 1; 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -