Adjusting top-level emulation logic, integrating breakpoints
This commit is contained in:
		
							parent
							
								
									e13c56e1e7
								
							
						
					
					
						commit
						167bc4f8bf
					
				| 
						 | 
					@ -0,0 +1,696 @@
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					    <meta charset="utf-8">
 | 
				
			||||||
 | 
					    <title>Expression Evaluator</title>
 | 
				
			||||||
 | 
					    <style>
 | 
				
			||||||
 | 
					      :root {
 | 
				
			||||||
 | 
					        font-family: Arial, sans-serif;
 | 
				
			||||||
 | 
					        font-size  : 16px;
 | 
				
			||||||
 | 
					        text-align : justify;
 | 
				
			||||||
 | 
					        -webkit-text-size-adjust: none;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      a     { text-decoration      : underline; }
 | 
				
			||||||
 | 
					      a.ext { text-decoration-style: dotted;    }
 | 
				
			||||||
 | 
					      body  { margin               : 8px;       }
 | 
				
			||||||
 | 
					      circle, path, rect {
 | 
				
			||||||
 | 
					        fill        : none;
 | 
				
			||||||
 | 
					        paint-order : markers fill stroke;
 | 
				
			||||||
 | 
					        stroke-width: 1.5;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      code, pre, .mono { font-family: Consolas, monospace; }
 | 
				
			||||||
 | 
					      h1 {
 | 
				
			||||||
 | 
					        border-radius: 8px;
 | 
				
			||||||
 | 
					        font-size    : 20px;
 | 
				
			||||||
 | 
					        font-weight  : normal;
 | 
				
			||||||
 | 
					        padding      : 4px 8px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      h1.top {
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					        font-size  : 24px;
 | 
				
			||||||
 | 
					        text-align : center;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      h1.bottom {
 | 
				
			||||||
 | 
					        font-size : 16px;
 | 
				
			||||||
 | 
					        padding   : 6px 8px;
 | 
				
			||||||
 | 
					        text-align: right;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      h2 {
 | 
				
			||||||
 | 
					        font-size  : 18px;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					        margin-top : 32px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      sup, .small { font-size: 10px; }
 | 
				
			||||||
 | 
					      table {
 | 
				
			||||||
 | 
					        border        : none;
 | 
				
			||||||
 | 
					        border-spacing: 0px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      td, th { padding-right : 12px; }
 | 
				
			||||||
 | 
					      tr     { vertical-align: top;  }
 | 
				
			||||||
 | 
					      .b {
 | 
				
			||||||
 | 
					        border-style: solid;
 | 
				
			||||||
 | 
					        border-width: 0;
 | 
				
			||||||
 | 
					        font-size   : 1px;
 | 
				
			||||||
 | 
					        height      : 4px;
 | 
				
			||||||
 | 
					        padding     : 0;
 | 
				
			||||||
 | 
					        width       : 16px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .bb { border-bottom-width: 1px; }
 | 
				
			||||||
 | 
					      .bc, .bd, .be {
 | 
				
			||||||
 | 
					        font-size : 12px;
 | 
				
			||||||
 | 
					        height    : 32px;
 | 
				
			||||||
 | 
					        position  : relative;
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .bd { height: 48px; }
 | 
				
			||||||
 | 
					      .be { height: 72px; }
 | 
				
			||||||
 | 
					      .bh {
 | 
				
			||||||
 | 
					        font-size : 10px;
 | 
				
			||||||
 | 
					        padding   : 2px 0;
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .bl { border-left-width  : 1px; }
 | 
				
			||||||
 | 
					      .br { border-right-width : 1px; }
 | 
				
			||||||
 | 
					      .bs, .by, .bz {
 | 
				
			||||||
 | 
					          box-sizing      : border-box;
 | 
				
			||||||
 | 
					          height          : 17px;
 | 
				
			||||||
 | 
					          left            : 17px;
 | 
				
			||||||
 | 
					          line-height     : 17px;
 | 
				
			||||||
 | 
					          margin-left     : -1px;
 | 
				
			||||||
 | 
					          position        : absolute;
 | 
				
			||||||
 | 
					          text-align      : center;
 | 
				
			||||||
 | 
					          top             : -4px;
 | 
				
			||||||
 | 
					          transform       : rotate(90deg);
 | 
				
			||||||
 | 
					          transform-origin: 0 0;
 | 
				
			||||||
 | 
					          white-space     : nowrap;
 | 
				
			||||||
 | 
					          width           : 41px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .by {
 | 
				
			||||||
 | 
					        font-size: 10px;
 | 
				
			||||||
 | 
					        width    : 82px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .bz {
 | 
				
			||||||
 | 
					        font-size: 10px;
 | 
				
			||||||
 | 
					        width    : 57px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .bt     { border-top-width : 1px;    }
 | 
				
			||||||
 | 
					      .center { text-align       : center; }
 | 
				
			||||||
 | 
					      .ednote {
 | 
				
			||||||
 | 
					        border-radius: 8px;
 | 
				
			||||||
 | 
					        border-style : solid;
 | 
				
			||||||
 | 
					        border-width : 1px;
 | 
				
			||||||
 | 
					        font-style   : italic;
 | 
				
			||||||
 | 
					        margin-left  : 16px;
 | 
				
			||||||
 | 
					        margin-right : 16px;
 | 
				
			||||||
 | 
					        padding      : 4px 8px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      .indent  { margin-left   : 16px;   }
 | 
				
			||||||
 | 
					      .middle  { vertical-align: middle; }
 | 
				
			||||||
 | 
					      .minor   { font-size     : 14px;   }
 | 
				
			||||||
 | 
					      .nowrap  { white-space   : nowrap; }
 | 
				
			||||||
 | 
					      .narrow  { width         : 1px;    }
 | 
				
			||||||
 | 
					      .outdent { margin-left   : -16px;  }
 | 
				
			||||||
 | 
					      .right   { text-align    : right;  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      :root      { color       : #000000; }
 | 
				
			||||||
 | 
					      a          { color       : #0099ff; }
 | 
				
			||||||
 | 
					      a.ext      { color       : #00bb66; }
 | 
				
			||||||
 | 
					      a.redlink  { color       : #ff3366; }
 | 
				
			||||||
 | 
					      body       { background  : #ffffff; }
 | 
				
			||||||
 | 
					      h1, .shade { background  : #d4d4d4; }
 | 
				
			||||||
 | 
					      .b         { border-color: #666666; }
 | 
				
			||||||
 | 
					      .ednote    { border-color: #999999; color: #666666; }
 | 
				
			||||||
 | 
					      .fill      { fill        : #ffffff; }
 | 
				
			||||||
 | 
					      .stroke    { stroke      : #666666; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .bordered {
 | 
				
			||||||
 | 
					        border-style: solid;
 | 
				
			||||||
 | 
					        border-color: #999999;
 | 
				
			||||||
 | 
					        border-width: 1px 0 0 1px;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .bordered td {
 | 
				
			||||||
 | 
					        border-style: solid;
 | 
				
			||||||
 | 
					        border-color: #999999;
 | 
				
			||||||
 | 
					        border-width: 0 1px 1px 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .bordered tr > :first-child {
 | 
				
			||||||
 | 
					        padding: 1px 12px 1px 12px;
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .bordered td.open { border-bottom: none; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h1 class="top">Expression Evaluator</h1>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  The emulator is capable of evaluating expressions within breakpoint
 | 
				
			||||||
 | 
					  conditions and Go To prompts. These expressions inspect the current emulation
 | 
				
			||||||
 | 
					  state and can be used to dynamically process registers, variables and other
 | 
				
			||||||
 | 
					  data elements that may change from one invocation to the next.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Expressions are organized into series of tokens with three main modes of
 | 
				
			||||||
 | 
					  significance:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<table class="indent">
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="narrow nowrap">• Value</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      Numeric value that can be used in computation. This may take the form of
 | 
				
			||||||
 | 
					      a literal number provided directly in the expression, or one of the
 | 
				
			||||||
 | 
					      named symbols that represent things in the CPU state, current
 | 
				
			||||||
 | 
					      instruction and/or current memory access.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="narrow nowrap">• Operator</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      Modifies one or two values through a given operation. Unary operators
 | 
				
			||||||
 | 
					      modify only the value on their right, while binary operators consider the
 | 
				
			||||||
 | 
					      values on their left and right and produce a new value as the result.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="nowrap">• Group</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      Operand groups, mainly through the use of parentheses <code>()</code>,
 | 
				
			||||||
 | 
					      override the default order of operations. Anything enclosed in a group
 | 
				
			||||||
 | 
					      is processed before any operations adjacent to that group.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Expressions are case-insensitive.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h2>Values</h2>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Values come in two forms:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<table class="indent">
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="narrow nowrap">• Literal</td>
 | 
				
			||||||
 | 
					    <td>Provided directly by the expression.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="nowrap">• Symbol</td>
 | 
				
			||||||
 | 
					    <td>Refers to something in the current emulation state.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Values may be one of four data types:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<table class="indent">
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="narrow nowrap">• Signed Word</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      32-bit, two's complement integer.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="nowrap">• Unsigned Word</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      32-bit, unsigned integer.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="nowrap">• Float</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      32-bit floating short in IEEE-754 format.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="nowrap">• Boolean</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      1-bit value representing whether a condition is true or false.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Signed word and unsigned word are represented as sequences of character
 | 
				
			||||||
 | 
					  digits. A numeric token that begins with the characters <code>0x</code>
 | 
				
			||||||
 | 
					  will be interpreted as hexadecimal, allowing letters <code>A</code> through
 | 
				
			||||||
 | 
					  <code>F</code> to be used as digits as well. If the given value can be
 | 
				
			||||||
 | 
					  represented in the signed word data type, the token is a signed word.
 | 
				
			||||||
 | 
					  Otherwise, if it can be represented in the unsigned word data type, the token
 | 
				
			||||||
 | 
					  is an unsigned word. If the value cannot be represented in either data type,
 | 
				
			||||||
 | 
					  a parsing error occurs.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Floats, like words, are represented as sequences of character digits. They
 | 
				
			||||||
 | 
					  are differentiated from words by the presence of a dot <code>.</code>
 | 
				
			||||||
 | 
					  character somewhere within the sequence. Only one dot may be present in a
 | 
				
			||||||
 | 
					  float literal, and dots cannot be used in hexadecimal literals. If the given
 | 
				
			||||||
 | 
					  value cannot be represented in the float data type, a parsing error occurs.
 | 
				
			||||||
 | 
					  Float values in the expression evaluator are subjected to the same
 | 
				
			||||||
 | 
					  restrictions as on the Virtual Boy's CPU: if the result of any float
 | 
				
			||||||
 | 
					  operation is NaN, an infinity, a denormal number or negative zero, it will be
 | 
				
			||||||
 | 
					  changed to positive zero.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Booleans are mechanically identical to signed words, but the semantics are
 | 
				
			||||||
 | 
					  slightly different. When used in a numeric operation, a boolean will use the
 | 
				
			||||||
 | 
					  value <code>0</code> if false or the value <code>1</code> if true. Boolean
 | 
				
			||||||
 | 
					  literals are specified with the named values <code>true</code> and
 | 
				
			||||||
 | 
					  <code>false</code> within the expression. In a boolean operation, any result
 | 
				
			||||||
 | 
					  that is zero is considered false, and any non-zero value is considered true.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Operators exist for converting between data types (see Operators below). A
 | 
				
			||||||
 | 
					  Go To expression will only be valid if its final data type is signed word or
 | 
				
			||||||
 | 
					  unsigned word.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  The following symbols may be used for accessing information about the current
 | 
				
			||||||
 | 
					  instruction being executed:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<table class="indent">
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono narrow">address</td>
 | 
				
			||||||
 | 
					    <td>Current memory access's address.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">break</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      Identifies what type of break scenario is being considered. See below for
 | 
				
			||||||
 | 
					      a list of identifiers.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">code</td>
 | 
				
			||||||
 | 
					    <td>Current exception's exception code.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">cond</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      Condition code for <code>Bcond</code> and <code>SETF</code>
 | 
				
			||||||
 | 
					      instructions. See below for a list of conditions.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">disp</td>
 | 
				
			||||||
 | 
					    <td>Displacement offset for jumps and memory accesses.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">fetch</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      Data unit index during a fetch operation, or <code>-1</code> if the read
 | 
				
			||||||
 | 
					      operation is not a fetch.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">format</td>
 | 
				
			||||||
 | 
					    <td>Current instruction's encoding format.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">id</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      Identifies which specific instruction is being executed, considering
 | 
				
			||||||
 | 
					      <code>opcode</code> and, where applicable, <code>subopcode</code>. See
 | 
				
			||||||
 | 
					      below for a list of identifiers.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">imm</td>
 | 
				
			||||||
 | 
					    <td>Immediate operand.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">opcode</td>
 | 
				
			||||||
 | 
					    <td>Current instruction's top-level opcode.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">reg1</td>
 | 
				
			||||||
 | 
					    <td>Source register index.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">reg2</td>
 | 
				
			||||||
 | 
					    <td>Destination register index.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">regid</td>
 | 
				
			||||||
 | 
					    <td>
 | 
				
			||||||
 | 
					      System register index in <code>LDSR</code> and <code>STSR</code>
 | 
				
			||||||
 | 
					      instructions.
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">size</td>
 | 
				
			||||||
 | 
					    <td>Number of bytes occupied by the current instruction.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">subopcode</td>
 | 
				
			||||||
 | 
					    <td>Current instruction's secondary opcode.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">type</td>
 | 
				
			||||||
 | 
					    <td>Data type of the current memory access.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">value</td>
 | 
				
			||||||
 | 
					    <td>Value read by the current memory access.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">vector</td>
 | 
				
			||||||
 | 
					    <td>Vector for <code>TRAP</code> instructions.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  The following symbols may be used in conjunction with the <code>break</code>
 | 
				
			||||||
 | 
					  symbol:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<div class="indent mono" style="column-width: 75px;">
 | 
				
			||||||
 | 
					  <div>exception</div><div>execute</div><div>read</div><div>write</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  The following symbols may be used in conjunction with the <code>cond</code>
 | 
				
			||||||
 | 
					  symbol:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<div class="indent mono" style="column-width: 75px;">
 | 
				
			||||||
 | 
					  <div>c </div><div>e </div><div>f </div><div>ge</div><div>gt</div>
 | 
				
			||||||
 | 
					  <div>h </div><div>l </div><div>le</div><div>lt</div><div>n </div>
 | 
				
			||||||
 | 
					  <div>nc</div><div>ne</div><div>nh</div><div>nl</div><div>nv</div>
 | 
				
			||||||
 | 
					  <div>nz</div><div>p </div><div>t </div><div>v </div><div>z </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  The following symbols may be used in conjunction with the <code>id</code>
 | 
				
			||||||
 | 
					  symbol:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<div class="indent mono" style="column-width: 75px;">
 | 
				
			||||||
 | 
					  <div>illegal</div><div>add_imm</div><div>add_reg</div><div>addf.s </div>
 | 
				
			||||||
 | 
					  <div>addi   </div><div>and    </div><div>andbsu </div><div>andi   </div>
 | 
				
			||||||
 | 
					  <div>andnbsu</div><div>bcond  </div><div>caxi   </div><div>cli    </div>
 | 
				
			||||||
 | 
					  <div>cmp_imm</div><div>cmp_reg</div><div>cmpf.s </div><div>cvt.sw </div>
 | 
				
			||||||
 | 
					  <div>cvt.ws </div><div>div    </div><div>divf.s </div><div>divu   </div>
 | 
				
			||||||
 | 
					  <div>halt   </div><div>in.b   </div><div>in.h   </div><div>in.w   </div>
 | 
				
			||||||
 | 
					  <div>jal    </div><div>jmp    </div><div>jr     </div><div>ld.b   </div>
 | 
				
			||||||
 | 
					  <div>ld.h   </div><div>ld.w   </div><div>ldsr   </div><div>mov_imm</div>
 | 
				
			||||||
 | 
					  <div>mov_reg</div><div>movbsu </div><div>movea  </div><div>movhi  </div>
 | 
				
			||||||
 | 
					  <div>mpyhw  </div><div>mul    </div><div>mulf.s </div><div>mulu   </div>
 | 
				
			||||||
 | 
					  <div>not    </div><div>notbsu </div><div>or     </div><div>orbsu  </div>
 | 
				
			||||||
 | 
					  <div>ori    </div><div>ornbsu </div><div>out.b  </div><div>out.h  </div>
 | 
				
			||||||
 | 
					  <div>out.w  </div><div>reti   </div><div>rev    </div><div>sar_imm</div>
 | 
				
			||||||
 | 
					  <div>sar_reg</div><div>sch0bsd</div><div>sch0bsu</div><div>sch1bsd</div>
 | 
				
			||||||
 | 
					  <div>sch1bsu</div><div>sei    </div><div>setf   </div><div>shl_imm</div>
 | 
				
			||||||
 | 
					  <div>shl_reg</div><div>shr_imm</div><div>shr_reg</div><div>st.b   </div>
 | 
				
			||||||
 | 
					  <div>st.h   </div><div>st.w   </div><div>stsr   </div><div>sub    </div>
 | 
				
			||||||
 | 
					  <div>subf.s </div><div>trap   </div><div>trnc.sw</div><div>xb     </div>
 | 
				
			||||||
 | 
					  <div>xh     </div><div>xor    </div><div>xorbsu </div><div>xori   </div>
 | 
				
			||||||
 | 
					  <div>xornbsu</div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  The following symbols may be used to retrieve the contents of a CPU program
 | 
				
			||||||
 | 
					  register:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<div class="indent mono" style="column-width: 75px;">
 | 
				
			||||||
 | 
					  <div>r0 </div><div>r1 </div><div>r2 </div><div>r3 </div><div>r4 </div>
 | 
				
			||||||
 | 
					  <div>r5 </div><div>r6 </div><div>r7 </div><div>r8 </div><div>r9 </div>
 | 
				
			||||||
 | 
					  <div>r10</div><div>r11</div><div>r12</div><div>r13</div><div>r14</div>
 | 
				
			||||||
 | 
					  <div>r15</div><div>r16</div><div>r17</div><div>r18</div><div>r19</div>
 | 
				
			||||||
 | 
					  <div>r20</div><div>r21</div><div>r22</div><div>r23</div><div>r24</div>
 | 
				
			||||||
 | 
					  <div>r25</div><div>r26</div><div>r27</div><div>r28</div><div>r29</div>
 | 
				
			||||||
 | 
					  <div>r30</div><div>r31</div><div>gp </div><div>hp </div><div>lp </div>
 | 
				
			||||||
 | 
					  <div>sp </div><div>tp </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  The following symbols may be used to retrieve the contents of a CPU system
 | 
				
			||||||
 | 
					  register:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<div class="indent mono" style="column-width: 75px;">
 | 
				
			||||||
 | 
					  <div>adtre</div><div>chcw </div><div>ecr  </div><div>eipc</div>
 | 
				
			||||||
 | 
					  <div>eipsw</div><div>fepc </div><div>fepsw</div><div>pc  </div>
 | 
				
			||||||
 | 
					  <div>pir  </div><div>psw  </div><div>tkcw </div><div>sr29</div>
 | 
				
			||||||
 | 
					  <div>sr30 </div><div>sr31 </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h2>Operators</h2>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Operators may apply to one (unary) or two (binary) values. All unary
 | 
				
			||||||
 | 
					  operators appear to the left of the value they modify (or another unary
 | 
				
			||||||
 | 
					  operator). Binary operators appear between the values they modify. Each
 | 
				
			||||||
 | 
					  operator considers the types of its operands in order to produce a new value
 | 
				
			||||||
 | 
					  of the appropriate type.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  If the operands of a binary operator have different types, one of the values
 | 
				
			||||||
 | 
					  will be converted to the other type before performing the operation. The
 | 
				
			||||||
 | 
					  conversion depends on the "greater" of the two types, in the following order
 | 
				
			||||||
 | 
					  (higher is "greater"):
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<table class="indent">
 | 
				
			||||||
 | 
					  <tr><td class="center narrow">↑</td><td>Float</td></tr>
 | 
				
			||||||
 | 
					  <tr><td class="center"></td><td>Unsigned word</td></tr>
 | 
				
			||||||
 | 
					  <tr><td class="center"></td><td>Signed word</td></tr>
 | 
				
			||||||
 | 
					  <tr><td class="center">↓</td><td>Boolean</td></tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  For example, if an operation contains both a signed word and a float, the
 | 
				
			||||||
 | 
					  signed word value is first converted to float.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Operators have assigned precedence that specifies the order of operations.
 | 
				
			||||||
 | 
					  For example, in the expression <code>1 + 2 * 3</code>, the multiplication
 | 
				
			||||||
 | 
					  happens before the addition because it has higher precedence. Parentheses
 | 
				
			||||||
 | 
					  <code>()</code> may be used to encapsulate operations and guarantee that they
 | 
				
			||||||
 | 
					  are evaluated first regardless of the relative precedence of the adjacent
 | 
				
			||||||
 | 
					  operators. For example, in the expression <code>(1 + 2) * 3</code>, the
 | 
				
			||||||
 | 
					  addition happens before the multiplication because it is enclosed in
 | 
				
			||||||
 | 
					  parentheses.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  The following operators may be used in expressions. Groups listed higher have
 | 
				
			||||||
 | 
					  higher precedence and happen before groups listed lower. Operators within
 | 
				
			||||||
 | 
					  groups have the same precedence and are processed in the order they appear in
 | 
				
			||||||
 | 
					  the expression from left to right.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<table class="indent bordered">
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">~</td>
 | 
				
			||||||
 | 
					    <td class="open">Not Bitwise</td>
 | 
				
			||||||
 | 
					    <td class="open">Cannot be used with a float value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">!</td>
 | 
				
			||||||
 | 
					    <td class="open">Not Logical</td>
 | 
				
			||||||
 | 
					    <td class="open">Always produces a boolean.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">-</td>
 | 
				
			||||||
 | 
					    <td class="open">Negate</td>
 | 
				
			||||||
 | 
					    <td class="open">Cannot be used with an unsigned word value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">bool</td>
 | 
				
			||||||
 | 
					    <td class="open">Cast to Boolean</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">ceil</td>
 | 
				
			||||||
 | 
					    <td class="open">Round Up</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">float</td>
 | 
				
			||||||
 | 
					    <td class="open">Cast to Float</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">floor</td>
 | 
				
			||||||
 | 
					    <td class="open">Round Down</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">round</td>
 | 
				
			||||||
 | 
					    <td class="open">Round to Nearest</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="open"><code>s8</code>, <code>byte</code></td>
 | 
				
			||||||
 | 
					    <td class="open">Cast to Signed Byte</td>
 | 
				
			||||||
 | 
					    <td class="open">Result is of type signed word.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="open"><code>s16</code>, <code>halfword</code></td>
 | 
				
			||||||
 | 
					    <td class="open">Cast to Signed Halfword</td>
 | 
				
			||||||
 | 
					    <td class="open">Result is of type signed word.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="open"><code>s32</code>, <code>word</code></td>
 | 
				
			||||||
 | 
					    <td class="open">Cast to Signed Word</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">trunc</td>
 | 
				
			||||||
 | 
					    <td class="open">Truncate</td>
 | 
				
			||||||
 | 
					    <td class="open">Removes any fraction.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="open"><code><code>u8</code>, ubyte</code></td>
 | 
				
			||||||
 | 
					    <td class="open">Cast to Unsigned Byte</td>
 | 
				
			||||||
 | 
					    <td class="open">Result is of type unsigned word.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="open"><code>u16</code>, <code>uhalfword</code></td>
 | 
				
			||||||
 | 
					    <td class="open">Cast to Unsigned Halfword</td>
 | 
				
			||||||
 | 
					    <td class="open">Result is of type unsigned word.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="open"><code>u32</code>, <code>uword</code></td>
 | 
				
			||||||
 | 
					    <td class="open">Cast to Unsigned Word</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">xfloat</td>
 | 
				
			||||||
 | 
					    <td class="open">Reinterpret as Float</td>
 | 
				
			||||||
 | 
					    <td class="open">The binary value is not modified.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="open"><code>xs32</code>, <code>xword</code></td>
 | 
				
			||||||
 | 
					    <td class="open">Reinterpret as Signed Word</td>
 | 
				
			||||||
 | 
					    <td class="open">The binary value is not modified.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td><code>xu32</code>, <code>xuword</code></td>
 | 
				
			||||||
 | 
					    <td>Reinterpret as Unsgned Word</td>
 | 
				
			||||||
 | 
					    <td>The binary value is not modified.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">/</td>
 | 
				
			||||||
 | 
					    <td class="open">Divide</td>
 | 
				
			||||||
 | 
					    <td class="open">Zero divisor yields zero as result.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">*</td>
 | 
				
			||||||
 | 
					    <td class="open">Multiply</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">%</td>
 | 
				
			||||||
 | 
					    <td>Remainder</td>
 | 
				
			||||||
 | 
					    <td>Zero divisor yields zero as result.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">+</td>
 | 
				
			||||||
 | 
					    <td class="open">Add</td>
 | 
				
			||||||
 | 
					    <td class="open"></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">-</td>
 | 
				
			||||||
 | 
					    <td>Subtract</td>
 | 
				
			||||||
 | 
					    <td></td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open"><<</td>
 | 
				
			||||||
 | 
					    <td class="open">Shift Left</td>
 | 
				
			||||||
 | 
					    <td class="open">Cannot be used with a float value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">>></td>
 | 
				
			||||||
 | 
					    <td class="open">Shift Right Arithmetic</td>
 | 
				
			||||||
 | 
					    <td class="open">Cannot be used with a float value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">>>></td>
 | 
				
			||||||
 | 
					    <td>Shift Right Logical</td>
 | 
				
			||||||
 | 
					    <td>Cannot be used with a float value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">></td>
 | 
				
			||||||
 | 
					    <td class="open">Greater</td>
 | 
				
			||||||
 | 
					    <td class="open">Always produces a boolean.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">>=</td>
 | 
				
			||||||
 | 
					    <td class="open">Greater or Equal</td>
 | 
				
			||||||
 | 
					    <td class="open">Always produces a boolean.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open"><</td>
 | 
				
			||||||
 | 
					    <td class="open">Less</td>
 | 
				
			||||||
 | 
					    <td class="open">Always produces a boolean.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono"><=</td>
 | 
				
			||||||
 | 
					    <td>Less or Equal</td>
 | 
				
			||||||
 | 
					    <td>Always produces a boolean.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono open">==</td>
 | 
				
			||||||
 | 
					    <td class="open">Equal</td>
 | 
				
			||||||
 | 
					    <td class="open">Always produces a boolean.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">!=</td>
 | 
				
			||||||
 | 
					    <td>Not Equal</td>
 | 
				
			||||||
 | 
					    <td>Always produces a boolean.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">&</td>
 | 
				
			||||||
 | 
					    <td>And Bitwise</td>
 | 
				
			||||||
 | 
					    <td>Cannot be used with a float value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">^</td>
 | 
				
			||||||
 | 
					    <td>Exclusive Or Bitwise</td>
 | 
				
			||||||
 | 
					    <td>Cannot be used with a float value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">|</td>
 | 
				
			||||||
 | 
					    <td>Or Bitwise</td>
 | 
				
			||||||
 | 
					    <td>Cannot be used with a float value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">&&</td>
 | 
				
			||||||
 | 
					    <td>And Logical</td>
 | 
				
			||||||
 | 
					    <td>If left is true, returns right; else returns left.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">^^</td>
 | 
				
			||||||
 | 
					    <td>Exclusive Or Logical</td>
 | 
				
			||||||
 | 
					    <td>If only one operand is true, returns the truthy value.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="mono">||</td>
 | 
				
			||||||
 | 
					    <td>Or Logical</td>
 | 
				
			||||||
 | 
					    <td>If left is true, returns left; else returns right.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h2>Memory Read</h2>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  A value can be read from the memory bus of the emulation state. This is done
 | 
				
			||||||
 | 
					  by enclosing the part of the expression that represents the address in square
 | 
				
			||||||
 | 
					  brackets <code>[]</code>. This functions in an identical manner to
 | 
				
			||||||
 | 
					  parentheses <code>()</code>, but will additionally perform the read
 | 
				
			||||||
 | 
					  operation.
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					  Under most circumstances, a signed word read is performed. Certain operators
 | 
				
			||||||
 | 
					  can be placed in front of the group to alter how the read is performed:
 | 
				
			||||||
 | 
					</p>
 | 
				
			||||||
 | 
					<table class="indent">
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="narrow nowrap">• <code>float</code></td>
 | 
				
			||||||
 | 
					    <td>Behaves like <code>xfloat</code> instead.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="nowrap">• <code>s8</code>, <code>u8</code></td>
 | 
				
			||||||
 | 
					    <td>Performs a byte read of the specified signedness.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr>
 | 
				
			||||||
 | 
					    <td class="nowrap">• <code>s16</code>, <code>u16</code></td>
 | 
				
			||||||
 | 
					    <td>Performs a halfword read of the specified signedness.</td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										192
									
								
								src/core/cpu.c
								
								
								
								
							
							
						
						
									
										192
									
								
								src/core/cpu.c
								
								
								
								
							| 
						 | 
					@ -116,7 +116,7 @@ static vbool cpuFloatReserved(Vue *vue, vbool left) {
 | 
				
			||||||
        )) continue;
 | 
					        )) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* The value is a reserved operand */
 | 
					        /* The value is a reserved operand */
 | 
				
			||||||
        vue->cpu.exception.code = 0xFF60;
 | 
					        vue->cpu.exception = 0xFF60;
 | 
				
			||||||
        vue->cpu.psw_fro   = 1;
 | 
					        vue->cpu.psw_fro   = 1;
 | 
				
			||||||
        return VUE_TRUE;
 | 
					        return VUE_TRUE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -150,7 +150,7 @@ static void cpuFloatConvert(Vue *vue, vbool round) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Invalid operation (word overflow) */
 | 
					    /* Invalid operation (word overflow) */
 | 
				
			||||||
    else if (bits >= 8) {
 | 
					    else if (bits >= 8) {
 | 
				
			||||||
        vue->cpu.exception.code = 0xFF70;
 | 
					        vue->cpu.exception = 0xFF70;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,7 +193,7 @@ static void cpuFloatResult(Vue *vue, vbool compare, double full) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Overflow */
 | 
					    /* Overflow */
 | 
				
			||||||
    if (full > result || full < -result) {
 | 
					    if (full > result || full < -result) {
 | 
				
			||||||
        vue->cpu.exception.code = 0xFF64;
 | 
					        vue->cpu.exception = 0xFF64;
 | 
				
			||||||
        vue->cpu.psw_fov   = 1;
 | 
					        vue->cpu.psw_fov   = 1;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -578,7 +578,7 @@ static void cpuDIV(Vue *vue) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Zero division */
 | 
					    /* Zero division */
 | 
				
			||||||
    if (right == 0) {
 | 
					    if (right == 0) {
 | 
				
			||||||
        vue->cpu.exception.code = 0xFF80;
 | 
					        vue->cpu.exception = 0xFF80;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -612,7 +612,7 @@ static void cpuDIVF_S(Vue *vue) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* An exception has occurred */
 | 
					    /* An exception has occurred */
 | 
				
			||||||
    if (!right) {
 | 
					    if (!right) {
 | 
				
			||||||
        vue->cpu.exception.code = left ? 0xFF68 : 0xFF70;
 | 
					        vue->cpu.exception = left ? 0xFF68 : 0xFF70;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -628,7 +628,7 @@ static void cpuDIVU(Vue *vue) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Zero division */
 | 
					    /* Zero division */
 | 
				
			||||||
    if (right == 0) {
 | 
					    if (right == 0) {
 | 
				
			||||||
        vue->cpu.exception.code = 0xFF80;
 | 
					        vue->cpu.exception = 0xFF80;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -848,7 +848,7 @@ static void cpuREV(Vue *vue) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Trap */
 | 
					/* Trap */
 | 
				
			||||||
#define cpuTRAP(vue) \
 | 
					#define cpuTRAP(vue) \
 | 
				
			||||||
    vue->cpu.exception.code = 0xFFA0 | (vue->cpu.inst.imm & 15), \
 | 
					    vue->cpu.exception = 0xFFA0 | (vue->cpu.inst.imm & 15), \
 | 
				
			||||||
    vue->cpu.pc += 2
 | 
					    vue->cpu.pc += 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Truncate Short Floating to Word */
 | 
					/* Truncate Short Floating to Word */
 | 
				
			||||||
| 
						 | 
					@ -908,8 +908,12 @@ static void cpuDecode(VueInstruction *inst) {
 | 
				
			||||||
            x = inst->bits >> 16 & 31;
 | 
					            x = inst->bits >> 16 & 31;
 | 
				
			||||||
            inst->reg2 = inst->bits >> 21 & 31;
 | 
					            inst->reg2 = inst->bits >> 21 & 31;
 | 
				
			||||||
            inst->imm  = extend < 0 ? SIGN_EXTEND(5, x) : x;
 | 
					            inst->imm  = extend < 0 ? SIGN_EXTEND(5, x) : x;
 | 
				
			||||||
            if (inst->id == BITSTRING)
 | 
					            if (inst->id == BITSTRING) {
 | 
				
			||||||
                inst->id = x >= 16 ? VUE_ILLEGAL : LOOKUP_BITSTRING[x];
 | 
					                inst->id = x >= 16 ? VUE_ILLEGAL : LOOKUP_BITSTRING[x];
 | 
				
			||||||
 | 
					                inst->subopcode = x;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (inst->id == VUE_SETF)
 | 
				
			||||||
 | 
					                inst->cond = x & 15;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case 3:
 | 
					        case 3:
 | 
				
			||||||
            x = inst->bits >> 16 & 0x1FF;
 | 
					            x = inst->bits >> 16 & 0x1FF;
 | 
				
			||||||
| 
						 | 
					@ -944,21 +948,84 @@ static void cpuDecode(VueInstruction *inst) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Operations for exception stage */
 | 
				
			||||||
 | 
					static vbool cpuException(Vue *vue) {
 | 
				
			||||||
 | 
					    vbool   isIRQ; /* The exception is an interrupt */
 | 
				
			||||||
 | 
					    int32_t psw;   /* Current value of PSW */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Application callback */
 | 
				
			||||||
 | 
					    if (vue->onException != NULL) {
 | 
				
			||||||
 | 
					        vue->breakCode = vue->onException(vue, vue->cpu.exception);
 | 
				
			||||||
 | 
					        if (vue->breakCode != 0)
 | 
				
			||||||
 | 
					            return VUE_TRUE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Configure working variables */
 | 
				
			||||||
 | 
					    vue->cpu.exception &= 0xFFFF;
 | 
				
			||||||
 | 
					    isIRQ = (vue->cpu.exception & 0xFF00) == 0xFE00;
 | 
				
			||||||
 | 
					    psw   = cpuGetSystemRegister(vue, VUE_PSW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Fatal exception */
 | 
				
			||||||
 | 
					    if (vue->cpu.psw_np != 0) {
 | 
				
			||||||
 | 
					        vueWrite(vue, 0x00000000, VUE_S32, 0xFFFF0000 | vue->cpu.exception);
 | 
				
			||||||
 | 
					        vueWrite(vue, 0x00000004, VUE_S32, psw);
 | 
				
			||||||
 | 
					        vueWrite(vue, 0x00000008, VUE_S32, vue->cpu.pc);
 | 
				
			||||||
 | 
					        vue->cpu.stage = CPU_FATAL;
 | 
				
			||||||
 | 
					        return VUE_TRUE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Duplexed exception */
 | 
				
			||||||
 | 
					    if (vue->cpu.psw_ep != 0) {
 | 
				
			||||||
 | 
					        vue->cpu.ecr_fecc = vue->cpu.exception;
 | 
				
			||||||
 | 
					        vue->cpu.fepc     = vue->cpu.pc;
 | 
				
			||||||
 | 
					        vue->cpu.fepsw    = psw;
 | 
				
			||||||
 | 
					        vue->cpu.psw_np   = 1;
 | 
				
			||||||
 | 
					        vue->cpu.pc       = 0xFFFFFFD0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Regular exception */
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        vue->cpu.ecr_eicc = vue->cpu.exception;
 | 
				
			||||||
 | 
					        vue->cpu.eipc     = vue->cpu.pc;
 | 
				
			||||||
 | 
					        vue->cpu.eipsw    = psw;
 | 
				
			||||||
 | 
					        vue->cpu.psw_ep   = 1;
 | 
				
			||||||
 | 
					        vue->cpu.pc       = 0xFFFF0000 | (vue->cpu.exception & 0xFFF0);
 | 
				
			||||||
 | 
					        if (vue->cpu.pc == (int32_t) 0xFFFFFF70) /* FIV */
 | 
				
			||||||
 | 
					            vue->cpu.pc = 0xFFFFFF60;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Interrupt */
 | 
				
			||||||
 | 
					    if (isIRQ) {
 | 
				
			||||||
 | 
					        psw = vue->cpu.exception >> 4 & 15;
 | 
				
			||||||
 | 
					        vue->cpu.psw_i = psw < 15 ? psw : 15;
 | 
				
			||||||
 | 
					        if (vue->cpu.stage == CPU_HALT)
 | 
				
			||||||
 | 
					            vue->cpu.pc += 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Common processing */
 | 
				
			||||||
 | 
					    vue->cpu.cycles    = 0; /* TODO: Determine the actual number */
 | 
				
			||||||
 | 
					    vue->cpu.exception = 0;
 | 
				
			||||||
 | 
					    vue->cpu.psw_ae    = 0;
 | 
				
			||||||
 | 
					    vue->cpu.psw_id    = 1;
 | 
				
			||||||
 | 
					    vue->cpu.stage     = CPU_FETCH;
 | 
				
			||||||
 | 
					    return VUE_FALSE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Check for an exception or interrupt */
 | 
					/* Check for an exception or interrupt */
 | 
				
			||||||
static vbool cpuTestException(Vue *vue) {
 | 
					static vbool cpuTestException(Vue *vue) {
 | 
				
			||||||
    int32_t level; /* Interrupt level */
 | 
					    int32_t level; /* Interrupt level */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Check for an interrupt */
 | 
					    /* Check for an interrupt */
 | 
				
			||||||
    if (vue->cpu.irq != 0 && (vue->cpu.exception.code |
 | 
					    if (vue->cpu.irq != 0 && (vue->cpu.exception |
 | 
				
			||||||
        vue->cpu.psw_id | vue->cpu.psw_ep | vue->cpu.psw_np) == 0) {
 | 
					        vue->cpu.psw_id | vue->cpu.psw_ep | vue->cpu.psw_np) == 0) {
 | 
				
			||||||
        for (level = 4; level >= 0; level--)
 | 
					        for (level = 4; level >= 0; level--)
 | 
				
			||||||
            if ((vue->cpu.irq >> level & 1) != 0)
 | 
					            if ((vue->cpu.irq >> level & 1) != 0)
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        vue->cpu.exception.code = 0xFE00 | level << 4;
 | 
					        vue->cpu.exception = 0xFE00 | level << 4;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* There is no exception */
 | 
					    /* There is no exception */
 | 
				
			||||||
    if (vue->cpu.exception.code == 0) /* No further processing */
 | 
					    if (vue->cpu.exception == 0) /* No further processing */
 | 
				
			||||||
        return vue->cpu.stage == CPU_HALT && vue->cpu.cycles == 0;
 | 
					        return vue->cpu.stage == CPU_HALT && vue->cpu.cycles == 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* An exception has occurred */
 | 
					    /* An exception has occurred */
 | 
				
			||||||
| 
						 | 
					@ -975,8 +1042,6 @@ static vbool cpuExecute(Vue *vue) {
 | 
				
			||||||
        vue->breakCode = vue->onExecute(vue, &vue->cpu.inst);
 | 
					        vue->breakCode = vue->onExecute(vue, &vue->cpu.inst);
 | 
				
			||||||
        if (vue->breakCode != 0)
 | 
					        if (vue->breakCode != 0)
 | 
				
			||||||
            return VUE_TRUE;
 | 
					            return VUE_TRUE;
 | 
				
			||||||
        vue->cpu.inst.reg1 &= 31;
 | 
					 | 
				
			||||||
        vue->cpu.inst.reg2 &= 31;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Processing by instruction ID */
 | 
					    /* Processing by instruction ID */
 | 
				
			||||||
| 
						 | 
					@ -1058,11 +1123,11 @@ static vbool cpuExecute(Vue *vue) {
 | 
				
			||||||
        case VUE_XORI   : cpuXORI   (vue); break;
 | 
					        case VUE_XORI   : cpuXORI   (vue); break;
 | 
				
			||||||
        /*case VUE_XORNBSU: cpuXORNBSU(vue); break;*/
 | 
					        /*case VUE_XORNBSU: cpuXORNBSU(vue); break;*/
 | 
				
			||||||
        default: /* Invalid instruction */
 | 
					        default: /* Invalid instruction */
 | 
				
			||||||
            vue->cpu.exception.code = 0xFF90;
 | 
					            vue->cpu.exception = 0xFF90;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Common processing */
 | 
					    /* Common processing */
 | 
				
			||||||
    if (vue->cpu.exception.code == 0) {
 | 
					    if (vue->cpu.exception == 0) {
 | 
				
			||||||
        vue->cpu.cycles += CYCLES[vue->cpu.inst.id];
 | 
					        vue->cpu.cycles += CYCLES[vue->cpu.inst.id];
 | 
				
			||||||
        vue->cpu.pc     += vue->cpu.inst.size;
 | 
					        vue->cpu.pc     += vue->cpu.inst.size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1082,10 +1147,15 @@ static int32_t cpuSize(int32_t opcode) {
 | 
				
			||||||
/* Operations for fetch stage */
 | 
					/* Operations for fetch stage */
 | 
				
			||||||
static vbool cpuFetch(Vue *vue) {
 | 
					static vbool cpuFetch(Vue *vue) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Entering the fetch stage */
 | 
				
			||||||
 | 
					    if (vue->cpu.fetch == -1)
 | 
				
			||||||
 | 
					        vue->cpu.fetch = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Read the bits from the bus */
 | 
					    /* Read the bits from the bus */
 | 
				
			||||||
    if (cpuRead(vue, vue->cpu.pc + (vue->cpu.fetch << 1),
 | 
					    if (cpuRead(vue, vue->cpu.pc + (vue->cpu.fetch << 1),
 | 
				
			||||||
        VUE_U16, vue->cpu.fetch))
 | 
					        VUE_U16, vue->cpu.fetch))
 | 
				
			||||||
        return VUE_TRUE;
 | 
					        return VUE_TRUE;
 | 
				
			||||||
 | 
					    /* TODO: Determine how many cycles this takes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* First unit */
 | 
					    /* First unit */
 | 
				
			||||||
    if (vue->cpu.fetch == 0) {
 | 
					    if (vue->cpu.fetch == 0) {
 | 
				
			||||||
| 
						 | 
					@ -1099,7 +1169,7 @@ static vbool cpuFetch(Vue *vue) {
 | 
				
			||||||
    /* Second unit */
 | 
					    /* Second unit */
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
        vue->cpu.inst.bits |= vue->cpu.access.value & 0xFFFF;
 | 
					        vue->cpu.inst.bits |= vue->cpu.access.value & 0xFFFF;
 | 
				
			||||||
        vue->cpu.fetch = 0;
 | 
					        vue->cpu.fetch      = -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Decode the instruction and advance to execute stage */
 | 
					    /* Decode the instruction and advance to execute stage */
 | 
				
			||||||
| 
						 | 
					@ -1108,94 +1178,30 @@ static vbool cpuFetch(Vue *vue) {
 | 
				
			||||||
    return VUE_FALSE;
 | 
					    return VUE_FALSE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Operations for exception stage */
 | 
					 | 
				
			||||||
static vbool cpuException(Vue *vue) {
 | 
					 | 
				
			||||||
    vbool   isIRQ; /* The exception is an interrupt */
 | 
					 | 
				
			||||||
    int32_t psw;   /* Current value of PSW */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Application callback */
 | 
					 | 
				
			||||||
    if (vue->onException != NULL) {
 | 
					 | 
				
			||||||
        vue->breakCode = vue->onException(vue, &vue->cpu.exception);
 | 
					 | 
				
			||||||
        if (vue->breakCode != 0)
 | 
					 | 
				
			||||||
            return VUE_TRUE;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Configure working variables */
 | 
					 | 
				
			||||||
    vue->cpu.exception.code &= 0xFFFF;
 | 
					 | 
				
			||||||
    isIRQ = (vue->cpu.exception.code & 0xFF00) == 0xFE00;
 | 
					 | 
				
			||||||
    psw   = cpuGetSystemRegister(vue, VUE_PSW);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Fatal exception */
 | 
					 | 
				
			||||||
    if (vue->cpu.psw_np != 0) {
 | 
					 | 
				
			||||||
        vueWrite(vue, 0x00000000, VUE_S32, 0xFFFF0000|vue->cpu.exception.code);
 | 
					 | 
				
			||||||
        vueWrite(vue, 0x00000004, VUE_S32, psw);
 | 
					 | 
				
			||||||
        vueWrite(vue, 0x00000008, VUE_S32, vue->cpu.pc);
 | 
					 | 
				
			||||||
        vue->cpu.stage = CPU_FATAL;
 | 
					 | 
				
			||||||
        return VUE_TRUE;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Duplexed exception */
 | 
					 | 
				
			||||||
    if (vue->cpu.psw_ep != 0) {
 | 
					 | 
				
			||||||
        vue->cpu.ecr_fecc = vue->cpu.exception.code;
 | 
					 | 
				
			||||||
        vue->cpu.fepc     = vue->cpu.pc;
 | 
					 | 
				
			||||||
        vue->cpu.fepsw    = psw;
 | 
					 | 
				
			||||||
        vue->cpu.psw_np   = 1;
 | 
					 | 
				
			||||||
        vue->cpu.pc       = 0xFFFFFFD0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Regular exception */
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
        vue->cpu.ecr_eicc = vue->cpu.exception.code;
 | 
					 | 
				
			||||||
        vue->cpu.eipc     = vue->cpu.pc;
 | 
					 | 
				
			||||||
        vue->cpu.eipsw    = psw;
 | 
					 | 
				
			||||||
        vue->cpu.psw_ep   = 1;
 | 
					 | 
				
			||||||
        vue->cpu.pc       = 0xFFFF0000 | (vue->cpu.exception.code & 0xFFF0);
 | 
					 | 
				
			||||||
        if (vue->cpu.pc == (int32_t) 0xFFFFFF70) /* FIV */
 | 
					 | 
				
			||||||
            vue->cpu.pc = 0xFFFFFF60;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Interrupt */
 | 
					 | 
				
			||||||
    if (isIRQ) {
 | 
					 | 
				
			||||||
        psw = vue->cpu.exception.code >> 4 & 15;
 | 
					 | 
				
			||||||
        vue->cpu.psw_i = psw < 15 ? psw : 15;
 | 
					 | 
				
			||||||
        if (vue->cpu.stage == CPU_HALT)
 | 
					 | 
				
			||||||
            vue->cpu.pc += 2;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Common processing */
 | 
					 | 
				
			||||||
    vue->cpu.cycles         = 0; /* TODO: Determine the actual number */
 | 
					 | 
				
			||||||
    vue->cpu.exception.code = 0;
 | 
					 | 
				
			||||||
    vue->cpu.psw_ae         = 0;
 | 
					 | 
				
			||||||
    vue->cpu.psw_id         = 1;
 | 
					 | 
				
			||||||
    vue->cpu.stage          = CPU_FETCH;
 | 
					 | 
				
			||||||
    return VUE_FALSE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Process the simulation */
 | 
					/* Process the simulation */
 | 
				
			||||||
static void cpuEmulate(Vue *vue, int32_t cycles) {
 | 
					static void cpuEmulate(Vue *vue, uint32_t cycles) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* The CPU is halting */
 | 
					    /* The CPU is in fatal halt status */
 | 
				
			||||||
    if (vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT)
 | 
					    if (vue->cpu.stage == CPU_FATAL)
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vue->cpu.cycles = 0; /* DEBUG: Stop processing after execute */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Process for the given number of cycles */
 | 
					    /* Process for the given number of cycles */
 | 
				
			||||||
    for (;;) {
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* The next event occurs after the given number of cycles */
 | 
					        /* The next stage occurs after the given number of cycles */
 | 
				
			||||||
        if (vue->cpu.cycles > cycles) {
 | 
					        if (vue->cpu.cycles > cycles) {
 | 
				
			||||||
            vue->cpu.cycles -= cycles;
 | 
					            vue->cpu.cycles -= cycles;
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Processing by stage */
 | 
					        /* Processing by stage */
 | 
				
			||||||
 | 
					        cycles         -= vue->cpu.cycles;
 | 
				
			||||||
        vue->cpu.cycles = 0;
 | 
					        vue->cpu.cycles = 0;
 | 
				
			||||||
        switch (vue->cpu.stage) {
 | 
					        switch (vue->cpu.stage) {
 | 
				
			||||||
            case CPU_EXCEPTION: if (cpuException(vue)) return; break;
 | 
					            case CPU_EXCEPTION: if (cpuException(vue)) return; break;
 | 
				
			||||||
            case CPU_EXECUTE  : if (cpuExecute  (vue)) return; break;
 | 
					            case CPU_EXECUTE  : if (cpuExecute  (vue)) return; break;
 | 
				
			||||||
            case CPU_FETCH    : if (cpuFetch    (vue)) return; break;
 | 
					            case CPU_FETCH    : if (cpuFetch    (vue)) return; break;
 | 
				
			||||||
            case CPU_HALT     : if (cpuTestException(vue)) return; break;
 | 
					            case CPU_HALT     : cpuTestException(vue); return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1208,8 +1214,8 @@ static void cpuReset(Vue *vue) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Configure instance fields */
 | 
					    /* Configure instance fields */
 | 
				
			||||||
    vue->cpu.cycles    =  0;
 | 
					    vue->cpu.cycles    =  0;
 | 
				
			||||||
    vue->cpu.exception.code = 0;
 | 
					    vue->cpu.exception =  0;
 | 
				
			||||||
    vue->cpu.fetch          = 0;
 | 
					    vue->cpu.fetch     = -1;
 | 
				
			||||||
    vue->cpu.irq       =  0;
 | 
					    vue->cpu.irq       =  0;
 | 
				
			||||||
    vue->cpu.stage     = CPU_FETCH;
 | 
					    vue->cpu.stage     = CPU_FETCH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1229,12 +1235,10 @@ static void cpuReset(Vue *vue) {
 | 
				
			||||||
    vue->cpu.psw_np   = 1;
 | 
					    vue->cpu.psw_np   = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Determine the number of CPU cycles until something can happen */
 | 
					/* Determine the number of CPU cycles until a breakpoint could trigger */
 | 
				
			||||||
static int32_t cpuUntil(Vue *vue, int32_t cycles) {
 | 
					static uint32_t cpuUntil(Vue *vue, uint32_t cycles) {
 | 
				
			||||||
    if (vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT)
 | 
					    return vue->cpu.stage == CPU_FATAL || vue->cpu.stage == CPU_HALT ?
 | 
				
			||||||
        return cycles;
 | 
					        cycles : cycles < vue->cpu.cycles ? cycles : vue->cpu.cycles;
 | 
				
			||||||
    return cycles < 0 ? vue->cpu.cycles :
 | 
					 | 
				
			||||||
        cycles < vue->cpu.cycles ? cycles : vue->cpu.cycles;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -154,11 +154,6 @@ typedef struct {
 | 
				
			||||||
    int8_t   type;    /* Data type */
 | 
					    int8_t   type;    /* Data type */
 | 
				
			||||||
} VueAccess;
 | 
					} VueAccess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Exception state */
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
    uint16_t code; /* Exception code */
 | 
					 | 
				
			||||||
} VueException;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Instruction state */
 | 
					/* Instruction state */
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    int32_t bits;      /* Binary encoding */
 | 
					    int32_t bits;      /* Binary encoding */
 | 
				
			||||||
| 
						 | 
					@ -174,31 +169,32 @@ typedef struct {
 | 
				
			||||||
    uint8_t subopcode; /* Instruction subopcode */
 | 
					    uint8_t subopcode; /* Instruction subopcode */
 | 
				
			||||||
} VueInstruction;
 | 
					} VueInstruction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Callbacks */
 | 
					/* Breakpoint handler callbacks */
 | 
				
			||||||
typedef int32_t (*VueOnException)(Vue *, VueException   *);
 | 
					typedef int32_t (*VueOnAccess   )(Vue *, VueAccess      *);
 | 
				
			||||||
 | 
					typedef int32_t (*VueOnException)(Vue *, uint16_t        );
 | 
				
			||||||
typedef int32_t (*VueOnExecute  )(Vue *, VueInstruction *);
 | 
					typedef int32_t (*VueOnExecute  )(Vue *, VueInstruction *);
 | 
				
			||||||
typedef int32_t (*VueOnRead     )(Vue *, VueAccess      *);
 | 
					typedef int32_t (*VueOnFrame    )(Vue *                  );
 | 
				
			||||||
typedef int32_t (*VueOnWrite    )(Vue *, VueAccess      *);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Emulation state */
 | 
					/* Emulation state */
 | 
				
			||||||
struct Vue {
 | 
					struct Vue {
 | 
				
			||||||
    int32_t breakCode;     /* Application break code */
 | 
					    int32_t breakCode;     /* Application break code */
 | 
				
			||||||
    uint8_t wram[0x10000]; /* System memory */
 | 
					    uint8_t wram[0x10000]; /* System memory */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Callback handlers */
 | 
					    /* Breakpoint handlers */
 | 
				
			||||||
    VueOnException onException;
 | 
					    VueOnException onException;
 | 
				
			||||||
    VueOnExecute   onExecute;
 | 
					    VueOnExecute   onExecute;
 | 
				
			||||||
    VueOnRead      onRead;
 | 
					    VueOnFrame     onFrame;
 | 
				
			||||||
    VueOnWrite     onWrite;
 | 
					    VueOnAccess    onRead;
 | 
				
			||||||
 | 
					    VueOnAccess    onWrite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* CPU state */
 | 
					    /* CPU state */
 | 
				
			||||||
    struct {
 | 
					    struct {
 | 
				
			||||||
        VueAccess      access;      /* Access state */
 | 
					        VueAccess      access;      /* Access state */
 | 
				
			||||||
        VueException   exception;   /* Exception state */
 | 
					 | 
				
			||||||
        VueInstruction inst;        /* Instruction state */
 | 
					        VueInstruction inst;        /* Instruction state */
 | 
				
			||||||
        int32_t        cycles;      /* Cycles until next stage */
 | 
					        uint32_t       cycles;      /* Cycles until next stage */
 | 
				
			||||||
        int32_t        jumpFrom[3]; /* Source PCs of most recent jumps */
 | 
					        int32_t        jumpFrom[3]; /* Source PCs of most recent jumps */
 | 
				
			||||||
        int32_t        jumpTo  [3]; /* Destination PCs of most recent jumps */
 | 
					        int32_t        jumpTo  [3]; /* Destination PCs of most recent jumps */
 | 
				
			||||||
 | 
					        uint16_t       exception;   /* Exception code */
 | 
				
			||||||
        uint16_t       irq;         /* Interrupt lines */
 | 
					        uint16_t       irq;         /* Interrupt lines */
 | 
				
			||||||
        int            fetch;       /* Fetch unit index */
 | 
					        int            fetch;       /* Fetch unit index */
 | 
				
			||||||
        int            stage;       /* Current processing stage */
 | 
					        int            stage;       /* Current processing stage */
 | 
				
			||||||
| 
						 | 
					@ -265,19 +261,21 @@ struct Vue {
 | 
				
			||||||
 *                            Function Prototypes                            *
 | 
					 *                            Function Prototypes                            *
 | 
				
			||||||
 *****************************************************************************/
 | 
					 *****************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VUEAPI int32_t vueEmulate     (Vue *vue, int32_t maxCycles);
 | 
					VUEAPI uint32_t       vueEmulate          (Vue *vue, uint32_t maxCycles);
 | 
				
			||||||
VUEAPI int32_t        vueGetBreakCode     (Vue *vue);
 | 
					VUEAPI int32_t        vueGetBreakCode     (Vue *vue);
 | 
				
			||||||
 | 
					VUEAPI uint16_t       vueGetExceptionCode (Vue *vue);
 | 
				
			||||||
VUEAPI int32_t        vueGetRegister      (Vue *vue, int32_t index, vbool system);
 | 
					VUEAPI int32_t        vueGetRegister      (Vue *vue, int32_t index, vbool system);
 | 
				
			||||||
VUEAPI void           vueInitialize       (Vue *vue);
 | 
					VUEAPI void           vueInitialize       (Vue *vue);
 | 
				
			||||||
 | 
					VUEAPI VueOnException vueOnException      (Vue *vue, VueOnException callback);
 | 
				
			||||||
 | 
					VUEAPI VueOnExecute   vueOnExecute        (Vue *vue, VueOnExecute callback);
 | 
				
			||||||
 | 
					VUEAPI VueOnFrame     vueOnFrame          (Vue *vue, VueOnFrame callback);
 | 
				
			||||||
 | 
					VUEAPI VueOnAccess    vueOnRead           (Vue *vue, VueOnAccess callback);
 | 
				
			||||||
 | 
					VUEAPI VueOnAccess    vueOnWrite          (Vue *vue, VueOnAccess callback);
 | 
				
			||||||
VUEAPI int32_t        vueRead             (Vue *vue, uint32_t address, int32_t type);
 | 
					VUEAPI int32_t        vueRead             (Vue *vue, uint32_t address, int32_t type);
 | 
				
			||||||
VUEAPI vbool          vueReadBytes        (Vue *vue, uint32_t address, uint8_t *dest, uint32_t length);
 | 
					VUEAPI vbool          vueReadBytes        (Vue *vue, uint32_t address, uint8_t *dest, uint32_t length);
 | 
				
			||||||
VUEAPI void           vueReset            (Vue *vue);
 | 
					VUEAPI void           vueReset            (Vue *vue);
 | 
				
			||||||
VUEAPI void    vueSetException(Vue *vue, VueOnException callback);
 | 
					 | 
				
			||||||
VUEAPI void    vueSetExecute  (Vue *vue, VueOnExecute callback);
 | 
					 | 
				
			||||||
VUEAPI void    vueSetRead     (Vue *vue, VueOnRead callback);
 | 
					 | 
				
			||||||
VUEAPI int32_t        vueSetRegister      (Vue *vue, int32_t index, vbool system, int32_t value);
 | 
					VUEAPI int32_t        vueSetRegister      (Vue *vue, int32_t index, vbool system, int32_t value);
 | 
				
			||||||
VUEAPI vbool          vueSetROM           (Vue *vue, uint8_t *rom, uint32_t size);
 | 
					VUEAPI vbool          vueSetROM           (Vue *vue, uint8_t *rom, uint32_t size);
 | 
				
			||||||
VUEAPI void    vueSetWrite    (Vue *vue, VueOnWrite callback);
 | 
					 | 
				
			||||||
VUEAPI void           vueWrite            (Vue *vue, uint32_t address, int32_t type, int32_t value);
 | 
					VUEAPI void           vueWrite            (Vue *vue, uint32_t address, int32_t type, int32_t value);
 | 
				
			||||||
VUEAPI vbool          vueWriteBytes       (Vue *vue, uint32_t address, uint8_t *src, uint32_t length);
 | 
					VUEAPI vbool          vueWriteBytes       (Vue *vue, uint32_t address, uint8_t *src, uint32_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										115
									
								
								src/core/vue.c
								
								
								
								
							
							
						
						
									
										115
									
								
								src/core/vue.c
								
								
								
								
							| 
						 | 
					@ -155,55 +155,46 @@ static void writeBytes(uint8_t *data, uint32_t datlen, uint32_t address,
 | 
				
			||||||
 *****************************************************************************/
 | 
					 *****************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Process the simulation */
 | 
					/* Process the simulation */
 | 
				
			||||||
int32_t vueEmulate(Vue *vue, int32_t maxCycles) {
 | 
					uint32_t vueEmulate(Vue *vue, uint32_t maxCycles) {
 | 
				
			||||||
    int32_t cycles; /* Number of cycles to process */
 | 
					    uint32_t cycles; /* Number of cycles to process */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Process up to the given number of cycles */
 | 
					    /* Process up to the given number of cycles */
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Determine the number of cycles during which nothing will happen */
 | 
					        /* Determine the number of cycles where no breakpoint will occur */
 | 
				
			||||||
        cycles = -1;
 | 
					        cycles = maxCycles; /* min(maxCycles, nextFrameCycles) */
 | 
				
			||||||
 | 
					        cycles = cpuUntil  (vue, cycles);
 | 
				
			||||||
        /*cycles = padUntil  (vue, cycles);*/
 | 
					        /*cycles = padUntil  (vue, cycles);*/
 | 
				
			||||||
        /*cycles = linkUntil (vue, cycles);*/
 | 
					        /*cycles = linkUntil (vue, cycles);*/
 | 
				
			||||||
        /*cycles = timerUntil(vue, cycles);*/
 | 
					        /*cycles = timerUntil(vue, cycles);*/
 | 
				
			||||||
        /*cycles = vipUntil  (vue, cycles);*/
 | 
					        /*cycles = vipUntil  (vue, cycles);*/
 | 
				
			||||||
        /*cycles = vsuUntil  (vue, cycles);*/
 | 
					 | 
				
			||||||
        cycles = cpuUntil  (vue, cycles);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Range checking */
 | 
					 | 
				
			||||||
        if (cycles == -1)   /* No activity on any component */
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        if (maxCycles >= 0) /* Restrict to given number of cycles */
 | 
					 | 
				
			||||||
            cycles = cycles < maxCycles ? cycles : maxCycles;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Process all system components */
 | 
					        /* Process all system components */
 | 
				
			||||||
        vue->breakCode = 0;
 | 
					        vue->breakCode = 0;
 | 
				
			||||||
 | 
					        cpuEmulate  (vue, cycles);
 | 
				
			||||||
        /*padEmulate  (vue, cycles);*/
 | 
					        /*padEmulate  (vue, cycles);*/
 | 
				
			||||||
        /*pakEmulate  (vue, cycles);*/
 | 
					        /*pakEmulate  (vue, cycles);*/
 | 
				
			||||||
        /*linkEmulate (vue, cycles);*/
 | 
					        /*linkEmulate (vue, cycles);*/
 | 
				
			||||||
        /*timerEmulate(vue, cycles);*/
 | 
					        /*timerEmulate(vue, cycles);*/
 | 
				
			||||||
        /*vipEmulate  (vue, cycles);*/
 | 
					        /*vipEmulate  (vue, cycles);*/
 | 
				
			||||||
        /*vsuEmulate  (vue, cycles);*/
 | 
					        /*vsuEmulate  (vue, cycles);*/
 | 
				
			||||||
        cpuEmulate  (vue, cycles);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* An application break was requested */
 | 
					 | 
				
			||||||
        if (vue->breakCode != 0)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Update the number of cycles remaining */
 | 
					 | 
				
			||||||
        if (maxCycles >= 0)
 | 
					 | 
				
			||||||
        maxCycles   -= cycles;
 | 
					        maxCycles   -= cycles;
 | 
				
			||||||
    } while (maxCycles != 0);
 | 
					    } while (vue->breakCode == 0 && maxCycles != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* A break condition has occurred */
 | 
					    /* A break condition has occurred */
 | 
				
			||||||
    return maxCycles;
 | 
					    return maxCycles;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Retrieve the application break code */
 | 
					/* Retrieve the most recent applicaiton break code */
 | 
				
			||||||
int32_t vueGetBreakCode(Vue *vue) {
 | 
					int32_t vueGetBreakCode(Vue *vue) {
 | 
				
			||||||
    return vue == NULL ? 0 : vue->breakCode;
 | 
					    return vue == NULL ? 0 : vue->breakCode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Retrieve the most recent exception code */
 | 
				
			||||||
 | 
					uint16_t vueGetExceptionCode(Vue *vue) {
 | 
				
			||||||
 | 
					    return vue == NULL ? 0 : vue->cpu.exception;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Retrieve the value of a register */
 | 
					/* Retrieve the value of a register */
 | 
				
			||||||
int32_t vueGetRegister(Vue *vue, int32_t index, vbool system) {
 | 
					int32_t vueGetRegister(Vue *vue, int32_t index, vbool system) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -234,17 +225,69 @@ void vueInitialize(Vue *vue) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    vue->onException = NULL;
 | 
					    vue->onException = NULL;
 | 
				
			||||||
    vue->onExecute   = NULL;
 | 
					    vue->onExecute   = NULL;
 | 
				
			||||||
 | 
					    vue->onFrame     = NULL;
 | 
				
			||||||
    vue->onRead      = NULL;
 | 
					    vue->onRead      = NULL;
 | 
				
			||||||
    vue->onWrite     = NULL;
 | 
					    vue->onWrite     = NULL;
 | 
				
			||||||
    vue->pak.ram     = NULL;
 | 
					    vue->pak.ram     = NULL;
 | 
				
			||||||
    vue->pak.rom     = NULL;
 | 
					    vue->pak.rom     = NULL;
 | 
				
			||||||
 | 
					    vueReset(vue);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Specify an exception breakpoint callback */
 | 
				
			||||||
 | 
					VueOnException vueOnException(Vue *vue, VueOnException callback) {
 | 
				
			||||||
 | 
					    VueOnException ret;
 | 
				
			||||||
 | 
					    if (vue == NULL)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    ret = vue->onException;
 | 
				
			||||||
 | 
					    vue->onException = callback;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Specify an execute breakpoint callback */
 | 
				
			||||||
 | 
					VueOnExecute vueOnExecute(Vue *vue, VueOnExecute callback) {
 | 
				
			||||||
 | 
					    VueOnExecute ret;
 | 
				
			||||||
 | 
					    if (vue == NULL)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    ret = vue->onExecute;
 | 
				
			||||||
 | 
					    vue->onExecute = callback;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Specify a frame breakpoint callback */
 | 
				
			||||||
 | 
					VueOnFrame vueOnFrame(Vue *vue, VueOnFrame callback) {
 | 
				
			||||||
 | 
					    VueOnFrame ret;
 | 
				
			||||||
 | 
					    if (vue == NULL)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    ret = vue->onFrame;
 | 
				
			||||||
 | 
					    vue->onFrame = callback;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Specify a read breakpoint callback */
 | 
				
			||||||
 | 
					VueOnAccess vueSetRead(Vue *vue, VueOnAccess callback) {
 | 
				
			||||||
 | 
					    VueOnAccess ret;
 | 
				
			||||||
 | 
					    if (vue == NULL)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    ret = vue->onRead;
 | 
				
			||||||
 | 
					    vue->onRead = callback;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Specify a write breakpoint callback */
 | 
				
			||||||
 | 
					VueOnAccess vueOnWrite(Vue *vue, VueOnAccess callback) {
 | 
				
			||||||
 | 
					    VueOnAccess ret;
 | 
				
			||||||
 | 
					    if (vue == NULL)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    ret = vue->onWrite;
 | 
				
			||||||
 | 
					    vue->onWrite = callback;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Read a value from the CPU bus */
 | 
					/* Read a value from the CPU bus */
 | 
				
			||||||
int32_t vueRead(Vue *vue, uint32_t address, int32_t type) {
 | 
					int32_t vueRead(Vue *vue, uint32_t address, int32_t type) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Error checking */
 | 
					    /* Error checking */
 | 
				
			||||||
    if (vue == NULL)
 | 
					    if (vue == NULL || type < 0 || type > 4)
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Perform the operation */
 | 
					    /* Perform the operation */
 | 
				
			||||||
| 
						 | 
					@ -299,28 +342,10 @@ void vueReset(Vue *vue) {
 | 
				
			||||||
    /* Reset state */
 | 
					    /* Reset state */
 | 
				
			||||||
    cpuReset(vue);
 | 
					    cpuReset(vue);
 | 
				
			||||||
    pakReset(vue);
 | 
					    pakReset(vue);
 | 
				
			||||||
    for (x = 0; x < 0x1000; x++)
 | 
					    for (x = 0; x < 0x10000; x++)
 | 
				
			||||||
        vue->wram[x] = 0;
 | 
					        vue->wram[x] = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Specify an exception breakpoint callback */
 | 
					 | 
				
			||||||
void vueSetException(Vue *vue, VueOnException callback) {
 | 
					 | 
				
			||||||
    if (vue != NULL)
 | 
					 | 
				
			||||||
        vue->onException = callback;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Specify an execute breakpoint callback */
 | 
					 | 
				
			||||||
void vueSetExecute(Vue *vue, VueOnExecute callback) {
 | 
					 | 
				
			||||||
    if (vue != NULL)
 | 
					 | 
				
			||||||
        vue->onExecute = callback;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Specify a read breakpoint callback */
 | 
					 | 
				
			||||||
void vueSetRead(Vue *vue, VueOnRead callback) {
 | 
					 | 
				
			||||||
    if (vue != NULL)
 | 
					 | 
				
			||||||
        vue->onRead = callback;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Specify a value for a register */
 | 
					/* Specify a value for a register */
 | 
				
			||||||
int32_t vueSetRegister(Vue *vue, int32_t index, vbool system, int32_t value) {
 | 
					int32_t vueSetRegister(Vue *vue, int32_t index, vbool system, int32_t value) {
 | 
				
			||||||
    return vue == NULL ? 0 :
 | 
					    return vue == NULL ? 0 :
 | 
				
			||||||
| 
						 | 
					@ -348,12 +373,6 @@ vbool vueSetROM(Vue *vue, uint8_t *rom, uint32_t size) {
 | 
				
			||||||
    return VUE_TRUE;
 | 
					    return VUE_TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Specify a write breakpoint callback */
 | 
					 | 
				
			||||||
void vueSetWrite(Vue *vue, VueOnRead callback) {
 | 
					 | 
				
			||||||
    if (vue != NULL)
 | 
					 | 
				
			||||||
        vue->onWrite = callback;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Write a value to the CPU bus */
 | 
					/* Write a value to the CPU bus */
 | 
				
			||||||
void vueWrite(Vue *vue, uint32_t address, int32_t type, int32_t value) {
 | 
					void vueWrite(Vue *vue, uint32_t address, int32_t type, int32_t value) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,43 +49,7 @@ public class Main {
 | 
				
			||||||
                useNative = true;
 | 
					                useNative = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Begin application operations
 | 
					        // Begin application operations
 | 
				
			||||||
        //new App(useNative);
 | 
					        new App(useNative);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        var brk = new Breakpoint(null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /*
 | 
					 | 
				
			||||||
        //String exp =
 | 
					 | 
				
			||||||
        //    "([sp - 8] & 3) << 6 != 12.0 + r6 * ecr && [0x0500008C + r8] == 0";
 | 
					 | 
				
			||||||
        //String exp = "float true + -3 * 4";
 | 
					 | 
				
			||||||
        String exp = "1100 ^ uword 1010";
 | 
					 | 
				
			||||||
        System.out.println("\n" + exp);
 | 
					 | 
				
			||||||
        if (brk.setCondition(exp))
 | 
					 | 
				
			||||||
            System.out.println(brk.debugTokens());
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            var err = brk.getConditionError();
 | 
					 | 
				
			||||||
            System.out.println("Error " +
 | 
					 | 
				
			||||||
                err.code     + "\t" +
 | 
					 | 
				
			||||||
                err.position + ":"  +
 | 
					 | 
				
			||||||
                err.text    
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /*
 | 
					 | 
				
			||||||
        exp = "123, 456 - 987 , f0-fffffff2";
 | 
					 | 
				
			||||||
        System.out.println("\n" + exp);
 | 
					 | 
				
			||||||
        if (brk.setAddresses(exp))
 | 
					 | 
				
			||||||
            System.out.println(brk.debugRanges());
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            var err = brk.getAddressError();
 | 
					 | 
				
			||||||
            System.out.println("Error " +
 | 
					 | 
				
			||||||
                err.code     + "\t" +
 | 
					 | 
				
			||||||
                err.position + ":"  +
 | 
					 | 
				
			||||||
                err.text    
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,7 +74,7 @@ public class App {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Specify whether using the native module
 | 
					    // Specify whether using the native module
 | 
				
			||||||
    boolean setUseNative(boolean useNative) {
 | 
					    boolean setUseNative(boolean useNative) {
 | 
				
			||||||
        return this.useNative = useNative && Vue.isNativeLoaded();
 | 
					        return this.useNative = useNative && Vue.getNativeID() != null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@ class ChildWindow extends JInternalFrame {
 | 
				
			||||||
        addInternalFrameListener(Util.onClose2(e->setVisible(false)));
 | 
					        addInternalFrameListener(Util.onClose2(e->setVisible(false)));
 | 
				
			||||||
        setClosable(true);
 | 
					        setClosable(true);
 | 
				
			||||||
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
 | 
					        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
 | 
				
			||||||
 | 
					        setMaximizable(true);
 | 
				
			||||||
        setResizable(true);
 | 
					        setResizable(true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,6 +63,7 @@ class DisassemblerPane extends JScrollPane {
 | 
				
			||||||
            Util.onFocus(e->client.repaint(), e->client.repaint()));
 | 
					            Util.onFocus(e->client.repaint(), e->client.repaint()));
 | 
				
			||||||
        client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
 | 
					        client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
 | 
				
			||||||
        client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
 | 
					        client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
 | 
				
			||||||
 | 
					        client.addMouseWheelListener(e->onMouseWheel(e));
 | 
				
			||||||
        client.setBackground(SystemColor.window);
 | 
					        client.setBackground(SystemColor.window);
 | 
				
			||||||
        client.setFocusable(true);
 | 
					        client.setFocusable(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,6 +99,7 @@ class DisassemblerPane extends JScrollPane {
 | 
				
			||||||
        int     code  = e.getKeyCode();
 | 
					        int     code  = e.getKeyCode();
 | 
				
			||||||
        int     count = tall(false);
 | 
					        int     count = tall(false);
 | 
				
			||||||
        int     mods  = e.getModifiersEx();
 | 
					        int     mods  = e.getModifiersEx();
 | 
				
			||||||
 | 
					        var     vue   = parent.parent.vue;
 | 
				
			||||||
        boolean alt   = (mods & InputEvent.ALT_DOWN_MASK ) != 0;
 | 
					        boolean alt   = (mods & InputEvent.ALT_DOWN_MASK ) != 0;
 | 
				
			||||||
        boolean ctrl  = (mods & InputEvent.CTRL_DOWN_MASK) != 0;
 | 
					        boolean ctrl  = (mods & InputEvent.CTRL_DOWN_MASK) != 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,16 +118,37 @@ class DisassemblerPane extends JScrollPane {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Processing by key code
 | 
					        // Processing by key code
 | 
				
			||||||
 | 
					        int pc   = vue.getRegister(Vue.PC, true);
 | 
				
			||||||
 | 
					        var step = parent.parent.brkStep;
 | 
				
			||||||
        switch (code) {
 | 
					        switch (code) {
 | 
				
			||||||
            case KeyEvent.VK_UP       : seek(address,      1); break;
 | 
					            case KeyEvent.VK_UP       : seek(address,      1); break;
 | 
				
			||||||
            case KeyEvent.VK_DOWN     : seek(address,     -1); break;
 | 
					            case KeyEvent.VK_DOWN     : seek(address,     -1); break;
 | 
				
			||||||
            case KeyEvent.VK_PAGE_UP  : seek(address,  count); break;
 | 
					            case KeyEvent.VK_PAGE_UP  : seek(address,  count); break;
 | 
				
			||||||
            case KeyEvent.VK_PAGE_DOWN: seek(address, -count); break;
 | 
					            case KeyEvent.VK_PAGE_DOWN: seek(address, -count); break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Single Step
 | 
				
			||||||
            case KeyEvent.VK_F11:
 | 
					            case KeyEvent.VK_F11:
 | 
				
			||||||
                parent.parent.vue.emulate(0);
 | 
					                step.setCondition("pc!=" + pc);
 | 
				
			||||||
 | 
					                step.setEnabled(true);
 | 
				
			||||||
 | 
					                vue.emulate(20000000);
 | 
				
			||||||
 | 
					                if (step.evaluate())
 | 
				
			||||||
 | 
					                    step.setEnabled(false);
 | 
				
			||||||
                parent.parent.refreshDebug();
 | 
					                parent.parent.refreshDebug();
 | 
				
			||||||
                int pc = parent.parent.vue.getRegister(Vue.PC, true);
 | 
					                pc = vue.getRegister(Vue.PC, true);
 | 
				
			||||||
 | 
					                if (!isVisible(pc))
 | 
				
			||||||
 | 
					                    seek(pc, count / 3);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Run to Next
 | 
				
			||||||
 | 
					            case KeyEvent.VK_F12:
 | 
				
			||||||
 | 
					                step.setCondition("pc==" +
 | 
				
			||||||
 | 
					                    (pc + Instruction.size(vue.read(pc, Vue.U16) >> 10)));
 | 
				
			||||||
 | 
					                step.setEnabled(true);
 | 
				
			||||||
 | 
					                vue.emulate(20000000);
 | 
				
			||||||
 | 
					                if (step.evaluate())
 | 
				
			||||||
 | 
					                    step.setEnabled(false);
 | 
				
			||||||
 | 
					                parent.parent.refreshDebug();
 | 
				
			||||||
 | 
					                pc = vue.getRegister(Vue.PC, true);
 | 
				
			||||||
                if (!isVisible(pc))
 | 
					                if (!isVisible(pc))
 | 
				
			||||||
                    seek(pc, count / 3);
 | 
					                    seek(pc, count / 3);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
| 
						 | 
					@ -133,6 +156,11 @@ class DisassemblerPane extends JScrollPane {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mouse wheel
 | 
				
			||||||
 | 
					    private void onMouseWheel(MouseWheelEvent e) {
 | 
				
			||||||
 | 
					        seek(address, -e.getUnitsToScroll());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Client paint
 | 
					    // Client paint
 | 
				
			||||||
    private void onPaint(Graphics2D g, int width, int height) {
 | 
					    private void onPaint(Graphics2D g, int width, int height) {
 | 
				
			||||||
        var vue = parent.parent.vue;
 | 
					        var vue = parent.parent.vue;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@ class MainWindow extends JFrame {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Instance fields
 | 
					    // Instance fields
 | 
				
			||||||
    App        app;     // Containing application
 | 
					    App        app;     // Containing application
 | 
				
			||||||
 | 
					    Breakpoint brkStep; // Single step internal breakpoint
 | 
				
			||||||
    Vue        vue;     // Emulation core context
 | 
					    Vue        vue;     // Emulation core context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Private fields
 | 
					    // Private fields
 | 
				
			||||||
| 
						 | 
					@ -97,6 +98,10 @@ class MainWindow extends JFrame {
 | 
				
			||||||
        desktop.add(cpu     = new CPUWindow    (this));
 | 
					        desktop.add(cpu     = new CPUWindow    (this));
 | 
				
			||||||
        desktop.add(memory  = new MemoryWindow (this));
 | 
					        desktop.add(memory  = new MemoryWindow (this));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Configure internal breakpoints
 | 
				
			||||||
 | 
					        brkStep = vue.breakpoint();
 | 
				
			||||||
 | 
					        brkStep.setExecute(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Display window
 | 
					        // Display window
 | 
				
			||||||
        refreshDebug();
 | 
					        refreshDebug();
 | 
				
			||||||
        pack();
 | 
					        pack();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,20 +63,23 @@ public class Breakpoint {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Functional symbol IDs
 | 
					    // Functional symbol IDs
 | 
				
			||||||
    private static final int ADDRESS   =  0;
 | 
					    private static final int ADDRESS   =  0;
 | 
				
			||||||
    private static final int CODE      =  1;
 | 
					    private static final int BREAK     =  1;
 | 
				
			||||||
    private static final int COND      =  2;
 | 
					    private static final int CODE      =  2;
 | 
				
			||||||
    private static final int DISP      =  3;
 | 
					    private static final int COND      =  3;
 | 
				
			||||||
    private static final int FORMAT    =  4;
 | 
					    private static final int DISP      =  4;
 | 
				
			||||||
    private static final int ID        =  5;
 | 
					    private static final int FETCH     =  5;
 | 
				
			||||||
    private static final int IMM       =  6;
 | 
					    private static final int FORMAT    =  6;
 | 
				
			||||||
    private static final int OPCODE    =  7;
 | 
					    private static final int ID        =  7;
 | 
				
			||||||
    private static final int REG1      =  8;
 | 
					    private static final int IMM       =  8;
 | 
				
			||||||
    private static final int REG2      =  9;
 | 
					    private static final int OPCODE    =  9;
 | 
				
			||||||
    private static final int REGID     = 10;
 | 
					    private static final int REG1      = 10;
 | 
				
			||||||
    private static final int SIZE      = 11;
 | 
					    private static final int REG2      = 11;
 | 
				
			||||||
    private static final int SUBOPCODE = 12;
 | 
					    private static final int REGID     = 12;
 | 
				
			||||||
    private static final int VALUE     = 13;
 | 
					    private static final int SIZE      = 13;
 | 
				
			||||||
    private static final int VECTOR    = 14;
 | 
					    private static final int SUBOPCODE = 14;
 | 
				
			||||||
 | 
					    private static final int TYPE      = 15;
 | 
				
			||||||
 | 
					    private static final int VALUE     = 16;
 | 
				
			||||||
 | 
					    private static final int VECTOR    = 17;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Evaluation operator IDs
 | 
					    // Evaluation operator IDs
 | 
				
			||||||
    private static final int GROUP     =   0; // ()
 | 
					    private static final int GROUP     =   0; // ()
 | 
				
			||||||
| 
						 | 
					@ -190,6 +193,12 @@ public class Breakpoint {
 | 
				
			||||||
        SYMDEFS.put("false", new Def(BOOL, 0));
 | 
					        SYMDEFS.put("false", new Def(BOOL, 0));
 | 
				
			||||||
        SYMDEFS.put("true" , new Def(BOOL, 1));
 | 
					        SYMDEFS.put("true" , new Def(BOOL, 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Break type symbl definitions
 | 
				
			||||||
 | 
					        SYMDEFS.put("exception", new Def(SIGNED, EXCEPTION));
 | 
				
			||||||
 | 
					        SYMDEFS.put("execute"  , new Def(SIGNED, EXECUTE  ));
 | 
				
			||||||
 | 
					        SYMDEFS.put("read"     , new Def(SIGNED, READ     ));
 | 
				
			||||||
 | 
					        SYMDEFS.put("write"    , new Def(SIGNED, WRITE    ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Condition code symbol definitions
 | 
					        // Condition code symbol definitions
 | 
				
			||||||
        SYMDEFS.put("c" , new Def(SIGNED,  1));
 | 
					        SYMDEFS.put("c" , new Def(SIGNED,  1));
 | 
				
			||||||
        SYMDEFS.put("e" , new Def(SIGNED,  2));
 | 
					        SYMDEFS.put("e" , new Def(SIGNED,  2));
 | 
				
			||||||
| 
						 | 
					@ -293,9 +302,11 @@ public class Breakpoint {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Functional symbol definitions
 | 
					        // Functional symbol definitions
 | 
				
			||||||
        SYMDEFS.put("address"  , new Def(SYMBOL, ADDRESS  ));
 | 
					        SYMDEFS.put("address"  , new Def(SYMBOL, ADDRESS  ));
 | 
				
			||||||
 | 
					        SYMDEFS.put("break"    , new Def(SYMBOL, BREAK    ));
 | 
				
			||||||
        SYMDEFS.put("code"     , new Def(SYMBOL, CODE     ));
 | 
					        SYMDEFS.put("code"     , new Def(SYMBOL, CODE     ));
 | 
				
			||||||
        SYMDEFS.put("cond"     , new Def(SYMBOL, COND     ));
 | 
					        SYMDEFS.put("cond"     , new Def(SYMBOL, COND     ));
 | 
				
			||||||
        SYMDEFS.put("disp"     , new Def(SYMBOL, DISP     ));
 | 
					        SYMDEFS.put("disp"     , new Def(SYMBOL, DISP     ));
 | 
				
			||||||
 | 
					        SYMDEFS.put("fetch"    , new Def(SYMBOL, FETCH    ));
 | 
				
			||||||
        SYMDEFS.put("format"   , new Def(SYMBOL, FORMAT   ));
 | 
					        SYMDEFS.put("format"   , new Def(SYMBOL, FORMAT   ));
 | 
				
			||||||
        SYMDEFS.put("id"       , new Def(SYMBOL, ID       ));
 | 
					        SYMDEFS.put("id"       , new Def(SYMBOL, ID       ));
 | 
				
			||||||
        SYMDEFS.put("imm"      , new Def(SYMBOL, IMM      ));
 | 
					        SYMDEFS.put("imm"      , new Def(SYMBOL, IMM      ));
 | 
				
			||||||
| 
						 | 
					@ -305,6 +316,7 @@ public class Breakpoint {
 | 
				
			||||||
        SYMDEFS.put("regid"    , new Def(SYMBOL, REGID    ));
 | 
					        SYMDEFS.put("regid"    , new Def(SYMBOL, REGID    ));
 | 
				
			||||||
        SYMDEFS.put("size"     , new Def(SYMBOL, SIZE     ));
 | 
					        SYMDEFS.put("size"     , new Def(SYMBOL, SIZE     ));
 | 
				
			||||||
        SYMDEFS.put("subopcode", new Def(SYMBOL, SUBOPCODE));
 | 
					        SYMDEFS.put("subopcode", new Def(SYMBOL, SUBOPCODE));
 | 
				
			||||||
 | 
					        SYMDEFS.put("type"     , new Def(SYMBOL, TYPE     ));
 | 
				
			||||||
        SYMDEFS.put("value"    , new Def(SYMBOL, VALUE    ));
 | 
					        SYMDEFS.put("value"    , new Def(SYMBOL, VALUE    ));
 | 
				
			||||||
        SYMDEFS.put("vector"   , new Def(SYMBOL, VECTOR   ));
 | 
					        SYMDEFS.put("vector"   , new Def(SYMBOL, VECTOR   ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -454,9 +466,34 @@ public class Breakpoint {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Evaluate the condition against the emulation context
 | 
					    // Evaluate the condition against the emulation context
 | 
				
			||||||
    public boolean evaluate() {
 | 
					    public boolean evaluate() {
 | 
				
			||||||
        return vue == null || conditionError.code != NONE ?
 | 
					
 | 
				
			||||||
            false : tokens.length == 0 ? true :
 | 
					        // Error checking
 | 
				
			||||||
            evaluate(null, null, null) != 0;
 | 
					        if (vue == null)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Retrieve state objects
 | 
				
			||||||
 | 
					        Access      acc       = vue.getAccess     ();
 | 
				
			||||||
 | 
					        int         breakType = vue.getBreakType  ();
 | 
				
			||||||
 | 
					        Instruction inst      = vue.getInstruction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Error checking
 | 
				
			||||||
 | 
					        if (!appliesTo(breakType))
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check address ranges for execute
 | 
				
			||||||
 | 
					        if (breakType == EXECUTE) {
 | 
				
			||||||
 | 
					            int pc = vue.getRegister(Vue.PC, true);
 | 
				
			||||||
 | 
					            if (!inRange(pc, pc + inst.size - 1))
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check address ranges for read and write
 | 
				
			||||||
 | 
					        else if (breakType == READ || breakType == WRITE &&
 | 
				
			||||||
 | 
					            !inRange(acc.address, acc.address+JavaVue.TYPE_SIZES[acc.type]-1))
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Evaluate the condition
 | 
				
			||||||
 | 
					        return isTrue(new int[depth], breakType, inst, acc);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve the most recent address text
 | 
					    // Retrieve the most recent address text
 | 
				
			||||||
| 
						 | 
					@ -504,6 +541,15 @@ public class Breakpoint {
 | 
				
			||||||
        return name;
 | 
					        return name;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Determine whether the breakpoint can be used
 | 
				
			||||||
 | 
					    boolean isActive() {
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					            isEnabled                   &&
 | 
				
			||||||
 | 
					            addressError  .code == NONE &&
 | 
				
			||||||
 | 
					            conditionError.code == NONE
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Determine whether the breakpoint is enabled
 | 
					    // Determine whether the breakpoint is enabled
 | 
				
			||||||
    public boolean isEnabled() {
 | 
					    public boolean isEnabled() {
 | 
				
			||||||
        return isEnabled;
 | 
					        return isEnabled;
 | 
				
			||||||
| 
						 | 
					@ -738,12 +784,16 @@ public class Breakpoint {
 | 
				
			||||||
    //                            Package Methods                            //
 | 
					    //                            Package Methods                            //
 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Cast a value to the condition evaluation's data type
 | 
					    // Determine whether the breakpoint applies to a break scenario
 | 
				
			||||||
    Object cast(int value) {
 | 
					    boolean appliesTo(int breakType) {
 | 
				
			||||||
        if (conditionError.code != NONE)
 | 
					        return isActive() && (breakType == 0 || (breakType & hooks) != 0);
 | 
				
			||||||
            return conditionError;
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Perform a typed evaluation of the condition expression
 | 
				
			||||||
 | 
					    Object evaluateTyped(int[]stack,int breakType,Instruction inst,Access acc){
 | 
				
			||||||
        if (tokens.length == 0)
 | 
					        if (tokens.length == 0)
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
 | 
					        int value = evaluate(stack, breakType, inst, acc);
 | 
				
			||||||
        switch (dataType) {
 | 
					        switch (dataType) {
 | 
				
			||||||
            case BOOL    : return (Boolean) (value != 0);
 | 
					            case BOOL    : return (Boolean) (value != 0);
 | 
				
			||||||
            case FLOAT   : return (Float  ) Float.intBitsToFloat(value);
 | 
					            case FLOAT   : return (Float  ) Float.intBitsToFloat(value);
 | 
				
			||||||
| 
						 | 
					@ -752,54 +802,28 @@ public class Breakpoint {
 | 
				
			||||||
        return (Integer) value;
 | 
					        return (Integer) value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Evaluate the condition, returning only the computed value
 | 
					    // Determine whether the breakpoint applies to a given address range
 | 
				
			||||||
    int evaluate(int[] stack, Instruction inst, Access acc) {
 | 
					    boolean inRange(int start, int end) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Error checking
 | 
					        // Implicit inclusion
 | 
				
			||||||
        if (conditionError.code != NONE)
 | 
					        if (ranges.length == 0)
 | 
				
			||||||
            return 0;
 | 
					            return true;
 | 
				
			||||||
        if (tokens.length == 0)
 | 
					 | 
				
			||||||
            return 1;
 | 
					 | 
				
			||||||
        if (stack == null)
 | 
					 | 
				
			||||||
            stack = new int[depth];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Process all tokens
 | 
					        // Check all ranges
 | 
				
			||||||
        int size = 0;
 | 
					        for (var range : ranges)
 | 
				
			||||||
        for (var tok : tokens) switch (tok.type) {
 | 
					            if (
 | 
				
			||||||
 | 
					                Integer.compareUnsigned(
 | 
				
			||||||
            // Binary operator
 | 
					                    start    - range[0], range[1] - range[0]) <= 0 ||
 | 
				
			||||||
            case BINARY:
 | 
					                Integer.compareUnsigned(
 | 
				
			||||||
                stack[size - 2] =
 | 
					                    range[0] - start   , end      - start   ) <= 0
 | 
				
			||||||
                    evalBinary(tok.id, stack[size - 2], stack[size - 1]);
 | 
					            ) return true;
 | 
				
			||||||
                break;
 | 
					        return false;
 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Literal
 | 
					 | 
				
			||||||
            case BOOL:
 | 
					 | 
				
			||||||
            case FLOAT:
 | 
					 | 
				
			||||||
            case SIGNED:
 | 
					 | 
				
			||||||
            case UNSIGNED:
 | 
					 | 
				
			||||||
                stack[size++] = tok.id;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // CPU register
 | 
					 | 
				
			||||||
            case PROREG:
 | 
					 | 
				
			||||||
            case SYSREG:
 | 
					 | 
				
			||||||
                stack[size++] = vue.getRegister(tok.id, tok.type == SYSREG);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Symbol
 | 
					 | 
				
			||||||
            case SYMBOL:
 | 
					 | 
				
			||||||
                stack[size++] = 0;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Unary operator
 | 
					 | 
				
			||||||
            case UNARY:
 | 
					 | 
				
			||||||
                stack[size - 1] = evalUnary(tok.id, stack[size - 1]);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Return the remaining stack value
 | 
					    // Determine whether the breakpoint's condition is truthy
 | 
				
			||||||
        return stack[0];
 | 
					    boolean isTrue(int[] stack, int breakType, Instruction inst, Access acc) {
 | 
				
			||||||
 | 
					        return tokens.length == 0 ? true :
 | 
				
			||||||
 | 
					            evaluate(stack, breakType, inst, acc) != 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Produce a one-dimensional array from the address ranges
 | 
					    // Produce a one-dimensional array from the address ranges
 | 
				
			||||||
| 
						 | 
					@ -829,21 +853,6 @@ public class Breakpoint {
 | 
				
			||||||
        return depth;
 | 
					        return depth;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 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
 | 
					    // The breakpoint is being removed from its emulation context
 | 
				
			||||||
    void remove() {
 | 
					    void remove() {
 | 
				
			||||||
        vue = null;
 | 
					        vue = null;
 | 
				
			||||||
| 
						 | 
					@ -1216,9 +1225,10 @@ public class Breakpoint {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Binary operators
 | 
					        // Binary operators
 | 
				
			||||||
        if (tok.type == BINARY) {
 | 
					        if (tok.type == BINARY) {
 | 
				
			||||||
 | 
					            int     dataType = Math.max(tok.left.dataType, tok.right.dataType);
 | 
				
			||||||
            int     id       = tok.id;
 | 
					            int     id       = tok.id;
 | 
				
			||||||
            boolean literal  = isLiteral(tok.left) && isLiteral(tok.right);
 | 
					            boolean literal  = isLiteral(tok.left) && isLiteral(tok.right);
 | 
				
			||||||
            tok.dataType    = Math.max(tok.left.dataType, tok.right.dataType);
 | 
					            tok.dataType     = dataType;
 | 
				
			||||||
            tok.id           = -id * 4 + tok.dataType;
 | 
					            tok.id           = -id * 4 + tok.dataType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Process by ID
 | 
					            // Process by ID
 | 
				
			||||||
| 
						 | 
					@ -1269,7 +1279,7 @@ public class Breakpoint {
 | 
				
			||||||
                var top = op == 0 ? tok.left : tok.right;
 | 
					                var top = op == 0 ? tok.left : tok.right;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // The operand is already the result type
 | 
					                // The operand is already the result type
 | 
				
			||||||
                if (top.dataType == tok.dataType)
 | 
					                if (top.dataType == dataType)
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Select the ID of the conversion operation
 | 
					                // Select the ID of the conversion operation
 | 
				
			||||||
| 
						 | 
					@ -1284,7 +1294,7 @@ public class Breakpoint {
 | 
				
			||||||
                // Convert the literal operand directly
 | 
					                // Convert the literal operand directly
 | 
				
			||||||
                if (isLiteral(top)) {
 | 
					                if (isLiteral(top)) {
 | 
				
			||||||
                    top.id = evalUnary(cvt, top);
 | 
					                    top.id = evalUnary(cvt, top);
 | 
				
			||||||
                    top.type = top.dataType = tok.dataType;
 | 
					                    top.type = top.dataType = dataType;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Insert a conversion token
 | 
					                // Insert a conversion token
 | 
				
			||||||
| 
						 | 
					@ -1296,7 +1306,7 @@ public class Breakpoint {
 | 
				
			||||||
                        case SIGNED  : imp.text = "s32"  ; break;
 | 
					                        case SIGNED  : imp.text = "s32"  ; break;
 | 
				
			||||||
                        case UNSIGNED: imp.text = "u32"  ; break;
 | 
					                        case UNSIGNED: imp.text = "u32"  ; break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    imp.dataType = tok.dataType;
 | 
					                    imp.dataType = dataType;
 | 
				
			||||||
                    imp.id       = -cvt * 4 + top.dataType;
 | 
					                    imp.id       = -cvt * 4 + top.dataType;
 | 
				
			||||||
                    imp.parent   = tok;
 | 
					                    imp.parent   = tok;
 | 
				
			||||||
                    imp.right    = top;
 | 
					                    imp.right    = top;
 | 
				
			||||||
| 
						 | 
					@ -1444,202 +1454,71 @@ public class Breakpoint {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
    //                            Private Methods                            //
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Adjust a float value as needed
 | 
					 | 
				
			||||||
    private static float adjust(float value) {
 | 
					 | 
				
			||||||
        int bits = Float.floatToRawIntBits(value);
 | 
					 | 
				
			||||||
        int exp  = bits & 0x7F800000;
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
            (bits & 0x7FFFFFFF) == 0 || // Zero
 | 
					 | 
				
			||||||
            exp == 0x7F800000        || // Indefinite
 | 
					 | 
				
			||||||
            exp == 0                    // Denormal
 | 
					 | 
				
			||||||
        ? 0 : value;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Determine the required stack size to evaluate the expression
 | 
					 | 
				
			||||||
    private int depth() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Error checking
 | 
					 | 
				
			||||||
        if (conditionError.code != NONE)
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Count the maximum size of the stack
 | 
					 | 
				
			||||||
        int max  = 0;
 | 
					 | 
				
			||||||
        int size = 0;
 | 
					 | 
				
			||||||
        for (var tok : tokens) switch (tok.type) {
 | 
					 | 
				
			||||||
            case BINARY: size--; break;
 | 
					 | 
				
			||||||
            case UNARY :         break;
 | 
					 | 
				
			||||||
            default    : max = Math.max(max, ++size);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return max;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Remove the fraction part of a float
 | 
					 | 
				
			||||||
    private static float trunc(float x) {
 | 
					 | 
				
			||||||
        return (float) (x < 0 ? Math.ceil(x) : Math.floor(x));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
    //                           Debugging Methods                           //
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Produce a string representation of the condition token list
 | 
					 | 
				
			||||||
    public String debugTokens() {
 | 
					 | 
				
			||||||
        var ret = new StringBuilder();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // The condition was not successfully parsed
 | 
					 | 
				
			||||||
        if (conditionError.code != NONE)
 | 
					 | 
				
			||||||
            return "Error";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Determine the maximum width of the text fields
 | 
					 | 
				
			||||||
        int max = 0;
 | 
					 | 
				
			||||||
        for (var tok : tokens)
 | 
					 | 
				
			||||||
            max = Math.max(max, tok.text.length());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Output all tokens
 | 
					 | 
				
			||||||
        var last = tokens[tokens.length - 1];
 | 
					 | 
				
			||||||
        for (var tok : tokens) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Text
 | 
					 | 
				
			||||||
            ret.append(String.format("%-" + max +  "s   ", tok.text));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Type
 | 
					 | 
				
			||||||
            String type = null;
 | 
					 | 
				
			||||||
            switch (tok.type) {
 | 
					 | 
				
			||||||
                case BINARY  : type = "Binary"  ; break;
 | 
					 | 
				
			||||||
                case BOOL    : type = "Bool"    ; break;
 | 
					 | 
				
			||||||
                case FLOAT   : type = "Float"   ; break;
 | 
					 | 
				
			||||||
                case PROREG  : type = "ProReg"  ; break;
 | 
					 | 
				
			||||||
                case SYSREG  : type = "SysReg"  ; break;
 | 
					 | 
				
			||||||
                case SIGNED  : type = "Signed"  ; break;
 | 
					 | 
				
			||||||
                case SYMBOL  : type = "Symbol"  ; break;
 | 
					 | 
				
			||||||
                case UNARY   : type = "Unary"   ; break;
 | 
					 | 
				
			||||||
                case UNSIGNED: type = "Unsigned"; break;
 | 
					 | 
				
			||||||
                default: type = Integer.toString(tok.type);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ret.append(String.format("%-8s   ", type));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Data type
 | 
					 | 
				
			||||||
            switch (tok.dataType) {
 | 
					 | 
				
			||||||
                case BOOL    : type = "Bool"    ; break;
 | 
					 | 
				
			||||||
                case FLOAT   : type = "Float"   ; break;
 | 
					 | 
				
			||||||
                case SIGNED  : type = "Signed"  ; break;
 | 
					 | 
				
			||||||
                case UNSIGNED: type = "Unsigned"; break;
 | 
					 | 
				
			||||||
                default: type = Integer.toString(tok.dataType);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ret.append(String.format("%-8s   ", type));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Operator
 | 
					 | 
				
			||||||
            if (tok.type == BINARY || tok.type == UNARY) {
 | 
					 | 
				
			||||||
                String id = Integer.toString(tok.id);
 | 
					 | 
				
			||||||
                switch (-tok.id / 4) {
 | 
					 | 
				
			||||||
                    case 0        : id = "REINTERPRET"; break;
 | 
					 | 
				
			||||||
                    case READ8    : id = "READ8"      ; break;
 | 
					 | 
				
			||||||
                    case READ16   : id = "READ16"     ; break;
 | 
					 | 
				
			||||||
                    case READ32   : id = "READ32"     ; break;
 | 
					 | 
				
			||||||
                    case ADD      : id = "ADD"        ; break;
 | 
					 | 
				
			||||||
                    case AND_B    : id = "AND_B"      ; break;
 | 
					 | 
				
			||||||
                    case AND_L    : id = "AND_L"      ; break;
 | 
					 | 
				
			||||||
                    case BOOL_    : id = "BOOL_"      ; break;
 | 
					 | 
				
			||||||
                    case CEIL     : id = "CEIL"       ; break;
 | 
					 | 
				
			||||||
                    case DIVIDE   : id = "DIVIDE"     ; break;
 | 
					 | 
				
			||||||
                    case EQUAL    : id = "EQUAL"      ; break;
 | 
					 | 
				
			||||||
                    case FLOAT_   : id = "FLOAT_"     ; break;
 | 
					 | 
				
			||||||
                    case FLOOR    : id = "FLOOR"      ; break;
 | 
					 | 
				
			||||||
                    case GREATER  : id = "GREATER"    ; break;
 | 
					 | 
				
			||||||
                    case GREQUAL  : id = "GREQUAL"    ; break;
 | 
					 | 
				
			||||||
                    case LEFT_L   : id = "LEFT_L"     ; break;
 | 
					 | 
				
			||||||
                    case LEQUAL   : id = "LEQUAL"     ; break;
 | 
					 | 
				
			||||||
                    case LESS     : id = "LESS"       ; break;
 | 
					 | 
				
			||||||
                    case MULTIPLY : id = "MULTIPLY"   ; break;
 | 
					 | 
				
			||||||
                    case NEQUAL   : id = "NEQUAL"     ; break;
 | 
					 | 
				
			||||||
                    case NOT_B    : id = "NOT_B"      ; break;
 | 
					 | 
				
			||||||
                    case NOT_L    : id = "NOT_L"      ; break;
 | 
					 | 
				
			||||||
                    case NEGATE   : id = "NEGATE"     ; break;
 | 
					 | 
				
			||||||
                    case OR_B     : id = "OR_B"       ; break;
 | 
					 | 
				
			||||||
                    case OR_L     : id = "OR_L"       ; break;
 | 
					 | 
				
			||||||
                    case REMAINDER: id = "REMAINDER"  ; break;
 | 
					 | 
				
			||||||
                    case RIGHT_A  : id = "RIGHT_A"    ; break;
 | 
					 | 
				
			||||||
                    case RIGHT_L  : id = "RIGHT_L"    ; break;
 | 
					 | 
				
			||||||
                    case ROUND    : id = "ROUND"      ; break;
 | 
					 | 
				
			||||||
                    case S8       : id = "S8"         ; break;
 | 
					 | 
				
			||||||
                    case S16      : id = "S16"        ; break;
 | 
					 | 
				
			||||||
                    case S32      : id = "S32"        ; break;
 | 
					 | 
				
			||||||
                    case SUBTRACT : id = "SUBTRACT"   ; break;
 | 
					 | 
				
			||||||
                    case TRUNC    : id = "TRUNC"      ; break;
 | 
					 | 
				
			||||||
                    case U8       : id = "U8"         ; break;
 | 
					 | 
				
			||||||
                    case U16      : id = "U16"        ; break;
 | 
					 | 
				
			||||||
                    case U32      : id = "U32"        ; break;
 | 
					 | 
				
			||||||
                    case XFLOAT   : id = "XFLOAT"     ; break;
 | 
					 | 
				
			||||||
                    case XOR_B    : id = "XOR_B"      ; break;
 | 
					 | 
				
			||||||
                    case XOR_L    : id = "XOR_L"      ; break;
 | 
					 | 
				
			||||||
                    case XS32     : id = "XS32"       ; break;
 | 
					 | 
				
			||||||
                    case XU32     : id = "XU32"       ; break;
 | 
					 | 
				
			||||||
                    default: ret.append(Integer.toString(tok.id));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                ret.append(String.format("%-11s", id));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Symbol or literal
 | 
					 | 
				
			||||||
            else switch (tok.type) {
 | 
					 | 
				
			||||||
                case PROREG:
 | 
					 | 
				
			||||||
                case SYSREG:
 | 
					 | 
				
			||||||
                case SYMBOL:
 | 
					 | 
				
			||||||
                    ret.append(Integer.toString(tok.id));
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case FLOAT:
 | 
					 | 
				
			||||||
                    ret.append(String.format("%.6f",
 | 
					 | 
				
			||||||
                        Float.intBitsToFloat(tok.id)));
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BOOL:
 | 
					 | 
				
			||||||
                case SIGNED:
 | 
					 | 
				
			||||||
                    ret.append(Integer.toString(tok.id));
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case UNSIGNED:
 | 
					 | 
				
			||||||
                    ret.append(Long.toString(tok.id & 0xFFFFFFFFL));
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                default: ret.append("Error");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Advance to the next line
 | 
					 | 
				
			||||||
            if (tok != last)
 | 
					 | 
				
			||||||
                ret.append("\n");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return ret.toString();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Produce a string representation of the internal address ranges
 | 
					 | 
				
			||||||
    public String debugRanges() {
 | 
					 | 
				
			||||||
        var ret = new StringBuilder();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // The address ranges were not successfully parsed
 | 
					 | 
				
			||||||
        if (addressError.code != NONE)
 | 
					 | 
				
			||||||
            return "Error";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Process ranges
 | 
					 | 
				
			||||||
        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]));
 | 
					 | 
				
			||||||
            if (range[0] != range[1])
 | 
					 | 
				
			||||||
                ret.append(String.format("-%08X", range[1]));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return ret.toString();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
    //                          Evaluation Methods                           //
 | 
					    //                          Evaluation Methods                           //
 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Evaluate the condition, returning only the computed value
 | 
				
			||||||
 | 
					    private int evaluate(int[]stack,int breakType,Instruction inst,Access acc){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Process all tokens
 | 
				
			||||||
 | 
					        int size = 0;
 | 
				
			||||||
 | 
					        for (var tok : tokens) switch (tok.type) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Binary operator
 | 
				
			||||||
 | 
					            case BINARY:
 | 
				
			||||||
 | 
					                stack[size - 2] =
 | 
				
			||||||
 | 
					                    evalBinary(tok.id, stack[size - 2], stack[size - 1]);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Literal
 | 
				
			||||||
 | 
					            case BOOL:
 | 
				
			||||||
 | 
					            case FLOAT:
 | 
				
			||||||
 | 
					            case SIGNED:
 | 
				
			||||||
 | 
					            case UNSIGNED:
 | 
				
			||||||
 | 
					                stack[size++] = tok.id;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // CPU register
 | 
				
			||||||
 | 
					            case PROREG:
 | 
				
			||||||
 | 
					            case SYSREG:
 | 
				
			||||||
 | 
					                stack[size++] = vue.getRegister(tok.id, tok.type == SYSREG);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Unary operator
 | 
				
			||||||
 | 
					            case UNARY:
 | 
				
			||||||
 | 
					                stack[size - 1] = evalUnary(tok.id, stack[size - 1]);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Symbol
 | 
				
			||||||
 | 
					            case SYMBOL:
 | 
				
			||||||
 | 
					                int sym = inst.imm; // IMM, REGID, VECTOR
 | 
				
			||||||
 | 
					                switch (tok.id) {
 | 
				
			||||||
 | 
					                    case ADDRESS  : sym = acc.address           ; break;
 | 
				
			||||||
 | 
					                    case BREAK    : sym = breakType             ; break;
 | 
				
			||||||
 | 
					                    case CODE     : sym = vue.getExceptionCode(); break;
 | 
				
			||||||
 | 
					                    case COND     : sym = inst.cond             ; break;
 | 
				
			||||||
 | 
					                    case DISP     : sym = inst.disp             ; break;
 | 
				
			||||||
 | 
					                    case FETCH    : sym = vue.getFetch        (); break;
 | 
				
			||||||
 | 
					                    case FORMAT   : sym = inst.format           ; break;
 | 
				
			||||||
 | 
					                    case ID       : sym = inst.id               ; break;
 | 
				
			||||||
 | 
					                    case OPCODE   : sym = inst.opcode           ; break;
 | 
				
			||||||
 | 
					                    case REG1     : sym = inst.reg1             ; break;
 | 
				
			||||||
 | 
					                    case REG2     : sym = inst.reg2             ; break;
 | 
				
			||||||
 | 
					                    case SIZE     : sym = inst.size             ; break;
 | 
				
			||||||
 | 
					                    case SUBOPCODE: sym = inst.subopcode        ; break;
 | 
				
			||||||
 | 
					                    case TYPE     : sym = acc.type              ; break;
 | 
				
			||||||
 | 
					                    case VALUE    : sym = acc.value             ; break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                stack[size++] = sym;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Return the remaining stack value
 | 
				
			||||||
 | 
					        return stack[0];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Evaluate a unary operator given a token
 | 
					    // Evaluate a unary operator given a token
 | 
				
			||||||
    private int evalUnary(int id, Token tok) {
 | 
					    private int evalUnary(int id, Token tok) {
 | 
				
			||||||
        return evalUnary(-id * 4 + tok.dataType, tok.id);
 | 
					        return evalUnary(-id * 4 + tok.dataType, tok.id);
 | 
				
			||||||
| 
						 | 
					@ -1988,4 +1867,196 @@ public class Breakpoint {
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					    //                            Private Methods                            //
 | 
				
			||||||
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Adjust a float value as needed
 | 
				
			||||||
 | 
					    private static float adjust(float value) {
 | 
				
			||||||
 | 
					        int bits = Float.floatToRawIntBits(value);
 | 
				
			||||||
 | 
					        int exp  = bits & 0x7F800000;
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					            (bits & 0x7FFFFFFF) == 0 || // Zero
 | 
				
			||||||
 | 
					            exp == 0x7F800000        || // Indefinite
 | 
				
			||||||
 | 
					            exp == 0                    // Denormal
 | 
				
			||||||
 | 
					        ? 0 : value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Determine the required stack size to evaluate the expression
 | 
				
			||||||
 | 
					    private int depth() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Error checking
 | 
				
			||||||
 | 
					        if (conditionError.code != NONE)
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Count the maximum size of the stack
 | 
				
			||||||
 | 
					        int max  = 0;
 | 
				
			||||||
 | 
					        int size = 0;
 | 
				
			||||||
 | 
					        for (var tok : tokens) switch (tok.type) {
 | 
				
			||||||
 | 
					            case BINARY: size--; break;
 | 
				
			||||||
 | 
					            case UNARY :         break;
 | 
				
			||||||
 | 
					            default    : max = Math.max(max, ++size);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return max;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Remove the fraction part of a float
 | 
				
			||||||
 | 
					    private static float trunc(float x) {
 | 
				
			||||||
 | 
					        return (float) (x < 0 ? Math.ceil(x) : Math.floor(x));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					    //                           Debugging Methods                           //
 | 
				
			||||||
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Produce a string representation of the condition token list
 | 
				
			||||||
 | 
					    public String debugTokens() {
 | 
				
			||||||
 | 
					        var ret = new StringBuilder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // The condition was not successfully parsed
 | 
				
			||||||
 | 
					        if (conditionError.code != NONE)
 | 
				
			||||||
 | 
					            return "Error";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Determine the maximum width of the text fields
 | 
				
			||||||
 | 
					        int max = 0;
 | 
				
			||||||
 | 
					        for (var tok : tokens)
 | 
				
			||||||
 | 
					            max = Math.max(max, tok.text.length());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Output all tokens
 | 
				
			||||||
 | 
					        var last = tokens[tokens.length - 1];
 | 
				
			||||||
 | 
					        for (var tok : tokens) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Text
 | 
				
			||||||
 | 
					            ret.append(String.format("%-" + max +  "s   ", tok.text));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Type
 | 
				
			||||||
 | 
					            String type = null;
 | 
				
			||||||
 | 
					            switch (tok.type) {
 | 
				
			||||||
 | 
					                case BINARY  : type = "Binary"  ; break;
 | 
				
			||||||
 | 
					                case BOOL    : type = "Bool"    ; break;
 | 
				
			||||||
 | 
					                case FLOAT   : type = "Float"   ; break;
 | 
				
			||||||
 | 
					                case PROREG  : type = "ProReg"  ; break;
 | 
				
			||||||
 | 
					                case SYSREG  : type = "SysReg"  ; break;
 | 
				
			||||||
 | 
					                case SIGNED  : type = "Signed"  ; break;
 | 
				
			||||||
 | 
					                case SYMBOL  : type = "Symbol"  ; break;
 | 
				
			||||||
 | 
					                case UNARY   : type = "Unary"   ; break;
 | 
				
			||||||
 | 
					                case UNSIGNED: type = "Unsigned"; break;
 | 
				
			||||||
 | 
					                default: type = Integer.toString(tok.type);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ret.append(String.format("%-8s   ", type));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Data type
 | 
				
			||||||
 | 
					            switch (tok.dataType) {
 | 
				
			||||||
 | 
					                case BOOL    : type = "Bool"    ; break;
 | 
				
			||||||
 | 
					                case FLOAT   : type = "Float"   ; break;
 | 
				
			||||||
 | 
					                case SIGNED  : type = "Signed"  ; break;
 | 
				
			||||||
 | 
					                case UNSIGNED: type = "Unsigned"; break;
 | 
				
			||||||
 | 
					                default: type = Integer.toString(tok.dataType);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ret.append(String.format("%-8s   ", type));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Operator
 | 
				
			||||||
 | 
					            if (tok.type == BINARY || tok.type == UNARY) {
 | 
				
			||||||
 | 
					                String id = Integer.toString(tok.id);
 | 
				
			||||||
 | 
					                switch (-tok.id / 4) {
 | 
				
			||||||
 | 
					                    case 0        : id = "REINTERPRET"; break;
 | 
				
			||||||
 | 
					                    case READ8    : id = "READ8"      ; break;
 | 
				
			||||||
 | 
					                    case READ16   : id = "READ16"     ; break;
 | 
				
			||||||
 | 
					                    case READ32   : id = "READ32"     ; break;
 | 
				
			||||||
 | 
					                    case ADD      : id = "ADD"        ; break;
 | 
				
			||||||
 | 
					                    case AND_B    : id = "AND_B"      ; break;
 | 
				
			||||||
 | 
					                    case AND_L    : id = "AND_L"      ; break;
 | 
				
			||||||
 | 
					                    case BOOL_    : id = "BOOL_"      ; break;
 | 
				
			||||||
 | 
					                    case CEIL     : id = "CEIL"       ; break;
 | 
				
			||||||
 | 
					                    case DIVIDE   : id = "DIVIDE"     ; break;
 | 
				
			||||||
 | 
					                    case EQUAL    : id = "EQUAL"      ; break;
 | 
				
			||||||
 | 
					                    case FLOAT_   : id = "FLOAT_"     ; break;
 | 
				
			||||||
 | 
					                    case FLOOR    : id = "FLOOR"      ; break;
 | 
				
			||||||
 | 
					                    case GREATER  : id = "GREATER"    ; break;
 | 
				
			||||||
 | 
					                    case GREQUAL  : id = "GREQUAL"    ; break;
 | 
				
			||||||
 | 
					                    case LEFT_L   : id = "LEFT_L"     ; break;
 | 
				
			||||||
 | 
					                    case LEQUAL   : id = "LEQUAL"     ; break;
 | 
				
			||||||
 | 
					                    case LESS     : id = "LESS"       ; break;
 | 
				
			||||||
 | 
					                    case MULTIPLY : id = "MULTIPLY"   ; break;
 | 
				
			||||||
 | 
					                    case NEQUAL   : id = "NEQUAL"     ; break;
 | 
				
			||||||
 | 
					                    case NOT_B    : id = "NOT_B"      ; break;
 | 
				
			||||||
 | 
					                    case NOT_L    : id = "NOT_L"      ; break;
 | 
				
			||||||
 | 
					                    case NEGATE   : id = "NEGATE"     ; break;
 | 
				
			||||||
 | 
					                    case OR_B     : id = "OR_B"       ; break;
 | 
				
			||||||
 | 
					                    case OR_L     : id = "OR_L"       ; break;
 | 
				
			||||||
 | 
					                    case REMAINDER: id = "REMAINDER"  ; break;
 | 
				
			||||||
 | 
					                    case RIGHT_A  : id = "RIGHT_A"    ; break;
 | 
				
			||||||
 | 
					                    case RIGHT_L  : id = "RIGHT_L"    ; break;
 | 
				
			||||||
 | 
					                    case ROUND    : id = "ROUND"      ; break;
 | 
				
			||||||
 | 
					                    case S8       : id = "S8"         ; break;
 | 
				
			||||||
 | 
					                    case S16      : id = "S16"        ; break;
 | 
				
			||||||
 | 
					                    case S32      : id = "S32"        ; break;
 | 
				
			||||||
 | 
					                    case SUBTRACT : id = "SUBTRACT"   ; break;
 | 
				
			||||||
 | 
					                    case TRUNC    : id = "TRUNC"      ; break;
 | 
				
			||||||
 | 
					                    case U8       : id = "U8"         ; break;
 | 
				
			||||||
 | 
					                    case U16      : id = "U16"        ; break;
 | 
				
			||||||
 | 
					                    case U32      : id = "U32"        ; break;
 | 
				
			||||||
 | 
					                    case XFLOAT   : id = "XFLOAT"     ; break;
 | 
				
			||||||
 | 
					                    case XOR_B    : id = "XOR_B"      ; break;
 | 
				
			||||||
 | 
					                    case XOR_L    : id = "XOR_L"      ; break;
 | 
				
			||||||
 | 
					                    case XS32     : id = "XS32"       ; break;
 | 
				
			||||||
 | 
					                    case XU32     : id = "XU32"       ; break;
 | 
				
			||||||
 | 
					                    default: ret.append(Integer.toString(tok.id));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                ret.append(String.format("%-11s", id));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Symbol or literal
 | 
				
			||||||
 | 
					            else switch (tok.type) {
 | 
				
			||||||
 | 
					                case PROREG:
 | 
				
			||||||
 | 
					                case SYSREG:
 | 
				
			||||||
 | 
					                case SYMBOL:
 | 
				
			||||||
 | 
					                    ret.append(Integer.toString(tok.id));
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case FLOAT:
 | 
				
			||||||
 | 
					                    ret.append(String.format("%.6f",
 | 
				
			||||||
 | 
					                        Float.intBitsToFloat(tok.id)));
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case BOOL:
 | 
				
			||||||
 | 
					                case SIGNED:
 | 
				
			||||||
 | 
					                    ret.append(Integer.toString(tok.id));
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case UNSIGNED:
 | 
				
			||||||
 | 
					                    ret.append(Long.toString(tok.id & 0xFFFFFFFFL));
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                default: ret.append("Error");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Advance to the next line
 | 
				
			||||||
 | 
					            if (tok != last)
 | 
				
			||||||
 | 
					                ret.append("\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return ret.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Produce a string representation of the internal address ranges
 | 
				
			||||||
 | 
					    public String debugRanges() {
 | 
				
			||||||
 | 
					        var ret = new StringBuilder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // The address ranges were not successfully parsed
 | 
				
			||||||
 | 
					        if (addressError.code != NONE)
 | 
				
			||||||
 | 
					            return "Error";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Process ranges
 | 
				
			||||||
 | 
					        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]));
 | 
				
			||||||
 | 
					            if (range[0] != range[1])
 | 
				
			||||||
 | 
					                ret.append(String.format("-%08X", range[1]));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ret.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@ class CPU {
 | 
				
			||||||
    // Package fields
 | 
					    // Package fields
 | 
				
			||||||
    Access      access;    // Access state
 | 
					    Access      access;    // Access state
 | 
				
			||||||
    int         cycles;    // Cycles until next stage
 | 
					    int         cycles;    // Cycles until next stage
 | 
				
			||||||
    Ecxeption   exception; // Exception state
 | 
					    int         exception; // Exception code
 | 
				
			||||||
    int         fetch;     // Fetch unit index
 | 
					    int         fetch;     // Fetch unit index
 | 
				
			||||||
    Instruction inst;      // Instruction state
 | 
					    Instruction inst;      // Instruction state
 | 
				
			||||||
    int         irq;       // Interrupt lines
 | 
					    int         irq;       // Interrupt lines
 | 
				
			||||||
| 
						 | 
					@ -97,7 +97,6 @@ class CPU {
 | 
				
			||||||
    // Default constructor
 | 
					    // Default constructor
 | 
				
			||||||
    CPU(JavaVue vue) {
 | 
					    CPU(JavaVue vue) {
 | 
				
			||||||
        access    = new Access();
 | 
					        access    = new Access();
 | 
				
			||||||
        exception = new Ecxeption();
 | 
					 | 
				
			||||||
        inst      = new Instruction();
 | 
					        inst      = new Instruction();
 | 
				
			||||||
        jumpFrom  = new int[3];
 | 
					        jumpFrom  = new int[3];
 | 
				
			||||||
        jumpTo    = new int[3];
 | 
					        jumpTo    = new int[3];
 | 
				
			||||||
| 
						 | 
					@ -114,28 +113,27 @@ class CPU {
 | 
				
			||||||
    // Process the simulation
 | 
					    // Process the simulation
 | 
				
			||||||
    void emulate(int cycles) {
 | 
					    void emulate(int cycles) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The CPU is halting
 | 
					        // The CPU is in fatal halt status
 | 
				
			||||||
        if (stage == HALT || stage == FATAL)
 | 
					        if (stage == FATAL)
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
this.cycles = 0; // DEBUG: Stop processing after execute
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Process for the given number of cycles
 | 
					        // Process for the given number of cycles
 | 
				
			||||||
        for (;;) {
 | 
					        for (;;) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // The next event occurs after the given number of cycles
 | 
					            // The next stage occurs after the given number of cycles
 | 
				
			||||||
            if (this.cycles > cycles) {
 | 
					            if (this.cycles > cycles) {
 | 
				
			||||||
                this.cycles -= cycles;
 | 
					                this.cycles -= cycles;
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Processing by stage
 | 
					            // Processing by stage
 | 
				
			||||||
 | 
					            cycles     -= this.cycles;
 | 
				
			||||||
            this.cycles = 0;
 | 
					            this.cycles = 0;
 | 
				
			||||||
            switch (stage) {
 | 
					            switch (stage) {
 | 
				
			||||||
                case EXCEPTION: if (exception()) return; break;
 | 
					                case EXCEPTION: if (exception()) return; break;
 | 
				
			||||||
                case EXECUTE  : if (execute  ()) return; break;
 | 
					                case EXECUTE  : if (execute  ()) return; break;
 | 
				
			||||||
                case FETCH    : if (fetch    ()) return; break;
 | 
					                case FETCH    : if (fetch    ()) return; break;
 | 
				
			||||||
                case HALT     : if (testException()) return; break;
 | 
					                case HALT     : testException(); return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -178,8 +176,8 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Configure instance fields
 | 
					        // Configure instance fields
 | 
				
			||||||
        cycles    =  0;
 | 
					        cycles    =  0;
 | 
				
			||||||
        exception.code = 0;
 | 
					        exception =  0;
 | 
				
			||||||
        fetch          = 0;
 | 
					        fetch     = -1;
 | 
				
			||||||
        irq       =  0;
 | 
					        irq       =  0;
 | 
				
			||||||
        stage     = FETCH;
 | 
					        stage     = FETCH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -257,11 +255,10 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
        return 1; // Unreachable
 | 
					        return 1; // Unreachable
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Determine the number of CPU cycles until something can happen
 | 
					    // Determine the number of CPU cycles until a breakpoint could trigger
 | 
				
			||||||
    int until(int cycles) {
 | 
					    int until(int cycles) {
 | 
				
			||||||
        if (stage == FATAL || stage == HALT)
 | 
					        return stage == FATAL || stage == HALT ?
 | 
				
			||||||
            return cycles;
 | 
					            cycles : Math.min(cycles, this.cycles);
 | 
				
			||||||
        return cycles < 0 ? this.cycles : Math.min(cycles, this.cycles);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -273,19 +270,18 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
    // Operations for exception stage
 | 
					    // Operations for exception stage
 | 
				
			||||||
    private boolean exception() {
 | 
					    private boolean exception() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Application callback
 | 
					        // Check for breakpoints
 | 
				
			||||||
        vue.breakCode = vue.onException() ? 1 : 0;
 | 
					        if (vue.onBreakpoint(Breakpoint.EXCEPTION))
 | 
				
			||||||
        if (vue.breakCode != 0)
 | 
					 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Configure working variables
 | 
					        // Configure working variables
 | 
				
			||||||
        exception.code &= 0xFFFF;
 | 
					        exception    &= 0xFFFF;
 | 
				
			||||||
        boolean isIRQ   = (exception.code & 0xFF00) == 0xFE00;
 | 
					        boolean isIRQ = (exception & 0xFF00) == 0xFE00;
 | 
				
			||||||
        int     psw   = getSystemRegister(Vue.PSW);
 | 
					        int     psw   = getSystemRegister(Vue.PSW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Fatal exception
 | 
					        // Fatal exception
 | 
				
			||||||
        if (psw_np != 0) {
 | 
					        if (psw_np != 0) {
 | 
				
			||||||
            vue.write(0x00000000, Vue.S32, 0xFFFF0000 | exception.code);
 | 
					            vue.write(0x00000000, Vue.S32, 0xFFFF0000 | exception);
 | 
				
			||||||
            vue.write(0x00000004, Vue.S32, psw);
 | 
					            vue.write(0x00000004, Vue.S32, psw);
 | 
				
			||||||
            vue.write(0x00000008, Vue.S32, pc);
 | 
					            vue.write(0x00000008, Vue.S32, pc);
 | 
				
			||||||
            stage = FATAL;
 | 
					            stage = FATAL;
 | 
				
			||||||
| 
						 | 
					@ -294,7 +290,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Duplexed exception
 | 
					        // Duplexed exception
 | 
				
			||||||
        if (psw_ep != 0) {
 | 
					        if (psw_ep != 0) {
 | 
				
			||||||
            ecr_fecc = exception.code;
 | 
					            ecr_fecc = exception;
 | 
				
			||||||
            fepc     = pc;
 | 
					            fepc     = pc;
 | 
				
			||||||
            fepsw    = psw;
 | 
					            fepsw    = psw;
 | 
				
			||||||
            psw_np   = 1;
 | 
					            psw_np   = 1;
 | 
				
			||||||
| 
						 | 
					@ -303,25 +299,25 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Regular exception
 | 
					        // Regular exception
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            ecr_eicc = exception.code;
 | 
					            ecr_eicc = exception;
 | 
				
			||||||
            eipc     = pc;
 | 
					            eipc     = pc;
 | 
				
			||||||
            eipsw    = psw;
 | 
					            eipsw    = psw;
 | 
				
			||||||
            psw_ep   = 1;
 | 
					            psw_ep   = 1;
 | 
				
			||||||
            pc       = 0xFFFF0000 | exception.code & 0xFFF0;
 | 
					            pc       = 0xFFFF0000 | exception & 0xFFF0;
 | 
				
			||||||
            if (pc == 0xFFFFFF70) // FIV
 | 
					            if (pc == 0xFFFFFF70) // FIV
 | 
				
			||||||
                pc = 0xFFFFFF60;
 | 
					                pc = 0xFFFFFF60;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Interrupt
 | 
					        // Interrupt
 | 
				
			||||||
        if (isIRQ) {
 | 
					        if (isIRQ) {
 | 
				
			||||||
            psw_i = Math.min(15, exception.code >> 4 & 15);
 | 
					            psw_i = Math.min(15, exception >> 4 & 15);
 | 
				
			||||||
            if (stage == HALT)
 | 
					            if (stage == HALT)
 | 
				
			||||||
                pc += 2;
 | 
					                pc += 2;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Common processing
 | 
					        // Common processing
 | 
				
			||||||
        cycles    = 0; // TODO: Determine the actual number
 | 
					        cycles    = 0; // TODO: Determine the actual number
 | 
				
			||||||
        exception.code = 0;
 | 
					        exception = 0;
 | 
				
			||||||
        psw_ae    = 0;
 | 
					        psw_ae    = 0;
 | 
				
			||||||
        psw_id    = 1;
 | 
					        psw_id    = 1;
 | 
				
			||||||
        stage     = FETCH;
 | 
					        stage     = FETCH;
 | 
				
			||||||
| 
						 | 
					@ -331,9 +327,8 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
    // Operations for execute stage
 | 
					    // Operations for execute stage
 | 
				
			||||||
    private boolean execute() {
 | 
					    private boolean execute() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Application callback
 | 
					        // Check for breakpoints
 | 
				
			||||||
        vue.breakCode = vue.onExecute() ? 1 : 0;
 | 
					        if (vue.onBreakpoint(Breakpoint.EXECUTE))
 | 
				
			||||||
        if (vue.breakCode != 0)
 | 
					 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Processing by instruction ID
 | 
					        // Processing by instruction ID
 | 
				
			||||||
| 
						 | 
					@ -415,7 +410,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
            case Vue.XORI   : XORI   (); break;
 | 
					            case Vue.XORI   : XORI   (); break;
 | 
				
			||||||
            //case Vue.XORNBSU: XORNBSU(); break;
 | 
					            //case Vue.XORNBSU: XORNBSU(); break;
 | 
				
			||||||
            default: // Invalid instruction
 | 
					            default: // Invalid instruction
 | 
				
			||||||
                exception.code = 0xFF90;
 | 
					                exception = 0xFF90;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // An application break was requested
 | 
					        // An application break was requested
 | 
				
			||||||
| 
						 | 
					@ -423,7 +418,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Common processing
 | 
					        // Common processing
 | 
				
			||||||
        if (exception.code == 0) {
 | 
					        if (exception == 0) {
 | 
				
			||||||
            cycles += CYCLES[inst.id];
 | 
					            cycles += CYCLES[inst.id];
 | 
				
			||||||
            pc     += inst.size;
 | 
					            pc     += inst.size;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -437,9 +432,14 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
    // Operations for fetch stage
 | 
					    // Operations for fetch stage
 | 
				
			||||||
    private boolean fetch() {
 | 
					    private boolean fetch() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Entering the fetch stage
 | 
				
			||||||
 | 
					        if (fetch == -1)
 | 
				
			||||||
 | 
					            fetch = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Read the bits from the bus
 | 
					        // Read the bits from the bus
 | 
				
			||||||
        if (read(pc + (fetch << 1), Vue.U16, fetch))
 | 
					        if (read(pc + (fetch << 1), Vue.U16, fetch))
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
 | 
					        // TODO: Determine how many cycles this takes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // First unit
 | 
					        // First unit
 | 
				
			||||||
        if (fetch == 0) {
 | 
					        if (fetch == 0) {
 | 
				
			||||||
| 
						 | 
					@ -453,7 +453,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
        // Second unit
 | 
					        // Second unit
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            inst.bits |= access.value & 0xFFFF;
 | 
					            inst.bits |= access.value & 0xFFFF;
 | 
				
			||||||
            fetch = 0;
 | 
					            fetch      = -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Decode the instruction and advance to execute stage
 | 
					        // Decode the instruction and advance to execute stage
 | 
				
			||||||
| 
						 | 
					@ -471,9 +471,8 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
        access.type    = type;
 | 
					        access.type    = type;
 | 
				
			||||||
        access.value   = vue.read(address, type);
 | 
					        access.value   = vue.read(address, type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Application callback
 | 
					        // Check for breakpoints
 | 
				
			||||||
        vue.breakCode = vue.onRead() ? 1 : 0;
 | 
					        return vue.onBreakpoint(Breakpoint.READ);
 | 
				
			||||||
        return vue.breakCode != 0;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Test a condition
 | 
					    // Test a condition
 | 
				
			||||||
| 
						 | 
					@ -495,16 +494,16 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
    private boolean testException() {
 | 
					    private boolean testException() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Check for an interrupt
 | 
					        // Check for an interrupt
 | 
				
			||||||
        if (irq != 0 && (exception.code | psw_id | psw_ep | psw_np) == 0) {
 | 
					        if (irq != 0 && (exception | psw_id | psw_ep | psw_np) == 0) {
 | 
				
			||||||
            int level;
 | 
					            int level;
 | 
				
			||||||
            for (level = 4; level >= 0; level--)
 | 
					            for (level = 4; level >= 0; level--)
 | 
				
			||||||
                if ((irq >> level & 1) != 0)
 | 
					                if ((irq >> level & 1) != 0)
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
            exception.code = 0xFE00 | level << 4;
 | 
					            exception = 0xFE00 | level << 4;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // There is no exception
 | 
					        // There is no exception
 | 
				
			||||||
        if (exception.code == 0)
 | 
					        if (exception == 0)
 | 
				
			||||||
            return stage == HALT && cycles == 0; // No further processing
 | 
					            return stage == HALT && cycles == 0; // No further processing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // An exception has occurred
 | 
					        // An exception has occurred
 | 
				
			||||||
| 
						 | 
					@ -522,14 +521,12 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
        access.type    = type;
 | 
					        access.type    = type;
 | 
				
			||||||
        access.value   = value;
 | 
					        access.value   = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Application callback
 | 
					        // Check for breakpoints
 | 
				
			||||||
        vue.breakCode = vue.onWrite() ? 1 : 0;
 | 
					        if (vue.onBreakpoint(Breakpoint.WRITE))
 | 
				
			||||||
        if (vue.breakCode != 0)
 | 
					 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        if (access.type == Vue.CANCEL)
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Perform the operation
 | 
					        // Perform the operation
 | 
				
			||||||
 | 
					        if (access.type != Vue.CANCEL)
 | 
				
			||||||
            vue.write(access.address, access.type, access.value);
 | 
					            vue.write(access.address, access.type, access.value);
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -572,7 +569,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Invalid operation
 | 
					        // Invalid operation
 | 
				
			||||||
        if (value > 0x7FFFFFFF || value < 0x80000000) {
 | 
					        if (value > 0x7FFFFFFF || value < 0x80000000) {
 | 
				
			||||||
            exception.code = 0xFF70;
 | 
					            exception = 0xFF70;
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -599,7 +596,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
            )) continue;
 | 
					            )) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // The value is a reserved operand
 | 
					            // The value is a reserved operand
 | 
				
			||||||
            exception.code = 0xFF60;
 | 
					            exception = 0xFF60;
 | 
				
			||||||
            psw_fro   = 1;
 | 
					            psw_fro   = 1;
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -611,7 +608,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Overflow
 | 
					        // Overflow
 | 
				
			||||||
        if (full > Float.MAX_VALUE || full < -Float.MAX_VALUE) {
 | 
					        if (full > Float.MAX_VALUE || full < -Float.MAX_VALUE) {
 | 
				
			||||||
            exception.code = 0xFF64;
 | 
					            exception = 0xFF64;
 | 
				
			||||||
            psw_fov   = 1;
 | 
					            psw_fov   = 1;
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -803,7 +800,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Zero division
 | 
					        // Zero division
 | 
				
			||||||
        if (right == 0) {
 | 
					        if (right == 0) {
 | 
				
			||||||
            exception.code = 0xFF80;
 | 
					            exception = 0xFF80;
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -837,7 +834,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // An exception has occurred
 | 
					        // An exception has occurred
 | 
				
			||||||
        if (right == 0) {
 | 
					        if (right == 0) {
 | 
				
			||||||
            exception.code = left == 0 ? 0xFF70 : 0xFF68;
 | 
					            exception = left == 0 ? 0xFF70 : 0xFF68;
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -854,7 +851,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Zero division
 | 
					        // Zero division
 | 
				
			||||||
        if (right == 0) {
 | 
					        if (right == 0) {
 | 
				
			||||||
            exception.code = 0xFF80;
 | 
					            exception = 0xFF80;
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1105,7 +1102,7 @@ this.cycles = 0; // DEBUG: Stop processing after execute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Trap
 | 
					    // Trap
 | 
				
			||||||
    private void TRAP() {
 | 
					    private void TRAP() {
 | 
				
			||||||
        exception.code = 0xFFA0 | inst.imm & 31;
 | 
					        exception = 0xFFA0 | inst.imm & 31;
 | 
				
			||||||
        pc += 2;
 | 
					        pc += 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
package vue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Intentionally misspelled to avoid ambiguity with java.lang.Exception
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Exception state
 | 
					 | 
				
			||||||
public class Ecxeption {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Instance fields
 | 
					 | 
				
			||||||
    public int code; // Exception code
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
    //                             Constructors                              //
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Default constructor
 | 
					 | 
				
			||||||
    Ecxeption() { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Cloning constructor
 | 
					 | 
				
			||||||
    Ecxeption(Ecxeption o) {
 | 
					 | 
				
			||||||
        this();
 | 
					 | 
				
			||||||
        code = o.code;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -135,8 +135,12 @@ public class Instruction {
 | 
				
			||||||
            case 2:
 | 
					            case 2:
 | 
				
			||||||
                reg2 = bits >> 21 & 31;
 | 
					                reg2 = bits >> 21 & 31;
 | 
				
			||||||
                imm  = extend < 0 ? bits << 11 >> 27 : bits >> 16 & 31;
 | 
					                imm  = extend < 0 ? bits << 11 >> 27 : bits >> 16 & 31;
 | 
				
			||||||
                if (id == BITSTRING)
 | 
					                if (id == BITSTRING) {
 | 
				
			||||||
                    id = imm >= 16 ? Vue.ILLEGAL : LOOKUP_BITSTRING[imm];
 | 
					                    id = imm >= 16 ? Vue.ILLEGAL : LOOKUP_BITSTRING[imm];
 | 
				
			||||||
 | 
					                    subopcode = imm;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (id == Vue.SETF)
 | 
				
			||||||
 | 
					                    cond = imm & 15;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 3:
 | 
					            case 3:
 | 
				
			||||||
                opcode = 0x20;
 | 
					                opcode = 0x20;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,11 +7,11 @@ import java.util.*;
 | 
				
			||||||
class JavaVue extends Vue {
 | 
					class JavaVue extends Vue {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Package fields
 | 
					    // Package fields
 | 
				
			||||||
    int     breakCode; // Application break code
 | 
					    int     breakCode; // Application breakpoint code
 | 
				
			||||||
 | 
					    int     breakType; // Most recent breakpoint scenario
 | 
				
			||||||
    CPU     cpu;       // Processor
 | 
					    CPU     cpu;       // Processor
 | 
				
			||||||
    int     hook;      // Most recent breakpoint hook
 | 
					 | 
				
			||||||
    GamePak pak;       // Game pak
 | 
					    GamePak pak;       // Game pak
 | 
				
			||||||
    int[]   stack;     // Breakpoint evaluation stack
 | 
					    int[]   stack;     // Breakpoint condition evaluation stack
 | 
				
			||||||
    byte[]  wram;      // System WRAM
 | 
					    byte[]  wram;      // System WRAM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,50 +53,47 @@ class JavaVue extends Vue {
 | 
				
			||||||
        // Process up to the given number of cycles
 | 
					        // Process up to the given number of cycles
 | 
				
			||||||
        do {
 | 
					        do {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Determine the number of cycles during which nothing will happen
 | 
					            // Determine the number of cycles where no breakpoint will occur
 | 
				
			||||||
            int cycles = -1;
 | 
					            int cycles = maxCycles; // min(maxCycles, nextFrameCycles)
 | 
				
			||||||
            cycles = cpu  .until(cycles);
 | 
					            cycles = cpu  .until(cycles);
 | 
				
			||||||
            //cycles = pad  .until(cycles);
 | 
					            //cycles = pad  .until(cycles);
 | 
				
			||||||
            //cycles = link .until(cycles);
 | 
					            //cycles = link .until(cycles);
 | 
				
			||||||
            //cycles = timer.until(cycles);
 | 
					            //cycles = timer.until(cycles);
 | 
				
			||||||
            //cycles = vip  .until(cycles);
 | 
					            //cycles = vip  .until(cycles);
 | 
				
			||||||
            //cycles = vsu  .until(cycles);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Range checking
 | 
					 | 
				
			||||||
            if (cycles == -1)   // No activity on any component
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            if (maxCycles >= 0) // Restrict to given number of cycles
 | 
					 | 
				
			||||||
                cycles = Math.min(cycles, maxCycles);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Process all system components
 | 
					            // Process all system components
 | 
				
			||||||
 | 
					            breakCode = 0;
 | 
				
			||||||
            cpu  .emulate(cycles);
 | 
					            cpu  .emulate(cycles);
 | 
				
			||||||
            //pad  .emulate(cycles);
 | 
					            //pad  .emulate(cycles);
 | 
				
			||||||
            //link .emulate(cycles);
 | 
					            //link .emulate(cycles);
 | 
				
			||||||
            //timer.emulate(cycles);
 | 
					            //timer.emulate(cycles);
 | 
				
			||||||
            //vip  .emulate(cycles);
 | 
					            //vip  .emulate(cycles);
 | 
				
			||||||
            //vsu  .emulate(cycles);
 | 
					            //vsu  .emulate(cycles);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            // An application break was requested
 | 
					 | 
				
			||||||
            //if (...)
 | 
					 | 
				
			||||||
            //    break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Update the number of cycles remaining
 | 
					 | 
				
			||||||
            if (maxCycles >= 0)
 | 
					 | 
				
			||||||
            maxCycles   -= cycles;
 | 
					            maxCycles   -= cycles;
 | 
				
			||||||
        } while (maxCycles != 0);
 | 
					        } while (breakCode == 0 && maxCycles != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // A break condition has occurred
 | 
					        // A break condition has occurred
 | 
				
			||||||
        return Math.max(0, maxCycles);
 | 
					        return maxCycles;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Evaluate an expression
 | 
					    // Retrieve a snapshot of the current state's memory access
 | 
				
			||||||
    public Object evaluate(String expression) {
 | 
					    public Access getAccess() {
 | 
				
			||||||
        return null;
 | 
					        return cpu.access;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve the most recent applicaiton break code
 | 
				
			||||||
 | 
					    public int getBreakCode() {
 | 
				
			||||||
 | 
					        return breakCode;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve the most recent exception code
 | 
					    // Retrieve the most recent exception code
 | 
				
			||||||
    public int getException() {
 | 
					    public int getExceptionCode() {
 | 
				
			||||||
        return cpu.exception.code;
 | 
					        return cpu.exception;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve a snapshot of the current state's instruction
 | 
				
			||||||
 | 
					    public Instruction getInstruction() {
 | 
				
			||||||
 | 
					        return cpu.inst;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve a register value
 | 
					    // Retrieve a register value
 | 
				
			||||||
| 
						 | 
					@ -139,6 +136,12 @@ class JavaVue extends Vue {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read a value from the CPU bus
 | 
					    // Read a value from the CPU bus
 | 
				
			||||||
    public int read(int address, int type) {
 | 
					    public int read(int address, int type) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Error checking
 | 
				
			||||||
 | 
					        if (type < 0 || type > 4)
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Perform the operation
 | 
				
			||||||
        switch (address >> 24 & 7) {
 | 
					        switch (address >> 24 & 7) {
 | 
				
			||||||
            case 5: return readBuffer(wram   , address, type);
 | 
					            case 5: return readBuffer(wram   , address, type);
 | 
				
			||||||
            case 6: return readBuffer(pak.ram, address, type);
 | 
					            case 6: return readBuffer(pak.ram, address, type);
 | 
				
			||||||
| 
						 | 
					@ -250,29 +253,48 @@ class JavaVue extends Vue {
 | 
				
			||||||
    //                            Package Methods                            //
 | 
					    //                            Package Methods                            //
 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Evaluate the condition in a breakpoint
 | 
					    // Retrieve the current state's breakpoint scenario
 | 
				
			||||||
    boolean evaluate(Breakpoint brk) {
 | 
					    int getBreakType() {
 | 
				
			||||||
        return false;
 | 
					        return breakType;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Exception break handler
 | 
					    // Retrieve the current instruction fetch index
 | 
				
			||||||
    boolean onException() {
 | 
					    int getFetch() {
 | 
				
			||||||
        return onHook(Breakpoint.EXCEPTION);
 | 
					        return cpu.fetch;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Execute break handler
 | 
					    // Check for breakpoints
 | 
				
			||||||
    boolean onExecute() {
 | 
					    boolean onBreakpoint(int breakType) {
 | 
				
			||||||
        return onHook(Breakpoint.EXECUTE);
 | 
					        int     end    = 0;
 | 
				
			||||||
 | 
					        boolean ranged = false;
 | 
				
			||||||
 | 
					        int     start  = 0;
 | 
				
			||||||
 | 
					        this.breakType = breakType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Processing for Execute
 | 
				
			||||||
 | 
					        if (breakType == Breakpoint.EXECUTE) {
 | 
				
			||||||
 | 
					            ranged = true;
 | 
				
			||||||
 | 
					            start  = cpu.pc;
 | 
				
			||||||
 | 
					            end    = start + cpu.inst.size - 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read break handler
 | 
					        // Processing for Read and Write
 | 
				
			||||||
    boolean onRead() {
 | 
					        else if (breakType==Breakpoint.READ || breakType==Breakpoint.WRITE) {
 | 
				
			||||||
        return onHook(Breakpoint.READ);
 | 
					            ranged = true;
 | 
				
			||||||
 | 
					            start  = cpu.access.address;
 | 
				
			||||||
 | 
					            end    = start + TYPE_SIZES[cpu.access.type] - 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Write break handler
 | 
					        // Check all breakpoints
 | 
				
			||||||
    boolean onWrite() {
 | 
					        int count = breakpoints.size();
 | 
				
			||||||
        return onHook(Breakpoint.WRITE);
 | 
					        for (int x = 0; breakCode == 0 && x < count; x++) {
 | 
				
			||||||
 | 
					            var brk = breakpoints.get(x);
 | 
				
			||||||
 | 
					            if (
 | 
				
			||||||
 | 
					                brk.appliesTo(breakType)             &&
 | 
				
			||||||
 | 
					                (!ranged || brk.inRange(start, end)) &&
 | 
				
			||||||
 | 
					                brk.isTrue(stack, breakType, cpu.inst, cpu.access)
 | 
				
			||||||
 | 
					            ) breakCode = x + 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return breakCode != 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read a value from a byte buffer
 | 
					    // Read a value from a byte buffer
 | 
				
			||||||
| 
						 | 
					@ -331,6 +353,16 @@ class JavaVue extends Vue {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // A breakpoint's condition tokens have changed
 | 
				
			||||||
 | 
					    void updateTokens(Breakpoint brk) {
 | 
				
			||||||
 | 
					        super.updateTokens(brk);
 | 
				
			||||||
 | 
					        int depth = 0;
 | 
				
			||||||
 | 
					        for (var bre : breakpoints)
 | 
				
			||||||
 | 
					            depth = Math.max(depth, bre.getDepth());
 | 
				
			||||||
 | 
					        if (depth != stack.length)
 | 
				
			||||||
 | 
					            stack = new int[depth];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Write a value to a byte buffer
 | 
					    // Write a value to a byte buffer
 | 
				
			||||||
    static void writeBuffer(byte[] data, int address, int type, int value) {
 | 
					    static void writeBuffer(byte[] data, int address, int type, int value) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -377,19 +409,4 @@ class JavaVue extends Vue {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
    //                            Private Methods                            //
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Check breakpoints during a hooked event
 | 
					 | 
				
			||||||
    private boolean onHook(int hook) {
 | 
					 | 
				
			||||||
        this.hook = hook;
 | 
					 | 
				
			||||||
        for (var brk : breakpoints)
 | 
					 | 
				
			||||||
            if (evaluate(brk))
 | 
					 | 
				
			||||||
                return true;
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,13 +117,20 @@ JNIEXPORT jint JNICALL Java_vue_NativeVue_emulate
 | 
				
			||||||
    return vueEmulate(&core->vue, maxCycles);
 | 
					    return vueEmulate(&core->vue, maxCycles);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Retrieve the application break code
 | 
					// Retrieve the most recent exception code
 | 
				
			||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getBreakCode
 | 
					JNIEXPORT jint JNICALL Java_vue_NativeVue_getBreakCode
 | 
				
			||||||
  (JNIEnv *env, jobject vue, jlong handle) {
 | 
					  (JNIEnv *env, jobject vue, jlong handle) {
 | 
				
			||||||
    Core *core = *(Core **)&handle;
 | 
					    Core *core = *(Core **)&handle;
 | 
				
			||||||
    return vueGetBreakCode(&core->vue);
 | 
					    return vueGetBreakCode(&core->vue);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Retrieve the most recent exception code
 | 
				
			||||||
 | 
					JNIEXPORT jint JNICALL Java_vue_NativeVue_getExceptionCode
 | 
				
			||||||
 | 
					  (JNIEnv *env, jobject vue, jlong handle) {
 | 
				
			||||||
 | 
					    Core *core = *(Core **)&handle;
 | 
				
			||||||
 | 
					    return vueGetExceptionCode(&core->vue);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Retrieve a register value
 | 
					// Retrieve a register value
 | 
				
			||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getRegister
 | 
					JNIEXPORT jint JNICALL Java_vue_NativeVue_getRegister
 | 
				
			||||||
  (JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system) {
 | 
					  (JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@ class NativeVue extends Vue {
 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Produce a new breakpoint and add it to the collection
 | 
					    // Produce a new breakpoint and add it to the collection
 | 
				
			||||||
 | 
					    private native void breakpoint(long handle);
 | 
				
			||||||
    public Breakpoint breakpoint() {
 | 
					    public Breakpoint breakpoint() {
 | 
				
			||||||
        var brk = super.breakpoint();
 | 
					        var brk = super.breakpoint();
 | 
				
			||||||
        breakpoint(handle);
 | 
					        breakpoint(handle);
 | 
				
			||||||
| 
						 | 
					@ -41,14 +42,26 @@ class NativeVue extends Vue {
 | 
				
			||||||
    public int emulate(int maxCycles)
 | 
					    public int emulate(int maxCycles)
 | 
				
			||||||
        { return emulate(handle, maxCycles); }
 | 
					        { return emulate(handle, maxCycles); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve the application break code
 | 
					    // Retrieve a snapshot of the current state's memory access
 | 
				
			||||||
 | 
					    private native Access getAccess(long handle, Access access);
 | 
				
			||||||
 | 
					    public Access getAccess() {
 | 
				
			||||||
 | 
					        return getAccess(handle, new Access());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve the most recent application break code
 | 
				
			||||||
    private native int getBreakCode(long handle);
 | 
					    private native int getBreakCode(long handle);
 | 
				
			||||||
    public int getBreakCode() { return getBreakCode(handle); }
 | 
					    public int getBreakCode() { return getBreakCode(handle); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve the most recent exception code
 | 
					    // Retrieve the most recent exception code
 | 
				
			||||||
    private native int getException(long handle);
 | 
					    private native int getExceptionCode(long handle);
 | 
				
			||||||
    public int getException() {
 | 
					    public int getExceptionCode() {
 | 
				
			||||||
        return getException(handle);
 | 
					        return getExceptionCode(handle);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve a snapshot of the current state's instruction
 | 
				
			||||||
 | 
					    private native Instruction getInstruction(long handle, Instruction inst);
 | 
				
			||||||
 | 
					    public Instruction getInstruction() {
 | 
				
			||||||
 | 
					        return getInstruction(handle, new Instruction());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve a register value
 | 
					    // Retrieve a register value
 | 
				
			||||||
| 
						 | 
					@ -75,6 +88,7 @@ class NativeVue extends Vue {
 | 
				
			||||||
        { return readBytes(handle, address, dest, offset, length); }
 | 
					        { return readBytes(handle, address, dest, offset, length); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Remove a breakpoint from the collection
 | 
					    // Remove a breakpoint from the collection
 | 
				
			||||||
 | 
					    private native void remove(long handle, int index);
 | 
				
			||||||
    public boolean remove(Breakpoint brk) {
 | 
					    public boolean remove(Breakpoint brk) {
 | 
				
			||||||
        int index = breakpoints.indexOf(brk);
 | 
					        int index = breakpoints.indexOf(brk);
 | 
				
			||||||
        if (!super.remove(brk))
 | 
					        if (!super.remove(brk))
 | 
				
			||||||
| 
						 | 
					@ -117,9 +131,16 @@ class NativeVue extends Vue {
 | 
				
			||||||
    //                            Package Methods                            //
 | 
					    //                            Package Methods                            //
 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Evaluate the condition in a breakpoint
 | 
					    // Retrieve the current state's breakpoint scenario
 | 
				
			||||||
    boolean evaluate(Breakpoint brk) {
 | 
					    private native int getBreakType(long handle);
 | 
				
			||||||
        return false;
 | 
					    int getBreakType() {
 | 
				
			||||||
 | 
					        return getBreakType(handle);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve the current instruction fetch index
 | 
				
			||||||
 | 
					    private native int getFetch(long handle);
 | 
				
			||||||
 | 
					    int getFetch() {
 | 
				
			||||||
 | 
					        return getFetch(handle);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // A breakpoint's address ranges have changed
 | 
					    // A breakpoint's address ranges have changed
 | 
				
			||||||
| 
						 | 
					@ -137,16 +158,4 @@ class NativeVue extends Vue {
 | 
				
			||||||
        super.updateTokens(brk);
 | 
					        super.updateTokens(brk);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
    //                            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);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,7 +138,7 @@ public abstract class Vue {
 | 
				
			||||||
    // Produce an emulation core context
 | 
					    // Produce an emulation core context
 | 
				
			||||||
    public static Vue create(boolean useNative) {
 | 
					    public static Vue create(boolean useNative) {
 | 
				
			||||||
        return !useNative ? new JavaVue() :
 | 
					        return !useNative ? new JavaVue() :
 | 
				
			||||||
            isNativeLoaded() ? new NativeVue() : null;
 | 
					            nativeID != null ? new NativeVue() : null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve the ID of the loaded native library, if any
 | 
					    // Retrieve the ID of the loaded native library, if any
 | 
				
			||||||
| 
						 | 
					@ -146,11 +146,6 @@ public abstract class Vue {
 | 
				
			||||||
        return nativeID;
 | 
					        return nativeID;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Determine whether the native module is loaded
 | 
					 | 
				
			||||||
    public static boolean isNativeLoaded() {
 | 
					 | 
				
			||||||
        return nativeID != null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Specify the ID of the loaded native library
 | 
					    // Specify the ID of the loaded native library
 | 
				
			||||||
    public static void setNativeID(String nativeID) {
 | 
					    public static void setNativeID(String nativeID) {
 | 
				
			||||||
        Vue.nativeID = nativeID;
 | 
					        Vue.nativeID = nativeID;
 | 
				
			||||||
| 
						 | 
					@ -180,40 +175,32 @@ public abstract class Vue {
 | 
				
			||||||
        return brk;
 | 
					        return brk;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Evaluate an expression
 | 
					 | 
				
			||||||
    public Object evaluate(String expression) {
 | 
					 | 
				
			||||||
        var brk = new Breakpoint(this);
 | 
					 | 
				
			||||||
        brk.setCondition(expression);
 | 
					 | 
				
			||||||
        return brk.evaluate(null, null, null);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Produce an array of the current breakpoint collection
 | 
					 | 
				
			||||||
    public Breakpoint[] listBreakpoints() {
 | 
					 | 
				
			||||||
        return breakpoints.toArray(new Breakpoint[breakpoints.size()]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Remove a breakpoint from the collection
 | 
					 | 
				
			||||||
    public boolean remove(Breakpoint brk) {
 | 
					 | 
				
			||||||
        if (!breakpoints.remove(brk))
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        brk.remove();
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
    //                           Abstract Methods                            //
 | 
					 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Release any used resources
 | 
					    // Release any used resources
 | 
				
			||||||
    public abstract void dispose();
 | 
					    public abstract void dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Process the simulation
 | 
					    // Process the simulation
 | 
				
			||||||
    public abstract int emulate(int maxCycles);
 | 
					    public abstract int emulate(int maxCycles);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Evaluate an expression
 | 
				
			||||||
 | 
					    public Object evaluate(String expression) {
 | 
				
			||||||
 | 
					        var brk = new Breakpoint(this);
 | 
				
			||||||
 | 
					        brk.setCondition(expression);
 | 
				
			||||||
 | 
					        brk.setEnabled  (true);
 | 
				
			||||||
 | 
					        return brk.evaluateTyped(new int[brk.getDepth()], 0,
 | 
				
			||||||
 | 
					            getInstruction(), getAccess());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve a snapshot of the current state's memory access
 | 
				
			||||||
 | 
					    public abstract Access getAccess();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve the most recent applicaiton break code
 | 
				
			||||||
 | 
					    public abstract int getBreakCode();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve the most recent exception code
 | 
					    // Retrieve the most recent exception code
 | 
				
			||||||
    public abstract int getException();
 | 
					    public abstract int getExceptionCode();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve a snapshot of the current state's instruction
 | 
				
			||||||
 | 
					    public abstract Instruction getInstruction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Retrieve a register value
 | 
					    // Retrieve a register value
 | 
				
			||||||
    public abstract int getRegister(int index, boolean system);
 | 
					    public abstract int getRegister(int index, boolean system);
 | 
				
			||||||
| 
						 | 
					@ -224,6 +211,11 @@ public abstract class Vue {
 | 
				
			||||||
    // Determine whether the context is native-backed
 | 
					    // Determine whether the context is native-backed
 | 
				
			||||||
    public abstract boolean isNative();
 | 
					    public abstract boolean isNative();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Produce an array of the current breakpoint collection
 | 
				
			||||||
 | 
					    public Breakpoint[] listBreakpoints() {
 | 
				
			||||||
 | 
					        return breakpoints.toArray(new Breakpoint[breakpoints.size()]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Read a value from the CPU bus
 | 
					    // Read a value from the CPU bus
 | 
				
			||||||
    public abstract int read(int address, int type);
 | 
					    public abstract int read(int address, int type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -231,6 +223,14 @@ public abstract class Vue {
 | 
				
			||||||
    public abstract boolean readBytes(int address, byte[] dest, int offset,
 | 
					    public abstract boolean readBytes(int address, byte[] dest, int offset,
 | 
				
			||||||
        int length);
 | 
					        int length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Remove a breakpoint from the collection
 | 
				
			||||||
 | 
					    public boolean remove(Breakpoint brk) {
 | 
				
			||||||
 | 
					        if (!breakpoints.remove(brk))
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        brk.remove();
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Initialize all system components
 | 
					    // Initialize all system components
 | 
				
			||||||
    public abstract void reset();
 | 
					    public abstract void reset();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -253,6 +253,12 @@ public abstract class Vue {
 | 
				
			||||||
    //                            Package Methods                            //
 | 
					    //                            Package Methods                            //
 | 
				
			||||||
    ///////////////////////////////////////////////////////////////////////////
 | 
					    ///////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve the current state's breakpoint scenario
 | 
				
			||||||
 | 
					    abstract int getBreakType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Retrieve the current instruction fetch index
 | 
				
			||||||
 | 
					    abstract int getFetch();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // A breakpoint's address ranges have changed
 | 
					    // A breakpoint's address ranges have changed
 | 
				
			||||||
    void updateRanges(Breakpoint brk) { }
 | 
					    void updateRanges(Breakpoint brk) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue