de.codesourcery.jasm16.disassembler.Disassembler.java Source code

Java tutorial

Introduction

Here is the source code for de.codesourcery.jasm16.disassembler.Disassembler.java

Source

/**
 * 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) + ">";

    }
}