Implementing disassembler back-end, yet more adjustments to CPU window
This commit is contained in:
		
							parent
							
								
									b7c2545ea7
								
							
						
					
					
						commit
						76c95b0523
					
				| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
Copyright (C) 2019 Planet Virtual Boy
 | 
			
		||||
Copyright (C) 2020 Planet Virtual Boy
 | 
			
		||||
 | 
			
		||||
This software is provided 'as-is', without any express or implied
 | 
			
		||||
warranty.  In no event will the authors be held liable for any damages
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,7 +79,6 @@ static void cpuDecode(VUE_INST *inst, int32_t bits) {
 | 
			
		|||
 | 
			
		||||
    /* Decode by format */
 | 
			
		||||
    switch (inst->format) {
 | 
			
		||||
        case 0: return; /* Illegal opcode */
 | 
			
		||||
        case 1:
 | 
			
		||||
            inst->reg2 = bits >> 21 & 31;
 | 
			
		||||
            inst->reg1 = bits >> 16 & 31;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,6 +159,7 @@ typedef struct {
 | 
			
		|||
 | 
			
		||||
/* Emulation state */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VUE_INST inst; /* Instruction state */
 | 
			
		||||
 | 
			
		||||
    /* Memory bus */
 | 
			
		||||
    struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -221,8 +222,6 @@ typedef struct {
 | 
			
		|||
        uint16_t ecr_fecc; /* Fatal Error Cause Code */
 | 
			
		||||
    } cpu;
 | 
			
		||||
 | 
			
		||||
    /* Additional fields */
 | 
			
		||||
    VUE_INST inst; /* Instruction state */
 | 
			
		||||
} VUE;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import vue.*;
 | 
			
		|||
public class App {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    private boolean   useNative; // Produce native core contexts
 | 
			
		||||
    private boolean useNative; // Produce native core contexts
 | 
			
		||||
    private Localizer.Locale[]    locales; // Language translations
 | 
			
		||||
    private ArrayList<MainWindow> windows; // Application windows
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,257 +0,0 @@
 | 
			
		|||
package app;
 | 
			
		||||
 | 
			
		||||
// Java imports
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.*;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
 | 
			
		||||
// Project imports
 | 
			
		||||
import util.*;
 | 
			
		||||
import vue.*;
 | 
			
		||||
 | 
			
		||||
// CPU window
 | 
			
		||||
class CPU extends ChildWindow {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    private int     expandWidth;  // Width of expand buttons
 | 
			
		||||
    private Font    font;         // Display font
 | 
			
		||||
    private int     fontHeight;   // Font line height
 | 
			
		||||
    private int     fontWidth;    // Font maximum character width
 | 
			
		||||
    private boolean shown;        // Window has been shown
 | 
			
		||||
    private int     systemHeight; // Initial height of system register list
 | 
			
		||||
 | 
			
		||||
    // UI components
 | 
			
		||||
    private JPanel dasm;    // Disassembler
 | 
			
		||||
    private JPanel system;  // System registers
 | 
			
		||||
    private JPanel program; // Program registers
 | 
			
		||||
    private ArrayList<Register> registers; // Register controls
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                             Constructors                              //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    CPU(MainWindow parent) {
 | 
			
		||||
        super(parent, "cpu.title");
 | 
			
		||||
        var client = getContentPane();
 | 
			
		||||
 | 
			
		||||
        // Configure instance fields
 | 
			
		||||
        font = new Font(Util.fontFamily(new String[]
 | 
			
		||||
            { "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14);
 | 
			
		||||
        registers = new ArrayList<Register>();
 | 
			
		||||
 | 
			
		||||
        dasm = new JPanel(null);
 | 
			
		||||
        dasm.setBackground(SystemColor.window);
 | 
			
		||||
        dasm.setFocusable(true);
 | 
			
		||||
 | 
			
		||||
        var inner = initRegisters();
 | 
			
		||||
        var outer = Util.splitPane(JSplitPane.HORIZONTAL_SPLIT);
 | 
			
		||||
        outer.setLeftComponent(new JScrollPane(dasm,
 | 
			
		||||
            JScrollPane.VERTICAL_SCROLLBAR_NEVER,
 | 
			
		||||
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
 | 
			
		||||
        outer.setRightComponent(inner);
 | 
			
		||||
        outer.setResizeWeight(1);
 | 
			
		||||
 | 
			
		||||
        client.add(outer);
 | 
			
		||||
        client.setPreferredSize(new Dimension(480, 300));
 | 
			
		||||
        setFont2(font);
 | 
			
		||||
        pack();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                         Register Constructors                         //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Initialize program register list
 | 
			
		||||
    private void initProgram() {
 | 
			
		||||
        Dimension target = null;
 | 
			
		||||
 | 
			
		||||
        // Program register container
 | 
			
		||||
        var lst = program = new JPanel(new GridBagLayout()) {
 | 
			
		||||
            public Dimension getPreferredSize() {
 | 
			
		||||
                var ret = super.getPreferredSize();
 | 
			
		||||
                if (!shown)
 | 
			
		||||
                    ret.height = 0;
 | 
			
		||||
                return ret;
 | 
			
		||||
            }
 | 
			
		||||
            public void paintComponent(Graphics g) {
 | 
			
		||||
                super.paintComponent(g);
 | 
			
		||||
                if (shown)
 | 
			
		||||
                    return;
 | 
			
		||||
                shown = true;
 | 
			
		||||
                system.revalidate();
 | 
			
		||||
                program.revalidate();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        lst.setBackground(SystemColor.window);
 | 
			
		||||
        lst.setFocusable(true);
 | 
			
		||||
        lst.addMouseListener(Util.onMouse(e->lst.requestFocus(),null));
 | 
			
		||||
 | 
			
		||||
        // Produce the list of program registers
 | 
			
		||||
        for (int x = 0; x < 32; x++) {
 | 
			
		||||
            String name = "r" + x;
 | 
			
		||||
            switch (x) {
 | 
			
		||||
                case VUE.GP: name = "gp"; break;
 | 
			
		||||
                case VUE.HP: name = "hp"; break;
 | 
			
		||||
                case VUE.LP: name = "lp"; break;
 | 
			
		||||
                case VUE.SP: name = "sp"; break;
 | 
			
		||||
                case VUE.TP: name = "tp"; break;
 | 
			
		||||
            }
 | 
			
		||||
            registers.add(new Register(
 | 
			
		||||
                parent, lst, name, x, Register.PROGRAM));
 | 
			
		||||
        }
 | 
			
		||||
        endList(lst);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Initialize register lists
 | 
			
		||||
    private JSplitPane initRegisters() {
 | 
			
		||||
        initSystem();
 | 
			
		||||
        initProgram();
 | 
			
		||||
 | 
			
		||||
        var ret = Util.splitPane(JSplitPane.VERTICAL_SPLIT);
 | 
			
		||||
        ret.setTopComponent(new JScrollPane(system,
 | 
			
		||||
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
 | 
			
		||||
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
 | 
			
		||||
        ));
 | 
			
		||||
        ret.setBottomComponent(new JScrollPane(program,
 | 
			
		||||
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
 | 
			
		||||
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
 | 
			
		||||
        ));
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Initialize system register list
 | 
			
		||||
    private void initSystem() {
 | 
			
		||||
 | 
			
		||||
        // System register container
 | 
			
		||||
        var lst = system = new JPanel(new GridBagLayout()) {
 | 
			
		||||
            public Dimension getPreferredSize() {
 | 
			
		||||
                var ret = super.getPreferredSize();
 | 
			
		||||
                if (!shown)
 | 
			
		||||
                    ret.height = systemHeight;
 | 
			
		||||
                return ret;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        system.setBackground(SystemColor.window);
 | 
			
		||||
        system.setFocusable(true);
 | 
			
		||||
        system.addMouseListener(Util.onMouse(e->system.requestFocus(), null));
 | 
			
		||||
        system.putClientProperty("shown", true);
 | 
			
		||||
 | 
			
		||||
        // Add the first two system registers and expand PSW
 | 
			
		||||
        int plain = Register.PLAIN;
 | 
			
		||||
        registers.add(new Register(parent, lst, "PC"   , VUE.PC   , plain   ));
 | 
			
		||||
        Register psw =new Register(parent, lst, "PSW"  , VUE.PSW  , VUE.PSW );
 | 
			
		||||
        psw.setExpanded(true);
 | 
			
		||||
        registers.add(psw);
 | 
			
		||||
        shown = true;
 | 
			
		||||
        systemHeight = system.getPreferredSize().height + 6;
 | 
			
		||||
        shown = false;
 | 
			
		||||
 | 
			
		||||
        // Add the remaining system registers
 | 
			
		||||
        registers.add(new Register(parent, lst, "EIPC" , VUE.EIPC , plain   ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "EIPSW", VUE.EIPSW, VUE.PSW ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "FEPC" , VUE.FEPC , plain   ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "FEPSW", VUE.FEPSW, VUE.PSW ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "ECR"  , VUE.ECR  , VUE.ECR ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "ADTRE", VUE.ADTRE, plain   ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "CHCW" , VUE.CHCW , VUE.CHCW));
 | 
			
		||||
        registers.add(new Register(parent, lst, "PIR"  , VUE.PIR  , VUE.PIR ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "TKCW" , VUE.TKCW , VUE.TKCW));
 | 
			
		||||
        registers.add(new Register(parent, lst, "29"   ,        29, plain   ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "30"   ,        30, plain   ));
 | 
			
		||||
        registers.add(new Register(parent, lst, "31"   ,        31, plain   ));
 | 
			
		||||
        endList(lst);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Event Handlers                             //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Client resize
 | 
			
		||||
    private void onResize() {
 | 
			
		||||
        //refreshDasm();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Package Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Update the display
 | 
			
		||||
    void refresh() {
 | 
			
		||||
 | 
			
		||||
        // The element is not ready
 | 
			
		||||
        if (registers == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // Refresh registers
 | 
			
		||||
        for (var reg : registers)
 | 
			
		||||
            reg.refresh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify a new font
 | 
			
		||||
    void setFont2(Font font) {
 | 
			
		||||
        this.font = font;
 | 
			
		||||
 | 
			
		||||
        // Configure the maximum font dimensions
 | 
			
		||||
        var fontMax = new JLabel("!");
 | 
			
		||||
        fontMax.setFont(font);
 | 
			
		||||
        fontHeight = Math.max(1, fontMax.getPreferredSize().height);
 | 
			
		||||
        fontWidth  = -1;
 | 
			
		||||
        for (int x = 0; x < 16; x++) {
 | 
			
		||||
            fontMax.setText(Integer.toString(x, 16).toUpperCase());
 | 
			
		||||
            fontWidth = Math.max(fontWidth, fontMax.getPreferredSize().width);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Configure register list scrolling
 | 
			
		||||
        for (int x = 0; x < 2; x++) {
 | 
			
		||||
            Component ctrl = x == 0 ? system : program;
 | 
			
		||||
            while (!(ctrl instanceof JScrollPane))
 | 
			
		||||
                ctrl = ctrl.getParent();
 | 
			
		||||
            ((JScrollPane) ctrl).getVerticalScrollBar()
 | 
			
		||||
                .setUnitIncrement(fontHeight);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Determine the width of the register expand buttons
 | 
			
		||||
        var expand = new JLabel("+");
 | 
			
		||||
        int width = expand.getPreferredSize().width;
 | 
			
		||||
        expand.setText("-");
 | 
			
		||||
        width = Math.max(width, expand.getPreferredSize().width) + 4;
 | 
			
		||||
 | 
			
		||||
        // Configure registers
 | 
			
		||||
        for (var reg : registers) {
 | 
			
		||||
            reg.setExpandWidth(width);
 | 
			
		||||
            reg.setFont(font, fontWidth, fontHeight);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        onResize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Private Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Terminate a register list
 | 
			
		||||
    private JPanel endList(JPanel list) {
 | 
			
		||||
        var spacer = new JPanel(null);
 | 
			
		||||
        spacer.setOpaque(false);
 | 
			
		||||
        spacer.setPreferredSize(new Dimension(1, 1));
 | 
			
		||||
        var gbc = new GridBagConstraints();
 | 
			
		||||
        gbc.gridheight = GridBagConstraints.REMAINDER;
 | 
			
		||||
        gbc.gridwidth  = GridBagConstraints.REMAINDER;
 | 
			
		||||
        gbc.weighty    = 1;
 | 
			
		||||
        list.add(spacer, gbc);
 | 
			
		||||
        return spacer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,179 @@
 | 
			
		|||
package app;
 | 
			
		||||
 | 
			
		||||
// Java imports
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.awt.event.*;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
 | 
			
		||||
// Project imports
 | 
			
		||||
import util.*;
 | 
			
		||||
import vue.*;
 | 
			
		||||
 | 
			
		||||
// CPU window
 | 
			
		||||
class CPUWindow extends ChildWindow {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    private int     expandWidth;  // Width of expand buttons
 | 
			
		||||
    private boolean shown;        // Window has been shown
 | 
			
		||||
    private int     systemHeight; // Initial height of system register list
 | 
			
		||||
 | 
			
		||||
    // UI components
 | 
			
		||||
    private JPanel       dasm;       // Disassembler
 | 
			
		||||
    private RegisterList lstProgram; // Program register list
 | 
			
		||||
    private RegisterList lstSystem;  // System register list
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Global Settings                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    static int       regExpandWidth; // Width of register list expand button
 | 
			
		||||
    static Font      regHexFont;     // Register list hex font
 | 
			
		||||
    static Dimension regHexFontSize; // Max dimensions
 | 
			
		||||
    static HashSet<CPUWindow> instances; // Spawned instances
 | 
			
		||||
 | 
			
		||||
    // Static initializer
 | 
			
		||||
    static {
 | 
			
		||||
        setDefaults();
 | 
			
		||||
        instances = new HashSet<CPUWindow>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Static Methods                             //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Apply configuration settings to all instances
 | 
			
		||||
    static void configureAll() {
 | 
			
		||||
        for (var inst : instances)
 | 
			
		||||
            inst.configure();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Reset all settings to their default values
 | 
			
		||||
    static void setDefaults() {
 | 
			
		||||
 | 
			
		||||
        // Register list hex font
 | 
			
		||||
        setRegHexFont(new Font(Util.fontFamily(new String[]
 | 
			
		||||
            { "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14));
 | 
			
		||||
 | 
			
		||||
        // Width of register list expand button
 | 
			
		||||
        var label = new JLabel("+");
 | 
			
		||||
        regExpandWidth = label.getPreferredSize().width;
 | 
			
		||||
        label.setText("-");
 | 
			
		||||
        regExpandWidth = Math.max(regExpandWidth,
 | 
			
		||||
            label.getPreferredSize().width);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify a font to use as the register list hex font
 | 
			
		||||
    static void setRegHexFont(Font font) {
 | 
			
		||||
        regHexFont     = font;
 | 
			
		||||
        regHexFontSize = measureHex(font);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                             Constructors                              //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    CPUWindow(MainWindow parent) {
 | 
			
		||||
        super(parent, "cpu.title");
 | 
			
		||||
        instances.add(this);
 | 
			
		||||
 | 
			
		||||
        var client = getContentPane();
 | 
			
		||||
 | 
			
		||||
        dasm = new JPanel(null);
 | 
			
		||||
        dasm.setBackground(SystemColor.window);
 | 
			
		||||
        dasm.setFocusable(true);
 | 
			
		||||
 | 
			
		||||
        lstSystem = new RegisterList(this, true);
 | 
			
		||||
        lstProgram = new RegisterList(this, false);
 | 
			
		||||
        var inner = Util.splitPane(JSplitPane.VERTICAL_SPLIT);
 | 
			
		||||
        inner.setTopComponent(lstSystem);
 | 
			
		||||
        inner.setBottomComponent(lstProgram);
 | 
			
		||||
 | 
			
		||||
        var outer = Util.splitPane(JSplitPane.HORIZONTAL_SPLIT);
 | 
			
		||||
        outer.setLeftComponent(new JScrollPane(dasm,
 | 
			
		||||
            JScrollPane.VERTICAL_SCROLLBAR_NEVER,
 | 
			
		||||
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
 | 
			
		||||
        outer.setRightComponent(inner);
 | 
			
		||||
        outer.setResizeWeight(1);
 | 
			
		||||
 | 
			
		||||
        client.add(outer);
 | 
			
		||||
        client.setPreferredSize(new Dimension(480, 300));
 | 
			
		||||
        configure();
 | 
			
		||||
        pack();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Public Methods                             //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // The window is closing
 | 
			
		||||
    public void dispose() {
 | 
			
		||||
        instances.remove(this);
 | 
			
		||||
        super.dispose();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Package Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Apply configuration settings
 | 
			
		||||
    void configure() {
 | 
			
		||||
        lstProgram.configure();
 | 
			
		||||
        lstSystem .configure();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update the display
 | 
			
		||||
    void refresh() {
 | 
			
		||||
        lstSystem.refresh();
 | 
			
		||||
        lstProgram.refresh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Event Handlers                             //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Client resize
 | 
			
		||||
    private void onResize() {
 | 
			
		||||
        //refreshDasm();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Private Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Determine the maximum character width of a hex character in a font
 | 
			
		||||
    private static Dimension measureHex(Font font) {
 | 
			
		||||
        int       ret  = 0;
 | 
			
		||||
        Dimension size = null;
 | 
			
		||||
 | 
			
		||||
        // Process all digits
 | 
			
		||||
        var label = new JLabel();
 | 
			
		||||
        label.setFont(font);
 | 
			
		||||
        for (int x = 0; x < 16; x++) {
 | 
			
		||||
            label.setText(String.format(
 | 
			
		||||
                "%" + (Disassembler.hexCaps ? "X" : "x"
 | 
			
		||||
            ), x));
 | 
			
		||||
            size = label.getPreferredSize();
 | 
			
		||||
            ret  = Math.max(ret, size.width);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new Dimension(ret, size.height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ import java.awt.*;
 | 
			
		|||
import javax.swing.*;
 | 
			
		||||
 | 
			
		||||
// Console window
 | 
			
		||||
class Console extends ChildWindow {
 | 
			
		||||
class ConsoleWindow extends ChildWindow {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    private boolean shown; // Component has been visible
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ class Console extends ChildWindow {
 | 
			
		|||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    Console(MainWindow parent) {
 | 
			
		||||
    ConsoleWindow(MainWindow parent) {
 | 
			
		||||
        super(parent, "console.title");
 | 
			
		||||
        getContentPane().setPreferredSize(new Dimension(384, 224));
 | 
			
		||||
        pack();
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,379 @@
 | 
			
		|||
package app;
 | 
			
		||||
 | 
			
		||||
// Project imports
 | 
			
		||||
import vue.*;
 | 
			
		||||
 | 
			
		||||
// Instruction disassembler
 | 
			
		||||
class Disassembler {
 | 
			
		||||
    private Disassembler() { } // Cannot be instantiated
 | 
			
		||||
    static { setDefaults(); }  // Initialize to default settings
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Global Settings                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    static boolean bcondCombine; // Merge Bcond condition into mnemonic
 | 
			
		||||
    static boolean bcondNames;   // Use symbolic condition names for Bcond
 | 
			
		||||
    static boolean condCaps;     // Uppercase condition mnemonics
 | 
			
		||||
    static boolean destLast;     // Destination register last
 | 
			
		||||
    static boolean dispDest;     // Resolve jump destination addresses
 | 
			
		||||
    static boolean dispInside;   // Load/store displacement inside brackets
 | 
			
		||||
    static boolean hexCaps;      // Upercase hexadecimal
 | 
			
		||||
    static int     hexMode;      // Hexadecimal decoration
 | 
			
		||||
    static boolean immNumber;    // Use number sign with immediate values
 | 
			
		||||
    static boolean jmpBrackets;  // Square brackets around JMP
 | 
			
		||||
    static boolean jumpAddress;  // Use jump destination addresses
 | 
			
		||||
    static boolean lower;        // Use L instead of C in conditions
 | 
			
		||||
    static boolean mnemonicCaps; // Uppercase mnemonics
 | 
			
		||||
    static boolean programCaps;  // Uppercase program register names
 | 
			
		||||
    static boolean programNames; // Use symbolic program register names
 | 
			
		||||
    static boolean setfCombine;  // Merge SETF condition into mnemonic
 | 
			
		||||
    static boolean setfNames;    // Use symbolic condition names for SETF
 | 
			
		||||
    static boolean systemCaps;   // Uppercase system register names
 | 
			
		||||
    static boolean systemNames;  // Use symbolic system register names
 | 
			
		||||
    static boolean zero;         // Use Z instead of E in conditions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                               Constants                               //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Hexadecimal decorations
 | 
			
		||||
    static final int DOLLAR = 0;
 | 
			
		||||
    static final int H      = 1;
 | 
			
		||||
    static final int ZEROX  = 2;
 | 
			
		||||
 | 
			
		||||
    // Condition mneonics
 | 
			
		||||
    static final String[] CONDITIONS = {
 | 
			
		||||
        "V" , "C" , "E" , "NH", "N", "T", "LT", "LE",
 | 
			
		||||
        "NV", "NC", "NE", "H" , "P", "F", "GE", "GT"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Mnemonics
 | 
			
		||||
    static final String[] MNEMONICS = {
 | 
			
		||||
        "---"    , "ADD"    , "ADD"    , "ADDF.S", "ADDI"   , "AND"    ,
 | 
			
		||||
        "ANDBSU" , "ANDI"   , "ANDNBSU", "Bcond" , "CAXI"   , "CLI"    ,
 | 
			
		||||
        "CMP"    , "CMP"    , "CMPF.S" , "CVT.SW", "CVT.WS" , "DIV"    ,
 | 
			
		||||
        "DIVF.S" , "DIVU"   , "HALT"   , "IN.B"  , "IN.H"   , "IN.W"   ,
 | 
			
		||||
        "JAL"    , "JMP"    , "JR"     , "LD.B"  , "LD.H"   , "LD.W"   ,
 | 
			
		||||
        "LDSR"   , "MOV"    , "MOV"    , "MOVBSU", "MOVEA"  , "MOVHI"  ,
 | 
			
		||||
        "MPYHW"  , "MUL"    , "MULF.S" , "MULU"  , "NOT"    , "NOTBSU" ,
 | 
			
		||||
        "OR"     , "ORBSU"  , "ORI"    , "ORNBSU", "OUT.B"  , "OUT.H"  ,
 | 
			
		||||
        "OUT.W"  , "RETI"   , "REV"    , "SAR"   , "SAR"    , "SCH0BSD",
 | 
			
		||||
        "SCH0BSU", "SCH1BSD", "SCH1BSU", "SEI"   , "SETF"   , "SHL"    ,
 | 
			
		||||
        "SHL"    , "SHR"    , "SHR"    , "ST.B"  , "ST.H"   , "ST.W"   ,
 | 
			
		||||
        "STSR"   , "SUB"    , "SUBF.S" , "TRAP"  , "TRNC.SW", "XB"     ,
 | 
			
		||||
        "XH"     , "XOR"    , "XORBSU" , "XORI"  , "XORNBSU"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Program register names
 | 
			
		||||
    private static final String[] PROGRAMS = {
 | 
			
		||||
        null, null, "hp", "sp", "gp", "tp", null, null,
 | 
			
		||||
        null, null, null, null, null, null, null, null,
 | 
			
		||||
        null, null, null, null, null, null, null, null,
 | 
			
		||||
        null, null, null, null, null, null, null, "lp"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // System register names
 | 
			
		||||
    private static final String[] SYSTEMS = {
 | 
			
		||||
        "EIPC", "EIPSW", "FEPC", "FEPSW", "ECR", "PSW", "PIR", "TKCW",
 | 
			
		||||
        null  , null   , null  , null   , null , null , null , null  ,
 | 
			
		||||
        null  , null   , null  , null   , null , null , null , null  ,
 | 
			
		||||
        "CHCW", "ADTRE", null  , null   , null , null , null , null
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                                Classes                                //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // One row of output
 | 
			
		||||
    static class Row {
 | 
			
		||||
        String address;  // Bus address
 | 
			
		||||
        String bytes;    // Encoded bytes in bus order
 | 
			
		||||
        String mnemonic; // Instruction mnemonic
 | 
			
		||||
        String operands; // Instruction operands, if any
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Static Methods                             //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Reset all settings to their default values
 | 
			
		||||
    static void setDefaults() {
 | 
			
		||||
        bcondCombine = true;
 | 
			
		||||
        bcondNames   = true;
 | 
			
		||||
        condCaps     = true;
 | 
			
		||||
        destLast     = true;
 | 
			
		||||
        dispDest     = true;
 | 
			
		||||
        dispInside   = false;
 | 
			
		||||
        hexCaps      = true;
 | 
			
		||||
        hexMode      = ZEROX;
 | 
			
		||||
        immNumber    = false;
 | 
			
		||||
        jmpBrackets  = true;
 | 
			
		||||
        jumpAddress  = true;
 | 
			
		||||
        lower        = true;
 | 
			
		||||
        mnemonicCaps = true;
 | 
			
		||||
        programCaps  = false;
 | 
			
		||||
        programNames = true;
 | 
			
		||||
        setfCombine  = false;
 | 
			
		||||
        setfNames    = true;
 | 
			
		||||
        systemCaps   = true;
 | 
			
		||||
        systemNames  = true;
 | 
			
		||||
        zero         = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Package Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Represent an instruction as text fields
 | 
			
		||||
    static void disassemble(int address, Instruction inst, Row row) {
 | 
			
		||||
 | 
			
		||||
        // Address
 | 
			
		||||
        String x = hexCaps ? "X" : "x";
 | 
			
		||||
        row.address = String.format("%08" + x, address);
 | 
			
		||||
 | 
			
		||||
        // Bytes
 | 
			
		||||
        x = "%02" + x;
 | 
			
		||||
        row.bytes = inst.size == 2 ?
 | 
			
		||||
            String.format(x + " " + x,
 | 
			
		||||
                inst.bits >> 16 & 0xFF,
 | 
			
		||||
                inst.bits >> 24 & 0xFF
 | 
			
		||||
            ) : String.format(x + " " + x + " " + x + " " + x,
 | 
			
		||||
                inst.bits >> 16 & 0xFF,
 | 
			
		||||
                inst.bits >> 24 & 0xFF,
 | 
			
		||||
                inst.bits       & 0xFF,
 | 
			
		||||
                inst.bits >>  8 & 0xFF
 | 
			
		||||
            )
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
        // Bcond mnemonic
 | 
			
		||||
        if (inst.id == VUE.BCOND && bcondCombine) {
 | 
			
		||||
            row.mnemonic = "B" + CONDITIONS[inst.cond];
 | 
			
		||||
            if (lower && (inst.cond & 7) == 1)
 | 
			
		||||
                row.mnemonic = inst.cond == 1 ? "BL" : "BNL";
 | 
			
		||||
            if (zero  && (inst.cond & 7) == 2)
 | 
			
		||||
                row.mnemonic = inst.cond == 2 ? "BZ" : "BNZ";
 | 
			
		||||
            if (         (inst.cond & 7) == 5)
 | 
			
		||||
                row.mnemonic = inst.cond == 5 ? "BR" : "NOP";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // SETF mnemonic
 | 
			
		||||
        else if (inst.id == VUE.SETF && setfCombine)
 | 
			
		||||
            row.mnemonic = "SETF" + CONDITIONS[inst.imm];
 | 
			
		||||
 | 
			
		||||
        // All other mnemonics
 | 
			
		||||
        else row.mnemonic = MNEMONICS[inst.id];
 | 
			
		||||
 | 
			
		||||
        // Adjust mnemonic case
 | 
			
		||||
        if (!mnemonicCaps)
 | 
			
		||||
            row.mnemonic = row.mnemonic.toLowerCase();
 | 
			
		||||
 | 
			
		||||
        // Operands by format
 | 
			
		||||
        row.operands = null;
 | 
			
		||||
        if (inst.id != VUE.ILLEGAL) switch (inst.format) {
 | 
			
		||||
            case 1: // Fallthrough
 | 
			
		||||
            case 7: row.operands = formatI_VII(inst         ); break;
 | 
			
		||||
            case 2: row.operands = formatII   (inst         ); break;
 | 
			
		||||
            case 3: row.operands = formatIII  (inst, address); break;
 | 
			
		||||
            case 4: row.operands = destination(inst, address); break;
 | 
			
		||||
            case 5: row.operands = formatV    (inst         ); break;
 | 
			
		||||
            case 6: row.operands = formatVI   (inst         ); break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Private Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Format the destination of a branch or jump
 | 
			
		||||
    private static String destination(Instruction inst, int address) {
 | 
			
		||||
        return !dispDest ? toHex(inst.disp, 1, immNumber) :
 | 
			
		||||
            String.format("%08" + (hexCaps ? "X" : "x"), address + inst.disp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Operands for Format I and Format VII
 | 
			
		||||
    private static String formatI_VII(Instruction inst) {
 | 
			
		||||
        String reg1 = program(inst.reg1);
 | 
			
		||||
        String reg2 = program(inst.reg2);
 | 
			
		||||
 | 
			
		||||
        // One-operand instructions
 | 
			
		||||
        switch (inst.id) {
 | 
			
		||||
            case VUE.JMP:
 | 
			
		||||
                return String.format(jmpBrackets ? "[%s]" : "%s", reg1);
 | 
			
		||||
            case VUE.XB: // Fallthrough
 | 
			
		||||
            case VUE.XH:
 | 
			
		||||
                return reg2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generic
 | 
			
		||||
        return String.format("%s, %s",
 | 
			
		||||
            destLast ? reg1 : reg2,
 | 
			
		||||
            destLast ? reg2 : reg1
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Operands for Format II
 | 
			
		||||
    private static String formatII(Instruction inst) {
 | 
			
		||||
 | 
			
		||||
        // Bit string
 | 
			
		||||
        if (inst.opcode == 0b011111)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        // Zero- or one-operand instructions
 | 
			
		||||
        switch (inst.id) {
 | 
			
		||||
 | 
			
		||||
            // Zero-operand
 | 
			
		||||
            case VUE.CLI : // Fallthrough
 | 
			
		||||
            case VUE.HALT: // Fallthrough
 | 
			
		||||
            case VUE.RETI: // Fallthrough
 | 
			
		||||
            case VUE.SEI :
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            // One-operand
 | 
			
		||||
            case VUE.TRAP:
 | 
			
		||||
                return Integer.toString(inst.imm);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Combined SETF
 | 
			
		||||
        String reg2 = program(inst.reg2);
 | 
			
		||||
        if (inst.id == VUE.SETF && setfCombine)
 | 
			
		||||
            return reg2;
 | 
			
		||||
 | 
			
		||||
        // Two-operand instructions
 | 
			
		||||
        String imm  = String.format("%s%d", immNumber ? "#" : "", inst.imm);
 | 
			
		||||
        switch (inst.id) {
 | 
			
		||||
            case VUE.LDSR: // Fallthrough
 | 
			
		||||
            case VUE.STSR:
 | 
			
		||||
                if (!systemNames || SYSTEMS[inst.imm] == null)
 | 
			
		||||
                    break;
 | 
			
		||||
                imm = SYSTEMS[inst.imm];
 | 
			
		||||
                if (!systemCaps)
 | 
			
		||||
                    imm = imm.toLowerCase();
 | 
			
		||||
                break;
 | 
			
		||||
            case VUE.SETF:
 | 
			
		||||
                if (!setfNames)
 | 
			
		||||
                    break;
 | 
			
		||||
                imm = CONDITIONS[inst.imm];
 | 
			
		||||
                if (!condCaps)
 | 
			
		||||
                    imm = imm.toLowerCase();
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generic
 | 
			
		||||
        return String.format("%s, %s",
 | 
			
		||||
            destLast ? imm  : reg2,
 | 
			
		||||
            destLast ? reg2 : imm
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Operands for Format III
 | 
			
		||||
    private static String formatIII(Instruction inst, int address) {
 | 
			
		||||
 | 
			
		||||
        // NOP
 | 
			
		||||
        if (bcondCombine && inst.cond == 13)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        // Format destination
 | 
			
		||||
        String dest = destination(inst, address);
 | 
			
		||||
 | 
			
		||||
        // One-operand notation
 | 
			
		||||
        if (bcondCombine)
 | 
			
		||||
            return dest;
 | 
			
		||||
 | 
			
		||||
        // Two-operand notation
 | 
			
		||||
        String cond = bcondNames ?
 | 
			
		||||
            CONDITIONS[inst.cond] : Integer.toString(inst.cond);
 | 
			
		||||
        if (bcondNames && !condCaps)
 | 
			
		||||
            cond = cond.toLowerCase();
 | 
			
		||||
        return String.format("%s, %s", cond, dest);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Operands for Format V
 | 
			
		||||
    private static String formatV(Instruction inst) {
 | 
			
		||||
        String reg1 = program(inst.reg1);
 | 
			
		||||
        String reg2 = program(inst.reg2);
 | 
			
		||||
        String imm  = toHex(
 | 
			
		||||
            inst.id == VUE.MOVEA ? inst.imm & 0xFFFF : inst.imm,
 | 
			
		||||
            inst.id == VUE.ADDI  ? 1 : 4,
 | 
			
		||||
            immNumber
 | 
			
		||||
        );
 | 
			
		||||
        return String.format("%s, %s, %s",
 | 
			
		||||
            destLast ? imm  : reg2,
 | 
			
		||||
            reg1,
 | 
			
		||||
            destLast ? reg2 : imm
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Operands for Format VI
 | 
			
		||||
    private static String formatVI(Instruction inst) {
 | 
			
		||||
        String src  = program(inst.reg1);
 | 
			
		||||
        String dest = program(inst.reg2);
 | 
			
		||||
 | 
			
		||||
        // Data operand
 | 
			
		||||
        src = inst.disp == 0 ? String.format("[%s]", src) :
 | 
			
		||||
            dispInside ? String.format(
 | 
			
		||||
                "[%s %s %s]",
 | 
			
		||||
                src,
 | 
			
		||||
                inst.disp < 0 ? "-" : "+",
 | 
			
		||||
                toHex(Math.abs(inst.disp), 1, immNumber)
 | 
			
		||||
            ) : String.format(
 | 
			
		||||
                "%s[%s]",
 | 
			
		||||
                toHex(inst.disp, 1, immNumber),
 | 
			
		||||
                src
 | 
			
		||||
            )
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
        // Write instruction
 | 
			
		||||
        switch (inst.id) {
 | 
			
		||||
            case VUE.OUT_B: // Fallthrough
 | 
			
		||||
            case VUE.OUT_H: // Fallthrough
 | 
			
		||||
            case VUE.OUT_W: // Fallthrough
 | 
			
		||||
            case VUE.ST_B : // Fallthrough
 | 
			
		||||
            case VUE.ST_H : // Fallthrough
 | 
			
		||||
            case VUE.ST_W :
 | 
			
		||||
                String temp = src;
 | 
			
		||||
                src  = dest;
 | 
			
		||||
                dest = temp;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Format operands
 | 
			
		||||
        return String.format("%s, %s",
 | 
			
		||||
            destLast ? src  : dest,
 | 
			
		||||
            destLast ? dest : src
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Format a program register
 | 
			
		||||
    private static String program(int index) {
 | 
			
		||||
        String ret = programNames ? PROGRAMS[index] : null;
 | 
			
		||||
        if (ret == null)
 | 
			
		||||
            ret = "r" + index;
 | 
			
		||||
        return programCaps ? ret.toUpperCase() : ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Represent an immediate value as hexadecimal
 | 
			
		||||
    private static String toHex(int value, int digits, boolean number) {
 | 
			
		||||
        return String.format(
 | 
			
		||||
            "%s%s%s%0" + digits + (hexCaps ? "X" : "x") + "%s",
 | 
			
		||||
            number ? "#" : "",
 | 
			
		||||
            value < 0 ? "-" : "",
 | 
			
		||||
            hexMode == DOLLAR ? "$" : hexMode == ZEROX ? "0x" : "",
 | 
			
		||||
            value < 0 ? -value : value,
 | 
			
		||||
            hexMode == H ? "h" : ""
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -27,13 +27,13 @@ class MainWindow extends JFrame {
 | 
			
		|||
    private File    romFile;   // Currently loaded ROM file
 | 
			
		||||
 | 
			
		||||
    // UI components
 | 
			
		||||
    private JPanel       client;  // Common client container
 | 
			
		||||
    private Console      console; // Console window
 | 
			
		||||
    private CPU          cpu;     // CPU window
 | 
			
		||||
    private JDesktopPane desktop; // Container for child windows
 | 
			
		||||
    private Memory       memory;  // Memory window
 | 
			
		||||
    private JPanel       video;   // Video output
 | 
			
		||||
    private JMenu     mnuDebug;         // Debug menu
 | 
			
		||||
    private JPanel        client;   // Common client container
 | 
			
		||||
    private ConsoleWindow console;  // Console window
 | 
			
		||||
    private CPUWindow     cpu;      // CPU window
 | 
			
		||||
    private JDesktopPane  desktop;  // Container for child windows
 | 
			
		||||
    private MemoryWindow  memory;   // Memory window
 | 
			
		||||
    private JMenu         mnuDebug; // Debug menu
 | 
			
		||||
    private JPanel        video;    // Video output
 | 
			
		||||
    private JMenuItem mnuFileDebugMode; // File -> Debug mode
 | 
			
		||||
    private JMenuItem mnuFileGameMode;  // File -> Game mode
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -92,9 +92,9 @@ class MainWindow extends JFrame {
 | 
			
		|||
        // Configure child windows
 | 
			
		||||
        desktop = new JDesktopPane();
 | 
			
		||||
        desktop.setBackground(SystemColor.controlShadow);
 | 
			
		||||
        desktop.add(console = new Console(this));
 | 
			
		||||
        desktop.add(cpu     = new CPU    (this));
 | 
			
		||||
        desktop.add(memory  = new Memory (this));
 | 
			
		||||
        desktop.add(console = new ConsoleWindow(this));
 | 
			
		||||
        desktop.add(cpu     = new CPUWindow    (this));
 | 
			
		||||
        desktop.add(memory  = new MemoryWindow (this));
 | 
			
		||||
 | 
			
		||||
        // Display window
 | 
			
		||||
        refreshDebug();
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +207,7 @@ class MainWindow extends JFrame {
 | 
			
		|||
    // Window close, File -> Exit
 | 
			
		||||
    private void onClose() {
 | 
			
		||||
        app.removeWindow(this);
 | 
			
		||||
        cpu.dispose();
 | 
			
		||||
        dispose();
 | 
			
		||||
        vue.dispose();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ import javax.swing.*;
 | 
			
		|||
import util.*;
 | 
			
		||||
 | 
			
		||||
// Memory viewer and hex editor window
 | 
			
		||||
class Memory extends ChildWindow {
 | 
			
		||||
class MemoryWindow extends ChildWindow {
 | 
			
		||||
 | 
			
		||||
    // Private fields
 | 
			
		||||
    private int  address;    // Address of top row
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ class Memory extends ChildWindow {
 | 
			
		|||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    Memory(MainWindow parent) {
 | 
			
		||||
    MemoryWindow(MainWindow parent) {
 | 
			
		||||
        super(parent, "memory.title");
 | 
			
		||||
 | 
			
		||||
        // Configure instance fields
 | 
			
		||||
| 
						 | 
				
			
			@ -14,26 +14,22 @@ import vue.*;
 | 
			
		|||
class Register {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    boolean    expandable; // The expansion area can be shown
 | 
			
		||||
    boolean    expanded;   // The expanded area is being shown
 | 
			
		||||
    Font       font;       // Hexadecimal font
 | 
			
		||||
    int        index;      // Register index
 | 
			
		||||
    int        mode;       // Display mode for program registers
 | 
			
		||||
    MainWindow parent;     // Containing window
 | 
			
		||||
    int        type;       // Expansion controls type
 | 
			
		||||
    int        value;      // Current register value
 | 
			
		||||
    private boolean      expandable; // The expansion area can be shown
 | 
			
		||||
    private boolean      expanded;   // The expanded area is being shown
 | 
			
		||||
    private int          index;      // Register index
 | 
			
		||||
    private int          mode;       // Display mode for program registers
 | 
			
		||||
    private String       name;       // Register name
 | 
			
		||||
    private RegisterList parent;     // Containing register list
 | 
			
		||||
    private int          type;       // Expansion controls type
 | 
			
		||||
    private int          value;      // Current register value
 | 
			
		||||
 | 
			
		||||
    // UI components
 | 
			
		||||
    private JPanel     expansion;   // Expansion area
 | 
			
		||||
    private JLabel     btnExpand;   // Expand button
 | 
			
		||||
    private JLabel     lblLastPC;   // Last PC name
 | 
			
		||||
    private JLabel     lblName;     // Register name
 | 
			
		||||
    private JPanel     list;        // Containing element
 | 
			
		||||
    private JPanel     spacer;      // Expansion area spacer
 | 
			
		||||
    private JTextField txtJumpFrom; // Jump-from value
 | 
			
		||||
    private JTextField txtJumpTo;   // Jump-to value
 | 
			
		||||
    private JTextField txtValue;    // Register value
 | 
			
		||||
    private ArrayList<JComponent> controls; // Expansion controls
 | 
			
		||||
    JPanel     expansion; // Expansion container
 | 
			
		||||
    JLabel     btnExpand; // Expand button
 | 
			
		||||
    JPanel     indent;    // Expansion area indentation
 | 
			
		||||
    JLabel     lblName;   // Register name
 | 
			
		||||
    JTextField txtValue;  // Register value
 | 
			
		||||
    ArrayList<JComponent> controls; // Expansion controls
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,8 +44,8 @@ class Register {
 | 
			
		|||
    static final int UNSIGNED = 2;
 | 
			
		||||
 | 
			
		||||
    // Types
 | 
			
		||||
    static final int PLAIN   = -1;
 | 
			
		||||
    static final int PROGRAM = -2;
 | 
			
		||||
    static final int PLAIN   = -2;
 | 
			
		||||
    static final int PROGRAM = -3;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -58,20 +54,21 @@ class Register {
 | 
			
		|||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    Register(MainWindow parent, JPanel list, String name, int index, int type){
 | 
			
		||||
    Register(RegisterList parent, String name, int index, int type) {
 | 
			
		||||
        parent.add(index, this);
 | 
			
		||||
 | 
			
		||||
        // Configure instance fields
 | 
			
		||||
        controls    = new ArrayList<JComponent>();
 | 
			
		||||
        expandable  = type != PLAIN && index != 0 || index == VUE.PC;
 | 
			
		||||
        expandable  = type != PLAIN && index != 0;
 | 
			
		||||
        this.index  = index;
 | 
			
		||||
        this.list   = list;
 | 
			
		||||
        this.mode   = HEX;
 | 
			
		||||
        mode        = HEX;
 | 
			
		||||
        this.name   = name;
 | 
			
		||||
        this.parent = parent;
 | 
			
		||||
        this.type   = type;
 | 
			
		||||
 | 
			
		||||
        // Click handler for expand and name controls
 | 
			
		||||
        MouseListener expand = !expandable ? null : Util.onMouse(e->{
 | 
			
		||||
                if (e.getButton() == 1) setExpanded(!expanded); }, null);
 | 
			
		||||
            if (e.getButton() == 1) setExpanded(!expanded); }, null);
 | 
			
		||||
 | 
			
		||||
        // Expand button
 | 
			
		||||
        btnExpand = new JLabel(expandable ? "+" : " ");
 | 
			
		||||
| 
						 | 
				
			
			@ -81,17 +78,17 @@ class Register {
 | 
			
		|||
        var gbc = new GridBagConstraints();
 | 
			
		||||
        gbc.anchor = GridBagConstraints.NORTH;
 | 
			
		||||
        gbc.fill   = GridBagConstraints.HORIZONTAL;
 | 
			
		||||
        list.add(btnExpand, gbc);
 | 
			
		||||
        parent.add(gbc, btnExpand);
 | 
			
		||||
 | 
			
		||||
        // Name label
 | 
			
		||||
        lblName = new JLabel(name);
 | 
			
		||||
        lblName = new JLabel(" ");
 | 
			
		||||
        if (expandable)
 | 
			
		||||
            lblName.addMouseListener(expand);
 | 
			
		||||
        gbc = new GridBagConstraints();
 | 
			
		||||
        gbc.anchor  = GridBagConstraints.NORTH;
 | 
			
		||||
        gbc.fill    = GridBagConstraints.HORIZONTAL;
 | 
			
		||||
        gbc.weightx = 1;
 | 
			
		||||
        list.add(lblName, gbc);
 | 
			
		||||
        parent.add(gbc, lblName);
 | 
			
		||||
 | 
			
		||||
        // Value text box
 | 
			
		||||
        txtValue = new JTextField();
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +98,7 @@ class Register {
 | 
			
		|||
        gbc = new GridBagConstraints();
 | 
			
		||||
        gbc.gridwidth = GridBagConstraints.REMAINDER;
 | 
			
		||||
        gbc.insets    = new Insets(0, 4, 0, 0);
 | 
			
		||||
        list.add(txtValue, gbc);
 | 
			
		||||
        parent.add(gbc, txtValue);
 | 
			
		||||
 | 
			
		||||
        // Value changed
 | 
			
		||||
        txtValue.addActionListener(e->{
 | 
			
		||||
| 
						 | 
				
			
			@ -129,14 +126,14 @@ class Register {
 | 
			
		|||
            default: return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Expansion spacer
 | 
			
		||||
        // Expansion indentation
 | 
			
		||||
        if (index != VUE.PC) {
 | 
			
		||||
            spacer = new JPanel(null);
 | 
			
		||||
            spacer.setOpaque(false);
 | 
			
		||||
            spacer.setPreferredSize(new Dimension(0, 0));
 | 
			
		||||
            spacer.setVisible(false);
 | 
			
		||||
            indent = new JPanel(null);
 | 
			
		||||
            indent.setOpaque(false);
 | 
			
		||||
            indent.setPreferredSize(new Dimension(0, 0));
 | 
			
		||||
            indent.setVisible(false);
 | 
			
		||||
            gbc = new GridBagConstraints();
 | 
			
		||||
            list.add(spacer, gbc);
 | 
			
		||||
            parent.add(gbc, indent);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Expansion area
 | 
			
		||||
| 
						 | 
				
			
			@ -149,7 +146,11 @@ class Register {
 | 
			
		|||
        gbc.gridwidth = GridBagConstraints.REMAINDER;
 | 
			
		||||
        gbc.insets    = new Insets(0, 4, 0, 0);
 | 
			
		||||
        gbc.weightx   = 1;
 | 
			
		||||
        list.add(expansion, gbc);
 | 
			
		||||
        parent.add(gbc, expansion);
 | 
			
		||||
 | 
			
		||||
        // Handling for PSW
 | 
			
		||||
        if (index == VUE.PSW && type == VUE.PSW)
 | 
			
		||||
            setExpanded(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -161,14 +162,14 @@ class Register {
 | 
			
		|||
    // Expansion controls for CHCW
 | 
			
		||||
    private void initCHCW() {
 | 
			
		||||
        expansion = new JPanel(new GridBagLayout());
 | 
			
		||||
        addCheckBox("ICE", 1, false); endRow();
 | 
			
		||||
        addCheckBox("ICE", 1, false, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Expansion controls for ECR
 | 
			
		||||
    private void initECR() {
 | 
			
		||||
        expansion = new JPanel(new GridBagLayout());
 | 
			
		||||
        addTextBox("EICC",  0, 16, false, true); endRow();
 | 
			
		||||
        addTextBox("FECC", 16, 16, false, true); endRow();
 | 
			
		||||
        addTextBox("EICC",  0, 16, false, true);
 | 
			
		||||
        addTextBox("FECC", 16, 16, false, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Expansion controls for program registers
 | 
			
		||||
| 
						 | 
				
			
			@ -189,38 +190,37 @@ class Register {
 | 
			
		|||
        for (int x = 0; x < 2; x++) {
 | 
			
		||||
 | 
			
		||||
            // Indentation
 | 
			
		||||
            var spacer = new JPanel(null);
 | 
			
		||||
            spacer.setOpaque(false);
 | 
			
		||||
            spacer.setPreferredSize(new Dimension(0, 0));
 | 
			
		||||
            indent = new JPanel(null);
 | 
			
		||||
            indent.setOpaque(false);
 | 
			
		||||
            indent.setPreferredSize(new Dimension(0, 0));
 | 
			
		||||
            var gbc = new GridBagConstraints();
 | 
			
		||||
            gbc.weightx = 1;
 | 
			
		||||
            expansion.add(spacer, gbc);
 | 
			
		||||
            expansion.add(indent, gbc);
 | 
			
		||||
        
 | 
			
		||||
            // Name label
 | 
			
		||||
            var label = new JLabel();
 | 
			
		||||
            parent.app.localizer.add(label,
 | 
			
		||||
            parent.parent.parent.app.localizer.add(label,
 | 
			
		||||
                x == 0 ? "cpu.jump_from" : "cpu.jump_to" );
 | 
			
		||||
            gbc = new GridBagConstraints();
 | 
			
		||||
            gbc.anchor = GridBagConstraints.NORTHWEST;
 | 
			
		||||
            expansion.add(label, gbc);
 | 
			
		||||
            controls.add(label);
 | 
			
		||||
        
 | 
			
		||||
            // Value text box
 | 
			
		||||
            var txt = new JTextField();
 | 
			
		||||
            txt.addActionListener(e->{
 | 
			
		||||
                txt.setText((String) txt.getClientProperty("text"));
 | 
			
		||||
                list.requestFocus();
 | 
			
		||||
                parent.requestFocus();
 | 
			
		||||
            });
 | 
			
		||||
            txt.putClientProperty("index",
 | 
			
		||||
                x == 0 ? VUE.JUMP_FROM : VUE.JUMP_TO);
 | 
			
		||||
            txt.setBorder(null);
 | 
			
		||||
            txt.setOpaque(false);
 | 
			
		||||
            gbc = new GridBagConstraints();
 | 
			
		||||
            gbc.gridwidth = GridBagConstraints.REMAINDER;
 | 
			
		||||
            gbc.insets    = new Insets(0, 4, 0, 0);
 | 
			
		||||
            expansion.add(txt, gbc);
 | 
			
		||||
        
 | 
			
		||||
            // Initialize the corresponding component field
 | 
			
		||||
            if (x == 0)
 | 
			
		||||
                txtJumpFrom = txt;
 | 
			
		||||
            else txtJumpTo = txt;
 | 
			
		||||
            controls.add(txt);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -228,40 +228,40 @@ class Register {
 | 
			
		|||
    // Expansion controls for PSW
 | 
			
		||||
    private void initPSW() {
 | 
			
		||||
        expansion = new JPanel(new GridBagLayout());
 | 
			
		||||
        addCheckBox("Z"  ,  0, false);
 | 
			
		||||
        addCheckBox("FRO",  9, false); endRow();
 | 
			
		||||
        addCheckBox("S"  ,  1, false);
 | 
			
		||||
        addCheckBox("FIV",  8, false); endRow();
 | 
			
		||||
        addCheckBox("OV" ,  2, false);
 | 
			
		||||
        addCheckBox("FZD",  7, false); endRow();
 | 
			
		||||
        addCheckBox("CY" ,  3, false);
 | 
			
		||||
        addCheckBox("FOV",  6, false); endRow();
 | 
			
		||||
        addCheckBox("EP" , 14, false);
 | 
			
		||||
        addCheckBox("FUD",  5, false); endRow();
 | 
			
		||||
        addCheckBox("NP" , 15, false);
 | 
			
		||||
        addCheckBox("FPR",  4, false); endRow();
 | 
			
		||||
        addCheckBox("AE" , 13, false); endRow();
 | 
			
		||||
        addCheckBox("ID" , 12, false);
 | 
			
		||||
        addTextBox ("I"  , 16, 4, false, false); endRow();
 | 
			
		||||
        addCheckBox("Z"  ,  0, false, false);
 | 
			
		||||
        addCheckBox("FRO",  9, false, true );
 | 
			
		||||
        addCheckBox("S"  ,  1, false, false);
 | 
			
		||||
        addCheckBox("FIV",  8, false, true );
 | 
			
		||||
        addCheckBox("OV" ,  2, false, false);
 | 
			
		||||
        addCheckBox("FZD",  7, false, true );
 | 
			
		||||
        addCheckBox("CY" ,  3, false, false);
 | 
			
		||||
        addCheckBox("FOV",  6, false, true );
 | 
			
		||||
        addCheckBox("EP" , 14, false, false);
 | 
			
		||||
        addCheckBox("FUD",  5, false, true );
 | 
			
		||||
        addCheckBox("NP" , 15, false, false);
 | 
			
		||||
        addCheckBox("FPR",  4, false, true );
 | 
			
		||||
        addCheckBox("AE" , 13, false, true );
 | 
			
		||||
        addCheckBox("ID" , 12, false, false);
 | 
			
		||||
        addTextBox ("I"  , 16, 4, false, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Expansion controls for PIR
 | 
			
		||||
    private void initPIR() {
 | 
			
		||||
        expansion = new JPanel(new GridBagLayout());
 | 
			
		||||
        addTextBox("PT",  0, 16, true, true); endRow();
 | 
			
		||||
        addTextBox("PT",  0, 16, true, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Expansion controls for TKCW
 | 
			
		||||
    private void initTKCW() {
 | 
			
		||||
        expansion = new JPanel(new GridBagLayout());
 | 
			
		||||
        addCheckBox("OTM", 8, true);
 | 
			
		||||
        addCheckBox("FVT", 5, true); endRow();
 | 
			
		||||
        addCheckBox("FIT", 7, true);
 | 
			
		||||
        addCheckBox("FUT", 4, true); endRow();
 | 
			
		||||
        addCheckBox("FZT", 6, true);
 | 
			
		||||
        addCheckBox("FPT", 3, true); endRow();
 | 
			
		||||
        addCheckBox("RDI", 2, true);
 | 
			
		||||
        addTextBox ("RD", 0, 2, true, false); endRow();
 | 
			
		||||
        addCheckBox("OTM", 8, true, false);
 | 
			
		||||
        addCheckBox("FVT", 5, true, true );
 | 
			
		||||
        addCheckBox("FIT", 7, true, false);
 | 
			
		||||
        addCheckBox("FUT", 4, true, true );
 | 
			
		||||
        addCheckBox("FZT", 6, true, false);
 | 
			
		||||
        addCheckBox("FPT", 3, true, true );
 | 
			
		||||
        addCheckBox("RDI", 2, true, false);
 | 
			
		||||
        addTextBox ("RD", 0, 2, true, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -270,11 +270,61 @@ class Register {
 | 
			
		|||
    //                            Package Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Refresh controls
 | 
			
		||||
    void refresh() {
 | 
			
		||||
    // Apply configuration settings
 | 
			
		||||
    void configure() {
 | 
			
		||||
        String name = null;
 | 
			
		||||
 | 
			
		||||
        // System register
 | 
			
		||||
        if (type != PROGRAM) {
 | 
			
		||||
            name = this.name;
 | 
			
		||||
            if (!Disassembler.systemCaps)
 | 
			
		||||
                name = name.toLowerCase();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Program register
 | 
			
		||||
        else {
 | 
			
		||||
            if (Disassembler.programNames)
 | 
			
		||||
                name = this.name;
 | 
			
		||||
            if (name == null)
 | 
			
		||||
                name = "r" + index;
 | 
			
		||||
            if (Disassembler.programCaps)
 | 
			
		||||
                name = name.toUpperCase();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Name label
 | 
			
		||||
        lblName.setText(name);
 | 
			
		||||
 | 
			
		||||
        // Expand button
 | 
			
		||||
        var size = btnExpand.getPreferredSize();
 | 
			
		||||
        size.width = CPUWindow.regExpandWidth;
 | 
			
		||||
        btnExpand.setPreferredSize(size);
 | 
			
		||||
 | 
			
		||||
        // Value text box
 | 
			
		||||
        value = parent.vue.getRegister(index, type != PROGRAM);
 | 
			
		||||
        var fontSize = CPUWindow.regHexFontSize;
 | 
			
		||||
            size     = new Dimension(8 * fontSize.width + 4, fontSize.height);
 | 
			
		||||
        txtValue.setFont(CPUWindow.regHexFont);
 | 
			
		||||
        txtValue.setPreferredSize(size);
 | 
			
		||||
 | 
			
		||||
        // Expansion controls
 | 
			
		||||
        for (var ctrl : controls) {
 | 
			
		||||
            if (!(ctrl instanceof JTextField))
 | 
			
		||||
                continue;
 | 
			
		||||
            if (type == VUE.PC || (Boolean) ctrl.getClientProperty("hex"))
 | 
			
		||||
                ((JTextField) ctrl).setFont(CPUWindow.regHexFont);
 | 
			
		||||
            int digits = type == VUE.PC ? 8 :
 | 
			
		||||
                (Integer) ctrl.getClientProperty("digits");
 | 
			
		||||
            size       = ctrl.getPreferredSize();
 | 
			
		||||
            size.width = digits * fontSize.width + 4;
 | 
			
		||||
            ctrl.setPreferredSize(size);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Refresh controls
 | 
			
		||||
    void refresh() {
 | 
			
		||||
        var vue = parent.parent.parent.vue;
 | 
			
		||||
 | 
			
		||||
        // Value text box
 | 
			
		||||
        value = vue.getRegister(index, type != PROGRAM);
 | 
			
		||||
        txtValue.setText(
 | 
			
		||||
            type != PROGRAM || mode == HEX ?
 | 
			
		||||
                String.format("%08X", value) :
 | 
			
		||||
| 
						 | 
				
			
			@ -283,18 +333,8 @@ class Register {
 | 
			
		|||
            Float.toString(Float.intBitsToFloat(value))
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // PC expansion controls
 | 
			
		||||
        if (index == VUE.PC) for (int x = 0; x < 2; x++) {
 | 
			
		||||
            JTextField txt = x == 0 ? txtJumpFrom : txtJumpTo;
 | 
			
		||||
            int index = x == 0 ? VUE.JUMP_FROM : VUE.JUMP_TO;
 | 
			
		||||
            int value = parent.vue.getRegister(index, true);
 | 
			
		||||
            String text = String.format("%08X", value);
 | 
			
		||||
            txt.putClientProperty("text", text);
 | 
			
		||||
            txt.setText(text);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Other expansion controls
 | 
			
		||||
        else for (var control : controls) {
 | 
			
		||||
        // Expansion controls
 | 
			
		||||
        for (var control : controls) {
 | 
			
		||||
 | 
			
		||||
            // Check box
 | 
			
		||||
            if (control instanceof JCheckBox) {
 | 
			
		||||
| 
						 | 
				
			
			@ -306,13 +346,32 @@ class Register {
 | 
			
		|||
            // Text box
 | 
			
		||||
            if (control instanceof JTextField) {
 | 
			
		||||
                var     ctrl   = (JTextField) control;
 | 
			
		||||
                int     bit    = (Integer) ctrl.getClientProperty("bit"  );
 | 
			
		||||
                int     digits = (Integer) ctrl.getClientProperty("digits");
 | 
			
		||||
                boolean hex    = (Boolean) ctrl.getClientProperty("hex");
 | 
			
		||||
                int     width  = (Integer) ctrl.getClientProperty("width");
 | 
			
		||||
                int     val    = value >> bit & (1 << width) - 1;
 | 
			
		||||
                ctrl.setText(!hex ? Integer.toString(val) :
 | 
			
		||||
                    String.format("%0" + digits + "X", val));
 | 
			
		||||
                int     digits; // Maximum digits that can be displayed
 | 
			
		||||
                boolean hex;    // The value is hexadecimal
 | 
			
		||||
                int     val;    // The value to be displayed
 | 
			
		||||
 | 
			
		||||
                // Jump history
 | 
			
		||||
                if (type == VUE.PC) {
 | 
			
		||||
                    digits = 8;
 | 
			
		||||
                    hex    = true;
 | 
			
		||||
                    val    = vue.getRegister((Integer)
 | 
			
		||||
                        ctrl.getClientProperty("index"), true);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // All other values
 | 
			
		||||
                else {
 | 
			
		||||
                    int bit    = (Integer) ctrl.getClientProperty("bit"  );
 | 
			
		||||
                        digits = (Integer) ctrl.getClientProperty("digits");
 | 
			
		||||
                        hex    = (Boolean) ctrl.getClientProperty("hex");
 | 
			
		||||
                    int width  = (Integer) ctrl.getClientProperty("width");
 | 
			
		||||
                        val = value >> bit & (1 << width) - 1;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Update the text
 | 
			
		||||
                String text = !hex ? Integer.toString(val) : String.format(
 | 
			
		||||
                    "%0" + digits + (Disassembler.hexCaps ? "X" : "x"), val);
 | 
			
		||||
                ctrl.putClientProperty("text", text);
 | 
			
		||||
                ctrl.setText(text);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -329,52 +388,16 @@ class Register {
 | 
			
		|||
        // Update controls
 | 
			
		||||
        this.expanded = expanded;
 | 
			
		||||
        btnExpand.setText(expanded ? "-" : "+");
 | 
			
		||||
        if (index != VUE.PC)
 | 
			
		||||
            spacer.setVisible(expanded);
 | 
			
		||||
        if (type != VUE.PC)
 | 
			
		||||
            indent.setVisible(expanded);
 | 
			
		||||
        expansion.setVisible(expanded);
 | 
			
		||||
        list.revalidate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify the width of the expand button
 | 
			
		||||
    void setExpandWidth(int width) {
 | 
			
		||||
        var size = btnExpand.getPreferredSize();
 | 
			
		||||
        size.width = width;
 | 
			
		||||
        btnExpand.setPreferredSize(size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify a new font
 | 
			
		||||
    void setFont(Font font, int fontWidth, int fontHeight) {
 | 
			
		||||
        this.font = font;
 | 
			
		||||
 | 
			
		||||
        // Value text box
 | 
			
		||||
        var size = new Dimension(8 * fontWidth + 4, fontHeight);
 | 
			
		||||
        txtValue.setFont(font);
 | 
			
		||||
        txtValue.setPreferredSize(size);
 | 
			
		||||
        if (index == VUE.PC) {
 | 
			
		||||
            txtJumpFrom.setFont(font);
 | 
			
		||||
            txtJumpFrom.setPreferredSize(size);
 | 
			
		||||
            txtJumpTo  .setFont(font);
 | 
			
		||||
            txtJumpTo  .setPreferredSize(size);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Expansion controls
 | 
			
		||||
        for (var ctrl : controls) {
 | 
			
		||||
            if (!(ctrl instanceof JTextField))
 | 
			
		||||
                continue;
 | 
			
		||||
            if ((Boolean) ctrl.getClientProperty("hex"))
 | 
			
		||||
                ((JTextField) ctrl).setFont(font);
 | 
			
		||||
            int digits = (Integer) ctrl.getClientProperty("digits");
 | 
			
		||||
            size       = ctrl.getPreferredSize();
 | 
			
		||||
            size.width = digits * fontWidth + 4;
 | 
			
		||||
            ctrl.setPreferredSize(size);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        parent.revalidate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Change the display mode of a program register
 | 
			
		||||
    void setMode(int mode) {
 | 
			
		||||
        this.mode = mode;
 | 
			
		||||
        txtValue.setFont(mode == HEX ? font : null);
 | 
			
		||||
        txtValue.setFont(mode == HEX ? CPUWindow.regHexFont : null);
 | 
			
		||||
        refresh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -385,7 +408,8 @@ class Register {
 | 
			
		|||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Add a check box to the expansion area
 | 
			
		||||
    private void addCheckBox(String name, int bit, boolean readOnly) {
 | 
			
		||||
    private void addCheckBox(String name, int bit, boolean readOnly,
 | 
			
		||||
        boolean last) {
 | 
			
		||||
        int mask = 1 << bit;
 | 
			
		||||
 | 
			
		||||
        // Configure control
 | 
			
		||||
| 
						 | 
				
			
			@ -406,7 +430,7 @@ class Register {
 | 
			
		|||
        // Configure expansion area
 | 
			
		||||
        var gbc = new GridBagConstraints();
 | 
			
		||||
        gbc.anchor    = GridBagConstraints.NORTHWEST;
 | 
			
		||||
        gbc.gridwidth = 2;
 | 
			
		||||
        gbc.gridwidth = last ? GridBagConstraints.REMAINDER : 2;
 | 
			
		||||
        gbc.insets    = new Insets(0, 4, 0, 4);
 | 
			
		||||
        expansion.add(ctrl, gbc);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -416,7 +440,7 @@ class Register {
 | 
			
		|||
 | 
			
		||||
        // Configure control
 | 
			
		||||
        var ctrl = new JRadioButton();
 | 
			
		||||
        parent.app.localizer.add(ctrl, key);
 | 
			
		||||
        parent.parent.parent.app.localizer.add(ctrl, key);
 | 
			
		||||
        ctrl.setBorder(null);
 | 
			
		||||
        ctrl.setFocusable(false);
 | 
			
		||||
        ctrl.setOpaque(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -465,27 +489,20 @@ class Register {
 | 
			
		|||
        // Configure expansion area
 | 
			
		||||
        var label = new JLabel(name);
 | 
			
		||||
        label.setEnabled(!readOnly);
 | 
			
		||||
        var gbc   = new GridBagConstraints();
 | 
			
		||||
        var gbc = new GridBagConstraints();
 | 
			
		||||
        gbc.anchor = GridBagConstraints.NORTHWEST;
 | 
			
		||||
        gbc.insets = new Insets(0, 4, 0, 4);
 | 
			
		||||
        expansion.add(label, gbc);
 | 
			
		||||
        expansion.add(ctrl , gbc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Terminate a row of expansion controls
 | 
			
		||||
    private void endRow() {
 | 
			
		||||
        var spacer = new JPanel(null);
 | 
			
		||||
        spacer.setOpaque(false);
 | 
			
		||||
        spacer.setPreferredSize(new Dimension(0, 0));
 | 
			
		||||
        var gbc = new GridBagConstraints();
 | 
			
		||||
        gbc = new GridBagConstraints();
 | 
			
		||||
        gbc.gridwidth = GridBagConstraints.REMAINDER;
 | 
			
		||||
        expansion.add(spacer, gbc);
 | 
			
		||||
        gbc.insets    = new Insets(0, 4, 0, 4);
 | 
			
		||||
        expansion.add(ctrl , gbc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update the register value
 | 
			
		||||
    private void setValue(int value) {
 | 
			
		||||
        list.requestFocus();
 | 
			
		||||
        parent.vue.setRegister(index, type != PROGRAM, value);
 | 
			
		||||
        parent.requestFocus();
 | 
			
		||||
        parent.parent.parent.vue.setRegister(index, type != PROGRAM, value);
 | 
			
		||||
        refresh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,201 @@
 | 
			
		|||
package app;
 | 
			
		||||
 | 
			
		||||
// Java imports
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
 | 
			
		||||
// Project imports
 | 
			
		||||
import vue.*;
 | 
			
		||||
 | 
			
		||||
// List of CPU registers
 | 
			
		||||
class RegisterList extends JScrollPane {
 | 
			
		||||
 | 
			
		||||
    // Package fields
 | 
			
		||||
    CPUWindow parent; // Containing CPU window
 | 
			
		||||
 | 
			
		||||
    // Private fields
 | 
			
		||||
    private boolean shown; // Component has been shown
 | 
			
		||||
    private HashMap<Integer, Register> registers; // Register items
 | 
			
		||||
 | 
			
		||||
    // UI components
 | 
			
		||||
    private JPanel client; // Client area
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                             Constructors                              //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    RegisterList(CPUWindow parent, boolean system) {
 | 
			
		||||
        super(VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_AS_NEEDED);
 | 
			
		||||
 | 
			
		||||
        // Configure instance fields
 | 
			
		||||
        this.parent = parent;
 | 
			
		||||
        registers   = new HashMap<Integer, Register>();
 | 
			
		||||
        shown       = true;
 | 
			
		||||
 | 
			
		||||
        // Configure client area
 | 
			
		||||
        client = new JPanel(new GridBagLayout()) {
 | 
			
		||||
            public Dimension getPreferredSize() {
 | 
			
		||||
                var ret = super.getPreferredSize();
 | 
			
		||||
                if (!shown) ret.height = system ? getInitialHeight() : 0;
 | 
			
		||||
                return ret;
 | 
			
		||||
            }
 | 
			
		||||
            public void paintComponent(Graphics g) {
 | 
			
		||||
                shown = true;
 | 
			
		||||
                super.paintComponent(g);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        client.setBackground(SystemColor.window);
 | 
			
		||||
        client.setFocusable(true);
 | 
			
		||||
 | 
			
		||||
        // Initialize system registers
 | 
			
		||||
        if (system) {
 | 
			
		||||
            new Register(this, "PC"   , VUE.PC   , VUE.PC        );
 | 
			
		||||
            new Register(this, "PSW"  , VUE.PSW  , VUE.PSW       );
 | 
			
		||||
            new Register(this, "EIPC" , VUE.EIPC , Register.PLAIN);
 | 
			
		||||
            new Register(this, "EIPSW", VUE.EIPSW, VUE.PSW       );
 | 
			
		||||
            new Register(this, "FEPC" , VUE.FEPC , Register.PLAIN);
 | 
			
		||||
            new Register(this, "FEPSW", VUE.FEPSW, VUE.PSW       );
 | 
			
		||||
            new Register(this, "ECR"  , VUE.ECR  , VUE.ECR       );
 | 
			
		||||
            new Register(this, "ADTRE", VUE.ADTRE, Register.PLAIN);
 | 
			
		||||
            new Register(this, "CHCW" , VUE.CHCW , VUE.CHCW      );
 | 
			
		||||
            new Register(this, "PIR"  , VUE.PIR  , VUE.PIR       );
 | 
			
		||||
            new Register(this, "TKCW" , VUE.TKCW , VUE.TKCW      );
 | 
			
		||||
            new Register(this, "29"   ,        29, Register.PLAIN);
 | 
			
		||||
            new Register(this, "30"   ,        30, Register.PLAIN);
 | 
			
		||||
            new Register(this, "31"   ,        31, Register.PLAIN);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Initialize program registers
 | 
			
		||||
        else for (int x = 0; x < 32; x++) {
 | 
			
		||||
            String name = null;
 | 
			
		||||
            switch (x) {
 | 
			
		||||
                case VUE.GP: name = "gp"; break;
 | 
			
		||||
                case VUE.HP: name = "hp"; break;
 | 
			
		||||
                case VUE.LP: name = "lp"; break;
 | 
			
		||||
                case VUE.SP: name = "sp"; break;
 | 
			
		||||
                case VUE.TP: name = "tp"; break;
 | 
			
		||||
            }
 | 
			
		||||
            new Register(this, name, x, Register.PROGRAM);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // List terminator
 | 
			
		||||
        var spacer = new JPanel(null);
 | 
			
		||||
        spacer.setOpaque(false);
 | 
			
		||||
        spacer.setPreferredSize(new Dimension(0, 0));
 | 
			
		||||
        var gbc = new GridBagConstraints();
 | 
			
		||||
        gbc.gridheight = GridBagConstraints.REMAINDER;
 | 
			
		||||
        gbc.gridwidth  = GridBagConstraints.REMAINDER;
 | 
			
		||||
        gbc.weighty    = 1;
 | 
			
		||||
        client.add(spacer, gbc);
 | 
			
		||||
 | 
			
		||||
        // Configure component
 | 
			
		||||
        shown = false;
 | 
			
		||||
        setViewportView(client);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Public Methods                             //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Draw the component
 | 
			
		||||
    public void paintComponent(Graphics g) {
 | 
			
		||||
        if (!shown) {
 | 
			
		||||
            shown = true;
 | 
			
		||||
            revalidate();
 | 
			
		||||
        }
 | 
			
		||||
        super.paintComponent(g);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Transfer focus to the client area
 | 
			
		||||
    public void requestFocus() {
 | 
			
		||||
        client.requestFocus();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Recalculate layout
 | 
			
		||||
    public void revalidate() {
 | 
			
		||||
        if (client != null)
 | 
			
		||||
            client.revalidate();
 | 
			
		||||
        super.revalidate();
 | 
			
		||||
        repaint();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Package Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Add a register component to the client area
 | 
			
		||||
    void add(GridBagConstraints gbc, JComponent comp) {
 | 
			
		||||
        client.add(comp, gbc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Associate a register with its index
 | 
			
		||||
    void add(int index, Register register) {
 | 
			
		||||
        registers.put(index, register);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Apply configuration settings
 | 
			
		||||
    void configure() {
 | 
			
		||||
 | 
			
		||||
        // Configure registers
 | 
			
		||||
        for (var reg : registers.values())
 | 
			
		||||
            reg.configure();
 | 
			
		||||
 | 
			
		||||
        // Configure component
 | 
			
		||||
        getVerticalScrollBar().setUnitIncrement(
 | 
			
		||||
            CPUWindow.regHexFontSize.height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update the display
 | 
			
		||||
    void refresh() {
 | 
			
		||||
        for (var reg : registers.values())
 | 
			
		||||
            reg.refresh();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Private Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Determine the initial height upon first show
 | 
			
		||||
    private int getInitialHeight() {
 | 
			
		||||
        int height = 0;
 | 
			
		||||
        var layout = (GridBagLayout) client.getLayout();
 | 
			
		||||
        int ret    = 0;
 | 
			
		||||
        int row    = 0;
 | 
			
		||||
 | 
			
		||||
        // Process controls until the target row is found
 | 
			
		||||
        for (var control : client.getComponents()) {
 | 
			
		||||
            var ctrl = (JComponent) control;
 | 
			
		||||
 | 
			
		||||
            // Track the tallest control on the row
 | 
			
		||||
            if (ctrl.isVisible())
 | 
			
		||||
                height = Math.max(height, ctrl.getPreferredSize().height);
 | 
			
		||||
 | 
			
		||||
            // This is not the last control on the row
 | 
			
		||||
            if (layout.getConstraints(control).gridwidth !=
 | 
			
		||||
                GridBagConstraints.REMAINDER)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            // Advance to the next row
 | 
			
		||||
            ret   += height;
 | 
			
		||||
            height = 0;
 | 
			
		||||
            row++;
 | 
			
		||||
 | 
			
		||||
            // The target row has been reached
 | 
			
		||||
            if (row == 4)
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,6 @@ public class Instruction {
 | 
			
		|||
 | 
			
		||||
        // Decode by format
 | 
			
		||||
        switch (format) {
 | 
			
		||||
            case 0: return; // Illegal opcode
 | 
			
		||||
            case 1:
 | 
			
		||||
                reg2 = bits >> 21 & 31;
 | 
			
		||||
                reg1 = bits >> 16 & 31;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,9 @@ package vue;
 | 
			
		|||
// Java emulation core implementation
 | 
			
		||||
class JavaVUE extends VUE {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    Instruction inst; // Instruction state
 | 
			
		||||
 | 
			
		||||
    // Components
 | 
			
		||||
    Bus bus; // Memory bus
 | 
			
		||||
    CPU cpu; // Processor
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +27,9 @@ class JavaVUE extends VUE {
 | 
			
		|||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    JavaVUE() {
 | 
			
		||||
        bus = new Bus(this);
 | 
			
		||||
        cpu = new CPU(this);
 | 
			
		||||
        bus  = new Bus(this);
 | 
			
		||||
        cpu  = new CPU(this);
 | 
			
		||||
        inst = new Instruction();
 | 
			
		||||
        reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue