commit 936619ba59f2c968e655c7e8cd9d988738c67edf Author: Gavan Fantom Date: Sun Feb 13 01:18:46 2011 +0000 First checkin of F2MC-16L disassembler and LC2412 EPROM bit twiddler. diff --git a/disassem.pl b/disassem.pl new file mode 100755 index 0000000..5cd8912 --- /dev/null +++ b/disassem.pl @@ -0,0 +1,1671 @@ +#!/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; + +$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", +); + + +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. + } +} + +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 = ""; + + if ($byte == 0x00) { + output_instruction("NOP"); + } elsif ($byte == 0x01) { + 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) { + 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) { + 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) { + read_operand_rel(); + unconditional_branch(); + output_instruction("BRA"); + } elsif ($byte == 0x61) { + set_operand('@A'); + unconditional_branch(); + output_instruction("JMP"); + } elsif ($byte == 0x62) { + read_operand_addr16(); + unconditional_branch(); + output_instruction("JMP"); + } elsif ($byte == 0x63) { + read_operand_addr24(); + unconditional_branch(); + output_instruction("JMPP"); + } elsif ($byte == 0x64) { + read_operand_addr16(); + output_instruction("CALL"); + } elsif ($byte == 0x65) { + read_operand_addr24(); + output_instruction("CALL"); + } elsif ($byte == 0x66) { + unconditional_branch(); + output_instruction("RETP"); + } elsif ($byte == 0x67) { + unconditional_branch(); + output_instruction("RET"); + } elsif ($byte == 0x68) { + read_operand_vct8(); + output_instruction("INT"); + } elsif ($byte == 0x68) { + read_operand_vct8(); + output_instruction("INT"); + } elsif ($byte == 0x69) { + read_operand_addr16(); + output_instruction("INT"); + } elsif ($byte == 0x6A) { + read_operand_addr24(); + output_instruction("INTP"); + } elsif ($byte == 0x6B) { + 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) { + set_operand_imm4($byte & 0xf); + output_instruction("CALLV"); + } elsif ($byte == 0xF0) { + read_operand_rel(); + output_instruction("BZ"); + } elsif ($byte == 0xF1) { + read_operand_rel(); + output_instruction("BNZ"); + } elsif ($byte == 0xF2) { + read_operand_rel(); + output_instruction("BC"); + } elsif ($byte == 0xF3) { + read_operand_rel(); + output_instruction("BNC"); + } elsif ($byte == 0xF4) { + read_operand_rel(); + output_instruction("BN"); + } elsif ($byte == 0xF5) { + read_operand_rel(); + output_instruction("BP"); + } elsif ($byte == 0xF6) { + read_operand_rel(); + output_instruction("BV"); + } elsif ($byte == 0xF7) { + read_operand_rel(); + output_instruction("BNV"); + } elsif ($byte == 0xF8) { + read_operand_rel(); + output_instruction("BT"); + } elsif ($byte == 0xF9) { + read_operand_rel(); + output_instruction("BNT"); + } elsif ($byte == 0xFA) { + read_operand_rel(); + output_instruction("BLT"); + } elsif ($byte == 0xFB) { + read_operand_rel(); + output_instruction("BGE"); + } elsif ($byte == 0xFC) { + read_operand_rel(); + output_instruction("BLE"); + } elsif ($byte == 0xFD) { + read_operand_rel(); + output_instruction("BGT"); + } elsif ($byte == 0xFE) { + read_operand_rel(); + output_instruction("BLS"); + } elsif ($byte == 0xFF) { + 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) { + read_operand_io_bp($byte & 0x7); + read_operand_rel(); + output_instruction("BBC"); + } elsif (($byte & 0xf8) == 0x88) { + read_operand_dir_bp($byte & 0x7); + read_operand_rel(); + output_instruction("BBC"); + } elsif (($byte & 0xf8) == 0x98) { + read_operand_addr16_bp($byte & 0x7); + read_operand_rel(); + output_instruction("BBC"); + } elsif (($byte & 0xf8) == 0xA0) { + read_operand_io_bp($byte & 0x7); + read_operand_rel(); + output_instruction("BBS"); + } elsif (($byte & 0xf8) == 0xA8) { + read_operand_dir_bp($byte & 0x7); + read_operand_rel(); + output_instruction("BBS"); + } elsif (($byte & 0xf8) == 0xB8) { + 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); + 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); + 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) { + set_operand_ea('@RL', $byte); + unconditional_branch(); + output_instruction("JMPP"); + } elsif ($op == 0x20) { + 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) { + set_operand_ea('@RW', $byte); + unconditional_branch(); + output_instruction("JMP"); + } elsif ($op == 0x20) { + 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); + 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); + 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; + 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 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; +} diff --git a/twiddle.pl b/twiddle.pl new file mode 100755 index 0000000..a8a5252 --- /dev/null +++ b/twiddle.pl @@ -0,0 +1,18 @@ +#!/usr/pkg/bin/perl + +binmode STDIN; +binmode STDOUT; + +while (1) +{ + my $byte = getc; + last unless defined($byte); + $byte = ord($byte); + $a = $byte & 0x08; + $b = $byte & 0x10; + $byte = $byte & 0xe7; + $byte = $byte | 0x08 if ($b); + $byte = $byte | 0x10 if ($a); + printf "%c", $byte; +} +