mirror of
https://github.com/cshepherd/yagsdisasm.git
synced 2024-11-29 16:49:54 +00:00
initial commit
This commit is contained in:
commit
0891665c81
603
Disassembler/Disassembler_65816.php
Normal file
603
Disassembler/Disassembler_65816.php
Normal file
@ -0,0 +1,603 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Disassembler_65816 - A 65816 disassembler, of course
|
||||||
|
* loosely references Andy McFadden's Ciderpress disassembler work at
|
||||||
|
* https://github.com/fadden/ciderpress/blob/master/reformat/DisasmTable.cpp
|
||||||
|
*/
|
||||||
|
class Disassembler_65816
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* initialization here
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->opcodes = array(
|
||||||
|
0x00 => array( 'BRK', 'StackInt' ),
|
||||||
|
0x01 => array( 'ORA', 'DPIndexXInd' ),
|
||||||
|
0x02 => array( 'COP', 'StackInt' ),
|
||||||
|
0x03 => array( 'ORA', 'StackRel' ),
|
||||||
|
0x04 => array( 'TSB', 'DP' ),
|
||||||
|
0x05 => array( 'ORA', 'DP' ),
|
||||||
|
0x06 => array( 'ASL', 'DP' ),
|
||||||
|
0x07 => array( 'ORA', 'DPIndLong' ),
|
||||||
|
0x08 => array( 'PHP', 'StackPush' ),
|
||||||
|
0x09 => array( 'ORA', 'Imm' ),
|
||||||
|
0x0A => array( 'ASL', 'Acc' ),
|
||||||
|
0x0B => array( 'PHD', 'StackPush' ),
|
||||||
|
0x0C => array( 'TSB', 'Abs' ),
|
||||||
|
0x0D => array( 'ORA', 'Abs' ),
|
||||||
|
0x0E => array( 'ASL', 'Abs' ),
|
||||||
|
0x0F => array( 'ORA', 'AbsLong' ),
|
||||||
|
|
||||||
|
0x10 => array( 'BPL', 'PCRel' ),
|
||||||
|
0x11 => array( 'ORA', 'DPIndIndexY' ),
|
||||||
|
0x12 => array( 'ORA', 'DPInd' ),
|
||||||
|
0x13 => array( 'ORA', 'StackRelIndexY' ),
|
||||||
|
0x14 => array( 'TRB', 'DP' ),
|
||||||
|
0x15 => array( 'ORA', 'DPIndexX' ),
|
||||||
|
0x16 => array( 'ASL', 'DPIndexX' ),
|
||||||
|
0x17 => array( 'ORA', 'DPIndexYLong' ),
|
||||||
|
0x18 => array( 'CLC', 'Implied' ),
|
||||||
|
0x19 => array( 'ORA', 'AbsIndexY' ),
|
||||||
|
0x1A => array( 'INC', 'Acc' ),
|
||||||
|
0x1B => array( 'TCS', 'Implied' ),
|
||||||
|
0x1C => array( 'TRB', 'Abs' ),
|
||||||
|
0x1D => array( 'ORA', 'AbsIndexX' ),
|
||||||
|
0x1E => array( 'ASL', 'AbsIndexX' ),
|
||||||
|
0x1F => array( 'ORA', 'AbsIndexXLong' ),
|
||||||
|
|
||||||
|
0x20 => array( 'JSR', 'Abs' ),
|
||||||
|
0x21 => array( 'AND', 'DPIndexXind' ),
|
||||||
|
0x22 => array( 'JSL', 'AbsLong' ),
|
||||||
|
0x23 => array( 'AND', 'StackRel' ),
|
||||||
|
0x24 => array( 'BIT', 'DP' ),
|
||||||
|
0x25 => array( 'AND', 'DP' ),
|
||||||
|
0x26 => array( 'ROL', 'DP' ),
|
||||||
|
0x27 => array( 'AND', 'DPIndLong' ),
|
||||||
|
0x28 => array( 'PLP', 'StackPull' ),
|
||||||
|
0x29 => array( 'AND', 'Imm' ),
|
||||||
|
0x2A => array( 'ROL', 'Acc' ),
|
||||||
|
0x2B => array( 'PLD', 'StackPull' ),
|
||||||
|
0x2C => array( 'BIT', 'Abs' ),
|
||||||
|
0x2D => array( 'AND', 'Abs' ),
|
||||||
|
0x2E => array( 'ROL', 'Abs' ),
|
||||||
|
0x2F => array( 'AND', 'AbsLong' ),
|
||||||
|
|
||||||
|
0x30 => array( 'BMI', 'PCRel' ),
|
||||||
|
0x31 => array( 'AND', 'DPIndIndexY' ),
|
||||||
|
0x32 => array( 'AND', 'DPInd' ),
|
||||||
|
0x33 => array( 'AND', 'StackRelIndexY' ),
|
||||||
|
0x34 => array( 'BIT', 'DPIndexX' ),
|
||||||
|
0x35 => array( 'AND', 'DPIndexX' ),
|
||||||
|
0x36 => array( 'ROL', 'DPIndexX' ),
|
||||||
|
0x37 => array( 'AND', 'DPIndIndexYLong' ),
|
||||||
|
0x38 => array( 'SEC', 'Implied' ),
|
||||||
|
0x39 => array( 'AND', 'AbsIndexY' ),
|
||||||
|
0x3A => array( 'DEC', 'Acc' ),
|
||||||
|
0x3B => array( 'TSC', 'Implied' ),
|
||||||
|
0x3C => array( 'BIT', 'AbsIndexX' ),
|
||||||
|
0x3D => array( 'AND', 'AbsIndexX' ),
|
||||||
|
0x3E => array( 'ROL', 'AbsIndexX' ),
|
||||||
|
0x3F => array( 'AND', 'AbsIndexXLong' ),
|
||||||
|
|
||||||
|
0x40 => array( 'RTI', 'StackRTI' ),
|
||||||
|
0x41 => array( 'EOR', 'DPIndexXind' ),
|
||||||
|
0x42 => array( 'WDM', 'WDM' ),
|
||||||
|
0x43 => array( 'EOR', 'StackRel' ),
|
||||||
|
0x44 => array( 'MVP', 'BlockMove' ),
|
||||||
|
0x45 => array( 'EOR', 'DP' ),
|
||||||
|
0x46 => array( 'LSR', 'DP' ),
|
||||||
|
0x47 => array( 'EOR', 'DPIndLong' ),
|
||||||
|
0x48 => array( 'PHA', 'StackPush' ),
|
||||||
|
0x49 => array( 'EOR', 'Imm' ),
|
||||||
|
0x4A => array( 'LSR', 'Acc' ),
|
||||||
|
0x4B => array( 'PHK', 'StackPush' ),
|
||||||
|
0x4C => array( 'JMP', 'Abs' ),
|
||||||
|
0x4D => array( 'EOR', 'Abs' ),
|
||||||
|
0x4E => array( 'LSR', 'Abs' ),
|
||||||
|
0x4F => array( 'EOR', 'AbsLong' ),
|
||||||
|
|
||||||
|
0x50 => array( 'BVC', 'PCRel' ),
|
||||||
|
0x51 => array( 'EOR', 'DPIndIndexY' ),
|
||||||
|
0x52 => array( 'EOR', 'DPInd' ),
|
||||||
|
0x53 => array( 'EOR', 'StackRelIndexY' ),
|
||||||
|
0x54 => array( 'MVN', 'BlockMove' ),
|
||||||
|
0x55 => array( 'EOR', 'DPIndexX' ),
|
||||||
|
0x56 => array( 'LSR', 'DPIndexX' ),
|
||||||
|
0x57 => array( 'EOR', 'DPIndIndexYLong' ),
|
||||||
|
0x58 => array( 'CLI', 'Implied' ),
|
||||||
|
0x59 => array( 'EOR', 'AbsIndexY' ),
|
||||||
|
0x5A => array( 'PHY', 'StackPush' ),
|
||||||
|
0x5B => array( 'TCD', 'Implied' ),
|
||||||
|
0x5C => array( 'JMP', 'AbsLong' ),
|
||||||
|
0x5D => array( 'EOR', 'AbsIndexX' ),
|
||||||
|
0x5E => array( 'LSR', 'AbsIndexX' ),
|
||||||
|
0x5F => array( 'EOR', 'AbsIndexXLong' ),
|
||||||
|
|
||||||
|
0x60 => array( 'RTS', 'StackRTS' ),
|
||||||
|
0x61 => array( 'ADC', 'DPIndexXInd' ),
|
||||||
|
0x62 => array( 'PER', 'StackPCRel' ),
|
||||||
|
0x63 => array( 'ADC', 'StackRel' ),
|
||||||
|
0x64 => array( 'STZ', 'DP' ),
|
||||||
|
0x65 => array( 'ADC', 'DP' ),
|
||||||
|
0x66 => array( 'ROR', 'DP' ),
|
||||||
|
0x67 => array( 'ADC', 'DPIndLong' ),
|
||||||
|
0x68 => array( 'PLA', 'StackPull' ),
|
||||||
|
0x69 => array( 'ADC', 'Imm' ),
|
||||||
|
0x6A => array( 'ROR', 'Acc' ),
|
||||||
|
0x6B => array( 'RTL', 'StackRTL' ),
|
||||||
|
0x6C => array( 'JMP', 'AbsInd' ),
|
||||||
|
0x6D => array( 'ADC', 'Abs' ),
|
||||||
|
0x6E => array( 'ROR', 'Abs' ),
|
||||||
|
0x6F => array( 'ADC', 'AbsLong' ),
|
||||||
|
|
||||||
|
0x70 => array( 'BVS', 'PCRel' ),
|
||||||
|
0x71 => array( 'ADC', 'DPIndIndexY' ),
|
||||||
|
0x72 => array( 'ADC', 'DPInd' ),
|
||||||
|
0x73 => array( 'ADC', 'StackRelIndexY' ),
|
||||||
|
0x74 => array( 'STZ', 'DPIndexX' ),
|
||||||
|
0x75 => array( 'ADC', 'DPIndexX' ),
|
||||||
|
0x76 => array( 'ROR', 'DPIndexX' ),
|
||||||
|
0x77 => array( 'ADC', 'DPIndIndexYLong' ),
|
||||||
|
0x78 => array( 'SEI', 'Implied' ),
|
||||||
|
0x79 => array( 'ADC', 'AbsIndexY' ),
|
||||||
|
0x7A => array( 'PLY', 'StackPull' ),
|
||||||
|
0x7B => array( 'TDC', 'Implied' ),
|
||||||
|
0x7C => array( 'JMP', 'AbsIndexXInd' ),
|
||||||
|
0x7D => array( 'ADC', 'AbsIndexX' ),
|
||||||
|
0x7E => array( 'ROR', 'AbsIndexX' ),
|
||||||
|
0x7F => array( 'ADC', 'AbsIndexXLong' ),
|
||||||
|
|
||||||
|
0x80 => array( 'BRA', 'PCRel' ),
|
||||||
|
0x81 => array( 'STA', 'DPIndexXind' ),
|
||||||
|
0x82 => array( 'BRL', 'PCRelLong' ),
|
||||||
|
0x83 => array( 'STA', 'StackRel' ),
|
||||||
|
0x84 => array( 'STY', 'DP' ),
|
||||||
|
0x85 => array( 'STA', 'DP' ),
|
||||||
|
0x86 => array( 'STX', 'DP' ),
|
||||||
|
0x87 => array( 'STA', 'DPIndLong' ),
|
||||||
|
0x88 => array( 'DEY', 'Implied' ),
|
||||||
|
0x89 => array( 'BIT', 'Imm' ),
|
||||||
|
0x8A => array( 'TXA', 'Implied' ),
|
||||||
|
0x8B => array( 'PHB', 'StackPush' ),
|
||||||
|
0x8C => array( 'STY', 'Abs' ),
|
||||||
|
0x8D => array( 'STA', 'Abs' ),
|
||||||
|
0x8E => array( 'STX', 'Abs' ),
|
||||||
|
0x8F => array( 'STA', 'AbsLong' ),
|
||||||
|
|
||||||
|
0x90 => array( 'BCC', 'PCRel' ),
|
||||||
|
0x91 => array( 'STA', 'DPIndIndexY' ),
|
||||||
|
0x92 => array( 'STA', 'DPInd' ),
|
||||||
|
0x93 => array( 'STA', 'StackRelIndexY' ),
|
||||||
|
0x94 => array( 'STY', 'DPIndexX' ),
|
||||||
|
0x95 => array( 'STA', 'DPIndexX' ),
|
||||||
|
0x96 => array( 'STX', 'DPIndexY' ),
|
||||||
|
0x97 => array( 'STA', 'DPIndIndexYLong' ),
|
||||||
|
0x98 => array( 'TYA', 'Implied' ),
|
||||||
|
0x99 => array( 'STA', 'AbsIndexY' ),
|
||||||
|
0x9A => array( 'TXS', 'Implied' ),
|
||||||
|
0x9B => array( 'TXY', 'Implied' ),
|
||||||
|
0x9C => array( 'STZ', 'Abs' ),
|
||||||
|
0x9D => array( 'STA', 'AbsIndexX' ),
|
||||||
|
0x9E => array( 'STZ', 'AbsIndexX' ),
|
||||||
|
0x9F => array( 'STA', 'AbsIndexXLong' ),
|
||||||
|
|
||||||
|
0xA0 => array( 'LDY', 'Imm' ),
|
||||||
|
0xA1 => array( 'LDA', 'DPIndexXInd' ),
|
||||||
|
0xA2 => array( 'LDX', 'Imm' ),
|
||||||
|
0xA3 => array( 'LDA', 'StackRel' ),
|
||||||
|
0xA4 => array( 'LDY', 'DP' ),
|
||||||
|
0xA5 => array( 'LDA', 'DP' ),
|
||||||
|
0xA6 => array( 'LDX', 'DP' ),
|
||||||
|
0xA7 => array( 'LDA', 'DPIndLong' ),
|
||||||
|
0xA8 => array( 'TAY', 'Implied' ),
|
||||||
|
0xA9 => array( 'LDA', 'Imm' ),
|
||||||
|
0xAA => array( 'TAX', 'Implied' ),
|
||||||
|
0xAB => array( 'PLB', 'StackPull' ),
|
||||||
|
0xAC => array( 'LDY', 'Abs' ),
|
||||||
|
0xAD => array( 'LDA', 'Abs' ),
|
||||||
|
0xAE => array( 'LDX', 'Abs' ),
|
||||||
|
0xAF => array( 'LDA', 'AbsLong' ),
|
||||||
|
|
||||||
|
0xB0 => array( 'BCS', 'PCRel' ),
|
||||||
|
0xB1 => array( 'LDA', 'DPIndIndexY' ),
|
||||||
|
0xB2 => array( 'LDA', 'DPInd' ),
|
||||||
|
0xB3 => array( 'LDA', 'StackRelIndexY' ),
|
||||||
|
0xB4 => array( 'LDY', 'DPIndexX' ),
|
||||||
|
0xB5 => array( 'LDA', 'DPIndexX' ),
|
||||||
|
0xB6 => array( 'LDX', 'DPIndexY' ),
|
||||||
|
0xB7 => array( 'LDA', 'DPIndIndexYLong' ),
|
||||||
|
0xB8 => array( 'CLV', 'Implied' ),
|
||||||
|
0xB9 => array( 'LDA', 'AbsIndexY' ),
|
||||||
|
0xBA => array( 'TSX', 'Implied' ),
|
||||||
|
0xBB => array( 'TYX', 'Implied' ),
|
||||||
|
0xBC => array( 'LDY', 'AbsIndexX' ),
|
||||||
|
0xBD => array( 'LDA', 'AbsIndexX' ),
|
||||||
|
0xBE => array( 'LDX', 'AbsIndexY' ),
|
||||||
|
0xBF => array( 'LDA', 'AbsIndexXLong' ),
|
||||||
|
|
||||||
|
0xC0 => array( 'CPY', 'Imm' ),
|
||||||
|
0xC1 => array( 'CMP', 'DPIndexXInd' ),
|
||||||
|
0xC2 => array( 'REP', 'Imm' ),
|
||||||
|
0xC3 => array( 'CMP', 'StackRel' ),
|
||||||
|
0xC4 => array( 'CPY', 'DP' ),
|
||||||
|
0xC5 => array( 'CMP', 'DP' ),
|
||||||
|
0xC6 => array( 'DEC', 'DP' ),
|
||||||
|
0xC7 => array( 'CMP', 'DPIndLong' ),
|
||||||
|
0xC8 => array( 'INY', 'Implied' ),
|
||||||
|
0xC9 => array( 'CMP', 'Imm' ),
|
||||||
|
0xCA => array( 'DEX', 'Implied' ),
|
||||||
|
0xCB => array( 'WAI', 'Implied' ),
|
||||||
|
0xCC => array( 'CPY', 'Abs' ),
|
||||||
|
0xCD => array( 'CMP', 'Abs' ),
|
||||||
|
0xCE => array( 'DEC', 'Abs' ),
|
||||||
|
0xCF => array( 'CMP', 'AbsLong' ),
|
||||||
|
|
||||||
|
0xD0 => array( 'BNE', 'PCRel' ),
|
||||||
|
0xD1 => array( 'CMP', 'DPIndIndexY' ),
|
||||||
|
0xD2 => array( 'CMP', 'DPInd' ),
|
||||||
|
0xD3 => array( 'CMP', 'StackRelIndexY' ),
|
||||||
|
0xD4 => array( 'PEI', 'StackDPInd' ),
|
||||||
|
0xD5 => array( 'CMP', 'DPIndexX' ),
|
||||||
|
0xD6 => array( 'DEC', 'DPIndexX' ),
|
||||||
|
0xD7 => array( 'CMP', 'DPIndIndexYLong' ),
|
||||||
|
0xD8 => array( 'CLD', 'Implied' ),
|
||||||
|
0xD9 => array( 'CMP', 'AbsIndexY' ),
|
||||||
|
0xDA => array( 'PHX', 'StackPush' ),
|
||||||
|
0xDB => array( 'STP', 'Implied' ),
|
||||||
|
0xDC => array( 'JML', 'AbsIndLong' ),
|
||||||
|
0xDD => array( 'CMP', 'AbsIndexX' ),
|
||||||
|
0xDE => array( 'DEC', 'AbsIndexX' ),
|
||||||
|
0xDF => array( 'CMP', 'AbsIndexXLong' ),
|
||||||
|
|
||||||
|
0xE0 => array( 'CPX', 'Imm' ),
|
||||||
|
0xE1 => array( 'SBC', 'DPIndexXInd' ),
|
||||||
|
0xE2 => array( 'SEP', 'Imm' ),
|
||||||
|
0xE3 => array( 'SBC', 'StackRel' ),
|
||||||
|
0xE4 => array( 'CPX', 'DP' ),
|
||||||
|
0xE5 => array( 'SBC', 'DP' ),
|
||||||
|
0xE6 => array( 'INC', 'DP' ),
|
||||||
|
0xE7 => array( 'SBC', 'DPIndLong' ),
|
||||||
|
0xE8 => array( 'INX', 'Implied' ),
|
||||||
|
0xE9 => array( 'SBC', 'Imm' ),
|
||||||
|
0xEA => array( 'NOP', 'Implied' ),
|
||||||
|
0xEB => array( 'XBA', 'Implied' ),
|
||||||
|
0xEC => array( 'CPX', 'Abs' ),
|
||||||
|
0xED => array( 'SBC', 'Abs' ),
|
||||||
|
0xEE => array( 'INC', 'Abs' ),
|
||||||
|
0xEF => array( 'SBC', 'AbsLong' ),
|
||||||
|
|
||||||
|
0xF0 => array( 'BEQ', 'PCRel' ),
|
||||||
|
0xF1 => array( 'SBC', 'DPIndIndexY' ),
|
||||||
|
0xF2 => array( 'SBC', 'DPInd' ),
|
||||||
|
0xF3 => array( 'SBC', 'StackRelIndexY' ),
|
||||||
|
0xF4 => array( 'PEA', 'StackAbs' ),
|
||||||
|
0xF5 => array( 'SBC', 'DPIndexX' ),
|
||||||
|
0xF6 => array( 'INC', 'DPIndexX' ),
|
||||||
|
0xF7 => array( 'SBC', 'DPIndIndexYLong' ),
|
||||||
|
0xF8 => array( 'SED', 'Implied' ),
|
||||||
|
0xF9 => array( 'SBC', 'AbsIndexY' ),
|
||||||
|
0xFA => array( 'PLX', 'StackPull' ),
|
||||||
|
0xFB => array( 'XCE', 'Implied' ),
|
||||||
|
0xFC => array( 'JSR', 'AbsIndexXInd' ),
|
||||||
|
0xFD => array( 'SBC', 'AbsIndexX' ),
|
||||||
|
0xFE => array( 'INC', 'AbsIndexX' ),
|
||||||
|
0xFF => array( 'SBC', 'AbsIndexXLong' ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rel_offset( $pc, $offset ) - compute absolute offset vs program counter for a branch offset
|
||||||
|
*
|
||||||
|
* @param $pc int, $offset int
|
||||||
|
*/
|
||||||
|
private function rel_offset( $pc, $offset, $offset2 )
|
||||||
|
{
|
||||||
|
if( $offset > 127 )
|
||||||
|
{
|
||||||
|
$result = $pc - (256-$offset);
|
||||||
|
} else {
|
||||||
|
$result = $pc + $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result += $offset2+1;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rel_long_offset( $pc, $offset ) - compute absolute offset vs program counter for a branch offset
|
||||||
|
*
|
||||||
|
* @param $pc int, $offset int
|
||||||
|
*/
|
||||||
|
private function rel_long_offset( $pc, $offset, $offset2 )
|
||||||
|
{
|
||||||
|
if( $offset > 32767 )
|
||||||
|
{
|
||||||
|
$result = $pc - (65536-$offset);
|
||||||
|
} else {
|
||||||
|
$result = $pc + $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result += $offset2+1;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print_instruction( $opcode_txt, $opcode, $mode, $arg_bytes, $pc ) - Output text-friendly disassembled output for one instruction
|
||||||
|
*
|
||||||
|
* @param $opcode_txt str, $opcode int, $mode str, $arg_bytes str, $pc int
|
||||||
|
*/
|
||||||
|
public function print_instruction( $opcode_txt, $opcode, $mode, $arg_bytes, $pc )
|
||||||
|
{
|
||||||
|
// first print the program counter and hex bytes
|
||||||
|
switch( strlen( $arg_bytes ))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
$output = sprintf( '%06X- %02X ', $pc, $opcode );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$output = sprintf( '%06X- %02X %02X ', $pc, $opcode, ord($arg_bytes[0]) );
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$output = sprintf( '%06X- %02X %02X %02X ', $pc, $opcode, ord($arg_bytes[0]), ord($arg_bytes[1]) );
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$output = sprintf( '%06X- %02X %02X %02X %02X ', $pc, $opcode, ord($arg_bytes[0]), ord($arg_bytes[1]), ord($arg_bytes[2]) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now the opcode
|
||||||
|
$output .= $opcode_txt;
|
||||||
|
|
||||||
|
// now the args depending on mode
|
||||||
|
switch( $mode )
|
||||||
|
{
|
||||||
|
case 'Implied':
|
||||||
|
case 'StackPull':
|
||||||
|
case 'StackPush':
|
||||||
|
case 'StackRTI':
|
||||||
|
case 'StackRTS':
|
||||||
|
case 'Acc':
|
||||||
|
break;
|
||||||
|
case 'DP':
|
||||||
|
$output .= sprintf( ' %02X', ord($arg_bytes[0] ));
|
||||||
|
break;
|
||||||
|
case 'DPIndexX':
|
||||||
|
$output .= sprintf( ' %02X,X', ord($arg_bytes[0] ));
|
||||||
|
break;
|
||||||
|
case 'DPIndexY':
|
||||||
|
$output .= sprintf( ' %02X,Y', ord($arg_bytes[0] ));
|
||||||
|
break;
|
||||||
|
case 'DPIndexXInd':
|
||||||
|
$output .= sprintf( ' (%02X,X)', ord($arg_bytes[0] ));
|
||||||
|
break;
|
||||||
|
case 'DPInd':
|
||||||
|
$output .= sprintf( ' (%02X)', ord($arg_bytes[0] ));
|
||||||
|
break;
|
||||||
|
case 'DPIndIndexY':
|
||||||
|
$output .= sprintf( ' (%02X),Y', ord($arg_bytes[0] ));
|
||||||
|
break;
|
||||||
|
case 'Imm':
|
||||||
|
if( strlen( $arg_bytes ) == 2 )
|
||||||
|
{
|
||||||
|
$output .= sprintf( ' #%02X%02X', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
} else {
|
||||||
|
$output .= sprintf( ' #%02X', ord($arg_bytes[0] ));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'PCRel':
|
||||||
|
if( ord($arg_bytes[0]) > 127)
|
||||||
|
{
|
||||||
|
$output .= sprintf( ' %04X {-%02X}', $this->rel_offset( $pc, ord($arg_bytes[0]),strlen($arg_bytes)), 256-ord($arg_bytes[0]));
|
||||||
|
} else {
|
||||||
|
$output .= sprintf( ' %04X {+%02X}', $this->rel_offset( $pc, ord($arg_bytes[0]),strlen($arg_bytes)), ord($arg_bytes[0]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Abs':
|
||||||
|
$output .= sprintf( ' %02X%02X', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'AbsIndexX':
|
||||||
|
$output .= sprintf( ' %02X%02X,X', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'AbsIndexY':
|
||||||
|
$output .= sprintf( ' %02X%02X,Y', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'AbsIndexXInd':
|
||||||
|
$output .= sprintf( ' (%02X%02X,X)', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'AbsInd':
|
||||||
|
$output .= sprintf( ' (%02X%02X)', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'WDM':
|
||||||
|
case 'StackInt':
|
||||||
|
if( strlen( $arg_bytes ) > 0 )
|
||||||
|
{
|
||||||
|
$output .= sprintf( ' %02X', ord($arg_bytes[0] ));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'AbsIndLong':
|
||||||
|
$output .= sprintf( ' (%02X%02X)', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'AbsLong':
|
||||||
|
$output .= sprintf( ' %02X%02X%02X', ord($arg_bytes[2]), ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'AbsIndexXLong':
|
||||||
|
$output .= sprintf( ' %02X%02X%02X,X', ord($arg_bytes[2]), ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'BlockMove':
|
||||||
|
$output .= sprintf( ' %02X,%02X', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'DPIndLong':
|
||||||
|
$output .= sprintf( ' [%02X]', ord($arg_bytes[0] ));
|
||||||
|
break;
|
||||||
|
case 'DPIndIndexYLong':
|
||||||
|
$output .= sprintf( ' [%02X],Y', ord($arg_bytes[0] ));
|
||||||
|
break;
|
||||||
|
case 'StackPCRel':
|
||||||
|
case 'PCRelLong':
|
||||||
|
$offset = (ord($arg_bytes[1])*256)+ord($arg_bytes[0]);
|
||||||
|
if( $offset > 32767 )
|
||||||
|
{
|
||||||
|
$output .= sprintf( ' %04X {-%02X}', $this->rel_long_offset( $pc, $offset, strlen($arg_bytes)), 65536-$offset);
|
||||||
|
} else {
|
||||||
|
$output .= sprintf( ' %04X {+%02X}', $this->rel_long_offset( $pc, $offset, strlen($arg_bytes)), $offset);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'StackAbs':
|
||||||
|
$output .= sprintf( ' %02X%02X', ord($arg_bytes[1]), ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'StackDPInd':
|
||||||
|
$output .= sprintf( ' %02X', ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'StackRel':
|
||||||
|
$output .= sprintf( ' %02X,S', ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
case 'StackRelIndexY':
|
||||||
|
$output .= sprintf( ' (%02X,S),Y', ord($arg_bytes[0]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disassemble( $m_flag, $x_flag, $e_flag, $origin, $data, $personality ) - Disassemble some data
|
||||||
|
*
|
||||||
|
* @param $m_flag bool, $x_flag bool, $e_flag bool, $origin int, $data str, $personality obj
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function disassemble( $m_flag, $x_flag, $e_flag, $origin, $data, $personality )
|
||||||
|
{
|
||||||
|
$pc = $origin;
|
||||||
|
$data_index = 0;
|
||||||
|
$last_output = '';
|
||||||
|
|
||||||
|
echo " ORG ".sprintf('%06X',$origin)."\n";
|
||||||
|
if( $m_flag > 0)
|
||||||
|
{
|
||||||
|
$print_m = '1';
|
||||||
|
} else {
|
||||||
|
$print_m = '0';
|
||||||
|
}
|
||||||
|
if( $x_flag > 0 )
|
||||||
|
{
|
||||||
|
$print_x = '1';
|
||||||
|
} else {
|
||||||
|
$print_x = '0';
|
||||||
|
}
|
||||||
|
echo " MX %{$print_m}{$print_x}\n\n";
|
||||||
|
|
||||||
|
while( $data_index < strlen( $data ))
|
||||||
|
{
|
||||||
|
$opcode = $data[$data_index];
|
||||||
|
$opcode_txt = $this->opcodes[ord($opcode)][0];
|
||||||
|
$mode = $this->opcodes[ord($opcode)][1];
|
||||||
|
|
||||||
|
// get opcode width
|
||||||
|
$width = 0;
|
||||||
|
switch( $mode )
|
||||||
|
{
|
||||||
|
case 'Acc':
|
||||||
|
case 'Implied':
|
||||||
|
case 'StackPull':
|
||||||
|
case 'StackPush':
|
||||||
|
case 'StackRTI':
|
||||||
|
case 'StackRTL':
|
||||||
|
case 'StackRTS':
|
||||||
|
$width = 1;
|
||||||
|
break;
|
||||||
|
case 'DP':
|
||||||
|
case 'DPIndexX':
|
||||||
|
case 'DPIndexY':
|
||||||
|
case 'DPIndexXInd':
|
||||||
|
case 'DPInd':
|
||||||
|
case 'DPIndLong':
|
||||||
|
case 'DPIndIndexY':
|
||||||
|
case 'DPIndIndexYLong':
|
||||||
|
case 'PCRel':
|
||||||
|
case 'StackRel':
|
||||||
|
case 'StackRelIndexY':
|
||||||
|
case 'StackDPInd':
|
||||||
|
$width = 2;
|
||||||
|
break;
|
||||||
|
case 'Abs':
|
||||||
|
case 'AbsIndexX':
|
||||||
|
case 'AbsIndexY':
|
||||||
|
case 'AbsIndexXInd':
|
||||||
|
case 'AbsInd':
|
||||||
|
case 'AbsIndLong':
|
||||||
|
case 'BlockMove':
|
||||||
|
case 'PCRelLong':
|
||||||
|
case 'StackAbs':
|
||||||
|
case 'StackPCRel':
|
||||||
|
$width = 3;
|
||||||
|
break;
|
||||||
|
case 'AbsLong':
|
||||||
|
case 'AbsIndexXLong':
|
||||||
|
$width = 4;
|
||||||
|
break;
|
||||||
|
case 'StackInt':
|
||||||
|
if( $e_flag )
|
||||||
|
{
|
||||||
|
$width = 1;
|
||||||
|
} else {
|
||||||
|
$width = 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Imm':
|
||||||
|
$width = 2;
|
||||||
|
if( $e_flag == 0 )
|
||||||
|
{
|
||||||
|
if( in_array( $opcode_txt, array( 'CPX', 'CPY', 'LDX', 'LDY' )))
|
||||||
|
{
|
||||||
|
if( $x_flag == 0 )
|
||||||
|
{
|
||||||
|
$width = 3;
|
||||||
|
}
|
||||||
|
} elseif( in_array( $opcode_txt, array( 'ADC', 'AND', 'BIT', 'CMP', 'EOR', 'LDA', 'ORA', 'SBC' )))
|
||||||
|
{
|
||||||
|
if( $m_flag == 0 )
|
||||||
|
{
|
||||||
|
$width = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'WDM':
|
||||||
|
$width = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$width = 1;
|
||||||
|
break;
|
||||||
|
} // switch
|
||||||
|
|
||||||
|
// fetch arguments if any
|
||||||
|
$arg_bytes = '';
|
||||||
|
for( $ind=1;$ind<$width;$ind++ )
|
||||||
|
{
|
||||||
|
$arg_bytes .= $data[$data_index + $ind];
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = $this->print_instruction( $opcode_txt, ord($opcode), $mode, $arg_bytes, $pc );
|
||||||
|
|
||||||
|
// Personality support
|
||||||
|
$this_output = substr( $output, 22 );
|
||||||
|
$comment = $personality->check( $last_output, $this_output );
|
||||||
|
if( $comment )
|
||||||
|
{
|
||||||
|
for($pad=strlen($output);$pad<42;$pad++)
|
||||||
|
{
|
||||||
|
$output .= ' ';
|
||||||
|
}
|
||||||
|
$output .= '; '.$comment;
|
||||||
|
}
|
||||||
|
$last_output = $this_output;
|
||||||
|
|
||||||
|
echo "{$output}\n";
|
||||||
|
$pc += $width;
|
||||||
|
$data_index += $width;
|
||||||
|
} // for
|
||||||
|
}
|
||||||
|
}
|
233
Input/Input_2MG.php
Normal file
233
Input/Input_2MG.php
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Input_2MG - YAGSDisasm Input block device for .2MG image files
|
||||||
|
* from http://apple2.org.za/gswv/a2zine/Docs/DiskImage_2MG_Info.txt
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Input_2MG
|
||||||
|
{
|
||||||
|
// have we been initialized yet?
|
||||||
|
private $is_initialized = false;
|
||||||
|
|
||||||
|
// source filename
|
||||||
|
private $source_filename;
|
||||||
|
|
||||||
|
// creator_id
|
||||||
|
private $creator_id;
|
||||||
|
|
||||||
|
// 2mg comment
|
||||||
|
private $comment = '';
|
||||||
|
|
||||||
|
// number of 512-byte blocks in image
|
||||||
|
private $total_blocks;
|
||||||
|
|
||||||
|
// header length
|
||||||
|
private $header_length;
|
||||||
|
|
||||||
|
// version number
|
||||||
|
private $version_number;
|
||||||
|
|
||||||
|
// image format
|
||||||
|
private $image_format;
|
||||||
|
|
||||||
|
// disk is locked?
|
||||||
|
private $is_locked=false;
|
||||||
|
|
||||||
|
// offset to image data
|
||||||
|
private $image_offset;
|
||||||
|
|
||||||
|
// DOS 3.3 Volume Number
|
||||||
|
private $volume_number;
|
||||||
|
|
||||||
|
// volume length in bytes
|
||||||
|
private $total_bytes;
|
||||||
|
|
||||||
|
// offset to comment
|
||||||
|
private $comment_offset;
|
||||||
|
|
||||||
|
// length of comment
|
||||||
|
private $comment_length;
|
||||||
|
|
||||||
|
// 2MG Creator data offset
|
||||||
|
private $creator_data_offset;
|
||||||
|
|
||||||
|
// 2MG Creator data length
|
||||||
|
private $creator_data_length;
|
||||||
|
|
||||||
|
// our file descriptor
|
||||||
|
private $fp;
|
||||||
|
|
||||||
|
public function __construct( $filename )
|
||||||
|
{
|
||||||
|
$fp = fopen( $filename, 'r' );
|
||||||
|
if( !$fp )
|
||||||
|
{
|
||||||
|
throw new Exception( 'Input_2MG: Unable to open source file '.$filename );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->source_filename = $filename;
|
||||||
|
|
||||||
|
// check for 2MG magic
|
||||||
|
$magic = fread( $fp, 4 );
|
||||||
|
if( $magic != '2IMG' )
|
||||||
|
{
|
||||||
|
throw new Exception( 'Input_2MG: source file not a 2MG file' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// save creator id
|
||||||
|
$this->creator_id = fread( $fp, 4 );
|
||||||
|
|
||||||
|
// get header length (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$this->header_length = (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// get version number (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$this->version_number = (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// get image format (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
$image_format_id = (ord( $byte4 )*16777216) + (ord( $byte3 )*65536) + (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
$known_format_ids = array(
|
||||||
|
0 => 'DOS 3.3',
|
||||||
|
1 => 'ProDOS',
|
||||||
|
2 => 'NIB',
|
||||||
|
);
|
||||||
|
$this->image_format = $known_format_ids[$image_format_id];
|
||||||
|
|
||||||
|
// flags / volume number (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
if( ord( $byte2 ) && 0x01 )
|
||||||
|
{
|
||||||
|
$this->volume_number = ord( $byte1 );
|
||||||
|
} else {
|
||||||
|
if( $image_format_id == 1 )
|
||||||
|
{
|
||||||
|
$this->volume_number = 254;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( ord( $byte4 ) && 0x80 )
|
||||||
|
{
|
||||||
|
$this->is_locked = true;
|
||||||
|
} else {
|
||||||
|
$this->is_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// block count (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
$this->total_blocks = (ord( $byte4 )*16777216) + (ord( $byte3 )*65536) + (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// offset to image data (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
$this->image_offset = (ord( $byte4 )*16777216) + (ord( $byte3 )*65536) + (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// bytes of disk data (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
$this->total_bytes = (ord( $byte4 )*16777216) + (ord( $byte3 )*65536) + (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// offset to comment (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
$this->comment_offset = (ord( $byte4 )*16777216) + (ord( $byte3 )*65536) + (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// comment length (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
$this->comment_length = (ord( $byte4 )*16777216) + (ord( $byte3 )*65536) + (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// creator data offset (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
$this->creator_data_offset = (ord( $byte4 )*16777216) + (ord( $byte3 )*65536) + (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// creator data length (little-endian)
|
||||||
|
$byte1 = fread( $fp, 1 );
|
||||||
|
$byte2 = fread( $fp, 1 );
|
||||||
|
$byte3 = fread( $fp, 1 );
|
||||||
|
$byte4 = fread( $fp, 1 );
|
||||||
|
$this->creator_data_length = (ord( $byte4 )*16777216) + (ord( $byte3 )*65536) + (ord( $byte2 )*256) + ord( $byte1 );
|
||||||
|
|
||||||
|
// reserved bytes
|
||||||
|
$reserved = fread( $fp, 8 );
|
||||||
|
|
||||||
|
// get Comment string if present
|
||||||
|
if( $this->comment_length > 0 )
|
||||||
|
{
|
||||||
|
fseek( $fp, $this->comment_offset, SEEK_SET );
|
||||||
|
$this->comment = fread( $fp, $this->comment_length );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->is_initialized = true;
|
||||||
|
$this->fp = $fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getBlocks( $starting_block, $num_blocks ) - Retrieve $num_blocks 512-byte blocks from the file, starting at $starting_block
|
||||||
|
* @param $starting_block int, $num_blocks int
|
||||||
|
* @return $data str
|
||||||
|
*/
|
||||||
|
public function getBlocks( $starting_block, $num_blocks )
|
||||||
|
{
|
||||||
|
fseek( $this->fp, $this->image_offset, SEEK_SET );
|
||||||
|
fseek( $this->fp, $starting_block*512, SEEK_CUR );
|
||||||
|
$data = '';
|
||||||
|
for( $blk=0;$blk<$num_blocks;$blk++ )
|
||||||
|
{
|
||||||
|
$data .= fread( $this->fp, 512 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* printInfo() - Print some information about this 2MG image
|
||||||
|
*/
|
||||||
|
public function printInfo()
|
||||||
|
{
|
||||||
|
echo "Source Filename: ".$this->source_filename."\n";
|
||||||
|
echo " Creator ID: ".$this->creator_id."\n";
|
||||||
|
echo " Header Length: ".$this->header_length."\n";
|
||||||
|
echo " Version Number: ".$this->version_number."\n";
|
||||||
|
echo " Image Format: ".$this->image_format."\n";
|
||||||
|
if( $this->image_format == 'DOS 3.3' )
|
||||||
|
{
|
||||||
|
echo " Volume Number: ".$this->volume_number."\n";
|
||||||
|
}
|
||||||
|
echo " Is Locked? ";
|
||||||
|
if( $this->is_locked )
|
||||||
|
{
|
||||||
|
echo "Yes\n";
|
||||||
|
} else {
|
||||||
|
echo "No\n";
|
||||||
|
}
|
||||||
|
echo " Block Count: ".$this->total_blocks."\n";
|
||||||
|
echo " Total Bytes: ".$this->total_bytes."\n";
|
||||||
|
if( $this->comment != '' )
|
||||||
|
{
|
||||||
|
echo " Comment: ".$this->comment."\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
Input/Input_BIN.php
Normal file
66
Input/Input_BIN.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Input_BIN - YAGSDisasm Input byte device for binary blobs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Input_BIN
|
||||||
|
{
|
||||||
|
// have we been initialized yet?
|
||||||
|
private $is_initialized = false;
|
||||||
|
|
||||||
|
// source filename
|
||||||
|
private $source_filename;
|
||||||
|
|
||||||
|
// volume length in bytes
|
||||||
|
private $total_bytes;
|
||||||
|
|
||||||
|
// our file descriptor
|
||||||
|
private $fp;
|
||||||
|
|
||||||
|
public function __construct( $filename )
|
||||||
|
{
|
||||||
|
$fp = fopen( $filename, 'r' );
|
||||||
|
if( !$fp )
|
||||||
|
{
|
||||||
|
throw new Exception( 'Input_BIN: Unable to open source file '.$filename );
|
||||||
|
}
|
||||||
|
|
||||||
|
// source filename
|
||||||
|
$this->source_filename = $filename;
|
||||||
|
|
||||||
|
// bytes of disk data
|
||||||
|
$this->total_bytes = filesize( $filename );
|
||||||
|
|
||||||
|
$this->is_initialized = true;
|
||||||
|
$this->fp = $fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getBytes( $starting_byte, $num_bytes ) - Retrieve $num_bytes bytes from the file, starting at $starting_byte
|
||||||
|
* @param $starting_byte int, $num_bytes int
|
||||||
|
* @return $data str
|
||||||
|
*/
|
||||||
|
public function getBytes( $starting_byte, $num_bytes )
|
||||||
|
{
|
||||||
|
if( $num_bytes == 'all' )
|
||||||
|
{
|
||||||
|
return file_get_contents( $this->source_filename );
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek( $fp, $starting_byte, SEEK_SET );
|
||||||
|
$data = '';
|
||||||
|
$data .= fread( $fp, $num_bytes );
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* printInfo() - Print some information about this binary image
|
||||||
|
*/
|
||||||
|
public function printInfo()
|
||||||
|
{
|
||||||
|
echo "Source Filename: ".$this->source_filename."\n";
|
||||||
|
echo " Image Format: Binary\n";
|
||||||
|
echo " Total Bytes: ".$this->total_bytes."\n";
|
||||||
|
}
|
||||||
|
}
|
72
Input/Input_PO.php
Normal file
72
Input/Input_PO.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Input_PO - YAGSDisasm Input block device for .PO image files
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Input_PO
|
||||||
|
{
|
||||||
|
// have we been initialized yet?
|
||||||
|
private $is_initialized = false;
|
||||||
|
|
||||||
|
// source filename
|
||||||
|
private $source_filename;
|
||||||
|
|
||||||
|
// number of 512-byte blocks in image
|
||||||
|
private $total_blocks;
|
||||||
|
|
||||||
|
// volume length in bytes
|
||||||
|
private $total_bytes;
|
||||||
|
|
||||||
|
// our file descriptor
|
||||||
|
private $fp;
|
||||||
|
|
||||||
|
public function __construct( $filename )
|
||||||
|
{
|
||||||
|
$fp = fopen( $filename, 'r' );
|
||||||
|
if( !$fp )
|
||||||
|
{
|
||||||
|
throw new Exception( 'Input_PO: Unable to open source file '.$filename );
|
||||||
|
}
|
||||||
|
|
||||||
|
// source filename
|
||||||
|
$this->source_filename = $filename;
|
||||||
|
|
||||||
|
// bytes of disk data
|
||||||
|
$this->total_bytes = filesize( $filename );
|
||||||
|
|
||||||
|
// block count (little-endian)
|
||||||
|
$this->total_blocks = $this->total_bytes / 512;
|
||||||
|
|
||||||
|
$this->is_initialized = true;
|
||||||
|
$this->fp = $fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getBlocks( $starting_block, $num_blocks ) - Retrieve $num_blocks 512-byte blocks from the file, starting at $starting_block
|
||||||
|
* @param $starting_block int, $num_blocks int
|
||||||
|
* @return $data str
|
||||||
|
*/
|
||||||
|
public function getBlocks( $starting_block, $num_blocks )
|
||||||
|
{
|
||||||
|
fseek( $fp, $this->image_offset, SEEK_SET );
|
||||||
|
fseek( $fp, $starting_block*512 );
|
||||||
|
$data = '';
|
||||||
|
for( $blk=0;$blk<$num_blocks;$blk++ )
|
||||||
|
{
|
||||||
|
$data .= fread( $fp, 512 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* printInfo() - Print some information about this PO image
|
||||||
|
*/
|
||||||
|
public function printInfo()
|
||||||
|
{
|
||||||
|
echo "Source Filename: ".$this->source_filename."\n";
|
||||||
|
echo " Image Format: ProDOS\n";
|
||||||
|
echo " Block Count: ".$this->total_blocks."\n";
|
||||||
|
echo " Total Bytes: ".$this->total_bytes."\n";
|
||||||
|
}
|
||||||
|
}
|
25
LICENSE.txt
Normal file
25
LICENSE.txt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2009, CiderPress project authors
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of FaddenSoft, LLC nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY FaddenSoft, LLC ``AS IS'' AND ANY
|
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL FaddenSoft, LLC BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
2516
NList.Data.TXT
Normal file
2516
NList.Data.TXT
Normal file
File diff suppressed because it is too large
Load Diff
87
Personality/Personality_AppleIIGS.php
Normal file
87
Personality/Personality_AppleIIGS.php
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Personality_AppleIIGS - Handle things specific to the Apple IIGS computer (for auto-documentation)
|
||||||
|
*/
|
||||||
|
class Personality_AppleIIGS
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* getlines( $fp, $numlines ) - Parse some lines out of the NiftyList file
|
||||||
|
*
|
||||||
|
* @param $fp res, $numlines int
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getlines( $fp, $numlines )
|
||||||
|
{
|
||||||
|
$retarr = array();
|
||||||
|
|
||||||
|
for($x=0;$x<$numlines;$x++)
|
||||||
|
{
|
||||||
|
$line = trim( fgets( $fp ));
|
||||||
|
$addr = substr( $line, 0, 4 );
|
||||||
|
$data = substr( $line, 5 );
|
||||||
|
$retarr[$addr] = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $retarr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$fp = fopen( 'NList.Data.TXT', 'r' );
|
||||||
|
if( !$fp )
|
||||||
|
{
|
||||||
|
throw new Exception( "Personality_AppleIIGS: Couldn't open NiftyList data file" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse some stuff out of the NiftyList data file
|
||||||
|
$throwaway = $this->getlines( $fp, 4 );
|
||||||
|
$this->nlist_prodos8 = $this->getlines( $fp, 33-5+1 );
|
||||||
|
$throwaway = $this->getlines( $fp, 1 );
|
||||||
|
$this->nlist_prodos16 = $this->getlines( $fp, 151-35+1 );
|
||||||
|
$throwaway = $this->getlines( $fp, 1 );
|
||||||
|
$this->nlist_toolbox = $this->getlines( $fp, 1544-153+1 );
|
||||||
|
$throwaway = $this->getlines( $fp, 1 );
|
||||||
|
$this->nlist_e1xxxx = $this->getlines( $fp, 1620-1546+1 );
|
||||||
|
$throwaway = $this->getlines( $fp, 1 );
|
||||||
|
$this->nlist_e0xxxx = $this->getlines( $fp, 1637-1622+1 );
|
||||||
|
$throwaway = $this->getlines( $fp, 1 );
|
||||||
|
$this->nlist_ssf8rom = $this->getlines( $fp, 1911-1639+1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check( $last_instruction, $this_instruction ) - Check if something comment-worthy has occurred
|
||||||
|
*
|
||||||
|
* @param $last_instruction str, $this_isntruction str
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function check( $last_instruction, $this_instruction )
|
||||||
|
{
|
||||||
|
$comment = false;
|
||||||
|
|
||||||
|
// softswitches and 8-bit firmware
|
||||||
|
$addr_part = substr( $this_instruction, -5 );
|
||||||
|
if( $addr_part[0] == ' ' )
|
||||||
|
{
|
||||||
|
if( $this->nlist_ssf8rom[substr($addr_part,1)] )
|
||||||
|
{
|
||||||
|
$comment = $this->nlist_ssf8rom[substr($addr_part,1)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// toolbox entry
|
||||||
|
if( $this_instruction == 'JSL E10000' )
|
||||||
|
{
|
||||||
|
if( substr( $last_instruction, 0, 3 ) == 'LDX' )
|
||||||
|
{
|
||||||
|
$toolcall_number = substr( $last_instruction, -4 );
|
||||||
|
|
||||||
|
if( $this->nlist_toolbox[$toolcall_number] )
|
||||||
|
{
|
||||||
|
$comment = 'Toolbox: '.$this->nlist_toolbox[$toolcall_number];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $comment;
|
||||||
|
}
|
||||||
|
}
|
48
README.md
Normal file
48
README.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
yagsdisasm - Yet Another GS Disassembler
|
||||||
|
========================================
|
||||||
|
|
||||||
|
yagsdisasm is written in PHP, which may be an unfortunate choice of languages to many, but is nearly-universally available and makes for a product that's easy to modify, when written properly.
|
||||||
|
|
||||||
|
the disassembly engine is largely inspired by Andy McFadden's Ciderpress disassembly engine, which is why we copy his license terms in LICENSE.txt
|
||||||
|
|
||||||
|
as of 5/25/2016, the project is only a couple hours old and is a proof of concept. future revisions to come later
|
||||||
|
|
||||||
|
### Example Run:
|
||||||
|
|
||||||
|
$ php yagsdisasm.php -x 0 -m 0 -e 0 -f /Applications/Emulation/Apple\ IIGS/images/WhatIs/Alien\ Mind/Alien\ Mind\ Dk1.2mg -s 1 -n 1 -k 1 -o 801| more
|
||||||
|
ORG 000801
|
||||||
|
MX %00
|
||||||
|
|
||||||
|
000801- 0A ASL
|
||||||
|
000802- A9 10 00 LDA #0010
|
||||||
|
000805- 8D 9F 0A STA 0A9F
|
||||||
|
000808- A9 00 01 LDA #0100
|
||||||
|
00080B- 8D A1 0A STA 0AA1
|
||||||
|
00080E- 60 RTS
|
||||||
|
00080F- 20 62 09 JSR 0962
|
||||||
|
000812- F4 00 00 PEA 0000
|
||||||
|
000815- F4 07 00 PEA 0007
|
||||||
|
000818- F4 00 20 PEA 2000
|
||||||
|
00081B- F4 00 40 PEA 4000
|
||||||
|
00081E- F4 00 00 PEA 0000
|
||||||
|
000821- F4 36 0A PEA 0A36
|
||||||
|
000824- F4 00 00 PEA 0000
|
||||||
|
000827- F4 3A 0A PEA 0A3A
|
||||||
|
00082A- A2 03 27 LDX #2703
|
||||||
|
00082D- 22 00 00 E1 JSL E10000 ; Toolbox: UnPackBytes(@Buff,BfSz,@StartPtr,@Sz):Size
|
||||||
|
000831- 68 PLA
|
||||||
|
000832- 8D 00 03 STA 0300
|
||||||
|
000835- 60 RTS
|
||||||
|
000836- 00 20 BRK 20
|
||||||
|
000838- E1 00 SBC (00,X)
|
||||||
|
00083A- 00 80 BRK 80
|
||||||
|
00083C- 20 67 09 JSR 0967
|
||||||
|
00083F- 2C 10 C0 BIT C010 ; r:KBDSTRB
|
||||||
|
000842- AD 00 C0 LDA C000 ; r:KBD w:CLR80COL
|
||||||
|
000845- 30 13 BMI 085A {+13}
|
||||||
|
000847- AD 61 C0 LDA C061 ; r:BUTN0
|
||||||
|
00084A- 30 0E BMI 085A {+0E}
|
||||||
|
00084C- AD 62 C0 LDA C062 ; r:BUTN1
|
||||||
|
00084F- 30 09 BMI 085A {+09}
|
||||||
|
000851- AD 27 C0 LDA C027 ; rw:KMSTATUS
|
||||||
|
000854- 89 80 D0 BIT #D080
|
181
yagsdisasm.php
Normal file
181
yagsdisasm.php
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* YAGSDisasm - A 65C816 disassembler for Apple IIGS code and disk images
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
require_once( 'Input/Input_2MG.php' );
|
||||||
|
require_once( 'Input/Input_PO.php' );
|
||||||
|
require_once( 'Input/Input_BIN.php' );
|
||||||
|
require_once( 'Disassembler/Disassembler_65816.php' );
|
||||||
|
require_once( 'Personality/Personality_AppleIIGS.php' );
|
||||||
|
|
||||||
|
// version string
|
||||||
|
$version_str = '1.0a';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* begin options parsing here
|
||||||
|
*/
|
||||||
|
$options = getopt( 'p:e:x:m:f:s:n:o:Vvhk:' );
|
||||||
|
|
||||||
|
if( isset( $options['V'] ))
|
||||||
|
{
|
||||||
|
echo "Version: {$version_str}\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( isset( $options['h'] ))
|
||||||
|
{
|
||||||
|
echo <<<EOF
|
||||||
|
YAGSDisasm - A 65C816 disassembler for Apple IIGS code and disk images
|
||||||
|
|
||||||
|
usage: php yagsdisasm.php [options]
|
||||||
|
-p specify machine personality (for auto commenting and formatting)
|
||||||
|
iigs - Apple IIGS (this is presently the only target)
|
||||||
|
-e value of E cpu flag (1 is emulation mode)
|
||||||
|
-x value of X cpu flag (1 is short X/Y register)
|
||||||
|
-m value of M cpu flag (1 is short accumulator)
|
||||||
|
-f specifies input file (required)
|
||||||
|
-i specifies format of input
|
||||||
|
2mg - .2mg disk (see -s, -n options)
|
||||||
|
po - .po disk image (see -s, -n options)
|
||||||
|
bin - binary blob (see -s, -n options which will refer to bytes instead of blocks, default is to disassemble the whole thing)
|
||||||
|
default behavior is to guess by file extension
|
||||||
|
-s starting disk block to disassemble (if input is binary blob, this is starting offset into file)
|
||||||
|
-n number of disk blocks to disassemble (if input is binary blob, this is length to disassemble from file)
|
||||||
|
-k skip this number of bytes from beginning when disassembling
|
||||||
|
-o 24-bit origin address, in hex (eg 002000)
|
||||||
|
addresses shorter than 24 bits will be zero-filled
|
||||||
|
addresses longer than 24 bits will be truncated
|
||||||
|
-v verbose/debugging info
|
||||||
|
-V print version information and exit
|
||||||
|
|
||||||
|
EOF;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle defaults and specification for filename and format
|
||||||
|
if( !isset( $options['f'] ))
|
||||||
|
{
|
||||||
|
echo "Filename must be specified with -f\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = $options['f'];
|
||||||
|
$format = 'po';
|
||||||
|
$parts = explode( '.', $filename );
|
||||||
|
if( strtolower( $parts[count($parts)-1] ) == '2mg' )
|
||||||
|
{
|
||||||
|
$format = '2mg';
|
||||||
|
}
|
||||||
|
|
||||||
|
if( isset( $options['i'] ))
|
||||||
|
{
|
||||||
|
$known_type = false;
|
||||||
|
if( $options['i'] == '2mg' )
|
||||||
|
{
|
||||||
|
$format = '2mg';
|
||||||
|
$known_type = true;
|
||||||
|
}
|
||||||
|
if( $options['i'] == 'po' )
|
||||||
|
{
|
||||||
|
$format = 'po';
|
||||||
|
$known_type = true;
|
||||||
|
}
|
||||||
|
if( $options['bin'] == 'bin' )
|
||||||
|
{
|
||||||
|
$format = 'bin';
|
||||||
|
$known_type = true;
|
||||||
|
}
|
||||||
|
if( !$known_type )
|
||||||
|
{
|
||||||
|
echo "Unknown input image type: ".$options['i']."\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle defaults and specification for starting block and ending block
|
||||||
|
if( $format == 'bin' )
|
||||||
|
{
|
||||||
|
$starting_block = 0;
|
||||||
|
$num_blocks = 'all';
|
||||||
|
} else {
|
||||||
|
$starting_block = 0;
|
||||||
|
$num_blocks = 1;
|
||||||
|
}
|
||||||
|
if( isset( $options['s'] ))
|
||||||
|
{
|
||||||
|
$starting_block = intval( $options['s'] );
|
||||||
|
}
|
||||||
|
if( isset( $options['n'] ))
|
||||||
|
{
|
||||||
|
$num_blocks = intval( $options['n'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle defaults and specifications for M, X, E cpu flags
|
||||||
|
$m_flag = 1;
|
||||||
|
$x_flag = 1;
|
||||||
|
$e_flag = 1;
|
||||||
|
if( isset( $options['m'] ))
|
||||||
|
{
|
||||||
|
$m_flag = intval( $options['m'] );
|
||||||
|
}
|
||||||
|
if( isset( $options['x'] ))
|
||||||
|
{
|
||||||
|
$x_flag = intval( $options['x'] );
|
||||||
|
}
|
||||||
|
if( isset( $options['e'] ))
|
||||||
|
{
|
||||||
|
$e_flag = intval( $options['e'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle verbosity
|
||||||
|
$verbose = false;
|
||||||
|
if( isset( $options['v'] ))
|
||||||
|
{
|
||||||
|
$verbose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle origin address
|
||||||
|
$origin = 0x1000;
|
||||||
|
if( isset( $options['o'] ))
|
||||||
|
{
|
||||||
|
$origin = hexdec( $options['o'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle skip amount
|
||||||
|
$skip = 0;
|
||||||
|
if( isset( $options['k'] ))
|
||||||
|
{
|
||||||
|
$skip = $options['k'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* begin main operations here
|
||||||
|
*/
|
||||||
|
switch( $format )
|
||||||
|
{
|
||||||
|
case 'bin': $fh = new Input_BIN( $filename );
|
||||||
|
$data = $fh->getBlocks( $starting_block, $num_blocks );
|
||||||
|
break;
|
||||||
|
case '2mg': $fh = new Input_2MG( $filename );
|
||||||
|
$data = $fh->getBlocks( $starting_block, $num_blocks );
|
||||||
|
break;
|
||||||
|
case 'po': $fh = new Input_PO( $filename );
|
||||||
|
$data = $fh->getBytes( $starting_block, $num_blocks );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( $verbose )
|
||||||
|
{
|
||||||
|
echo "Processed {$format} file {$filename}\n";
|
||||||
|
$fh->printInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $skip > 0 )
|
||||||
|
{
|
||||||
|
$data = substr( $data, $skip );
|
||||||
|
}
|
||||||
|
|
||||||
|
$pers = new Personality_AppleIIGS;
|
||||||
|
|
||||||
|
$dh = new Disassembler_65816;
|
||||||
|
$dh->disassemble( $m_flag, $x_flag, $e_flag, $origin, $data, $pers );
|
Loading…
Reference in New Issue
Block a user