Java tutorial
/** * Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.codesourcery.jasm16.disassembler; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.ArrayUtils; import de.codesourcery.jasm16.Address; import de.codesourcery.jasm16.Size; import de.codesourcery.jasm16.ast.OperandNode.OperandPosition; import de.codesourcery.jasm16.compiler.io.FileResource; import de.codesourcery.jasm16.compiler.io.IResource.ResourceType; import de.codesourcery.jasm16.emulator.ICPU; import de.codesourcery.jasm16.emulator.memory.IReadOnlyMemory; import de.codesourcery.jasm16.emulator.memory.MemUtils; import de.codesourcery.jasm16.emulator.memory.MemoryIterator; import de.codesourcery.jasm16.utils.IMemoryIterator; import de.codesourcery.jasm16.utils.Misc; /** * Crude DCPU-16 disassembler. * * @author tobias.gierke@code-sourcery.de */ public class Disassembler { public static final int DISASSEMBLE_EVERYTHING = -1; public static void main(String[] args) throws IOException { if (ArrayUtils.isEmpty(args)) { System.err.println("ERROR: No input file"); System.exit(1); } if (args.length != 1) { System.err.println("ERROR: Bad command-line, expected exactly one input file."); System.exit(1); } final byte[] data = Misc.readBytes(new FileResource(new File(args[0]), ResourceType.OBJECT_FILE)); System.out.println("Input file has " + data.length + " (" + Misc.toHexString(data.length) + ") bytes."); for (DisassembledLine line : new Disassembler().disassemble(data, true)) { System.out.println(Misc.toHexString(line.getAddress()) + ": " + line.getContents()); } } public List<DisassembledLine> disassemble(final Address startingAddress, final byte[] data, final int instructionCountToDisassemble, boolean printHexDump) { final IReadOnlyMemory mem = new ByteArrayMemoryAdapter(data); return disassemble(mem, startingAddress, instructionCountToDisassemble, printHexDump); } public List<DisassembledLine> disassemble(final byte[] data, boolean printHexDump) { final IReadOnlyMemory mem = new ByteArrayMemoryAdapter(data); return disassemble(mem, Address.ZERO, DISASSEMBLE_EVERYTHING, printHexDump); } public List<DisassembledLine> disassemble(final IReadOnlyMemory memory, final Address startingAddress, final int instructionCountToDisassemble, boolean printHexDump) { final int[] instructionsLeft = { instructionCountToDisassemble }; final IMemoryIterator iterator = new MemoryIterator(memory, startingAddress, true); final List<DisassembledLine> lines = new ArrayList<DisassembledLine>(); while ((instructionCountToDisassemble == DISASSEMBLE_EVERYTHING || instructionsLeft[0] > 0) && iterator.hasNext()) { final Address current = iterator.currentAddress(); String contents = dissassembleInstruction(iterator); final Size instructionLength = Address.calcDistanceInBytes(current, iterator.currentAddress()); if (printHexDump) { byte[] data = MemUtils.getBytes(memory, current, instructionLength, true); final String hex = " ; " + Misc.toHexDumpWithoutAddresses(Address.byteAddress(0), data, data.length, 8) .replaceAll("\n", ""); contents = contents + hex; } lines.add(new DisassembledLine(current, contents, instructionLength)); instructionsLeft[0]--; } return lines; } private String dissassembleInstruction(IMemoryIterator iterator) { final int instructionWord = iterator.nextWord(); final int basicOpCode = (instructionWord & 0x1f); // 1+2+4+8+16 switch (basicOpCode) { case 0x00: return handleSpecialOpCode(iterator, instructionWord); case 0x01: return handleSET(iterator, instructionWord); case 0x02: return handleADD(iterator, instructionWord); case 0x03: return handleSUB(iterator, instructionWord); case 0x04: return handleMUL(iterator, instructionWord); case 0x05: return handleMLI(iterator, instructionWord); case 0x06: return handleDIV(iterator, instructionWord); case 0x07: return handleDVI(iterator, instructionWord); case 0x08: return handleMOD(iterator, instructionWord); case 0x09: return handleMDI(iterator, instructionWord); case 0x0a: return handleAND(iterator, instructionWord); case 0x0b: return handleBOR(iterator, instructionWord); case 0x0c: return handleXOR(iterator, instructionWord); case 0x0d: return handleSHR(iterator, instructionWord); case 0x0e: return handleASR(iterator, instructionWord); case 0x0f: return handleSHL(iterator, instructionWord); case 0x10: return handleIFB(iterator, instructionWord); case 0x11: return handleIFC(iterator, instructionWord); case 0x12: return handleIFE(iterator, instructionWord); case 0x13: return handleIFN(iterator, instructionWord); case 0x14: return handleIFG(iterator, instructionWord); case 0x15: return handleIFA(iterator, instructionWord); case 0x16: return handleIFL(iterator, instructionWord); case 0x17: return handleIFU(iterator, instructionWord); case 0x18: case 0x19: return handleUnknownOpCode(iterator, instructionWord); case 0x1a: return handleADX(iterator, instructionWord); case 0x1b: return handleSBX(iterator, instructionWord); case 0x1c: case 0x1d: return handleUnknownOpCode(iterator, instructionWord); case 0x1e: return handleSTI(iterator, instructionWord); case 0x1f: return handleSTD(iterator, instructionWord); default: return handleUnknownOpCode(iterator, instructionWord); } } private String handleSTD(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("STD", it, instructionWord); } private String disassembleBasicInstruction(String opCode, IMemoryIterator it, int instructionWord) { final String src = disassembleOperand(it, OperandPosition.SOURCE_OPERAND, instructionWord); final String target = disassembleOperand(it, OperandPosition.TARGET_OPERAND, instructionWord); return opCode + " " + target + " , " + src; } private String disassembleSpecialInstruction(String opCode, IMemoryIterator it, int instructionWord) { return opCode + " " + disassembleOperand(it, OperandPosition.SOURCE_OPERAND, instructionWord); } private String handleSTI(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("STI", it, instructionWord); } private String handleSBX(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("SBX", it, instructionWord); } private String handleADX(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("ADX", it, instructionWord); } private String handleUnknownOpCode(IMemoryIterator it, int instructionWord) { return "< unknown opcode: " + Misc.toBinaryString(instructionWord, 16) + " >"; } private String handleIFU(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("IFU", it, instructionWord); } private String handleIFL(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("IFL", it, instructionWord); } private String handleIFA(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("IFA", it, instructionWord); } private String handleIFG(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("IFG", it, instructionWord); } private String handleIFN(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("IFN", it, instructionWord); } private String handleIFE(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("IFE", it, instructionWord); } private String handleIFC(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("IFC", it, instructionWord); } private String handleIFB(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("IFB", it, instructionWord); } private String handleSHL(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("SHL", it, instructionWord); } private String handleASR(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("ASR", it, instructionWord); } private String handleSHR(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("SHR", it, instructionWord); } private String handleXOR(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("XOR", it, instructionWord); } private String handleBOR(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("BOR", it, instructionWord); } private String handleAND(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("AND", it, instructionWord); } private String handleMDI(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("MDI", it, instructionWord); } private String handleMOD(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("MOD", it, instructionWord); } private String handleDVI(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("DVI", it, instructionWord); } private String handleDIV(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("DIV", it, instructionWord); } private String handleMLI(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("MLI", it, instructionWord); } private String handleMUL(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("MUL", it, instructionWord); } private String handleSUB(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("SUB", it, instructionWord); } private String handleADD(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("ADD", it, instructionWord); } private String handleSET(IMemoryIterator it, int instructionWord) { return disassembleBasicInstruction("SET", it, instructionWord); } private String handleSpecialOpCode(IMemoryIterator it, int instructionWord) { final int opCode = (instructionWord >> 5) & 0x1f; switch (opCode) { case 0x00: return handleUnknownOpCode(it, instructionWord); case 0x01: return handleJSR(it, instructionWord); case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: return handleUnknownOpCode(it, instructionWord); case 0x07: return handleHCF(it, instructionWord); case 0x08: return handleINT(it, instructionWord); case 0x09: return handleIAG(it, instructionWord); case 0x0a: return handleIAS(it, instructionWord); case 0x0b: return handleRFI(it, instructionWord); case 0x0c: return handleIAQ(it, instructionWord); case 0x0d: case 0x0e: case 0x0f: return handleUnknownOpCode(it, instructionWord); case 0x10: return handleHWN(it, instructionWord); case 0x11: return handleHWQ(it, instructionWord); case 0x12: return handleHWI(it, instructionWord); case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: default: return handleUnknownOpCode(it, instructionWord); } } private String handleHWI(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("HWI", it, instructionWord); } private String handleHWQ(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("HWQ", it, instructionWord); } private String handleHWN(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("HWN", it, instructionWord); } private String handleIAQ(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("IAQ", it, instructionWord); } private String handleRFI(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("RFI", it, instructionWord); } private String handleIAS(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("IAS", it, instructionWord); } private String handleIAG(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("IAG", it, instructionWord); } private String handleINT(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("INT", it, instructionWord); } private String handleHCF(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("HCF", it, instructionWord); } private String handleJSR(IMemoryIterator it, int instructionWord) { return disassembleSpecialInstruction("JSR", it, instructionWord); } protected String disassembleOperand(IMemoryIterator it, OperandPosition position, int instructionWord) { final boolean specialInstruction = (instructionWord & 0x1f) == 0; /* * SET b,a * * b = TARGET operand * a = SOURCE operand * * SOURCE is always handled by the processor BEFORE TARGET, and is the lower five bits. * In bits (in LSB-0 format), a basic instruction has the format: * * aaaaaabbbbbooooo * * SPECIAL opcodes always have their lower five bits unset, have one value and a * five bit opcode. In binary, they have the format: * * aaaaaaooooo00000 * * The value (a) is in the same six bit format as defined earlier. * * --- Values: (5/6 bits) --------------------------------------------------------- * * | C | VALUE | DESCRIPTION * +---+-----------+---------------------------------------------------------------- * | 0 | 0x00-0x07 | register (A, B, C, X, Y, Z, I or J, in that order) * | 0 | 0x08-0x0f | [register] * | 1 | 0x10-0x17 | [register + next word] * | 0 | 0x18 | (PUSH / [--SP]) if in TARGET, or (POP / [SP++]) if in SOURCE * | 0 | 0x19 | [SP] / PEEK * | 1 | 0x1a | [SP + next word] / PICK n * | 0 | 0x1b | SP * | 0 | 0x1c | PC * | 0 | 0x1d | EX * | 1 | 0x1e | [next word] * | 1 | 0x1f | next word (literal) * | 0 | 0x20-0x3f | literal value 0xffff-0x1e (-1..30) (literal) (only for SOURCE) * +---+-----------+---------------------------------------------------------------- */ final int operandBits; if (specialInstruction || position == OperandPosition.SOURCE_OPERAND) { // aaaaaa bbbbb ooooo // System.out.println("Instruction: "+Misc.toHexString( instructionWord )+" => "+Misc.toBinaryString( instructionWord , 16 , 4, 9 )+" ( special: "+specialInstruction+")"); operandBits = (instructionWord >> 10) & (1 + 2 + 4 + 8 + 16 + 32); // 6 operand bit } else { // aaaaaa bbbbb ooooo // System.out.println("Instruction: "+Misc.toHexString( instructionWord )+" => "+Misc.toBinaryString( instructionWord , 16 , 4, 9 )+" ( special: "+specialInstruction+")"); operandBits = (instructionWord >> 5) & (1 + 2 + 4 + 8 + 16); // 5 operand bits } if (operandBits < 0) { throw new RuntimeException("Internal error"); } if (operandBits <= 0x07) { return ICPU.COMMON_REGISTER_NAMES[operandBits]; } if (operandBits <= 0x0f) { return "[" + ICPU.COMMON_REGISTER_NAMES[(operandBits - 0x08)] + "]"; } if (operandBits <= 0x17) { if (!it.hasNext()) { return "operand word missing"; } final int nextWord = it.nextWord(); return "[" + ICPU.COMMON_REGISTER_NAMES[operandBits - 0x10] + " + 0x" + Misc.toHexString(nextWord) + "]"; } switch (operandBits) { case 0x18: return "[SP++]"; case 0x19: return "[SP]"; case 0x1a: if (!it.hasNext()) { return "operand word missing"; } int nextWord = it.nextWord(); return "[SP + 0x" + Misc.toHexString(nextWord) + "]"; case 0x1b: return "SP"; case 0x1c: return "PC"; case 0x1d: return "EX"; case 0x1e: if (!it.hasNext()) { return "operand word missing"; } nextWord = it.nextWord(); return "[ 0x" + Misc.toHexString(nextWord) + " ]"; case 0x1f: if (!it.hasNext()) { return "operand word missing"; } nextWord = it.nextWord(); return "0x" + Misc.toHexString(nextWord); } if (position == OperandPosition.SOURCE_OPERAND || specialInstruction) { final int literalValue = operandBits - 0x21; return "0x" + Misc.toHexString(literalValue); } return "<illegal operand bits: " + Misc.toBinaryString(operandBits, 5) + ">"; } }