📄 risc8_asm.pl
字号:
#! /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 + -