Implementing native breakpoint interface
This commit is contained in:
		
							parent
							
								
									2d048a74c0
								
							
						
					
					
						commit
						826e921dac
					
				
							
								
								
									
										2
									
								
								makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								makefile
								
								
								
								
							| 
						 | 
				
			
			@ -10,7 +10,7 @@ default:
 | 
			
		|||
	@echo $(include_linux)
 | 
			
		||||
	@echo "Planet Virtual Boy Emulator"
 | 
			
		||||
	@echo "  https://www.planetvb.com/"
 | 
			
		||||
	@echo "  October 13, 2020"
 | 
			
		||||
	@echo "  October 16, 2020"
 | 
			
		||||
	@echo
 | 
			
		||||
	@echo "Intended build environment: Debian i386 or amd64"
 | 
			
		||||
	@echo "  gcc-multilib"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ public class Main {
 | 
			
		|||
        // Begin application operations
 | 
			
		||||
        new App(useNative);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        var brk = new Breakpoint(null);
 | 
			
		||||
 | 
			
		||||
        String exp =
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +74,7 @@ public class Main {
 | 
			
		|||
            brk.getErrorPosition(Breakpoint.ADDRESS) + ":"  +
 | 
			
		||||
            brk.getErrorText    (Breakpoint.ADDRESS)
 | 
			
		||||
        );
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -612,13 +612,13 @@ static void evalUnary(Vue *vue, int32_t id, int32_t *stack, int32_t size) {
 | 
			
		|||
int32_t evaluate(Vue *vue, Breakpoint *brk, int32_t *stack) {
 | 
			
		||||
 | 
			
		||||
    // The condition is empty
 | 
			
		||||
    if (brk->numCondition == 0)
 | 
			
		||||
    if (brk->numTokens == 0)
 | 
			
		||||
        return brk->enabled;
 | 
			
		||||
 | 
			
		||||
    // Process tokens
 | 
			
		||||
    int size = 0;
 | 
			
		||||
    for (int x = 0; x < brk->numCondition; x++) {
 | 
			
		||||
        Token *tok = &brk->condition[x];
 | 
			
		||||
    for (int x = 0; x < brk->numTokens; x++) {
 | 
			
		||||
        Token *tok = &brk->tokens[x];
 | 
			
		||||
        switch (tok->type) {
 | 
			
		||||
            case BINARY: size =
 | 
			
		||||
                evalBinary(     tok->value, stack, size); continue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,15 +7,16 @@ import java.util.*;
 | 
			
		|||
public class Breakpoint {
 | 
			
		||||
 | 
			
		||||
    // Instance fields
 | 
			
		||||
    private int[][]  addresses;   // Applicable address ranges
 | 
			
		||||
    private String   addressText; // Un-processed address ranges
 | 
			
		||||
    private String   addresses;   // Un-processed address ranges
 | 
			
		||||
    private String   condition;   // Un-processed condition
 | 
			
		||||
    private int[]    errCode;     // Error codes
 | 
			
		||||
    private int[]    errPosition; // Character position of errors
 | 
			
		||||
    private String[] errText;     // Offending error text
 | 
			
		||||
    private int      hooks;       // Applied breakpoint types
 | 
			
		||||
    private boolean  isEnabled;   // Breakpoint is active
 | 
			
		||||
    private String   name;        // Display name
 | 
			
		||||
    private Token[]  tokens;      // Evaluation tokens
 | 
			
		||||
    private int[][]  ranges;      // Applicable address ranges
 | 
			
		||||
    private Token[]  tokens;      // Condition tokens
 | 
			
		||||
    private Vue      vue;         // Containing emulation context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +40,12 @@ public class Breakpoint {
 | 
			
		|||
    public static final int ADDRESS   = 0;
 | 
			
		||||
    public static final int CONDITION = 1;
 | 
			
		||||
 | 
			
		||||
    // Breakpoint hooks
 | 
			
		||||
    private static final int EXCEPTION = 0x00000001;
 | 
			
		||||
    private static final int EXECUTE   = 0x00000002;
 | 
			
		||||
    private static final int READ      = 0x00000004;
 | 
			
		||||
    private static final int WRITE     = 0x00000008;
 | 
			
		||||
 | 
			
		||||
    // Token types
 | 
			
		||||
    private static final int BINARY  = 4;
 | 
			
		||||
    private static final int CLOSE   = 6;
 | 
			
		||||
| 
						 | 
				
			
			@ -296,6 +303,11 @@ public class Breakpoint {
 | 
			
		|||
            this.type  = type;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Retrieve the applicable serialized "value"
 | 
			
		||||
        int flatten() {
 | 
			
		||||
            return type == FLOAT || type == WORD ? value : id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -306,13 +318,13 @@ public class Breakpoint {
 | 
			
		|||
 | 
			
		||||
    // Default constructor
 | 
			
		||||
    public Breakpoint(Vue vue) {
 | 
			
		||||
        addresses   = new int[0][];
 | 
			
		||||
        addressText = "";
 | 
			
		||||
        addresses   = "";
 | 
			
		||||
        condition   = "";
 | 
			
		||||
        errCode     = new int   [] { NONE, NONE };
 | 
			
		||||
        errPosition = new int   [] {    0,    0 };
 | 
			
		||||
        errText     = new String[] {   "",   "" };
 | 
			
		||||
        name        = "";
 | 
			
		||||
        ranges      = new int[0][];
 | 
			
		||||
        tokens      = new Token[0];
 | 
			
		||||
        this.vue    = vue;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -378,8 +390,8 @@ public class Breakpoint {
 | 
			
		|||
    // Produce a string representation of the internal address ranges
 | 
			
		||||
    public String test() {
 | 
			
		||||
        var ret = new StringBuilder();
 | 
			
		||||
        for (int x = 0; x < addresses.length; x++) {
 | 
			
		||||
            var range = addresses[x];
 | 
			
		||||
        for (int x = 0; x < ranges.length; x++) {
 | 
			
		||||
            var range = ranges[x];
 | 
			
		||||
            if (x > 0)
 | 
			
		||||
                ret.append("\n");
 | 
			
		||||
            ret.append(String.format("%08X", range[0]));
 | 
			
		||||
| 
						 | 
				
			
			@ -396,7 +408,7 @@ public class Breakpoint {
 | 
			
		|||
 | 
			
		||||
    // Retrieve the most recent input addresses
 | 
			
		||||
    public String getAddresses() {
 | 
			
		||||
        return addressText;
 | 
			
		||||
        return addresses;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve the most recent input condition
 | 
			
		||||
| 
						 | 
				
			
			@ -419,6 +431,26 @@ public class Breakpoint {
 | 
			
		|||
        return type < 0 || type > 1 ? null : errText[type];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve whether the breakpoint hooks exceptions
 | 
			
		||||
    public boolean getException() {
 | 
			
		||||
        return (hooks & EXCEPTION) != 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve whether the breakpoint hooks executions
 | 
			
		||||
    public boolean getExecute() {
 | 
			
		||||
        return (hooks & EXECUTE) != 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve whether the breakpoint hooks reads
 | 
			
		||||
    public boolean getRead() {
 | 
			
		||||
        return (hooks & READ) != 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve whether the breakpoint hooks writes
 | 
			
		||||
    public boolean getWrite() {
 | 
			
		||||
        return (hooks & WRITE) != 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve the display name
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return name;
 | 
			
		||||
| 
						 | 
				
			
			@ -438,7 +470,7 @@ public class Breakpoint {
 | 
			
		|||
        int     x      = 0;    // Input position
 | 
			
		||||
 | 
			
		||||
        // Configure instance fields
 | 
			
		||||
        addressText = addresses == null ? addresses = "" : addresses;
 | 
			
		||||
        this.addresses = addresses == null ? addresses = "" : addresses;
 | 
			
		||||
 | 
			
		||||
        // Parse the input
 | 
			
		||||
        var chars = (addresses + " ").toCharArray();
 | 
			
		||||
| 
						 | 
				
			
			@ -485,7 +517,7 @@ public class Breakpoint {
 | 
			
		|||
                    errPosition[ADDRESS] = start + 1;
 | 
			
		||||
                    errText    [ADDRESS] = text;
 | 
			
		||||
                    if (vue != null)
 | 
			
		||||
                        vue.update(this);
 | 
			
		||||
                        vue.updateRanges(this);
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -535,7 +567,7 @@ public class Breakpoint {
 | 
			
		|||
            errPosition[ADDRESS] = x + 1;
 | 
			
		||||
            errText    [ADDRESS] = Character.toString(c);
 | 
			
		||||
            if (vue != null)
 | 
			
		||||
                vue.update(this);
 | 
			
		||||
                vue.updateRanges(this);
 | 
			
		||||
            return false;
 | 
			
		||||
        } // x
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -545,7 +577,7 @@ public class Breakpoint {
 | 
			
		|||
            errPosition[ADDRESS] = x + 1;
 | 
			
		||||
            errText    [ADDRESS] = "";
 | 
			
		||||
            if (vue != null)
 | 
			
		||||
                vue.update(this);
 | 
			
		||||
                vue.updateRanges(this);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -554,13 +586,12 @@ public class Breakpoint {
 | 
			
		|||
            ranges.add(new int[] { first, first });
 | 
			
		||||
 | 
			
		||||
        // Parsing was successful
 | 
			
		||||
        this.addresses   = ranges.toArray(new int[ranges.size()][]);
 | 
			
		||||
        this.addressText = addresses;
 | 
			
		||||
        this.ranges = ranges.toArray(new int[ranges.size()][]);
 | 
			
		||||
        errCode    [ADDRESS] = NONE;
 | 
			
		||||
        errPosition[ADDRESS] = 0;
 | 
			
		||||
        errText    [ADDRESS] = "";
 | 
			
		||||
        if (vue != null)
 | 
			
		||||
            vue.update(this);
 | 
			
		||||
            vue.updateRanges(this);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -578,7 +609,7 @@ public class Breakpoint {
 | 
			
		|||
        var tokens = parse();
 | 
			
		||||
        if (tokens == null || !validate(tokens)) {
 | 
			
		||||
            if (vue != null)
 | 
			
		||||
                vue.update(this);
 | 
			
		||||
                vue.updateTokens(this);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        tree(tokens);
 | 
			
		||||
| 
						 | 
				
			
			@ -586,7 +617,7 @@ public class Breakpoint {
 | 
			
		|||
        // The expression is empty
 | 
			
		||||
        if (tokens.size() == 0) {
 | 
			
		||||
            if (vue != null)
 | 
			
		||||
                vue.update(this);
 | 
			
		||||
                vue.updateTokens(this);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -616,15 +647,48 @@ public class Breakpoint {
 | 
			
		|||
 | 
			
		||||
        // The expression was successfully parsed
 | 
			
		||||
        if (vue != null)
 | 
			
		||||
            vue.update(this);
 | 
			
		||||
            vue.updateTokens(this);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify whether the breakpoint is enabled
 | 
			
		||||
    public void setEnabled(boolean enabled) {
 | 
			
		||||
        isEnabled = enabled;
 | 
			
		||||
        if (vue != null)
 | 
			
		||||
            vue.updateState(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify whether the breakpoint hooks exceptions
 | 
			
		||||
    public void setException(boolean hook) {
 | 
			
		||||
        hooks = hook ? hooks | EXCEPTION : hooks & ~EXCEPTION;
 | 
			
		||||
        if (vue != null)
 | 
			
		||||
            vue.updateState(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify whether the breakpoint hooks executions
 | 
			
		||||
    public void setExecute(boolean hook) {
 | 
			
		||||
        hooks = hook ? hooks | EXECUTE : hooks & ~EXECUTE;
 | 
			
		||||
        if (vue != null)
 | 
			
		||||
            vue.updateState(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify the display name
 | 
			
		||||
    public void setName(String name) {
 | 
			
		||||
        this.name = name == null ? "" : name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify whether the breakpoint hooks reads
 | 
			
		||||
    public void setRead(boolean hook) {
 | 
			
		||||
        hooks = hook ? hooks | READ : hooks & ~READ;
 | 
			
		||||
        if (vue != null)
 | 
			
		||||
            vue.update(this);
 | 
			
		||||
            vue.updateState(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Specify whether the breakpoint hooks reads
 | 
			
		||||
    public void setWrite(boolean hook) {
 | 
			
		||||
        hooks = hook ? hooks | WRITE : hooks & ~WRITE;
 | 
			
		||||
        if (vue != null)
 | 
			
		||||
            vue.updateState(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -634,7 +698,7 @@ public class Breakpoint {
 | 
			
		|||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Evaluate the condition for a Java emulation context
 | 
			
		||||
    boolean evaluate(JavaVue vue, int[] stack) {
 | 
			
		||||
    boolean evaluate(int[] stack) {
 | 
			
		||||
 | 
			
		||||
        // The condition is empty
 | 
			
		||||
        if (tokens.length == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -645,11 +709,11 @@ public class Breakpoint {
 | 
			
		|||
        for (var tok : tokens) {
 | 
			
		||||
            switch (tok.type) {
 | 
			
		||||
                case BINARY: size =
 | 
			
		||||
                    evalBinary(     tok.id, stack, size); continue;
 | 
			
		||||
                    evalBinary(tok.id, stack, size); continue;
 | 
			
		||||
                case SYMBOL: size =
 | 
			
		||||
                    evalSymbol(vue, tok.id, stack, size); continue;
 | 
			
		||||
                    evalSymbol(tok.id, stack, size); continue;
 | 
			
		||||
                case UNARY :
 | 
			
		||||
                    evalUnary (vue, tok.id, stack, size); continue;
 | 
			
		||||
                    evalUnary (tok.id, stack, size); continue;
 | 
			
		||||
            }
 | 
			
		||||
            stack[size++] = tok.type;
 | 
			
		||||
            stack[size++] = tok.value;
 | 
			
		||||
| 
						 | 
				
			
			@ -676,6 +740,43 @@ public class Breakpoint {
 | 
			
		|||
        return max;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Produce a one-dimensional array from the address ranges
 | 
			
		||||
    int[] flattenRanges() {
 | 
			
		||||
        var ret = new int[ranges.length * 2];
 | 
			
		||||
        for (int x = 0; x < ranges.length; x++) {
 | 
			
		||||
            var range = ranges[x];
 | 
			
		||||
            ret[x / 2    ] = range[0];
 | 
			
		||||
            ret[x / 2 + 1] = range[1];
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Produce a one-dimensional array from the condition tokens
 | 
			
		||||
    int[] flattenTokens() {
 | 
			
		||||
        var ret = new int[tokens.length * 2];
 | 
			
		||||
        for (int x = 0; x < tokens.length; x++) {
 | 
			
		||||
            var token = tokens[x];
 | 
			
		||||
            ret[x / 2    ] = token.type;
 | 
			
		||||
            ret[x / 2 + 1] = token.flatten();
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve the bit mask for enabled hooks
 | 
			
		||||
    int getHooks() {
 | 
			
		||||
        return hooks;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve the list of address ranges
 | 
			
		||||
    int[][] getRanges() {
 | 
			
		||||
        return ranges;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Retrieve the list of condition tokens
 | 
			
		||||
    Token[] getTokens() {
 | 
			
		||||
        return tokens;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The breakpoint is being removed from its emulation context
 | 
			
		||||
    void remove() {
 | 
			
		||||
        vue = null;
 | 
			
		||||
| 
						 | 
				
			
			@ -1155,8 +1256,9 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate a functional symbol
 | 
			
		||||
    private static int evalSymbol(JavaVue vue, int id, int[] stack, int size) {
 | 
			
		||||
    private int evalSymbol(int id, int[] stack, int size) {
 | 
			
		||||
        int ret = 0;
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        if (id == Vue.PC)
 | 
			
		||||
            ret = vue.cpu.pc;
 | 
			
		||||
        else if (id >= 200)
 | 
			
		||||
| 
						 | 
				
			
			@ -1166,20 +1268,20 @@ public class Breakpoint {
 | 
			
		|||
        else if (vue.cpu.stage == CPU.EXCEPTION && id == CODE)
 | 
			
		||||
            ret = vue.cpu.exception.code;
 | 
			
		||||
        else if (vue.cpu.stage == CPU.EXECUTE) switch (id) {
 | 
			
		||||
            case ADDRESS  : ret = evalAddress   (vue); break;
 | 
			
		||||
            case COND     : ret = evalCond      (vue); break;
 | 
			
		||||
            case DISP     : ret = evalDisp      (vue); break;
 | 
			
		||||
            case ADDRESS  : ret = evalAddress      (); break;
 | 
			
		||||
            case COND     : ret = evalCond         (); break;
 | 
			
		||||
            case DISP     : ret = evalDisp         (); break;
 | 
			
		||||
            case FORMAT   : ret = vue.cpu.inst.format; break;
 | 
			
		||||
            case ID       : ret = vue.cpu.inst.id    ; break;
 | 
			
		||||
            case IMM      : ret = evalImm       (vue); break;
 | 
			
		||||
            case IMM      : ret = evalImm          (); break;
 | 
			
		||||
            case OPCODE   : ret = vue.cpu.inst.opcode; break;
 | 
			
		||||
            case REG1     : ret = evalReg1      (vue); break;
 | 
			
		||||
            case REG2     : ret = evalReg2      (vue); break;
 | 
			
		||||
            case REGID    : ret = evalRegId     (vue); break;
 | 
			
		||||
            case REG1     : ret = evalReg1         (); break;
 | 
			
		||||
            case REG2     : ret = evalReg2         (); break;
 | 
			
		||||
            case REGID    : ret = evalRegId        (); break;
 | 
			
		||||
            case SIZE     : ret = vue.cpu.inst.size  ; break;
 | 
			
		||||
            case SUBOPCODE: ret = evalSubopcode (vue); break;
 | 
			
		||||
            case VALUE    : ret = evalValue     (vue); break;
 | 
			
		||||
            case VECTOR   : ret = evalVector    (vue); break;
 | 
			
		||||
            case SUBOPCODE: ret = evalSubopcode    (); break;
 | 
			
		||||
            case VALUE    : ret = evalValue        (); break;
 | 
			
		||||
            case VECTOR   : ret = evalVector       (); break;
 | 
			
		||||
        }
 | 
			
		||||
        stack[size++] = WORD;
 | 
			
		||||
        stack[size++] = ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -1187,7 +1289,7 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate a unary operator
 | 
			
		||||
    private static void evalUnary(JavaVue vue, int id, int[] stack, int size) {
 | 
			
		||||
    private void evalUnary(int id, int[] stack, int size) {
 | 
			
		||||
        int     type   = stack[size - 2];
 | 
			
		||||
        int     value  = stack[size - 1];
 | 
			
		||||
        boolean isWord = type == WORD;
 | 
			
		||||
| 
						 | 
				
			
			@ -1201,7 +1303,7 @@ public class Breakpoint {
 | 
			
		|||
            case FLOAT      : value = evalFloat     (isWord, value);
 | 
			
		||||
                type = FLOAT; break;
 | 
			
		||||
            case FLOOR      : value = evalFloor     (isWord, value); break;
 | 
			
		||||
            case READ_WORD  : value = evalReadWord  (isWord, value, vue);
 | 
			
		||||
            case READ_WORD  : value = evalReadWord  (isWord, value);
 | 
			
		||||
                type = WORD ; break;
 | 
			
		||||
            case ROUND      : value = evalRound     (isWord, value); break;
 | 
			
		||||
            case TRUNC      : value = evalTrunc     (isWord, value); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1414,7 +1516,8 @@ public class Breakpoint {
 | 
			
		|||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Evaluate address
 | 
			
		||||
    private static int evalAddress(JavaVue vue) {
 | 
			
		||||
    private int evalAddress() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        if (vue.cpu.inst.format == 6)
 | 
			
		||||
            return vue.cpu.program[vue.cpu.inst.reg1] + vue.cpu.inst.disp;
 | 
			
		||||
        switch (vue.cpu.inst.id) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1429,7 +1532,8 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate cond
 | 
			
		||||
    private static int evalCond(JavaVue vue) {
 | 
			
		||||
    private int evalCond() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        switch (vue.cpu.inst.id) {
 | 
			
		||||
            case Vue.BCOND: return vue.cpu.inst.cond;
 | 
			
		||||
            case Vue.SETF : return vue.cpu.inst.imm;
 | 
			
		||||
| 
						 | 
				
			
			@ -1438,7 +1542,8 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate disp
 | 
			
		||||
    private static int evalDisp(JavaVue vue) {
 | 
			
		||||
    private int evalDisp() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        switch (vue.cpu.inst.format) {
 | 
			
		||||
            case 3: case 4: case 6: return vue.cpu.inst.disp;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1446,7 +1551,8 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate imm
 | 
			
		||||
    private static int evalImm(JavaVue vue) {
 | 
			
		||||
    private int evalImm() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        switch (vue.cpu.inst.format) {
 | 
			
		||||
            case 2: case 5: return vue.cpu.inst.imm;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1454,7 +1560,8 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate reg1
 | 
			
		||||
    private static int evalReg1(JavaVue vue) {
 | 
			
		||||
    private int evalReg1() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        switch (vue.cpu.inst.format) {
 | 
			
		||||
            case 1: case 5: case 6: case 7: return vue.cpu.inst.reg1;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1462,7 +1569,8 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate reg2
 | 
			
		||||
    private static int evalReg2(JavaVue vue) {
 | 
			
		||||
    private int evalReg2() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        switch (vue.cpu.inst.format) {
 | 
			
		||||
            case 1: case 2: case 5: case 6: case 7: return vue.cpu.inst.reg2;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1470,7 +1578,8 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate regid
 | 
			
		||||
    private static int evalRegId(JavaVue vue) {
 | 
			
		||||
    private int evalRegId() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        switch (vue.cpu.inst.id) {
 | 
			
		||||
            case Vue.LDSR: case Vue.STSR: return vue.cpu.inst.imm;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1478,7 +1587,8 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate subopcode
 | 
			
		||||
    private static int evalSubopcode(JavaVue vue) {
 | 
			
		||||
    private int evalSubopcode() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        switch (vue.cpu.inst.opcode) {
 | 
			
		||||
            case 0x1F: return vue.cpu.inst.imm;
 | 
			
		||||
            case 0x3E: return vue.cpu.inst.subopcode;
 | 
			
		||||
| 
						 | 
				
			
			@ -1487,12 +1597,14 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate value
 | 
			
		||||
    private static int evalValue(JavaVue vue) {
 | 
			
		||||
    private int evalValue() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        return vue.cpu.inst.format == 6 ? vue.cpu.access.value : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate vector
 | 
			
		||||
    private static int evalVector(JavaVue vue) {
 | 
			
		||||
    private int evalVector() {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        return vue.cpu.inst.id == Vue.TRAP ? vue.cpu.inst.imm : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1533,7 +1645,8 @@ public class Breakpoint {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Evaluate []
 | 
			
		||||
    private static int evalReadWord(boolean isWord, int value, JavaVue vue) {
 | 
			
		||||
    private int evalReadWord(boolean isWord, int value) {
 | 
			
		||||
        var vue = (JavaVue) this.vue;
 | 
			
		||||
        return vue.read(isWord ? value : toWord(asFloat(value)), Vue.S32);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,19 +22,27 @@ static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
 | 
			
		|||
//                                   Types                                   //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// Breakpoint token
 | 
			
		||||
// Breakpoint address range
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int32_t type;
 | 
			
		||||
    int32_t value;
 | 
			
		||||
    int32_t start; // First address, inclusive
 | 
			
		||||
    int32_t end;   // Last address, inclusive
 | 
			
		||||
} Range;
 | 
			
		||||
 | 
			
		||||
// Breakpoint condition token
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int32_t type;  // Token category
 | 
			
		||||
    int32_t value; // Operator or symbol ID, or literal value
 | 
			
		||||
} Token;
 | 
			
		||||
 | 
			
		||||
// Precompiled breakpoint
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int32_t  depth;     // Maximum number of stack entries
 | 
			
		||||
    int32_t  enabled;   // The breakpoint is enabled
 | 
			
		||||
    int32_t  numAddresses; // Number of address ranges
 | 
			
		||||
    int32_t  numCondition; // Number of tokens in condition
 | 
			
		||||
    int32_t *addresses;    // Address ranges
 | 
			
		||||
    Token   *condition;    // Condition tokens in RPN order
 | 
			
		||||
    int32_t  hooks;     // Events hooked by the breakpoint
 | 
			
		||||
    int32_t  numRanges; // Number of address ranges
 | 
			
		||||
    int32_t  numTokens; // Number of condition tokens
 | 
			
		||||
    Range   *ranges;    // Address ranges
 | 
			
		||||
    Token   *tokens;    // Condition tokens in RPN order
 | 
			
		||||
} Breakpoint;
 | 
			
		||||
 | 
			
		||||
// Core context state type
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +75,7 @@ typedef struct {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//                             Method Functions                              //
 | 
			
		||||
//                              Public Methods                               //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// Native constructor
 | 
			
		||||
| 
						 | 
				
			
			@ -84,6 +92,17 @@ JNIEXPORT jlong JNICALL Java_vue_NativeVue_construct
 | 
			
		|||
JNIEXPORT void JNICALL Java_vue_NativeVue_dispose
 | 
			
		||||
  (JNIEnv *env, jobject vue, jlong handle) {
 | 
			
		||||
    Core       *core = *(Core **)&handle;
 | 
			
		||||
    Breakpoint *brk; // Handle to breakpoint
 | 
			
		||||
    int        x;    // Iterator
 | 
			
		||||
 | 
			
		||||
    // Delete breakpoints
 | 
			
		||||
    for (x = 0; x < core->numBreakpoints; x++) {
 | 
			
		||||
        brk = &core->breakpoints[x];
 | 
			
		||||
        if (brk->ranges != NULL) free(brk->ranges);
 | 
			
		||||
        if (brk->tokens != NULL) free(brk->tokens);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Delete core
 | 
			
		||||
    if (core->breakpoints != NULL) free(core->breakpoints);
 | 
			
		||||
    if (core->stack       != NULL) free(core->stack      );
 | 
			
		||||
    if (core->vue.pak.rom != NULL) free(core->vue.pak.rom);
 | 
			
		||||
| 
						 | 
				
			
			@ -234,3 +253,108 @@ JNIEXPORT jboolean JNICALL Java_vue_NativeVue_writeBytes
 | 
			
		|||
    (*env)->ReleaseByteArrayElements(env, data, elems, 0);
 | 
			
		||||
    return JNI_TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//                              Private Methods                              //
 | 
			
		||||
///////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// Produce a new breakpoint and add it to the collection
 | 
			
		||||
JNIEXPORT void JNICALL Java_vue_NativeVue_breakpoint
 | 
			
		||||
  (JNIEnv *env, jobject vue, jlong handle) {
 | 
			
		||||
    Core   *core = *(Core **)&handle;
 | 
			
		||||
    int32_t size; // Number of bytes to allocate
 | 
			
		||||
 | 
			
		||||
    // Allocate memory for the breakpoint
 | 
			
		||||
    core->numBreakpoints++;
 | 
			
		||||
    size = core->numBreakpoints * sizeof (Breakpoint);
 | 
			
		||||
    core->breakpoints = core->breakpoints == NULL ?
 | 
			
		||||
        malloc(size) : realloc(core->breakpoints, size);
 | 
			
		||||
 | 
			
		||||
    // Initialize the breakpoint
 | 
			
		||||
    memset(&core->breakpoints[core->numBreakpoints-1], 0, sizeof (Breakpoint));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove a breakpoint from the collection
 | 
			
		||||
JNIEXPORT void JNICALL Java_vue_NativeVue_remove
 | 
			
		||||
  (JNIEnv *env, jobject vue, jlong handle, jint index) {
 | 
			
		||||
    Core       *core = *(Core **)&handle;
 | 
			
		||||
    Breakpoint *brk  = &core->breakpoints[index];
 | 
			
		||||
 | 
			
		||||
    // Delete the breakpoint
 | 
			
		||||
    if (brk->ranges != NULL) free(brk->ranges);
 | 
			
		||||
    if (brk->tokens != NULL) free(brk->tokens);
 | 
			
		||||
 | 
			
		||||
    // Move all subsequent breakpoints forward
 | 
			
		||||
    if (index != core->numBreakpoints - 1)
 | 
			
		||||
        memmove(brk, &brk[1],
 | 
			
		||||
            (core->numBreakpoints - index) * sizeof (Breakpoint));
 | 
			
		||||
    core->numBreakpoints--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A breakpoint's address ranges have changed
 | 
			
		||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateRanges
 | 
			
		||||
  (JNIEnv *env, jobject vue, jlong handle, jint index, jintArray ranges) {
 | 
			
		||||
    Core       *core = *(Core **)&handle;
 | 
			
		||||
    Breakpoint *brk  = &core->breakpoints[index];
 | 
			
		||||
    jint       *elems; // Array elements
 | 
			
		||||
    int32_t     size;  // Number of bytes to allocate
 | 
			
		||||
 | 
			
		||||
    // Determine the number of address ranges
 | 
			
		||||
    brk->numRanges = (*env)->GetArrayLength(env, ranges) / 2;
 | 
			
		||||
    if (brk->numRanges == 0) {
 | 
			
		||||
        if (brk->ranges != NULL)
 | 
			
		||||
            free(brk->ranges);
 | 
			
		||||
        brk->ranges = NULL;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Allocate memory for the address ranges
 | 
			
		||||
    size        = brk->numRanges * sizeof (Range);
 | 
			
		||||
    brk->ranges = brk->ranges == NULL ?
 | 
			
		||||
        malloc(size) : realloc(brk->ranges, size);
 | 
			
		||||
 | 
			
		||||
    // Initialize address ranges
 | 
			
		||||
    elems = (*env)->GetIntArrayElements(env, ranges, NULL);
 | 
			
		||||
    memcpy(brk->ranges, elems, size);
 | 
			
		||||
    (*env)->ReleaseIntArrayElements(env, ranges, elems, JNI_ABORT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A breakpoint's enabled/hook state has changed
 | 
			
		||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateState
 | 
			
		||||
  (JNIEnv *env, jobject vue, jlong handle, jint index, jboolean enabled,
 | 
			
		||||
  jint hooks) {
 | 
			
		||||
    Core       *core = *(Core **)&handle;
 | 
			
		||||
    Breakpoint *brk  = &core->breakpoints[index];
 | 
			
		||||
    brk->enabled     = enabled;
 | 
			
		||||
    brk->hooks       = hooks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A breakpoint's condition tokens have changed
 | 
			
		||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateTokens
 | 
			
		||||
  (JNIEnv *env, jobject vue, jlong handle, jint index, jintArray tokens) {
 | 
			
		||||
    Core       *core = *(Core **)&handle;
 | 
			
		||||
    Breakpoint *brk  = &core->breakpoints[index];
 | 
			
		||||
    jint       *elems; // Array elements
 | 
			
		||||
    int32_t     size;  // Number of bytes to allocate
 | 
			
		||||
 | 
			
		||||
    // Determine the number of condition tokens
 | 
			
		||||
    brk->numTokens = (*env)->GetArrayLength(env, tokens) / 2;
 | 
			
		||||
    if (brk->numTokens == 0) {
 | 
			
		||||
        if (brk->tokens != NULL)
 | 
			
		||||
            free(brk->tokens);
 | 
			
		||||
        brk->tokens = NULL;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Allocate memory for the condition tokens
 | 
			
		||||
    size           = brk->numTokens * sizeof (Token);
 | 
			
		||||
    brk->tokens    = brk->tokens == NULL ?
 | 
			
		||||
        malloc(size) : realloc(brk->tokens, size);
 | 
			
		||||
 | 
			
		||||
    // Initialize condition tokens
 | 
			
		||||
    elems = (*env)->GetIntArrayElements(env, tokens, NULL);
 | 
			
		||||
    memcpy(brk->tokens, elems, size);
 | 
			
		||||
    (*env)->ReleaseIntArrayElements(env, tokens, elems, JNI_ABORT);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,13 @@ class NativeVue extends Vue {
 | 
			
		|||
    //                            Public Methods                             //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Produce a new breakpoint and add it to the collection
 | 
			
		||||
    public Breakpoint breakpoint() {
 | 
			
		||||
        var brk = super.breakpoint();
 | 
			
		||||
        breakpoint(handle);
 | 
			
		||||
        return brk;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Release any used resources
 | 
			
		||||
    private native void dispose(long handle);
 | 
			
		||||
    public void dispose()
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +68,15 @@ class NativeVue extends Vue {
 | 
			
		|||
    public boolean readBytes(int address, byte[] dest, int offset, int length)
 | 
			
		||||
        { return readBytes(handle, address, dest, offset, length); }
 | 
			
		||||
 | 
			
		||||
    // Remove a breakpoint from the collection
 | 
			
		||||
    public boolean remove(Breakpoint brk) {
 | 
			
		||||
        int index = breakpoints.indexOf(brk);
 | 
			
		||||
        if (!super.remove(brk))
 | 
			
		||||
            return false;
 | 
			
		||||
        remove(handle, index);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Initialize all system components
 | 
			
		||||
    private native void reset(long handle);
 | 
			
		||||
    public void reset()
 | 
			
		||||
| 
						 | 
				
			
			@ -100,4 +116,45 @@ class NativeVue extends Vue {
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // A breakpoint's address ranges have changed
 | 
			
		||||
    void updateRanges(Breakpoint brk) {
 | 
			
		||||
        super.updateRanges(brk);
 | 
			
		||||
        updateRanges(handle, breakpoints.indexOf(brk), brk.flattenRanges());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // A breakpoint's enabled/hook state has changed
 | 
			
		||||
    void updateState(Breakpoint brk) {
 | 
			
		||||
        super.updateState(brk);
 | 
			
		||||
        updateState(handle, breakpoints.indexOf(brk),
 | 
			
		||||
            brk.isEnabled(), brk.getHooks());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // A breakpoint's condition tokens have changed
 | 
			
		||||
    void updateTokens(Breakpoint brk) {
 | 
			
		||||
        super.updateTokens(brk);
 | 
			
		||||
        updateTokens(handle, breakpoints.indexOf(brk), brk.flattenTokens());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
    //                            Private Methods                            //
 | 
			
		||||
    ///////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
    // Produce a new breakpoint and add it to the collection
 | 
			
		||||
    private native void breakpoint(long handle);
 | 
			
		||||
 | 
			
		||||
    // Remove a breakpoint from the collection
 | 
			
		||||
    private native void remove(long handle, int index);
 | 
			
		||||
 | 
			
		||||
    // A breakpoint's address ranges have changed
 | 
			
		||||
    private native void updateRanges(long handle, int index, int[] ranges);
 | 
			
		||||
 | 
			
		||||
    // A breakpoint's enabled/hook state has changed
 | 
			
		||||
    private native void updateState(long handle, int index, boolean enabled,
 | 
			
		||||
        int hooks);
 | 
			
		||||
 | 
			
		||||
    // A breakpoint's condition tokens have changed
 | 
			
		||||
    private native void updateTokens(long handle, int index, int[] tokens);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -249,8 +249,13 @@ public abstract class Vue {
 | 
			
		|||
    // Evaluate the condition in a breakpoint
 | 
			
		||||
    abstract boolean evaluate(Breakpoint brk);
 | 
			
		||||
 | 
			
		||||
    // A breakpoint has been updated
 | 
			
		||||
    void update(Breakpoint brk) {
 | 
			
		||||
    }
 | 
			
		||||
    // A breakpoint's address ranges have changed
 | 
			
		||||
    void updateRanges(Breakpoint brk) { }
 | 
			
		||||
 | 
			
		||||
    // A breakpoint's enabled/hook state has changed
 | 
			
		||||
    void updateState(Breakpoint brk) { }
 | 
			
		||||
 | 
			
		||||
    // A breakpoint's condition tokens have changed
 | 
			
		||||
    void updateTokens(Breakpoint brk) { }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue