de.codesourcery.jasm16.ide.ui.views.CPUView.java Source code

Java tutorial

Introduction

Here is the source code for de.codesourcery.jasm16.ide.ui.views.CPUView.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.ide.ui.views;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

import org.apache.commons.lang.StringUtils;

import de.codesourcery.jasm16.Address;
import de.codesourcery.jasm16.Size;
import de.codesourcery.jasm16.emulator.EmulationListener;
import de.codesourcery.jasm16.emulator.ICPU;
import de.codesourcery.jasm16.emulator.IEmulationListener;
import de.codesourcery.jasm16.emulator.IEmulator;
import de.codesourcery.jasm16.emulator.IReadOnlyCPU;
import de.codesourcery.jasm16.emulator.memory.MemUtils;
import de.codesourcery.jasm16.ide.ui.utils.UIUtils;
import de.codesourcery.jasm16.utils.ITextRegion;
import de.codesourcery.jasm16.utils.Misc;
import de.codesourcery.jasm16.utils.TextRegion;

public class CPUView extends AbstractView {
    public static final String VIEW_ID = "cpu-view";

    private JPanel panel;
    @SuppressWarnings("unused")
    private final SimpleAttributeSet defaultStyle;
    private final SimpleAttributeSet errorStyle;
    private final JTextPane textArea = new JTextPane();

    private volatile IEmulator emulator;

    private final IEmulationListener listener = new EmulationListener() {

        @Override
        public void afterCommandExecution(IEmulator emulator, int commandDuration) {
            if (!isFullSpeedMode()) {
                refreshDisplay();
            }
        }

        @Override
        public void afterReset(IEmulator emulator) {
            if (!isFullSpeedMode()) {
                refreshDisplay();
            }
        }

        @Override
        public void afterMemoryLoad(IEmulator emulator, Address startAddress, int lengthInBytes) {
            if (!isFullSpeedMode()) {
                refreshDisplay();
            }
        }

        @Override
        public void onStopHook(IEmulator emulator, Address previousPC, Throwable emulationError) {
            refreshDisplay();
        }
    };

    public CPUView() {
        errorStyle = createStyle(Color.RED);
        defaultStyle = createStyle(Color.GREEN);
    }

    public CPUView(IEmulator emulator) {
        this();
        setEmulator(emulator);
    }

    protected final static SimpleAttributeSet createStyle(Color color) {
        SimpleAttributeSet result = new SimpleAttributeSet();
        StyleConstants.setForeground(result, color);
        return result;
    }

    @Override
    public void refreshDisplay() {
        UIUtils.invokeLater(new Runnable() {

            @Override
            public void run() {
                internalRefreshDisplay();
            }
        });
    }

    private void internalRefreshDisplay() {
        if (emulator == null) {
            return;
        }
        final IReadOnlyCPU cpu = emulator.getCPU();

        final StringBuilder builder = new StringBuilder();
        final List<ITextRegion> redRegions = new ArrayList<ITextRegion>();

        Throwable lastError = emulator.getLastEmulationError();
        if (lastError != null) {
            final String msg = StringUtils.isBlank(lastError.getMessage()) ? lastError.getClass().getName()
                    : lastError.getMessage();
            builder.append("Emulation stopped with an error: " + msg + "\n");
            redRegions.add(new TextRegion(0, builder.length()));
        }

        int itemsInLine = 0;
        for (int i = 0; i < ICPU.COMMON_REGISTER_NAMES.length; i++) {
            final int value = cpu.getRegisterValue(ICPU.COMMON_REGISTERS[i]);
            builder.append(ICPU.COMMON_REGISTER_NAMES[i] + ": " + Misc.toHexString(value) + "    ");

            Address address = Address.wordAddress(value);
            final byte[] data = MemUtils.getBytes(emulator.getMemory(), address, Size.words(4), true);

            builder.append(Misc.toHexDump(address, data, data.length, 4, true, false, true));
            builder.append("\n");
            itemsInLine++;
            if (itemsInLine == 4) {
                itemsInLine = 0;
                builder.append("\n");
            }
        }
        builder.append("\nPC: " + Misc.toHexString(cpu.getPC().getValue()));
        builder.append(" (elapsed cycles: " + cpu.getCurrentCycleCount()).append(")");
        builder.append("\n");

        builder.append("EX: " + Misc.toHexString(cpu.getEX())).append("\n");
        builder.append("IA: " + Misc.toHexString(cpu.getInterruptAddress())).append("\n");

        builder.append("IQ: Interrupt queueing is ");
        if (cpu.isQueueInterrupts()) {
            int start = builder.length();
            builder.append("ON");
            redRegions.add(new TextRegion(start, builder.length() - start));
        } else {
            builder.append("OFF");
        }
        builder.append("\n");
        builder.append("IRQs: " + StringUtils.join(cpu.getInterruptQueue(), ",")).append("\n");
        builder.append("SP: " + Misc.toHexString(cpu.getSP().getValue())).append("\n");

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                final StyledDocument doc = textArea.getStyledDocument();
                doc.putProperty(Document.StreamDescriptionProperty, null);

                textArea.setText(builder.toString());
                for (ITextRegion region : redRegions) {
                    doc.setCharacterAttributes(region.getStartingOffset(), region.getLength(), errorStyle, true);
                }
            }
        });
    }

    public void setEmulator(IEmulator emulator) {
        if (emulator == null) {
            throw new IllegalArgumentException("emulator must not be NULL.");
        }
        if (this.emulator == emulator) {
            return;
        }

        if (this.emulator != null) {
            this.emulator.removeEmulationListener(listener);
        }
        this.emulator = emulator;

        emulator.addEmulationListener(listener);
    }

    @Override
    public void disposeHook() {
        if (this.emulator != null) {
            this.emulator.removeEmulationListener(listener);
            this.emulator = null;
        }
    }

    protected JPanel createPanel() {
        textArea.setFont(getMonospacedFont());
        textArea.setEditable(false);
        setColors(textArea);

        final JPanel panel = new JPanel();
        setColors(panel);
        panel.setLayout(new GridBagLayout());
        final GridBagConstraints cnstrs = constraints(0, 0, true, true, GridBagConstraints.BOTH);
        panel.add(textArea, cnstrs);
        return panel;
    }

    @Override
    public JPanel getPanel() {
        if (panel == null) {
            panel = createPanel();
        }
        return panel;
    }

    @Override
    public String getTitle() {
        return "CPU view";
    }

    @Override
    public String getID() {
        return VIEW_ID;
    }

}