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.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; } }