#!/usr/pkg/bin/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, ") { chomp; if (($name, $addr) = /(.*): (.*)/) { $addr = hex $addr; $labels{$addr} = $name; if ($name =~ /^L(\d+)$/) { $labelnum = $1 + 1 if ($labelnum >= $1); } } } } close LABELS; $output = 0; %io = ( 0x01 => "PDR1", 0x02 => "PDR2", 0x03 => "PDR3", 0x04 => "PDR3", 0x05 => "PDR3", 0x06 => "PDR3", 0x07 => "PDR3", 0x08 => "PDR3", 0x09 => "PDR3", 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 => "ICR22", 0xBD => "ICR33", 0xBE => "ICR44", 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: %.6x\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; 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; }