Disassembler for f2mc-16l, as used in the Behringer LC2412 lighting console
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.

1774 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;
}