You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1773 lines
40 KiB
1773 lines
40 KiB
#!/usr/bin/env perl |
|
|
|
open FILE, "input.bin" or die $!; |
|
|
|
binmode FILE; |
|
|
|
$bytecount = 0; |
|
|
|
|
|
# Addressing modes |
|
# |
|
# 0) (nothing) |
|
# 1) immediate value (#imm) [4,8,16,32] |
|
# 2) compressed direct address (dir) |
|
# 3) direct address (addr16) |
|
# 4) register direct (Ri, RWi, RLi, |
|
# A, AL, SP, PCB, DTB, USB, SSB, ADB, DPR, |
|
# PS, CCR, RP, ILM) |
|
# 5) register indirect (@RWj 0<=j<=3) |
|
# 6) register indirect with post-incrementing (@RWj + 0<=j<=3) |
|
# 7) register indirect with displacement (@RWi + disp8 0<=i<=7) |
|
# (@RWj + disp16 0<=j<=3) |
|
# 8) register indirect with base index (@RW0 + RW7, @RW1 + RW7) |
|
# 9) program counter indirect with displacement (@PC + disp16) |
|
#10) accumulator indirect (@A) |
|
#11) direct I/O (io) |
|
#12) long register indirect with displacement (@RLi + disp8 0<=i<=3) |
|
#13) compressed direct bit address (dir:bp) |
|
#14) I/O direct bit address (io:bp) |
|
#15) direct bit address (addr16:bp) |
|
#16) register list (rlst) |
|
#17) program counter relative branching address (rel) |
|
#18) direct branching address (addr16) |
|
#19) physical direct branching address (addr24) |
|
#20) accumulator indirect branching address (@A) |
|
#21) vector address (#vct) |
|
#22) indirect specification branching address (@ear) |
|
#23) indirect specification branching address (@eam) |
|
|
|
|
|
# Instructions which should terminate disassembly: |
|
# RET |
|
# RETP |
|
# RETI |
|
# BRA |
|
# JMP |
|
# JMPP |
|
# Undefined instruction |
|
|
|
@memory = (); |
|
@targets = (0xff19f6); |
|
$stopat = 0xffc645; |
|
|
|
$baseaddr = 0xff0000; |
|
|
|
%labels = {}; |
|
$labelnum = 0; |
|
|
|
if (open LABELS, "<input.labels") { |
|
while (<LABELS>) { |
|
chomp; |
|
if (($name, $addr) = /(.*): (.*)/) { |
|
$addr = hex $addr; |
|
$labels{$addr} = $name; |
|
if ($name =~ /^L(\d+)$/) { |
|
$labelnum = $1 + 1 if ($1 >= $labelnum); |
|
} |
|
} |
|
} |
|
} |
|
|
|
close LABELS; |
|
|
|
$output = 0; |
|
|
|
%io = ( |
|
0x01 => "PDR1", |
|
0x02 => "PDR2", |
|
0x03 => "PDR3", |
|
0x04 => "PDR4", |
|
0x05 => "PDR5", |
|
0x06 => "PDR6", |
|
0x07 => "PDR7", |
|
0x08 => "PDR8", |
|
0x09 => "PDR9", |
|
0x0A => "PDRA", |
|
0x11 => "DDR1", |
|
0x12 => "DDR2", |
|
0x13 => "DDR3", |
|
0x14 => "DDR4", |
|
0x15 => "DDR5", |
|
0x16 => "ADER", |
|
0x17 => "DDR7", |
|
0x18 => "DDR8", |
|
0x19 => "DDR9", |
|
0x1A => "DDRA", |
|
0x20 => "SMR0", |
|
0x21 => "SCR0", |
|
0x22 => "S[IO]DR0", |
|
0x23 => "SSR0", |
|
0x24 => "SMR1", |
|
0x25 => "SCR1", |
|
0x26 => "S[IO]DR1", |
|
0x27 => "SSR1", |
|
0x28 => "ENIR", |
|
0x29 => "EIRR", |
|
0x2A => "ELVRl", |
|
0x2B => "ELVRh", |
|
0x2C => "ADCSl", |
|
0x2D => "ADCSh", |
|
0x2E => "ADCRl", |
|
0x2F => "ADCRh", |
|
0x30 => "PPGC0", |
|
0x31 => "PPGC1", |
|
0x34 => "PRL0l", |
|
0x35 => "PRL0h", |
|
0x36 => "PRL1l", |
|
0x37 => "PRL1h", |
|
0x38 => "TMCSR0l", |
|
0x39 => "TMCSR0h", |
|
0x3A => "TMR(LR)0l", |
|
0x3B => "TMR(LR)0h", |
|
0x3C => "TMCSR1l", |
|
0x3D => "TMCSR1h", |
|
0x3E => "TMR(LR)1l", |
|
0x3F => "TMR(LR)1h", |
|
0x44 => "SMR2", |
|
0x45 => "SCR2", |
|
0x46 => "S[IO]DR2", |
|
0x47 => "SSR2", |
|
0x48 => "CSCR0", |
|
0x49 => "CSCR1", |
|
0x4A => "CSCR2", |
|
0x4B => "CSCR3", |
|
0x4C => "CSCR4", |
|
0x4D => "CSCR5", |
|
0x4E => "CSCR6", |
|
0x4F => "CSCR7", |
|
0x51 => "CDCR0", |
|
0x53 => "CDCR1", |
|
0x9F => "DIRR", |
|
0xA0 => "LPMCR", |
|
0xA1 => "CKSCR", |
|
0xA5 => "ARSR", |
|
0xA6 => "HACR", |
|
0xA7 => "ECSR", |
|
0xA8 => "WDTC", |
|
0xA9 => "TBTC", |
|
0xB0 => "ICR00", |
|
0xB1 => "ICR01", |
|
0xB2 => "ICR02", |
|
0xB3 => "ICR03", |
|
0xB4 => "ICR04", |
|
0xB5 => "ICR05", |
|
0xB6 => "ICR06", |
|
0xB7 => "ICR07", |
|
0xB8 => "ICR08", |
|
0xB9 => "ICR09", |
|
0xBA => "ICR10", |
|
0xBB => "ICR11", |
|
0xBC => "ICR12", |
|
0xBD => "ICR13", |
|
0xBE => "ICR14", |
|
0xBF => "ICR15", |
|
# Specific to LC2412 |
|
0xC0 => "KEY0", |
|
0xC1 => "KEY1", |
|
0xC2 => "KEY2", |
|
0xC3 => "KEY3", |
|
0xC4 => "KEY4", |
|
0xC5 => "LEDC", |
|
0xC6 => "LCD", |
|
0xC8 => "PC_ADL", |
|
0xC9 => "PC_ADM", |
|
0xCA => "PC_ADH", |
|
0xCB => "PC_DW", |
|
0xCC => "PC_DR", |
|
0xCD => "PC_CR", |
|
); |
|
|
|
|
|
while (1) |
|
{ |
|
my $byte = getc FILE; |
|
last unless defined($byte); |
|
$byte = ord($byte); |
|
push(@memory, $byte); |
|
} |
|
|
|
close(FILE); |
|
|
|
@initialtargets = @targets; |
|
|
|
for my $pass (0..1) { |
|
@targets = @initialtargets; |
|
%targets_all = {}; |
|
foreach $target (@targets) { |
|
$targets_all{$target} = 1; |
|
} |
|
|
|
$output = $pass; |
|
while (@targets) { |
|
$target = shift @targets; |
|
printf "Disassembling from %x:\n", $target if $output; |
|
disassemble($target); |
|
@targets = (); # XXX stop here. |
|
} |
|
} |
|
|
|
open LABELS, ">input.labels" or die $!; |
|
|
|
foreach my $addr (sort keys %labels) { |
|
printf LABELS "%s: %06x\n", $labels{$addr}, $addr |
|
if defined($labels{$addr}); |
|
} |
|
|
|
close LABELS; |
|
|
|
sub disassemble |
|
{ |
|
my ($start) = @_; |
|
setaddress($start); |
|
$finish_disassembly = 0; |
|
$newline = 0; |
|
while (!$finish_disassembly) |
|
{ |
|
local @instr = (); |
|
my $byte = getbyte(); |
|
last unless defined($byte); |
|
local $address = $bytecount-1; |
|
decode_instruction($byte); |
|
$finish_disassembly = 1 if ($address >= $stopat); |
|
} |
|
} |
|
|
|
sub setaddress |
|
{ |
|
my ($address) = @_; |
|
$bytecount = $address; |
|
} |
|
|
|
sub getbyte |
|
{ |
|
return undef if ($bytecount - $baseaddr > @memory); |
|
return undef if ($bytecount - $baseaddr < 0); |
|
my $ret = $memory[$bytecount++ - $baseaddr]; |
|
push(@instr, $ret); |
|
return $ret; |
|
} |
|
|
|
sub decode_instruction |
|
{ |
|
my ($byte) = @_; |
|
local $amode = undef; |
|
local @operands = (); |
|
local $comment = ""; |
|
local $branch = 0; |
|
|
|
if ($byte == 0x00) { |
|
output_instruction("NOP"); |
|
} elsif ($byte == 0x01) { |
|
branch(); |
|
output_instruction("INT9"); |
|
} elsif ($byte == 0x02) { |
|
set_operand("A"); |
|
output_instruction("ADDDC"); |
|
} elsif ($byte == 0x03) { |
|
set_operand("A"); |
|
output_instruction("NEG"); |
|
} elsif ($byte == 0x04) { |
|
output_instruction("PCB"); |
|
} elsif ($byte == 0x05) { |
|
output_instruction("DTB"); |
|
} elsif ($byte == 0x06) { |
|
output_instruction("ADB"); |
|
} elsif ($byte == 0x07) { |
|
output_instruction("SDB"); |
|
} elsif ($byte == 0x08) { |
|
read_operand_imm8(); |
|
output_instruction("LINK"); |
|
} elsif ($byte == 0x09) { |
|
output_instruction("UNLINK"); |
|
} elsif ($byte == 0x0A) { |
|
set_operand("RP"); |
|
read_operand_imm8(); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x0B) { |
|
set_operand("A"); |
|
output_instruction("NEGW"); |
|
} elsif ($byte == 0x0C) { |
|
set_operand("A"); |
|
output_instruction("LSLW"); |
|
} elsif ($byte == 0x0E) { |
|
set_operand("A"); |
|
output_instruction("ASRW"); |
|
} elsif ($byte == 0x0F) { |
|
set_operand("A"); |
|
output_instruction("LSRW"); |
|
} elsif ($byte == 0x10) { |
|
output_instruction("CMR"); |
|
} elsif ($byte == 0x11) { |
|
output_instruction("NCC"); |
|
} elsif ($byte == 0x12) { |
|
set_operand("A"); |
|
output_instruction("SUBDC"); |
|
} elsif ($byte == 0x13) { |
|
branch(); |
|
set_operand('@A'); |
|
output_instruction("JCTX"); |
|
} elsif ($byte == 0x14) { |
|
output_instruction("EXT"); |
|
} elsif ($byte == 0x15) { |
|
output_instruction("ZEXT"); |
|
} elsif ($byte == 0x16) { |
|
output_instruction("SWAP"); |
|
} elsif ($byte == 0x17) { |
|
read_operand_imm8(); |
|
output_instruction("ADDSP"); |
|
} elsif ($byte == 0x18) { |
|
set_operand("A"); |
|
read_operand_imm32(); |
|
output_instruction("ADDL"); |
|
} elsif ($byte == 0x19) { |
|
set_operand("A"); |
|
read_operand_imm32(); |
|
output_instruction("SUBL"); |
|
} elsif ($byte == 0x1A) { |
|
set_operand("ILM"); |
|
read_operand_imm8(); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x1B) { |
|
set_operand("A"); |
|
read_operand_imm32(); |
|
output_instruction("CMPL"); |
|
} elsif ($byte == 0x1C) { |
|
output_instruction("EXTW"); |
|
} elsif ($byte == 0x1D) { |
|
output_instruction("ZEXTW"); |
|
} elsif ($byte == 0x1E) { |
|
output_instruction("SWAPW"); |
|
} elsif ($byte == 0x1F) { |
|
read_operand_imm16(); |
|
output_instruction("ADDSP"); |
|
} elsif ($byte == 0x20) { |
|
set_operand("A"); |
|
read_operand_dir(); |
|
output_instruction("ADD"); |
|
} elsif ($byte == 0x21) { |
|
set_operand("A"); |
|
read_operand_dir(); |
|
output_instruction("SUB"); |
|
} elsif ($byte == 0x22) { |
|
set_operand("A"); |
|
output_instruction("ADDC"); |
|
} elsif ($byte == 0x23) { |
|
set_operand("A"); |
|
output_instruction("CMP"); |
|
} elsif ($byte == 0x24) { |
|
set_operand("CCR"); |
|
read_operand_imm8(); |
|
output_instruction("AND"); |
|
} elsif ($byte == 0x25) { |
|
set_operand("CCR"); |
|
read_operand_imm8(); |
|
output_instruction("OR"); |
|
} elsif ($byte == 0x26) { |
|
set_operand("A"); |
|
output_instruction("DIVU"); |
|
} elsif ($byte == 0x27) { |
|
set_operand("A"); |
|
output_instruction("MULU"); |
|
} elsif ($byte == 0x28) { |
|
set_operand("A"); |
|
output_instruction("ADDW"); |
|
} elsif ($byte == 0x29) { |
|
set_operand("A"); |
|
output_instruction("SUBW"); |
|
} elsif ($byte == 0x2A) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
read_operand_rel(); |
|
output_instruction("CBNE"); |
|
} elsif ($byte == 0x2B) { |
|
set_operand("A"); |
|
output_instruction("CMPW"); |
|
} elsif ($byte == 0x2C) { |
|
set_operand("A"); |
|
output_instruction("ANDW"); |
|
} elsif ($byte == 0x2D) { |
|
set_operand("A"); |
|
output_instruction("ORW"); |
|
} elsif ($byte == 0x2E) { |
|
set_operand("A"); |
|
output_instruction("XORW"); |
|
} elsif ($byte == 0x2F) { |
|
set_operand("A"); |
|
output_instruction("MULUW"); |
|
} elsif ($byte == 0x30) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
output_instruction("ADD"); |
|
} elsif ($byte == 0x31) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
output_instruction("SUB"); |
|
} elsif ($byte == 0x32) { |
|
set_operand("A"); |
|
output_instruction("SUBC"); |
|
} elsif ($byte == 0x33) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
output_instruction("CMP"); |
|
} elsif ($byte == 0x34) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
output_instruction("AND"); |
|
} elsif ($byte == 0x35) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
output_instruction("OR"); |
|
} elsif ($byte == 0x36) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
output_instruction("XOR"); |
|
} elsif ($byte == 0x37) { |
|
set_operand("A"); |
|
output_instruction("NOT"); |
|
} elsif ($byte == 0x38) { |
|
set_operand("A"); |
|
read_operand_imm16(); |
|
output_instruction("ADDW"); |
|
} elsif ($byte == 0x39) { |
|
set_operand("A"); |
|
read_operand_imm16(); |
|
output_instruction("SUBW"); |
|
} elsif ($byte == 0x3A) { |
|
branch(); |
|
set_operand("A"); |
|
read_operand_imm16(); |
|
read_operand_rel(); |
|
output_instruction("CWBNE"); |
|
} elsif ($byte == 0x3B) { |
|
set_operand("A"); |
|
read_operand_imm16(); |
|
output_instruction("CMPW"); |
|
} elsif ($byte == 0x3C) { |
|
set_operand("A"); |
|
read_operand_imm16(); |
|
output_instruction("ANDW"); |
|
} elsif ($byte == 0x3D) { |
|
set_operand("A"); |
|
read_operand_imm16(); |
|
output_instruction("ORW"); |
|
} elsif ($byte == 0x3E) { |
|
set_operand("A"); |
|
read_operand_imm16(); |
|
output_instruction("XORW"); |
|
} elsif ($byte == 0x3F) { |
|
set_operand("A"); |
|
output_instruction("NOTW"); |
|
} elsif ($byte == 0x40) { |
|
set_operand("A"); |
|
read_operand_dir(); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x41) { |
|
read_operand_dir(); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x42) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x43) { |
|
set_operand("A"); |
|
read_operand_imm8(); |
|
output_instruction("MOVX"); |
|
} elsif ($byte == 0x44) { |
|
read_operand_dir(); |
|
read_operand_imm8(); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x45) { |
|
set_operand("A"); |
|
read_operand_dir(); |
|
output_instruction("MOVX"); |
|
} elsif ($byte == 0x46) { |
|
set_operand("A"); |
|
set_operand("SP"); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x47) { |
|
set_operand("SP"); |
|
set_operand("A"); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x48) { |
|
set_operand("A"); |
|
read_operand_dir(); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x49) { |
|
read_operand_dir(); |
|
set_operand("A"); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x4A) { |
|
set_operand("A"); |
|
read_operand_imm16(); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x4B) { |
|
set_operand("A"); |
|
read_operand_imm32(); |
|
output_instruction("MOVL"); |
|
} elsif ($byte == 0x4C) { |
|
set_operand("A"); |
|
output_instruction("PUSHW"); |
|
} elsif ($byte == 0x4D) { |
|
set_operand("AH"); |
|
output_instruction("PUSHW"); |
|
} elsif ($byte == 0x4E) { |
|
set_operand("PS"); |
|
output_instruction("PUSHW"); |
|
} elsif ($byte == 0x4F) { |
|
read_operand_rlst(); |
|
output_instruction("PUSHW"); |
|
} elsif ($byte == 0x50) { |
|
set_operand("A"); |
|
read_operand_io(); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x51) { |
|
read_operand_io(); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x52) { |
|
set_operand("A"); |
|
read_operand_addr16(); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x53) { |
|
read_operand_addr16(); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x54) { |
|
read_operand_io(); |
|
read_operand_imm8(); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x55) { |
|
set_operand("A"); |
|
read_operand_io(); |
|
output_instruction("MOVX"); |
|
} elsif ($byte == 0x56) { |
|
read_operand_io(); |
|
read_operand_imm16(); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x57) { |
|
set_operand("A"); |
|
read_operand_addr16(); |
|
output_instruction("MOVX"); |
|
} elsif ($byte == 0x58) { |
|
set_operand("A"); |
|
read_operand_io(); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x59) { |
|
read_operand_io(); |
|
set_operand("A"); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x5A) { |
|
set_operand("A"); |
|
read_operand_addr16(); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x5B) { |
|
read_operand_addr16(); |
|
set_operand("A"); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x5C) { |
|
set_operand("A"); |
|
output_instruction("POPW"); |
|
} elsif ($byte == 0x5D) { |
|
set_operand("AH"); |
|
output_instruction("POPW"); |
|
} elsif ($byte == 0x5E) { |
|
set_operand("PS"); |
|
output_instruction("POPW"); |
|
} elsif ($byte == 0x5F) { |
|
read_operand_rlst(); |
|
output_instruction("POPW"); |
|
} elsif ($byte == 0x60) { |
|
branch(); |
|
read_operand_rel(); |
|
unconditional_branch(); |
|
output_instruction("BRA"); |
|
} elsif ($byte == 0x61) { |
|
branch(); |
|
set_operand('@A'); |
|
unconditional_branch(); |
|
output_instruction("JMP"); |
|
} elsif ($byte == 0x62) { |
|
branch(); |
|
read_operand_addr16(); |
|
unconditional_branch(); |
|
output_instruction("JMP"); |
|
} elsif ($byte == 0x63) { |
|
branch(); |
|
read_operand_addr24(); |
|
unconditional_branch(); |
|
output_instruction("JMPP"); |
|
} elsif ($byte == 0x64) { |
|
branch(); |
|
read_operand_addr16(); |
|
output_instruction("CALL"); |
|
} elsif ($byte == 0x65) { |
|
branch(); |
|
read_operand_addr24(); |
|
output_instruction("CALL"); |
|
} elsif ($byte == 0x66) { |
|
branch(); |
|
unconditional_branch(); |
|
output_instruction("RETP"); |
|
} elsif ($byte == 0x67) { |
|
branch(); |
|
unconditional_branch(); |
|
output_instruction("RET"); |
|
} elsif ($byte == 0x68) { |
|
branch(); |
|
read_operand_vct8(); |
|
output_instruction("INT"); |
|
} elsif ($byte == 0x68) { |
|
branch(); |
|
read_operand_vct8(); |
|
output_instruction("INT"); |
|
} elsif ($byte == 0x69) { |
|
branch(); |
|
read_operand_addr16(); |
|
output_instruction("INT"); |
|
} elsif ($byte == 0x6A) { |
|
branch(); |
|
read_operand_addr24(); |
|
output_instruction("INTP"); |
|
} elsif ($byte == 0x6B) { |
|
branch(); |
|
unconditional_branch(); |
|
output_instruction("RETI"); |
|
} elsif ($byte == 0x6C) { |
|
decode_bit_manipulation(); |
|
} elsif ($byte == 0x6E) { |
|
decode_string_manipulation(); |
|
} elsif ($byte == 0x6F) { |
|
decode_two_byte(); |
|
} elsif ($byte == 0x70) { |
|
decode_ea_70(); |
|
} elsif ($byte == 0x71) { |
|
decode_ea_71(); |
|
} elsif ($byte == 0x72) { |
|
decode_ea_72(); |
|
} elsif ($byte == 0x73) { |
|
decode_ea_73(); |
|
} elsif ($byte == 0x74) { |
|
decode_ea_74(); |
|
} elsif ($byte == 0x75) { |
|
decode_ea_75(); |
|
} elsif ($byte == 0x76) { |
|
decode_ea_76(); |
|
} elsif ($byte == 0x77) { |
|
decode_ea_77(); |
|
} elsif ($byte == 0x78) { |
|
decode_ea_78(); |
|
} elsif ($byte == 0x79) { |
|
decode_ea_79(); |
|
} elsif ($byte == 0x7A) { |
|
decode_ea_7a(); |
|
} elsif ($byte == 0x7B) { |
|
decode_ea_7b(); |
|
} elsif ($byte == 0x7C) { |
|
decode_ea_7c(); |
|
} elsif ($byte == 0x7D) { |
|
decode_ea_7d(); |
|
} elsif ($byte == 0x7E) { |
|
decode_ea_7e(); |
|
} elsif ($byte == 0x7F) { |
|
decode_ea_7f(); |
|
} elsif (($byte & 0xf8) == 0x80) { |
|
set_operand("A"); |
|
set_operand_register("R", $byte & 0x7); |
|
output_instruction("MOV"); |
|
} elsif (($byte & 0xf8) == 0x88) { |
|
set_operand("A"); |
|
set_operand_register("RW", $byte & 0x7); |
|
output_instruction("MOVW"); |
|
} elsif (($byte & 0xf8) == 0x90) { |
|
set_operand_register("R", $byte & 0x7); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif (($byte & 0xf8) == 0x98) { |
|
set_operand_register("RW", $byte & 0x7); |
|
set_operand("A"); |
|
output_instruction("MOVW"); |
|
} elsif (($byte & 0xf8) == 0xA0) { |
|
set_operand_register("R", $byte & 0x7); |
|
read_operand_imm8(); |
|
output_instruction("MOV"); |
|
} elsif (($byte & 0xf8) == 0xA8) { |
|
set_operand_register("RW", $byte & 0x7); |
|
read_operand_imm16(); |
|
output_instruction("MOVW"); |
|
} elsif (($byte & 0xf8) == 0xB0) { |
|
set_operand("A"); |
|
set_operand_register("R", $byte & 0x7); |
|
output_instruction("MOVX"); |
|
} elsif (($byte & 0xf8) == 0xB8) { |
|
set_operand("A"); |
|
set_operand_register_disp8("RW", $byte & 0x7); |
|
output_instruction("MOVW"); |
|
} elsif (($byte & 0xf8) == 0xC0) { |
|
set_operand("A"); |
|
set_operand_register_disp8("RW", $byte & 0x7); |
|
output_instruction("MOVX"); |
|
} elsif (($byte & 0xf8) == 0xC8) { |
|
set_operand_register_disp8("RW", $byte & 0x7); |
|
set_operand("A"); |
|
output_instruction("MOVW"); |
|
} elsif (($byte & 0xf0) == 0xD0) { |
|
set_operand("A"); |
|
set_operand_imm4($byte & 0xf); |
|
output_instruction("MOVN"); |
|
} elsif (($byte & 0xf0) == 0xE0) { |
|
branch(); |
|
set_operand_imm4($byte & 0xf); |
|
output_instruction("CALLV"); |
|
} elsif ($byte == 0xF0) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BZ"); |
|
} elsif ($byte == 0xF1) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BNZ"); |
|
} elsif ($byte == 0xF2) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BC"); |
|
} elsif ($byte == 0xF3) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BNC"); |
|
} elsif ($byte == 0xF4) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BN"); |
|
} elsif ($byte == 0xF5) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BP"); |
|
} elsif ($byte == 0xF6) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BV"); |
|
} elsif ($byte == 0xF7) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BNV"); |
|
} elsif ($byte == 0xF8) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BT"); |
|
} elsif ($byte == 0xF9) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BNT"); |
|
} elsif ($byte == 0xFA) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BLT"); |
|
} elsif ($byte == 0xFB) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BGE"); |
|
} elsif ($byte == 0xFC) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BLE"); |
|
} elsif ($byte == 0xFD) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BGT"); |
|
} elsif ($byte == 0xFE) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BLS"); |
|
} elsif ($byte == 0xFF) { |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("BHI"); |
|
} else { |
|
undefined_instruction("first byte"); |
|
} |
|
} |
|
|
|
sub decode_bit_manipulation |
|
{ |
|
my $byte = getbyte(); |
|
if (($byte & 0xf8) == 0x00) { |
|
set_operand("A"); |
|
read_operand_io_bp($byte & 0x7); |
|
output_instruction("MOVB"); |
|
} elsif (($byte & 0xf8) == 0x08) { |
|
set_operand("A"); |
|
read_operand_dir_bp($byte & 0x7); |
|
output_instruction("MOVB"); |
|
} elsif (($byte & 0xf8) == 0x18) { |
|
set_operand("A"); |
|
read_operand_addr16_bp($byte & 0x7); |
|
output_instruction("MOVB"); |
|
} elsif (($byte & 0xf8) == 0x20) { |
|
read_operand_io_bp($byte & 0x7); |
|
set_operand("A"); |
|
output_instruction("MOVB"); |
|
} elsif (($byte & 0xf8) == 0x28) { |
|
read_operand_dir_bp($byte & 0x7); |
|
set_operand("A"); |
|
output_instruction("MOVB"); |
|
} elsif (($byte & 0xf8) == 0x38) { |
|
read_operand_addr16_bp($byte & 0x7); |
|
set_operand("A"); |
|
output_instruction("MOVB"); |
|
} elsif (($byte & 0xf8) == 0x40) { |
|
read_operand_io_bp($byte & 0x7); |
|
output_instruction("CLRB"); |
|
} elsif (($byte & 0xf8) == 0x48) { |
|
read_operand_dir_bp($byte & 0x7); |
|
output_instruction("CLRB"); |
|
} elsif (($byte & 0xf8) == 0x58) { |
|
read_operand_addr16_bp($byte & 0x7); |
|
output_instruction("CLRB"); |
|
} elsif (($byte & 0xf8) == 0x60) { |
|
read_operand_io_bp($byte & 0x7); |
|
output_instruction("SETB"); |
|
} elsif (($byte & 0xf8) == 0x68) { |
|
read_operand_dir_bp($byte & 0x7); |
|
output_instruction("SETB"); |
|
} elsif (($byte & 0xf8) == 0x78) { |
|
read_operand_addr16_bp($byte & 0x7); |
|
output_instruction("SETB"); |
|
} elsif (($byte & 0xf8) == 0x80) { |
|
branch(); |
|
read_operand_io_bp($byte & 0x7); |
|
read_operand_rel(); |
|
output_instruction("BBC"); |
|
} elsif (($byte & 0xf8) == 0x88) { |
|
branch(); |
|
read_operand_dir_bp($byte & 0x7); |
|
read_operand_rel(); |
|
output_instruction("BBC"); |
|
} elsif (($byte & 0xf8) == 0x98) { |
|
branch(); |
|
read_operand_addr16_bp($byte & 0x7); |
|
read_operand_rel(); |
|
output_instruction("BBC"); |
|
} elsif (($byte & 0xf8) == 0xA0) { |
|
branch(); |
|
read_operand_io_bp($byte & 0x7); |
|
read_operand_rel(); |
|
output_instruction("BBS"); |
|
} elsif (($byte & 0xf8) == 0xA8) { |
|
branch(); |
|
read_operand_dir_bp($byte & 0x7); |
|
read_operand_rel(); |
|
output_instruction("BBS"); |
|
} elsif (($byte & 0xf8) == 0xB8) { |
|
branch(); |
|
read_operand_addr16_bp($byte & 0x7); |
|
read_operand_rel(); |
|
output_instruction("BBS"); |
|
} elsif (($byte & 0xf8) == 0xC0) { |
|
read_operand_io_bp($byte & 0x7); |
|
output_instruction("WBTS"); |
|
} elsif (($byte & 0xf8) == 0xE0) { |
|
read_operand_io_bp($byte & 0x7); |
|
output_instruction("WBTC"); |
|
} elsif (($byte & 0xf8) == 0xF8) { |
|
read_operand_io_bp($byte & 0x7); |
|
output_instruction("SBBS"); |
|
} else { |
|
undefined_instruction("bit manipulation"); |
|
} |
|
} |
|
|
|
sub decode_string_manipulation |
|
{ |
|
my $byte = getbyte(); |
|
my $arg1 = ($byte & 0xc) >> 2; |
|
my $arg2 = ($byte & 0x3); |
|
my $op = ($byte) >> 4; |
|
my @r = ("PCB", "DTB", "ADB", "SPB"); |
|
my @i = ("MOVSI", "MOVSD", "MOVSWI", "MOVSWD", "", "", "", "", |
|
"SCEQI", "SCEQD", "SCWEQI", "SCWEQD", "FILSI", "", "FILSWI", ""); |
|
if ($op < 4) { |
|
set_operand($r[$arg1]); |
|
set_operand($r[$arg2]); |
|
output_instruction($i[$op]); |
|
} elsif (((($op >= 8) && ($op <= 0xc)) || ($op == 0xe)) && |
|
($arg1 == 0)) { |
|
set_operand($r[$arg2]); |
|
output_instruction($i[$op]); |
|
} else { |
|
undefined_instruction("string manipulation"); |
|
} |
|
} |
|
|
|
sub decode_two_byte |
|
{ |
|
my $byte = getbyte(); |
|
if ($byte == 0x00) { |
|
set_operand("A"); |
|
set_operand("DTB"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x01) { |
|
set_operand("A"); |
|
set_operand("ADB"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x02) { |
|
set_operand("A"); |
|
set_operand("SSB"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x03) { |
|
set_operand("A"); |
|
set_operand("USB"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x04) { |
|
set_operand("A"); |
|
set_operand("DPR"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x05) { |
|
set_operand("A"); |
|
set_operand('@A'); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x06) { |
|
set_operand("A"); |
|
set_operand("PCB"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x07) { |
|
set_operand("A"); |
|
output_instruction("ROLC"); |
|
} elsif ($byte == 0x0C) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("LSLW"); |
|
} elsif ($byte == 0x0D) { |
|
set_operand("A"); |
|
set_operand('@A'); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x0E) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("ASRW"); |
|
} elsif ($byte == 0x0F) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("LSRW"); |
|
} elsif ($byte == 0x10) { |
|
set_operand("DTB"); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x11) { |
|
set_operand("ADB"); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x12) { |
|
set_operand("SSB"); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x13) { |
|
set_operand("USB"); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x14) { |
|
set_operand("DPR"); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x15) { |
|
set_operand('@AL'); |
|
set_operand("AH"); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x16) { |
|
set_operand("A"); |
|
set_operand('@A'); |
|
output_instruction("MOV"); |
|
} elsif ($byte == 0x17) { |
|
set_operand("A"); |
|
output_instruction("RORC"); |
|
} elsif ($byte == 0x1C) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("LSLL"); |
|
} elsif ($byte == 0x1D) { |
|
set_operand('@AL'); |
|
set_operand("AH"); |
|
output_instruction("MOVW"); |
|
} elsif ($byte == 0x1E) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("ASRL"); |
|
} elsif ($byte == 0x1F) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("LSRL"); |
|
} elsif ($byte == 0x2C) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("LSL"); |
|
} elsif ($byte == 0x2D) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("NRML"); |
|
} elsif ($byte == 0x2E) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("ASR"); |
|
} elsif ($byte == 0x2F) { |
|
set_operand("A"); |
|
set_operand_register("R", 0); |
|
output_instruction("LSR"); |
|
} elsif (($byte & 0xf9) == 0x20) { |
|
set_operand("A"); |
|
set_operand_register_disp8("RL", ($byte & 7) >>1); |
|
output_instruction("MOVX"); |
|
} elsif (($byte & 0xf9) == 0x30) { |
|
set_operand_register_disp8("RL", ($byte & 7) >>1); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif (($byte & 0xf9) == 0x38) { |
|
set_operand_register_disp8("RL", ($byte & 7) >>1); |
|
set_operand("A"); |
|
output_instruction("MOVW"); |
|
} elsif (($byte & 0xf9) == 0x40) { |
|
set_operand("A"); |
|
set_operand_register_disp8("RL", ($byte & 7) >>1); |
|
output_instruction("MOV"); |
|
} elsif (($byte & 0xf9) == 0x48) { |
|
set_operand("A"); |
|
set_operand_register_disp8("RL", ($byte & 7) >>1); |
|
output_instruction("MOVW"); |
|
} else { |
|
undefined_instruction("two byte"); |
|
} |
|
} |
|
|
|
sub decode_ea_70 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
set_operand("A"); |
|
set_operand_ea("RL", $byte); |
|
output_instruction("ADDL"); |
|
} elsif ($op == 0x20) { |
|
set_operand("A"); |
|
set_operand_ea("RL", $byte); |
|
output_instruction("SUBL"); |
|
} elsif ($op == 0x40) { |
|
set_operand_ea("RW", $byte); |
|
branch(); |
|
read_operand_imm16(); |
|
read_operand_rel(); |
|
output_instruction("CWBNE"); |
|
} elsif ($op == 0x60) { |
|
set_operand("A"); |
|
set_operand_ea("RL", $byte); |
|
output_instruction("CMPL"); |
|
} elsif ($op == 0x80) { |
|
set_operand("A"); |
|
set_operand_ea("RL", $byte); |
|
output_instruction("ANDL"); |
|
} elsif ($op == 0xA0) { |
|
set_operand("A"); |
|
set_operand_ea("RL", $byte); |
|
output_instruction("ORL"); |
|
} elsif ($op == 0xC0) { |
|
set_operand("A"); |
|
set_operand_ea("RL", $byte); |
|
output_instruction("XORL"); |
|
} elsif ($op == 0xE0) { |
|
set_operand_ea("R", $byte); |
|
branch(); |
|
read_operand_imm8(); |
|
read_operand_rel(); |
|
output_instruction("CBNE"); |
|
} else { |
|
undefined_instruction("ea (70)"); |
|
} |
|
} |
|
|
|
sub decode_ea_71 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
branch(); |
|
set_operand_ea('@RL', $byte); |
|
unconditional_branch(); |
|
output_instruction("JMPP"); |
|
} elsif ($op == 0x20) { |
|
branch(); |
|
set_operand_ea('@RL', $byte); |
|
output_instruction("CALLP"); |
|
} elsif ($op == 0x40) { |
|
set_operand_ea("RL", $byte); |
|
output_instruction("INCL"); |
|
} elsif ($op == 0x60) { |
|
set_operand_ea("RL", $byte); |
|
output_instruction("DECL"); |
|
} elsif ($op == 0x80) { |
|
set_operand("A"); |
|
set_operand_ea("RL", $byte); |
|
output_instruction("MOVL"); |
|
} elsif ($op == 0xA0) { |
|
set_operand_ea("RL", $byte); |
|
set_operand("A"); |
|
output_instruction("MOVL"); |
|
} elsif ($op == 0xC0) { |
|
set_operand_ea("R", $byte); |
|
read_operand_imm8(); |
|
output_instruction("MOV"); |
|
} elsif ($op == 0xE0) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("MOVEA"); |
|
} else { |
|
undefined_instruction("ea (71)"); |
|
} |
|
} |
|
|
|
sub decode_ea_72 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
set_operand_ea("R", $byte); |
|
output_instruction("ROLC"); |
|
} elsif ($op == 0x20) { |
|
set_operand_ea("R", $byte); |
|
output_instruction("RORC"); |
|
} elsif ($op == 0x40) { |
|
set_operand_ea("R", $byte); |
|
output_instruction("INC"); |
|
} elsif ($op == 0x60) { |
|
set_operand_ea("R", $byte); |
|
output_instruction("DEC"); |
|
} elsif ($op == 0x80) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("MOV"); |
|
} elsif ($op == 0xA0) { |
|
set_operand_ea("R", $byte); |
|
set_operand("A"); |
|
output_instruction("MOV"); |
|
} elsif ($op == 0xC0) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("MOVX"); |
|
} elsif ($op == 0xE0) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("XCH"); |
|
} else { |
|
undefined_instruction("ea (72)"); |
|
} |
|
} |
|
|
|
sub decode_ea_73 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
branch(); |
|
set_operand_ea('@RW', $byte); |
|
unconditional_branch(); |
|
output_instruction("JMP"); |
|
} elsif ($op == 0x20) { |
|
branch(); |
|
set_operand_ea('@RW', $byte); |
|
output_instruction("CALL"); |
|
} elsif ($op == 0x40) { |
|
set_operand_ea("RW", $byte); |
|
output_instruction("INCW"); |
|
} elsif ($op == 0x60) { |
|
set_operand_ea("RW", $byte); |
|
output_instruction("DECW"); |
|
} elsif ($op == 0x80) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("MOVW"); |
|
} elsif ($op == 0xA0) { |
|
set_operand_ea("RW", $byte); |
|
set_operand("A"); |
|
output_instruction("MOVW"); |
|
} elsif ($op == 0xC0) { |
|
set_operand_ea("RW", $byte); |
|
read_operand_imm16(); |
|
output_instruction("MOVW"); |
|
} elsif ($op == 0xE0) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("XCHW"); |
|
} else { |
|
undefined_instruction("ea (73)"); |
|
} |
|
} |
|
|
|
sub decode_ea_74 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("ADD"); |
|
} elsif ($op == 0x20) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("SUB"); |
|
} elsif ($op == 0x40) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("ADDC"); |
|
} elsif ($op == 0x60) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("CMP"); |
|
} elsif ($op == 0x80) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("AND"); |
|
} elsif ($op == 0xA0) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("OR"); |
|
} elsif ($op == 0xC0) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("XOR"); |
|
} elsif ($op == 0xE0) { |
|
set_operand_ea("R", $byte); |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("DBNZ"); |
|
} else { |
|
undefined_instruction("ea (74)"); |
|
} |
|
} |
|
|
|
sub decode_ea_75 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
set_operand_ea("R", $byte); |
|
set_operand("A"); |
|
output_instruction("ADD"); |
|
} elsif ($op == 0x20) { |
|
set_operand_ea("R", $byte); |
|
set_operand("A"); |
|
output_instruction("SUB"); |
|
} elsif ($op == 0x40) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("SUBC"); |
|
} elsif ($op == 0x60) { |
|
set_operand_ea("R", $byte); |
|
output_instruction("NEG"); |
|
} elsif ($op == 0x80) { |
|
set_operand_ea("R", $byte); |
|
set_operand("A"); |
|
output_instruction("AND"); |
|
} elsif ($op == 0xA0) { |
|
set_operand_ea("R", $byte); |
|
set_operand("A"); |
|
output_instruction("OR"); |
|
} elsif ($op == 0xC0) { |
|
set_operand_ea("R", $byte); |
|
set_operand("A"); |
|
output_instruction("XOR"); |
|
} elsif ($op == 0xE0) { |
|
set_operand_ea("R", $byte); |
|
output_instruction("NOT"); |
|
} else { |
|
undefined_instruction("ea (75)"); |
|
} |
|
} |
|
|
|
sub decode_ea_76 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("ADDW"); |
|
} elsif ($op == 0x20) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("SUBW"); |
|
} elsif ($op == 0x40) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("ADDCW"); |
|
} elsif ($op == 0x60) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("CMPW"); |
|
} elsif ($op == 0x80) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("ANDW"); |
|
} elsif ($op == 0xA0) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("ORW"); |
|
} elsif ($op == 0xC0) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("XORW"); |
|
} elsif ($op == 0xE0) { |
|
set_operand_ea("RW", $byte); |
|
branch(); |
|
read_operand_rel(); |
|
output_instruction("DWBNZ"); |
|
} else { |
|
undefined_instruction("ea (76)"); |
|
} |
|
} |
|
|
|
sub decode_ea_77 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
set_operand_ea("RW", $byte); |
|
set_operand("A"); |
|
output_instruction("ADDW"); |
|
} elsif ($op == 0x20) { |
|
set_operand_ea("RW", $byte); |
|
set_operand("A"); |
|
output_instruction("SUBW"); |
|
} elsif ($op == 0x40) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("SUBCW"); |
|
} elsif ($op == 0x60) { |
|
set_operand_ea("RW", $byte); |
|
output_instruction("NEGW"); |
|
} elsif ($op == 0x80) { |
|
set_operand_ea("RW", $byte); |
|
set_operand("A"); |
|
output_instruction("ANDW"); |
|
} elsif ($op == 0xA0) { |
|
set_operand_ea("RW", $byte); |
|
set_operand("A"); |
|
output_instruction("ORW"); |
|
} elsif ($op == 0xC0) { |
|
set_operand_ea("RW", $byte); |
|
set_operand("A"); |
|
output_instruction("XORW"); |
|
} elsif ($op == 0xE0) { |
|
set_operand_ea("RW", $byte); |
|
output_instruction("NOTW"); |
|
} else { |
|
undefined_instruction("ea (77)"); |
|
} |
|
} |
|
|
|
sub decode_ea_78 |
|
{ |
|
my $byte = getbyte(); |
|
my $op = $byte & 0xe0; |
|
if ($op == 0x00) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("MULU"); |
|
} elsif ($op == 0x20) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("MULUW"); |
|
} elsif ($op == 0x80) { |
|
set_operand("A"); |
|
set_operand_ea("R", $byte); |
|
output_instruction("DIVU"); |
|
} elsif ($op == 0xA0) { |
|
set_operand("A"); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("DIVUW"); |
|
} else { |
|
undefined_instruction("ea (78)"); |
|
} |
|
} |
|
|
|
sub decode_ea_79 |
|
{ |
|
my $byte = getbyte(); |
|
my $reg = ($byte & 0xe0) >> 5; |
|
set_operand_register("RW", $reg); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("MOVEA"); |
|
} |
|
|
|
sub decode_ea_7a |
|
{ |
|
my $byte = getbyte(); |
|
my $reg = ($byte & 0xe0) >> 5; |
|
set_operand_register("R", $reg); |
|
set_operand_ea("R", $byte); |
|
output_instruction("MOV"); |
|
} |
|
|
|
sub decode_ea_7b |
|
{ |
|
my $byte = getbyte(); |
|
my $reg = ($byte & 0xe0) >> 5; |
|
set_operand_register("RW", $reg); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("MOVW"); |
|
} |
|
|
|
sub decode_ea_7c |
|
{ |
|
my $byte = getbyte(); |
|
my $reg = ($byte & 0xe0) >> 5; |
|
set_operand_ea("R", $byte); |
|
set_operand_register("R", $reg); |
|
output_instruction("MOV"); |
|
} |
|
|
|
sub decode_ea_7d |
|
{ |
|
my $byte = getbyte(); |
|
my $reg = ($byte & 0xe0) >> 5; |
|
set_operand_ea("RW", $byte); |
|
set_operand_register("RW", $reg); |
|
output_instruction("MOVW"); |
|
} |
|
|
|
sub decode_ea_7e |
|
{ |
|
my $byte = getbyte(); |
|
my $reg = ($byte & 0xe0) >> 5; |
|
set_operand_register("R", $reg); |
|
set_operand_ea("R", $byte); |
|
output_instruction("XCH"); |
|
} |
|
|
|
sub decode_ea_7f |
|
{ |
|
my $byte = getbyte(); |
|
my $reg = ($byte & 0xe0) >> 5; |
|
set_operand_register("RW", $reg); |
|
set_operand_ea("RW", $byte); |
|
output_instruction("XCHW"); |
|
} |
|
|
|
sub signextend8 |
|
{ |
|
my ($byte) = @_; |
|
if ($byte & 0x80) { |
|
$byte -= 0x100; |
|
} |
|
return $byte; |
|
} |
|
|
|
sub signextend16 |
|
{ |
|
my ($word) = @_; |
|
if ($word & 0x8000) { |
|
$word -= 0x10000; |
|
} |
|
return $word; |
|
} |
|
|
|
sub set_operand |
|
{ |
|
my ($operand) = @_; |
|
push (@operands, $operand); |
|
} |
|
|
|
sub read_operand_dir |
|
{ |
|
my $byte = getbyte(); |
|
set_operand(sprintf("dir:0x%.2x", $byte)); |
|
} |
|
|
|
sub read_operand_dir_bp |
|
{ |
|
my ($bp) = @_; |
|
my $byte = getbyte(); |
|
set_operand(sprintf("dir:0x%.2x:%d", $byte, $bp)); |
|
} |
|
|
|
sub read_operand_io |
|
{ |
|
my $byte = getbyte(); |
|
if ($io{$byte}) { |
|
set_operand(sprintf("I:%s", $io{$byte})); |
|
add_comment(sprintf("0x%.2x", $byte)); |
|
} else { |
|
set_operand(sprintf("I:0x%.2x", $byte)); |
|
} |
|
} |
|
|
|
sub read_operand_io_bp |
|
{ |
|
my ($bp) = @_; |
|
my $byte = getbyte(); |
|
if ($io{$byte}) { |
|
set_operand(sprintf("I:%s:%d", $io{$byte}, $bp)); |
|
add_comment(sprintf("0x%.2x", $byte)); |
|
} else { |
|
set_operand(sprintf("I:0x%.2x:%d", $byte, $bp)); |
|
} |
|
} |
|
|
|
sub read_operand_vct8 |
|
{ |
|
my $byte = getbyte(); |
|
set_operand(sprintf("#vct:0x%.2x", $byte)); |
|
} |
|
|
|
sub read_operand_addr16 |
|
{ |
|
my ($at) = @_; |
|
my $byte1 = getbyte(); |
|
my $byte2 = getbyte(); |
|
my $addr = $byte1; |
|
$addr += $byte2 << 8; |
|
if ($branch) { |
|
$addr = ($addr & 0xffff) | ($address & ~0xffff); |
|
set_operand(sprintf("%s%s", $at, get_label($addr))); |
|
add_comment(sprintf("0x%.6x", $addr)); |
|
} else { |
|
set_operand(sprintf("%sD:0x%.4x", $at, $addr)); |
|
} |
|
} |
|
|
|
sub read_operand_addr16_bp |
|
{ |
|
my ($bp) = @_; |
|
my $byte1 = getbyte(); |
|
my $byte2 = getbyte(); |
|
my $addr = $byte1; |
|
$addr += $byte2 << 8; |
|
set_operand(sprintf("D:0x%.4x:%d", $addr, $bp)); |
|
} |
|
|
|
sub read_operand_addr24 |
|
{ |
|
my $byte1 = getbyte(); |
|
my $byte2 = getbyte(); |
|
my $byte3 = getbyte(); |
|
my $addr = $byte1; |
|
$addr += $byte2 << 8; |
|
$addr += $byte3 << 16; |
|
if ($branch) { |
|
set_operand(sprintf("%s", get_label($addr))); |
|
add_comment(sprintf("0x%.6x", $addr)); |
|
} else { |
|
set_operand(sprintf("0x%.6x", $addr)); |
|
} |
|
} |
|
|
|
## ASSUMPTION: This is always the last operand!!! |
|
sub read_operand_rel |
|
{ |
|
my $byte = getbyte(); |
|
my $addr = $bytecount + signextend8($byte); |
|
$addr = $addr & 0xffff; |
|
$addr = $addr | ($address &~0xffff); |
|
# add_target($addr); |
|
set_operand(get_label($addr)); |
|
add_comment(sprintf("0x%x", $addr)); |
|
} |
|
|
|
sub get_label |
|
{ |
|
($addr) = @_; |
|
return $labels{$addr} if defined($labels{$addr}); |
|
$labels{$addr}="L" . $labelnum++; |
|
return $labels{$addr}; |
|
} |
|
|
|
sub add_target |
|
{ |
|
($addr) = @_; |
|
return if defined($targets_all{$addr}); |
|
push(@targets, $addr); |
|
$targets_all{$addr}=1; |
|
} |
|
|
|
sub add_comment |
|
{ |
|
($text) = @_; |
|
$comment = $comment . " " unless ($comment eq ""); |
|
$comment = $comment . $text; |
|
} |
|
|
|
sub read_operand_rlst |
|
{ |
|
my $byte = getbyte(); |
|
my $string = "["; |
|
my $comma = ""; |
|
my $inrange = 0; |
|
my $reg = 0; |
|
while ($byte != 0) { |
|
if ($byte & 1) { |
|
if ($inrange) { |
|
if (($byte & 2) == 0) { |
|
$string .= "-RW" . $reg; |
|
$inrange = 0; |
|
} |
|
} else { |
|
$string .= $comma . "RW" . $reg; |
|
$comma = ", "; |
|
if ($byte & 2) { |
|
$inrange = 1; |
|
} |
|
} |
|
} |
|
$byte = $byte >> 1; |
|
$reg++; |
|
} |
|
$string .= "]"; |
|
set_operand($string); |
|
} |
|
|
|
sub set_operand_imm4 |
|
{ |
|
my ($byte) = @_; |
|
set_operand(sprintf("#%d", $byte)); |
|
} |
|
|
|
sub read_operand_imm8 |
|
{ |
|
my $byte = getbyte(); |
|
set_operand(sprintf("#%d", $byte)); |
|
} |
|
|
|
sub read_operand_imm16 |
|
{ |
|
my $byte1 = getbyte(); |
|
my $byte2 = getbyte(); |
|
my $word = $byte1; |
|
$word += ($byte2 << 8); |
|
set_operand(sprintf("#%d", $word)); |
|
} |
|
|
|
sub read_operand_imm32 |
|
{ |
|
my $byte1 = getbyte(); |
|
my $byte2 = getbyte(); |
|
my $byte3 = getbyte(); |
|
my $byte4 = getbyte(); |
|
my $word = $byte1; |
|
$word += ($byte2 << 8); |
|
$word += ($byte3 << 16); |
|
$word += ($byte4 << 24); |
|
set_operand(sprintf("#0x%x", $word)); |
|
} |
|
|
|
sub set_operand_register |
|
{ |
|
my ($type, $reg) = @_; |
|
set_operand(sprintf("%s%d", $type, $reg)); |
|
} |
|
|
|
sub set_operand_register_disp8 |
|
{ |
|
my ($type, $reg) = @_; |
|
my $byte = getbyte(); |
|
my $disp = signextend8($byte); |
|
set_operand(sprintf("\@%s%d%+d", $type, $reg, $disp)); |
|
} |
|
|
|
sub set_operand_register_disp16 |
|
{ |
|
my ($type, $reg) = @_; |
|
my $byte1 = getbyte(); |
|
my $byte2 = getbyte(); |
|
my $word = $byte1 + ($byte2 << 8); |
|
my $disp = signextend16($word); |
|
set_operand(sprintf("\@%s%d%+d", $type, $reg, $disp)); |
|
} |
|
|
|
sub set_operand_pc_disp16 |
|
{ |
|
my ($at) = @_; |
|
my $byte1 = getbyte(); |
|
my $byte2 = getbyte(); |
|
my $word = $byte1 + ($byte2 << 8); |
|
my $disp = signextend16($word); |
|
set_operand(sprintf("%s\@PC%+d", $at, $disp)); |
|
} |
|
|
|
sub set_operand_ea |
|
{ |
|
my ($type, $byte) = @_; |
|
my $at = ""; |
|
$at = '@' if ($type =~ /@/); |
|
$byte = $byte & 0x1f; |
|
if ($byte < 0x08) { |
|
my $rn = $byte; |
|
$rn = $rn >> 1 if ($type =~ /RL/); |
|
set_operand(sprintf("%s%d", $type, $rn)); |
|
} elsif ($byte < 0x0c) { |
|
set_operand(sprintf('%s@RW%d', $at, $byte & 3)); |
|
} elsif ($byte < 0x10) { |
|
set_operand(sprintf('%s@RW%d+', $at, $byte & 3)); |
|
} elsif ($byte < 0x18) { |
|
set_operand_register_disp8($at."RW", $byte & 7); |
|
} elsif ($byte < 0x1c) { |
|
set_operand_register_disp16($at."RW", $byte & 3); |
|
} elsif ($byte == 0x1c) { |
|
set_operand($at . '@RW0+RW7'); |
|
} elsif ($byte == 0x1d) { |
|
set_operand($at . '@RW1+RW7'); |
|
} elsif ($byte == 0x1e) { |
|
set_operand_pc_disp16($at); |
|
} elsif ($byte == 0x1f) { |
|
read_operand_addr16($at); |
|
} else { |
|
printf "Unknown ea operand: %x\n", $byte if $output; |
|
} |
|
} |
|
|
|
sub branch |
|
{ |
|
$branch = 1; |
|
} |
|
|
|
sub unconditional_branch |
|
{ |
|
# $finish_disassembly = 1; |
|
$newline = 1; |
|
} |
|
|
|
sub undefined_instruction |
|
{ |
|
my ($type) = @_; |
|
|
|
@operands = (); |
|
output_instruction("Undefined instruction: $type"); |
|
} |
|
|
|
sub output_instruction |
|
{ |
|
my ($decode) = @_; |
|
my $spaces = 16; |
|
my $comma = ""; |
|
|
|
return unless $output; |
|
|
|
printf "\n%s:\n", $labels{$address} if ($labels{$address}); |
|
|
|
printf "%.8x: ", $address; |
|
for $byte (@instr) { |
|
printf "%.2x ", $byte; |
|
$spaces = $spaces - 3; |
|
} |
|
for (0..$spaces) { |
|
print " "; |
|
} |
|
printf "%s", $decode; |
|
for $operand (@operands) { |
|
printf "%s %s", $comma, $operand; |
|
$comma = ","; |
|
} |
|
if ($comment ne "") { |
|
printf " ; %s", $comment; |
|
} |
|
print "\n"; |
|
|
|
print "\n" if $newline; |
|
$newline = 0; |
|
}
|
|
|