Resetting for web (previous moved to branch old-java)
This commit is contained in:
parent
c6d5332828
commit
4b3852a1d2
|
@ -1,11 +1,14 @@
|
||||||
* text=auto
|
* text=auto
|
||||||
|
|
||||||
*.c text diff=c
|
*.c text diff=c
|
||||||
|
*.css text diff=css
|
||||||
*.h text diff=c
|
*.h text diff=c
|
||||||
*.html text diff=html
|
*.html text diff=html
|
||||||
*.java text diff=java
|
*.java text diff=java
|
||||||
|
*.js text diff=js
|
||||||
*.sample text
|
*.sample text
|
||||||
*.txt text
|
*.txt text
|
||||||
|
|
||||||
*.class binary
|
*.class binary
|
||||||
*.dll binary
|
*.dll binary
|
||||||
|
*.wasm binary
|
||||||
|
|
705
expressions.html
705
expressions.html
|
@ -1,705 +0,0 @@
|
||||||
<!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, .op1 {
|
|
||||||
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 distinguished 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 following
|
|
||||||
restrictions: if the value of any float literal or 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 value
|
|
||||||
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 or to be written 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.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Each operator considers the types of its operands in order to produce a new
|
|
||||||
value of the appropriate type. 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 selects 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 converted to float before performing the operation.
|
|
||||||
</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 according to the order in
|
|
||||||
which they appear in the expression: right-to-left for unary operators,
|
|
||||||
left-to-right for binary operators.
|
|
||||||
</p>
|
|
||||||
<table class="indent bordered">
|
|
||||||
<tr>
|
|
||||||
<td rowSpan="18" class="middle">Unary</td>
|
|
||||||
<td class="mono open op1">~</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 rowSpan="20" class="middle">Binary</td>
|
|
||||||
<td class="mono open op1">/</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 float values.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="mono open">>></td>
|
|
||||||
<td class="open">Shift Right Arithmetic</td>
|
|
||||||
<td class="open">Cannot be used with float values.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="mono">>>></td>
|
|
||||||
<td>Shift Right Logical</td>
|
|
||||||
<td>Cannot be used with float values.</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 float values.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="mono">^</td>
|
|
||||||
<td>Exclusive Or Bitwise</td>
|
|
||||||
<td>Cannot be used with float values.</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="mono">|</td>
|
|
||||||
<td>Or Bitwise</td>
|
|
||||||
<td>Cannot be used with float values.</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>
|
|
||||||
<p>
|
|
||||||
Reads are subjected to the alginment restrictions of the Virtual Boy's CPU:
|
|
||||||
the lowest bit of the address is ignored for halfword reads, and the lowest
|
|
||||||
two bits of the address are ignored for word reads.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h1> </h1>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Binary file not shown.
Before Width: | Height: | Size: 220 B |
|
@ -1,588 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CLASSFILE_CONSTANTS_H
|
|
||||||
#define CLASSFILE_CONSTANTS_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Classfile version number for this information */
|
|
||||||
#define JVM_CLASSFILE_MAJOR_VERSION 59
|
|
||||||
#define JVM_CLASSFILE_MINOR_VERSION 0
|
|
||||||
|
|
||||||
/* Flags */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_ACC_PUBLIC = 0x0001,
|
|
||||||
JVM_ACC_PRIVATE = 0x0002,
|
|
||||||
JVM_ACC_PROTECTED = 0x0004,
|
|
||||||
JVM_ACC_STATIC = 0x0008,
|
|
||||||
JVM_ACC_FINAL = 0x0010,
|
|
||||||
JVM_ACC_SYNCHRONIZED = 0x0020,
|
|
||||||
JVM_ACC_SUPER = 0x0020,
|
|
||||||
JVM_ACC_VOLATILE = 0x0040,
|
|
||||||
JVM_ACC_BRIDGE = 0x0040,
|
|
||||||
JVM_ACC_TRANSIENT = 0x0080,
|
|
||||||
JVM_ACC_VARARGS = 0x0080,
|
|
||||||
JVM_ACC_NATIVE = 0x0100,
|
|
||||||
JVM_ACC_INTERFACE = 0x0200,
|
|
||||||
JVM_ACC_ABSTRACT = 0x0400,
|
|
||||||
JVM_ACC_STRICT = 0x0800,
|
|
||||||
JVM_ACC_SYNTHETIC = 0x1000,
|
|
||||||
JVM_ACC_ANNOTATION = 0x2000,
|
|
||||||
JVM_ACC_ENUM = 0x4000,
|
|
||||||
JVM_ACC_MODULE = 0x8000
|
|
||||||
};
|
|
||||||
|
|
||||||
#define JVM_ACC_PUBLIC_BIT 0
|
|
||||||
#define JVM_ACC_PRIVATE_BIT 1
|
|
||||||
#define JVM_ACC_PROTECTED_BIT 2
|
|
||||||
#define JVM_ACC_STATIC_BIT 3
|
|
||||||
#define JVM_ACC_FINAL_BIT 4
|
|
||||||
#define JVM_ACC_SYNCHRONIZED_BIT 5
|
|
||||||
#define JVM_ACC_SUPER_BIT 5
|
|
||||||
#define JVM_ACC_VOLATILE_BIT 6
|
|
||||||
#define JVM_ACC_BRIDGE_BIT 6
|
|
||||||
#define JVM_ACC_TRANSIENT_BIT 7
|
|
||||||
#define JVM_ACC_VARARGS_BIT 7
|
|
||||||
#define JVM_ACC_NATIVE_BIT 8
|
|
||||||
#define JVM_ACC_INTERFACE_BIT 9
|
|
||||||
#define JVM_ACC_ABSTRACT_BIT 10
|
|
||||||
#define JVM_ACC_STRICT_BIT 11
|
|
||||||
#define JVM_ACC_SYNTHETIC_BIT 12
|
|
||||||
#define JVM_ACC_ANNOTATION_BIT 13
|
|
||||||
#define JVM_ACC_ENUM_BIT 14
|
|
||||||
|
|
||||||
/* Used in newarray instruction. */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_T_BOOLEAN = 4,
|
|
||||||
JVM_T_CHAR = 5,
|
|
||||||
JVM_T_FLOAT = 6,
|
|
||||||
JVM_T_DOUBLE = 7,
|
|
||||||
JVM_T_BYTE = 8,
|
|
||||||
JVM_T_SHORT = 9,
|
|
||||||
JVM_T_INT = 10,
|
|
||||||
JVM_T_LONG = 11
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Constant Pool Entries */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_CONSTANT_Utf8 = 1,
|
|
||||||
JVM_CONSTANT_Unicode = 2, /* unused */
|
|
||||||
JVM_CONSTANT_Integer = 3,
|
|
||||||
JVM_CONSTANT_Float = 4,
|
|
||||||
JVM_CONSTANT_Long = 5,
|
|
||||||
JVM_CONSTANT_Double = 6,
|
|
||||||
JVM_CONSTANT_Class = 7,
|
|
||||||
JVM_CONSTANT_String = 8,
|
|
||||||
JVM_CONSTANT_Fieldref = 9,
|
|
||||||
JVM_CONSTANT_Methodref = 10,
|
|
||||||
JVM_CONSTANT_InterfaceMethodref = 11,
|
|
||||||
JVM_CONSTANT_NameAndType = 12,
|
|
||||||
JVM_CONSTANT_MethodHandle = 15, // JSR 292
|
|
||||||
JVM_CONSTANT_MethodType = 16, // JSR 292
|
|
||||||
JVM_CONSTANT_Dynamic = 17,
|
|
||||||
JVM_CONSTANT_InvokeDynamic = 18,
|
|
||||||
JVM_CONSTANT_Module = 19,
|
|
||||||
JVM_CONSTANT_Package = 20,
|
|
||||||
JVM_CONSTANT_ExternalMax = 20
|
|
||||||
};
|
|
||||||
|
|
||||||
/* JVM_CONSTANT_MethodHandle subtypes */
|
|
||||||
enum {
|
|
||||||
JVM_REF_getField = 1,
|
|
||||||
JVM_REF_getStatic = 2,
|
|
||||||
JVM_REF_putField = 3,
|
|
||||||
JVM_REF_putStatic = 4,
|
|
||||||
JVM_REF_invokeVirtual = 5,
|
|
||||||
JVM_REF_invokeStatic = 6,
|
|
||||||
JVM_REF_invokeSpecial = 7,
|
|
||||||
JVM_REF_newInvokeSpecial = 8,
|
|
||||||
JVM_REF_invokeInterface = 9
|
|
||||||
};
|
|
||||||
|
|
||||||
/* StackMapTable type item numbers */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_ITEM_Top = 0,
|
|
||||||
JVM_ITEM_Integer = 1,
|
|
||||||
JVM_ITEM_Float = 2,
|
|
||||||
JVM_ITEM_Double = 3,
|
|
||||||
JVM_ITEM_Long = 4,
|
|
||||||
JVM_ITEM_Null = 5,
|
|
||||||
JVM_ITEM_UninitializedThis = 6,
|
|
||||||
JVM_ITEM_Object = 7,
|
|
||||||
JVM_ITEM_Uninitialized = 8
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Type signatures */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_SIGNATURE_SLASH = '/',
|
|
||||||
JVM_SIGNATURE_DOT = '.',
|
|
||||||
JVM_SIGNATURE_SPECIAL = '<',
|
|
||||||
JVM_SIGNATURE_ENDSPECIAL = '>',
|
|
||||||
JVM_SIGNATURE_ARRAY = '[',
|
|
||||||
JVM_SIGNATURE_BYTE = 'B',
|
|
||||||
JVM_SIGNATURE_CHAR = 'C',
|
|
||||||
JVM_SIGNATURE_CLASS = 'L',
|
|
||||||
JVM_SIGNATURE_ENDCLASS = ';',
|
|
||||||
JVM_SIGNATURE_ENUM = 'E',
|
|
||||||
JVM_SIGNATURE_FLOAT = 'F',
|
|
||||||
JVM_SIGNATURE_DOUBLE = 'D',
|
|
||||||
JVM_SIGNATURE_FUNC = '(',
|
|
||||||
JVM_SIGNATURE_ENDFUNC = ')',
|
|
||||||
JVM_SIGNATURE_INT = 'I',
|
|
||||||
JVM_SIGNATURE_LONG = 'J',
|
|
||||||
JVM_SIGNATURE_SHORT = 'S',
|
|
||||||
JVM_SIGNATURE_VOID = 'V',
|
|
||||||
JVM_SIGNATURE_BOOLEAN = 'Z'
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Opcodes */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_OPC_nop = 0,
|
|
||||||
JVM_OPC_aconst_null = 1,
|
|
||||||
JVM_OPC_iconst_m1 = 2,
|
|
||||||
JVM_OPC_iconst_0 = 3,
|
|
||||||
JVM_OPC_iconst_1 = 4,
|
|
||||||
JVM_OPC_iconst_2 = 5,
|
|
||||||
JVM_OPC_iconst_3 = 6,
|
|
||||||
JVM_OPC_iconst_4 = 7,
|
|
||||||
JVM_OPC_iconst_5 = 8,
|
|
||||||
JVM_OPC_lconst_0 = 9,
|
|
||||||
JVM_OPC_lconst_1 = 10,
|
|
||||||
JVM_OPC_fconst_0 = 11,
|
|
||||||
JVM_OPC_fconst_1 = 12,
|
|
||||||
JVM_OPC_fconst_2 = 13,
|
|
||||||
JVM_OPC_dconst_0 = 14,
|
|
||||||
JVM_OPC_dconst_1 = 15,
|
|
||||||
JVM_OPC_bipush = 16,
|
|
||||||
JVM_OPC_sipush = 17,
|
|
||||||
JVM_OPC_ldc = 18,
|
|
||||||
JVM_OPC_ldc_w = 19,
|
|
||||||
JVM_OPC_ldc2_w = 20,
|
|
||||||
JVM_OPC_iload = 21,
|
|
||||||
JVM_OPC_lload = 22,
|
|
||||||
JVM_OPC_fload = 23,
|
|
||||||
JVM_OPC_dload = 24,
|
|
||||||
JVM_OPC_aload = 25,
|
|
||||||
JVM_OPC_iload_0 = 26,
|
|
||||||
JVM_OPC_iload_1 = 27,
|
|
||||||
JVM_OPC_iload_2 = 28,
|
|
||||||
JVM_OPC_iload_3 = 29,
|
|
||||||
JVM_OPC_lload_0 = 30,
|
|
||||||
JVM_OPC_lload_1 = 31,
|
|
||||||
JVM_OPC_lload_2 = 32,
|
|
||||||
JVM_OPC_lload_3 = 33,
|
|
||||||
JVM_OPC_fload_0 = 34,
|
|
||||||
JVM_OPC_fload_1 = 35,
|
|
||||||
JVM_OPC_fload_2 = 36,
|
|
||||||
JVM_OPC_fload_3 = 37,
|
|
||||||
JVM_OPC_dload_0 = 38,
|
|
||||||
JVM_OPC_dload_1 = 39,
|
|
||||||
JVM_OPC_dload_2 = 40,
|
|
||||||
JVM_OPC_dload_3 = 41,
|
|
||||||
JVM_OPC_aload_0 = 42,
|
|
||||||
JVM_OPC_aload_1 = 43,
|
|
||||||
JVM_OPC_aload_2 = 44,
|
|
||||||
JVM_OPC_aload_3 = 45,
|
|
||||||
JVM_OPC_iaload = 46,
|
|
||||||
JVM_OPC_laload = 47,
|
|
||||||
JVM_OPC_faload = 48,
|
|
||||||
JVM_OPC_daload = 49,
|
|
||||||
JVM_OPC_aaload = 50,
|
|
||||||
JVM_OPC_baload = 51,
|
|
||||||
JVM_OPC_caload = 52,
|
|
||||||
JVM_OPC_saload = 53,
|
|
||||||
JVM_OPC_istore = 54,
|
|
||||||
JVM_OPC_lstore = 55,
|
|
||||||
JVM_OPC_fstore = 56,
|
|
||||||
JVM_OPC_dstore = 57,
|
|
||||||
JVM_OPC_astore = 58,
|
|
||||||
JVM_OPC_istore_0 = 59,
|
|
||||||
JVM_OPC_istore_1 = 60,
|
|
||||||
JVM_OPC_istore_2 = 61,
|
|
||||||
JVM_OPC_istore_3 = 62,
|
|
||||||
JVM_OPC_lstore_0 = 63,
|
|
||||||
JVM_OPC_lstore_1 = 64,
|
|
||||||
JVM_OPC_lstore_2 = 65,
|
|
||||||
JVM_OPC_lstore_3 = 66,
|
|
||||||
JVM_OPC_fstore_0 = 67,
|
|
||||||
JVM_OPC_fstore_1 = 68,
|
|
||||||
JVM_OPC_fstore_2 = 69,
|
|
||||||
JVM_OPC_fstore_3 = 70,
|
|
||||||
JVM_OPC_dstore_0 = 71,
|
|
||||||
JVM_OPC_dstore_1 = 72,
|
|
||||||
JVM_OPC_dstore_2 = 73,
|
|
||||||
JVM_OPC_dstore_3 = 74,
|
|
||||||
JVM_OPC_astore_0 = 75,
|
|
||||||
JVM_OPC_astore_1 = 76,
|
|
||||||
JVM_OPC_astore_2 = 77,
|
|
||||||
JVM_OPC_astore_3 = 78,
|
|
||||||
JVM_OPC_iastore = 79,
|
|
||||||
JVM_OPC_lastore = 80,
|
|
||||||
JVM_OPC_fastore = 81,
|
|
||||||
JVM_OPC_dastore = 82,
|
|
||||||
JVM_OPC_aastore = 83,
|
|
||||||
JVM_OPC_bastore = 84,
|
|
||||||
JVM_OPC_castore = 85,
|
|
||||||
JVM_OPC_sastore = 86,
|
|
||||||
JVM_OPC_pop = 87,
|
|
||||||
JVM_OPC_pop2 = 88,
|
|
||||||
JVM_OPC_dup = 89,
|
|
||||||
JVM_OPC_dup_x1 = 90,
|
|
||||||
JVM_OPC_dup_x2 = 91,
|
|
||||||
JVM_OPC_dup2 = 92,
|
|
||||||
JVM_OPC_dup2_x1 = 93,
|
|
||||||
JVM_OPC_dup2_x2 = 94,
|
|
||||||
JVM_OPC_swap = 95,
|
|
||||||
JVM_OPC_iadd = 96,
|
|
||||||
JVM_OPC_ladd = 97,
|
|
||||||
JVM_OPC_fadd = 98,
|
|
||||||
JVM_OPC_dadd = 99,
|
|
||||||
JVM_OPC_isub = 100,
|
|
||||||
JVM_OPC_lsub = 101,
|
|
||||||
JVM_OPC_fsub = 102,
|
|
||||||
JVM_OPC_dsub = 103,
|
|
||||||
JVM_OPC_imul = 104,
|
|
||||||
JVM_OPC_lmul = 105,
|
|
||||||
JVM_OPC_fmul = 106,
|
|
||||||
JVM_OPC_dmul = 107,
|
|
||||||
JVM_OPC_idiv = 108,
|
|
||||||
JVM_OPC_ldiv = 109,
|
|
||||||
JVM_OPC_fdiv = 110,
|
|
||||||
JVM_OPC_ddiv = 111,
|
|
||||||
JVM_OPC_irem = 112,
|
|
||||||
JVM_OPC_lrem = 113,
|
|
||||||
JVM_OPC_frem = 114,
|
|
||||||
JVM_OPC_drem = 115,
|
|
||||||
JVM_OPC_ineg = 116,
|
|
||||||
JVM_OPC_lneg = 117,
|
|
||||||
JVM_OPC_fneg = 118,
|
|
||||||
JVM_OPC_dneg = 119,
|
|
||||||
JVM_OPC_ishl = 120,
|
|
||||||
JVM_OPC_lshl = 121,
|
|
||||||
JVM_OPC_ishr = 122,
|
|
||||||
JVM_OPC_lshr = 123,
|
|
||||||
JVM_OPC_iushr = 124,
|
|
||||||
JVM_OPC_lushr = 125,
|
|
||||||
JVM_OPC_iand = 126,
|
|
||||||
JVM_OPC_land = 127,
|
|
||||||
JVM_OPC_ior = 128,
|
|
||||||
JVM_OPC_lor = 129,
|
|
||||||
JVM_OPC_ixor = 130,
|
|
||||||
JVM_OPC_lxor = 131,
|
|
||||||
JVM_OPC_iinc = 132,
|
|
||||||
JVM_OPC_i2l = 133,
|
|
||||||
JVM_OPC_i2f = 134,
|
|
||||||
JVM_OPC_i2d = 135,
|
|
||||||
JVM_OPC_l2i = 136,
|
|
||||||
JVM_OPC_l2f = 137,
|
|
||||||
JVM_OPC_l2d = 138,
|
|
||||||
JVM_OPC_f2i = 139,
|
|
||||||
JVM_OPC_f2l = 140,
|
|
||||||
JVM_OPC_f2d = 141,
|
|
||||||
JVM_OPC_d2i = 142,
|
|
||||||
JVM_OPC_d2l = 143,
|
|
||||||
JVM_OPC_d2f = 144,
|
|
||||||
JVM_OPC_i2b = 145,
|
|
||||||
JVM_OPC_i2c = 146,
|
|
||||||
JVM_OPC_i2s = 147,
|
|
||||||
JVM_OPC_lcmp = 148,
|
|
||||||
JVM_OPC_fcmpl = 149,
|
|
||||||
JVM_OPC_fcmpg = 150,
|
|
||||||
JVM_OPC_dcmpl = 151,
|
|
||||||
JVM_OPC_dcmpg = 152,
|
|
||||||
JVM_OPC_ifeq = 153,
|
|
||||||
JVM_OPC_ifne = 154,
|
|
||||||
JVM_OPC_iflt = 155,
|
|
||||||
JVM_OPC_ifge = 156,
|
|
||||||
JVM_OPC_ifgt = 157,
|
|
||||||
JVM_OPC_ifle = 158,
|
|
||||||
JVM_OPC_if_icmpeq = 159,
|
|
||||||
JVM_OPC_if_icmpne = 160,
|
|
||||||
JVM_OPC_if_icmplt = 161,
|
|
||||||
JVM_OPC_if_icmpge = 162,
|
|
||||||
JVM_OPC_if_icmpgt = 163,
|
|
||||||
JVM_OPC_if_icmple = 164,
|
|
||||||
JVM_OPC_if_acmpeq = 165,
|
|
||||||
JVM_OPC_if_acmpne = 166,
|
|
||||||
JVM_OPC_goto = 167,
|
|
||||||
JVM_OPC_jsr = 168,
|
|
||||||
JVM_OPC_ret = 169,
|
|
||||||
JVM_OPC_tableswitch = 170,
|
|
||||||
JVM_OPC_lookupswitch = 171,
|
|
||||||
JVM_OPC_ireturn = 172,
|
|
||||||
JVM_OPC_lreturn = 173,
|
|
||||||
JVM_OPC_freturn = 174,
|
|
||||||
JVM_OPC_dreturn = 175,
|
|
||||||
JVM_OPC_areturn = 176,
|
|
||||||
JVM_OPC_return = 177,
|
|
||||||
JVM_OPC_getstatic = 178,
|
|
||||||
JVM_OPC_putstatic = 179,
|
|
||||||
JVM_OPC_getfield = 180,
|
|
||||||
JVM_OPC_putfield = 181,
|
|
||||||
JVM_OPC_invokevirtual = 182,
|
|
||||||
JVM_OPC_invokespecial = 183,
|
|
||||||
JVM_OPC_invokestatic = 184,
|
|
||||||
JVM_OPC_invokeinterface = 185,
|
|
||||||
JVM_OPC_invokedynamic = 186,
|
|
||||||
JVM_OPC_new = 187,
|
|
||||||
JVM_OPC_newarray = 188,
|
|
||||||
JVM_OPC_anewarray = 189,
|
|
||||||
JVM_OPC_arraylength = 190,
|
|
||||||
JVM_OPC_athrow = 191,
|
|
||||||
JVM_OPC_checkcast = 192,
|
|
||||||
JVM_OPC_instanceof = 193,
|
|
||||||
JVM_OPC_monitorenter = 194,
|
|
||||||
JVM_OPC_monitorexit = 195,
|
|
||||||
JVM_OPC_wide = 196,
|
|
||||||
JVM_OPC_multianewarray = 197,
|
|
||||||
JVM_OPC_ifnull = 198,
|
|
||||||
JVM_OPC_ifnonnull = 199,
|
|
||||||
JVM_OPC_goto_w = 200,
|
|
||||||
JVM_OPC_jsr_w = 201,
|
|
||||||
JVM_OPC_MAX = 201
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Opcode length initializer, use with something like:
|
|
||||||
* unsigned char opcode_length[JVM_OPC_MAX+1] = JVM_OPCODE_LENGTH_INITIALIZER;
|
|
||||||
*/
|
|
||||||
#define JVM_OPCODE_LENGTH_INITIALIZER { \
|
|
||||||
1, /* nop */ \
|
|
||||||
1, /* aconst_null */ \
|
|
||||||
1, /* iconst_m1 */ \
|
|
||||||
1, /* iconst_0 */ \
|
|
||||||
1, /* iconst_1 */ \
|
|
||||||
1, /* iconst_2 */ \
|
|
||||||
1, /* iconst_3 */ \
|
|
||||||
1, /* iconst_4 */ \
|
|
||||||
1, /* iconst_5 */ \
|
|
||||||
1, /* lconst_0 */ \
|
|
||||||
1, /* lconst_1 */ \
|
|
||||||
1, /* fconst_0 */ \
|
|
||||||
1, /* fconst_1 */ \
|
|
||||||
1, /* fconst_2 */ \
|
|
||||||
1, /* dconst_0 */ \
|
|
||||||
1, /* dconst_1 */ \
|
|
||||||
2, /* bipush */ \
|
|
||||||
3, /* sipush */ \
|
|
||||||
2, /* ldc */ \
|
|
||||||
3, /* ldc_w */ \
|
|
||||||
3, /* ldc2_w */ \
|
|
||||||
2, /* iload */ \
|
|
||||||
2, /* lload */ \
|
|
||||||
2, /* fload */ \
|
|
||||||
2, /* dload */ \
|
|
||||||
2, /* aload */ \
|
|
||||||
1, /* iload_0 */ \
|
|
||||||
1, /* iload_1 */ \
|
|
||||||
1, /* iload_2 */ \
|
|
||||||
1, /* iload_3 */ \
|
|
||||||
1, /* lload_0 */ \
|
|
||||||
1, /* lload_1 */ \
|
|
||||||
1, /* lload_2 */ \
|
|
||||||
1, /* lload_3 */ \
|
|
||||||
1, /* fload_0 */ \
|
|
||||||
1, /* fload_1 */ \
|
|
||||||
1, /* fload_2 */ \
|
|
||||||
1, /* fload_3 */ \
|
|
||||||
1, /* dload_0 */ \
|
|
||||||
1, /* dload_1 */ \
|
|
||||||
1, /* dload_2 */ \
|
|
||||||
1, /* dload_3 */ \
|
|
||||||
1, /* aload_0 */ \
|
|
||||||
1, /* aload_1 */ \
|
|
||||||
1, /* aload_2 */ \
|
|
||||||
1, /* aload_3 */ \
|
|
||||||
1, /* iaload */ \
|
|
||||||
1, /* laload */ \
|
|
||||||
1, /* faload */ \
|
|
||||||
1, /* daload */ \
|
|
||||||
1, /* aaload */ \
|
|
||||||
1, /* baload */ \
|
|
||||||
1, /* caload */ \
|
|
||||||
1, /* saload */ \
|
|
||||||
2, /* istore */ \
|
|
||||||
2, /* lstore */ \
|
|
||||||
2, /* fstore */ \
|
|
||||||
2, /* dstore */ \
|
|
||||||
2, /* astore */ \
|
|
||||||
1, /* istore_0 */ \
|
|
||||||
1, /* istore_1 */ \
|
|
||||||
1, /* istore_2 */ \
|
|
||||||
1, /* istore_3 */ \
|
|
||||||
1, /* lstore_0 */ \
|
|
||||||
1, /* lstore_1 */ \
|
|
||||||
1, /* lstore_2 */ \
|
|
||||||
1, /* lstore_3 */ \
|
|
||||||
1, /* fstore_0 */ \
|
|
||||||
1, /* fstore_1 */ \
|
|
||||||
1, /* fstore_2 */ \
|
|
||||||
1, /* fstore_3 */ \
|
|
||||||
1, /* dstore_0 */ \
|
|
||||||
1, /* dstore_1 */ \
|
|
||||||
1, /* dstore_2 */ \
|
|
||||||
1, /* dstore_3 */ \
|
|
||||||
1, /* astore_0 */ \
|
|
||||||
1, /* astore_1 */ \
|
|
||||||
1, /* astore_2 */ \
|
|
||||||
1, /* astore_3 */ \
|
|
||||||
1, /* iastore */ \
|
|
||||||
1, /* lastore */ \
|
|
||||||
1, /* fastore */ \
|
|
||||||
1, /* dastore */ \
|
|
||||||
1, /* aastore */ \
|
|
||||||
1, /* bastore */ \
|
|
||||||
1, /* castore */ \
|
|
||||||
1, /* sastore */ \
|
|
||||||
1, /* pop */ \
|
|
||||||
1, /* pop2 */ \
|
|
||||||
1, /* dup */ \
|
|
||||||
1, /* dup_x1 */ \
|
|
||||||
1, /* dup_x2 */ \
|
|
||||||
1, /* dup2 */ \
|
|
||||||
1, /* dup2_x1 */ \
|
|
||||||
1, /* dup2_x2 */ \
|
|
||||||
1, /* swap */ \
|
|
||||||
1, /* iadd */ \
|
|
||||||
1, /* ladd */ \
|
|
||||||
1, /* fadd */ \
|
|
||||||
1, /* dadd */ \
|
|
||||||
1, /* isub */ \
|
|
||||||
1, /* lsub */ \
|
|
||||||
1, /* fsub */ \
|
|
||||||
1, /* dsub */ \
|
|
||||||
1, /* imul */ \
|
|
||||||
1, /* lmul */ \
|
|
||||||
1, /* fmul */ \
|
|
||||||
1, /* dmul */ \
|
|
||||||
1, /* idiv */ \
|
|
||||||
1, /* ldiv */ \
|
|
||||||
1, /* fdiv */ \
|
|
||||||
1, /* ddiv */ \
|
|
||||||
1, /* irem */ \
|
|
||||||
1, /* lrem */ \
|
|
||||||
1, /* frem */ \
|
|
||||||
1, /* drem */ \
|
|
||||||
1, /* ineg */ \
|
|
||||||
1, /* lneg */ \
|
|
||||||
1, /* fneg */ \
|
|
||||||
1, /* dneg */ \
|
|
||||||
1, /* ishl */ \
|
|
||||||
1, /* lshl */ \
|
|
||||||
1, /* ishr */ \
|
|
||||||
1, /* lshr */ \
|
|
||||||
1, /* iushr */ \
|
|
||||||
1, /* lushr */ \
|
|
||||||
1, /* iand */ \
|
|
||||||
1, /* land */ \
|
|
||||||
1, /* ior */ \
|
|
||||||
1, /* lor */ \
|
|
||||||
1, /* ixor */ \
|
|
||||||
1, /* lxor */ \
|
|
||||||
3, /* iinc */ \
|
|
||||||
1, /* i2l */ \
|
|
||||||
1, /* i2f */ \
|
|
||||||
1, /* i2d */ \
|
|
||||||
1, /* l2i */ \
|
|
||||||
1, /* l2f */ \
|
|
||||||
1, /* l2d */ \
|
|
||||||
1, /* f2i */ \
|
|
||||||
1, /* f2l */ \
|
|
||||||
1, /* f2d */ \
|
|
||||||
1, /* d2i */ \
|
|
||||||
1, /* d2l */ \
|
|
||||||
1, /* d2f */ \
|
|
||||||
1, /* i2b */ \
|
|
||||||
1, /* i2c */ \
|
|
||||||
1, /* i2s */ \
|
|
||||||
1, /* lcmp */ \
|
|
||||||
1, /* fcmpl */ \
|
|
||||||
1, /* fcmpg */ \
|
|
||||||
1, /* dcmpl */ \
|
|
||||||
1, /* dcmpg */ \
|
|
||||||
3, /* ifeq */ \
|
|
||||||
3, /* ifne */ \
|
|
||||||
3, /* iflt */ \
|
|
||||||
3, /* ifge */ \
|
|
||||||
3, /* ifgt */ \
|
|
||||||
3, /* ifle */ \
|
|
||||||
3, /* if_icmpeq */ \
|
|
||||||
3, /* if_icmpne */ \
|
|
||||||
3, /* if_icmplt */ \
|
|
||||||
3, /* if_icmpge */ \
|
|
||||||
3, /* if_icmpgt */ \
|
|
||||||
3, /* if_icmple */ \
|
|
||||||
3, /* if_acmpeq */ \
|
|
||||||
3, /* if_acmpne */ \
|
|
||||||
3, /* goto */ \
|
|
||||||
3, /* jsr */ \
|
|
||||||
2, /* ret */ \
|
|
||||||
99, /* tableswitch */ \
|
|
||||||
99, /* lookupswitch */ \
|
|
||||||
1, /* ireturn */ \
|
|
||||||
1, /* lreturn */ \
|
|
||||||
1, /* freturn */ \
|
|
||||||
1, /* dreturn */ \
|
|
||||||
1, /* areturn */ \
|
|
||||||
1, /* return */ \
|
|
||||||
3, /* getstatic */ \
|
|
||||||
3, /* putstatic */ \
|
|
||||||
3, /* getfield */ \
|
|
||||||
3, /* putfield */ \
|
|
||||||
3, /* invokevirtual */ \
|
|
||||||
3, /* invokespecial */ \
|
|
||||||
3, /* invokestatic */ \
|
|
||||||
5, /* invokeinterface */ \
|
|
||||||
5, /* invokedynamic */ \
|
|
||||||
3, /* new */ \
|
|
||||||
2, /* newarray */ \
|
|
||||||
3, /* anewarray */ \
|
|
||||||
1, /* arraylength */ \
|
|
||||||
1, /* athrow */ \
|
|
||||||
3, /* checkcast */ \
|
|
||||||
3, /* instanceof */ \
|
|
||||||
1, /* monitorenter */ \
|
|
||||||
1, /* monitorexit */ \
|
|
||||||
0, /* wide */ \
|
|
||||||
4, /* multianewarray */ \
|
|
||||||
3, /* ifnull */ \
|
|
||||||
3, /* ifnonnull */ \
|
|
||||||
5, /* goto_w */ \
|
|
||||||
5 /* jsr_w */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* CLASSFILE_CONSTANTS */
|
|
356
jni/linux/jawt.h
356
jni/linux/jawt.h
|
@ -1,356 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JAVASOFT_JAWT_H_
|
|
||||||
#define _JAVASOFT_JAWT_H_
|
|
||||||
|
|
||||||
#include "jni.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AWT native interface.
|
|
||||||
*
|
|
||||||
* The AWT native interface allows a native C or C++ application a means
|
|
||||||
* by which to access native structures in AWT. This is to facilitate moving
|
|
||||||
* legacy C and C++ applications to Java and to target the needs of the
|
|
||||||
* developers who need to do their own native rendering to canvases
|
|
||||||
* for performance or other reasons.
|
|
||||||
*
|
|
||||||
* Conversely it also provides mechanisms for an application which already
|
|
||||||
* has a native window to provide that to AWT for AWT rendering.
|
|
||||||
*
|
|
||||||
* Since every platform may be different in its native data structures
|
|
||||||
* and APIs for windowing systems the application must necessarily
|
|
||||||
* provided per-platform source and compile and deliver per-platform
|
|
||||||
* native code to use this API.
|
|
||||||
*
|
|
||||||
* These interfaces are not part of the Java SE specification and
|
|
||||||
* a VM is not required to implement this API. However it is strongly
|
|
||||||
* recommended that all implementations which support headful AWT
|
|
||||||
* also support these interfaces.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AWT Native Drawing Surface (JAWT_DrawingSurface).
|
|
||||||
*
|
|
||||||
* For each platform, there is a native drawing surface structure. This
|
|
||||||
* platform-specific structure can be found in jawt_md.h. It is recommended
|
|
||||||
* that additional platforms follow the same model. It is also recommended
|
|
||||||
* that VMs on all platforms support the existing structures in jawt_md.h.
|
|
||||||
*
|
|
||||||
*******************
|
|
||||||
* EXAMPLE OF USAGE:
|
|
||||||
*******************
|
|
||||||
*
|
|
||||||
* In Win32, a programmer wishes to access the HWND of a canvas to perform
|
|
||||||
* native rendering into it. The programmer has declared the paint() method
|
|
||||||
* for their canvas subclass to be native:
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* MyCanvas.java:
|
|
||||||
*
|
|
||||||
* import java.awt.*;
|
|
||||||
*
|
|
||||||
* public class MyCanvas extends Canvas {
|
|
||||||
*
|
|
||||||
* static {
|
|
||||||
* System.loadLibrary("mylib");
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public native void paint(Graphics g);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* myfile.c:
|
|
||||||
*
|
|
||||||
* #include "jawt_md.h"
|
|
||||||
* #include <assert.h>
|
|
||||||
*
|
|
||||||
* JNIEXPORT void JNICALL
|
|
||||||
* Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics)
|
|
||||||
* {
|
|
||||||
* JAWT awt;
|
|
||||||
* JAWT_DrawingSurface* ds;
|
|
||||||
* JAWT_DrawingSurfaceInfo* dsi;
|
|
||||||
* JAWT_Win32DrawingSurfaceInfo* dsi_win;
|
|
||||||
* jboolean result;
|
|
||||||
* jint lock;
|
|
||||||
*
|
|
||||||
* // Get the AWT. Request version 9 to access features in that release.
|
|
||||||
* awt.version = JAWT_VERSION_9;
|
|
||||||
* result = JAWT_GetAWT(env, &awt);
|
|
||||||
* assert(result != JNI_FALSE);
|
|
||||||
*
|
|
||||||
* // Get the drawing surface
|
|
||||||
* ds = awt.GetDrawingSurface(env, canvas);
|
|
||||||
* assert(ds != NULL);
|
|
||||||
*
|
|
||||||
* // Lock the drawing surface
|
|
||||||
* lock = ds->Lock(ds);
|
|
||||||
* assert((lock & JAWT_LOCK_ERROR) == 0);
|
|
||||||
*
|
|
||||||
* // Get the drawing surface info
|
|
||||||
* dsi = ds->GetDrawingSurfaceInfo(ds);
|
|
||||||
*
|
|
||||||
* // Get the platform-specific drawing info
|
|
||||||
* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
|
|
||||||
*
|
|
||||||
* //////////////////////////////
|
|
||||||
* // !!! DO PAINTING HERE !!! //
|
|
||||||
* //////////////////////////////
|
|
||||||
*
|
|
||||||
* // Free the drawing surface info
|
|
||||||
* ds->FreeDrawingSurfaceInfo(dsi);
|
|
||||||
*
|
|
||||||
* // Unlock the drawing surface
|
|
||||||
* ds->Unlock(ds);
|
|
||||||
*
|
|
||||||
* // Free the drawing surface
|
|
||||||
* awt.FreeDrawingSurface(ds);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JAWT_Rectangle
|
|
||||||
* Structure for a native rectangle.
|
|
||||||
*/
|
|
||||||
typedef struct jawt_Rectangle {
|
|
||||||
jint x;
|
|
||||||
jint y;
|
|
||||||
jint width;
|
|
||||||
jint height;
|
|
||||||
} JAWT_Rectangle;
|
|
||||||
|
|
||||||
struct jawt_DrawingSurface;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JAWT_DrawingSurfaceInfo
|
|
||||||
* Structure for containing the underlying drawing information of a component.
|
|
||||||
*/
|
|
||||||
typedef struct jawt_DrawingSurfaceInfo {
|
|
||||||
/*
|
|
||||||
* Pointer to the platform-specific information. This can be safely
|
|
||||||
* cast to a JAWT_Win32DrawingSurfaceInfo on Windows or a
|
|
||||||
* JAWT_X11DrawingSurfaceInfo on Linux and Solaris. On Mac OS X this is a
|
|
||||||
* pointer to a NSObject that conforms to the JAWT_SurfaceLayers
|
|
||||||
* protocol. See jawt_md.h for details.
|
|
||||||
*/
|
|
||||||
void* platformInfo;
|
|
||||||
/* Cached pointer to the underlying drawing surface */
|
|
||||||
struct jawt_DrawingSurface* ds;
|
|
||||||
/* Bounding rectangle of the drawing surface */
|
|
||||||
JAWT_Rectangle bounds;
|
|
||||||
/* Number of rectangles in the clip */
|
|
||||||
jint clipSize;
|
|
||||||
/* Clip rectangle array */
|
|
||||||
JAWT_Rectangle* clip;
|
|
||||||
} JAWT_DrawingSurfaceInfo;
|
|
||||||
|
|
||||||
#define JAWT_LOCK_ERROR 0x00000001
|
|
||||||
#define JAWT_LOCK_CLIP_CHANGED 0x00000002
|
|
||||||
#define JAWT_LOCK_BOUNDS_CHANGED 0x00000004
|
|
||||||
#define JAWT_LOCK_SURFACE_CHANGED 0x00000008
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JAWT_DrawingSurface
|
|
||||||
* Structure for containing the underlying drawing information of a component.
|
|
||||||
* All operations on a JAWT_DrawingSurface MUST be performed from the same
|
|
||||||
* thread as the call to GetDrawingSurface.
|
|
||||||
*/
|
|
||||||
typedef struct jawt_DrawingSurface {
|
|
||||||
/*
|
|
||||||
* Cached reference to the Java environment of the calling thread.
|
|
||||||
* If Lock(), Unlock(), GetDrawingSurfaceInfo() or
|
|
||||||
* FreeDrawingSurfaceInfo() are called from a different thread,
|
|
||||||
* this data member should be set before calling those functions.
|
|
||||||
*/
|
|
||||||
JNIEnv* env;
|
|
||||||
/* Cached reference to the target object */
|
|
||||||
jobject target;
|
|
||||||
/*
|
|
||||||
* Lock the surface of the target component for native rendering.
|
|
||||||
* When finished drawing, the surface must be unlocked with
|
|
||||||
* Unlock(). This function returns a bitmask with one or more of the
|
|
||||||
* following values:
|
|
||||||
*
|
|
||||||
* JAWT_LOCK_ERROR - When an error has occurred and the surface could not
|
|
||||||
* be locked.
|
|
||||||
*
|
|
||||||
* JAWT_LOCK_CLIP_CHANGED - When the clip region has changed.
|
|
||||||
*
|
|
||||||
* JAWT_LOCK_BOUNDS_CHANGED - When the bounds of the surface have changed.
|
|
||||||
*
|
|
||||||
* JAWT_LOCK_SURFACE_CHANGED - When the surface itself has changed
|
|
||||||
*/
|
|
||||||
jint (JNICALL *Lock)
|
|
||||||
(struct jawt_DrawingSurface* ds);
|
|
||||||
/*
|
|
||||||
* Get the drawing surface info.
|
|
||||||
* The value returned may be cached, but the values may change if
|
|
||||||
* additional calls to Lock() or Unlock() are made.
|
|
||||||
* Lock() must be called before this can return a valid value.
|
|
||||||
* Returns NULL if an error has occurred.
|
|
||||||
* When finished with the returned value, FreeDrawingSurfaceInfo must be
|
|
||||||
* called.
|
|
||||||
*/
|
|
||||||
JAWT_DrawingSurfaceInfo* (JNICALL *GetDrawingSurfaceInfo)
|
|
||||||
(struct jawt_DrawingSurface* ds);
|
|
||||||
/*
|
|
||||||
* Free the drawing surface info.
|
|
||||||
*/
|
|
||||||
void (JNICALL *FreeDrawingSurfaceInfo)
|
|
||||||
(JAWT_DrawingSurfaceInfo* dsi);
|
|
||||||
/*
|
|
||||||
* Unlock the drawing surface of the target component for native rendering.
|
|
||||||
*/
|
|
||||||
void (JNICALL *Unlock)
|
|
||||||
(struct jawt_DrawingSurface* ds);
|
|
||||||
} JAWT_DrawingSurface;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JAWT
|
|
||||||
* Structure for containing native AWT functions.
|
|
||||||
*/
|
|
||||||
typedef struct jawt {
|
|
||||||
/*
|
|
||||||
* Version of this structure. This must always be set before
|
|
||||||
* calling JAWT_GetAWT(). It affects the functions returned.
|
|
||||||
* Must be one of the known pre-defined versions.
|
|
||||||
*/
|
|
||||||
jint version;
|
|
||||||
/*
|
|
||||||
* Return a drawing surface from a target jobject. This value
|
|
||||||
* may be cached.
|
|
||||||
* Returns NULL if an error has occurred.
|
|
||||||
* Target must be a java.awt.Component (should be a Canvas
|
|
||||||
* or Window for native rendering).
|
|
||||||
* FreeDrawingSurface() must be called when finished with the
|
|
||||||
* returned JAWT_DrawingSurface.
|
|
||||||
*/
|
|
||||||
JAWT_DrawingSurface* (JNICALL *GetDrawingSurface)
|
|
||||||
(JNIEnv* env, jobject target);
|
|
||||||
/*
|
|
||||||
* Free the drawing surface allocated in GetDrawingSurface.
|
|
||||||
*/
|
|
||||||
void (JNICALL *FreeDrawingSurface)
|
|
||||||
(JAWT_DrawingSurface* ds);
|
|
||||||
/*
|
|
||||||
* Since 1.4
|
|
||||||
* Locks the entire AWT for synchronization purposes
|
|
||||||
*/
|
|
||||||
void (JNICALL *Lock)(JNIEnv* env);
|
|
||||||
/*
|
|
||||||
* Since 1.4
|
|
||||||
* Unlocks the entire AWT for synchronization purposes
|
|
||||||
*/
|
|
||||||
void (JNICALL *Unlock)(JNIEnv* env);
|
|
||||||
/*
|
|
||||||
* Since 1.4
|
|
||||||
* Returns a reference to a java.awt.Component from a native
|
|
||||||
* platform handle. On Windows, this corresponds to an HWND;
|
|
||||||
* on Solaris and Linux, this is a Drawable. For other platforms,
|
|
||||||
* see the appropriate machine-dependent header file for a description.
|
|
||||||
* The reference returned by this function is a local
|
|
||||||
* reference that is only valid in this environment.
|
|
||||||
* This function returns a NULL reference if no component could be
|
|
||||||
* found with matching platform information.
|
|
||||||
*/
|
|
||||||
jobject (JNICALL *GetComponent)(JNIEnv* env, void* platformInfo);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since 9
|
|
||||||
* Creates a java.awt.Frame placed in a native container. Container is
|
|
||||||
* referenced by the native platform handle. For example on Windows this
|
|
||||||
* corresponds to an HWND. For other platforms, see the appropriate
|
|
||||||
* machine-dependent header file for a description. The reference returned
|
|
||||||
* by this function is a local reference that is only valid in this
|
|
||||||
* environment. This function returns a NULL reference if no frame could be
|
|
||||||
* created with matching platform information.
|
|
||||||
*/
|
|
||||||
jobject (JNICALL *CreateEmbeddedFrame) (JNIEnv *env, void* platformInfo);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since 9
|
|
||||||
* Moves and resizes the embedded frame. The new location of the top-left
|
|
||||||
* corner is specified by x and y parameters relative to the native parent
|
|
||||||
* component. The new size is specified by width and height.
|
|
||||||
*
|
|
||||||
* The embedded frame should be created by CreateEmbeddedFrame() method, or
|
|
||||||
* this function will not have any effect.
|
|
||||||
*
|
|
||||||
* java.awt.Component.setLocation() and java.awt.Component.setBounds() for
|
|
||||||
* EmbeddedFrame really don't move it within the native parent. These
|
|
||||||
* methods always locate the embedded frame at (0, 0) for backward
|
|
||||||
* compatibility. To allow moving embedded frames this method was
|
|
||||||
* introduced, and it works just the same way as setLocation() and
|
|
||||||
* setBounds() for usual, non-embedded components.
|
|
||||||
*
|
|
||||||
* Using usual get/setLocation() and get/setBounds() together with this new
|
|
||||||
* method is not recommended.
|
|
||||||
*/
|
|
||||||
void (JNICALL *SetBounds) (JNIEnv *env, jobject embeddedFrame,
|
|
||||||
jint x, jint y, jint w, jint h);
|
|
||||||
/**
|
|
||||||
* Since 9
|
|
||||||
* Synthesize a native message to activate or deactivate an EmbeddedFrame
|
|
||||||
* window depending on the value of parameter doActivate, if "true"
|
|
||||||
* activates the window; otherwise, deactivates the window.
|
|
||||||
*
|
|
||||||
* The embedded frame should be created by CreateEmbeddedFrame() method, or
|
|
||||||
* this function will not have any effect.
|
|
||||||
*/
|
|
||||||
void (JNICALL *SynthesizeWindowActivation) (JNIEnv *env,
|
|
||||||
jobject embeddedFrame, jboolean doActivate);
|
|
||||||
} JAWT;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the AWT native structure. This function returns JNI_FALSE if
|
|
||||||
* an error occurs.
|
|
||||||
*/
|
|
||||||
_JNI_IMPORT_OR_EXPORT_
|
|
||||||
jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Specify one of these constants as the JAWT.version
|
|
||||||
* Specifying an earlier version will limit the available functions to
|
|
||||||
* those provided in that earlier version of JAWT.
|
|
||||||
* See the "Since" note on each API. Methods with no "Since"
|
|
||||||
* may be presumed to be present in JAWT_VERSION_1_3.
|
|
||||||
*/
|
|
||||||
#define JAWT_VERSION_1_3 0x00010003
|
|
||||||
#define JAWT_VERSION_1_4 0x00010004
|
|
||||||
#define JAWT_VERSION_1_7 0x00010007
|
|
||||||
#define JAWT_VERSION_9 0x00090000
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !_JAVASOFT_JAWT_H_ */
|
|
|
@ -1,276 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Java Debug Wire Protocol Transport Service Provider Interface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef JDWPTRANSPORT_H
|
|
||||||
#define JDWPTRANSPORT_H
|
|
||||||
|
|
||||||
#include "jni.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JDWPTRANSPORT_VERSION_1_0 = 0x00010000,
|
|
||||||
JDWPTRANSPORT_VERSION_1_1 = 0x00010001
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct jdwpTransportNativeInterface_;
|
|
||||||
|
|
||||||
struct _jdwpTransportEnv;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
typedef _jdwpTransportEnv jdwpTransportEnv;
|
|
||||||
#else
|
|
||||||
typedef const struct jdwpTransportNativeInterface_ *jdwpTransportEnv;
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Errors. Universal errors with JVMTI/JVMDI equivalents keep the
|
|
||||||
* values the same.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
JDWPTRANSPORT_ERROR_NONE = 0,
|
|
||||||
JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT = 103,
|
|
||||||
JDWPTRANSPORT_ERROR_OUT_OF_MEMORY = 110,
|
|
||||||
JDWPTRANSPORT_ERROR_INTERNAL = 113,
|
|
||||||
JDWPTRANSPORT_ERROR_ILLEGAL_STATE = 201,
|
|
||||||
JDWPTRANSPORT_ERROR_IO_ERROR = 202,
|
|
||||||
JDWPTRANSPORT_ERROR_TIMEOUT = 203,
|
|
||||||
JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE = 204
|
|
||||||
} jdwpTransportError;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structure to define capabilities
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int can_timeout_attach :1;
|
|
||||||
unsigned int can_timeout_accept :1;
|
|
||||||
unsigned int can_timeout_handshake :1;
|
|
||||||
unsigned int reserved3 :1;
|
|
||||||
unsigned int reserved4 :1;
|
|
||||||
unsigned int reserved5 :1;
|
|
||||||
unsigned int reserved6 :1;
|
|
||||||
unsigned int reserved7 :1;
|
|
||||||
unsigned int reserved8 :1;
|
|
||||||
unsigned int reserved9 :1;
|
|
||||||
unsigned int reserved10 :1;
|
|
||||||
unsigned int reserved11 :1;
|
|
||||||
unsigned int reserved12 :1;
|
|
||||||
unsigned int reserved13 :1;
|
|
||||||
unsigned int reserved14 :1;
|
|
||||||
unsigned int reserved15 :1;
|
|
||||||
} JDWPTransportCapabilities;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structures to define packet layout.
|
|
||||||
*
|
|
||||||
* See: http://java.sun.com/j2se/1.5/docs/guide/jpda/jdwp-spec.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define JDWP_HEADER_SIZE 11
|
|
||||||
|
|
||||||
enum {
|
|
||||||
/*
|
|
||||||
* If additional flags are added that apply to jdwpCmdPacket,
|
|
||||||
* then debugLoop.c: reader() will need to be updated to
|
|
||||||
* accept more than JDWPTRANSPORT_FLAGS_NONE.
|
|
||||||
*/
|
|
||||||
JDWPTRANSPORT_FLAGS_NONE = 0x0,
|
|
||||||
JDWPTRANSPORT_FLAGS_REPLY = 0x80
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
jint len;
|
|
||||||
jint id;
|
|
||||||
jbyte flags;
|
|
||||||
jbyte cmdSet;
|
|
||||||
jbyte cmd;
|
|
||||||
jbyte *data;
|
|
||||||
} jdwpCmdPacket;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
jint len;
|
|
||||||
jint id;
|
|
||||||
jbyte flags;
|
|
||||||
jshort errorCode;
|
|
||||||
jbyte *data;
|
|
||||||
} jdwpReplyPacket;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
union {
|
|
||||||
jdwpCmdPacket cmd;
|
|
||||||
jdwpReplyPacket reply;
|
|
||||||
} type;
|
|
||||||
} jdwpPacket;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JDWP functions called by the transport.
|
|
||||||
*/
|
|
||||||
typedef struct jdwpTransportCallback {
|
|
||||||
void *(*alloc)(jint numBytes); /* Call this for all allocations */
|
|
||||||
void (*free)(void *buffer); /* Call this for all deallocations */
|
|
||||||
} jdwpTransportCallback;
|
|
||||||
|
|
||||||
typedef jint (JNICALL *jdwpTransport_OnLoad_t)(JavaVM *jvm,
|
|
||||||
jdwpTransportCallback *callback,
|
|
||||||
jint version,
|
|
||||||
jdwpTransportEnv** env);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JDWP transport configuration from the agent.
|
|
||||||
*/
|
|
||||||
typedef struct jdwpTransportConfiguration {
|
|
||||||
/* Field added in JDWPTRANSPORT_VERSION_1_1: */
|
|
||||||
const char* allowed_peers; /* Peers allowed for connection */
|
|
||||||
} jdwpTransportConfiguration;
|
|
||||||
|
|
||||||
|
|
||||||
/* Function Interface */
|
|
||||||
|
|
||||||
struct jdwpTransportNativeInterface_ {
|
|
||||||
/* 1 : RESERVED */
|
|
||||||
void *reserved1;
|
|
||||||
|
|
||||||
/* 2 : Get Capabilities */
|
|
||||||
jdwpTransportError (JNICALL *GetCapabilities)(jdwpTransportEnv* env,
|
|
||||||
JDWPTransportCapabilities *capabilities_ptr);
|
|
||||||
|
|
||||||
/* 3 : Attach */
|
|
||||||
jdwpTransportError (JNICALL *Attach)(jdwpTransportEnv* env,
|
|
||||||
const char* address,
|
|
||||||
jlong attach_timeout,
|
|
||||||
jlong handshake_timeout);
|
|
||||||
|
|
||||||
/* 4: StartListening */
|
|
||||||
jdwpTransportError (JNICALL *StartListening)(jdwpTransportEnv* env,
|
|
||||||
const char* address,
|
|
||||||
char** actual_address);
|
|
||||||
|
|
||||||
/* 5: StopListening */
|
|
||||||
jdwpTransportError (JNICALL *StopListening)(jdwpTransportEnv* env);
|
|
||||||
|
|
||||||
/* 6: Accept */
|
|
||||||
jdwpTransportError (JNICALL *Accept)(jdwpTransportEnv* env,
|
|
||||||
jlong accept_timeout,
|
|
||||||
jlong handshake_timeout);
|
|
||||||
|
|
||||||
/* 7: IsOpen */
|
|
||||||
jboolean (JNICALL *IsOpen)(jdwpTransportEnv* env);
|
|
||||||
|
|
||||||
/* 8: Close */
|
|
||||||
jdwpTransportError (JNICALL *Close)(jdwpTransportEnv* env);
|
|
||||||
|
|
||||||
/* 9: ReadPacket */
|
|
||||||
jdwpTransportError (JNICALL *ReadPacket)(jdwpTransportEnv* env,
|
|
||||||
jdwpPacket *pkt);
|
|
||||||
|
|
||||||
/* 10: Write Packet */
|
|
||||||
jdwpTransportError (JNICALL *WritePacket)(jdwpTransportEnv* env,
|
|
||||||
const jdwpPacket* pkt);
|
|
||||||
|
|
||||||
/* 11: GetLastError */
|
|
||||||
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
|
|
||||||
char** error);
|
|
||||||
|
|
||||||
/* 12: SetTransportConfiguration added in JDWPTRANSPORT_VERSION_1_1 */
|
|
||||||
jdwpTransportError (JNICALL *SetTransportConfiguration)(jdwpTransportEnv* env,
|
|
||||||
jdwpTransportConfiguration *config);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use inlined functions so that C++ code can use syntax such as
|
|
||||||
* env->Attach("mymachine:5000", 10*1000, 0);
|
|
||||||
*
|
|
||||||
* rather than using C's :-
|
|
||||||
*
|
|
||||||
* (*env)->Attach(env, "mymachine:5000", 10*1000, 0);
|
|
||||||
*/
|
|
||||||
struct _jdwpTransportEnv {
|
|
||||||
const struct jdwpTransportNativeInterface_ *functions;
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
jdwpTransportError GetCapabilities(JDWPTransportCapabilities *capabilities_ptr) {
|
|
||||||
return functions->GetCapabilities(this, capabilities_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError Attach(const char* address, jlong attach_timeout,
|
|
||||||
jlong handshake_timeout) {
|
|
||||||
return functions->Attach(this, address, attach_timeout, handshake_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError StartListening(const char* address,
|
|
||||||
char** actual_address) {
|
|
||||||
return functions->StartListening(this, address, actual_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError StopListening(void) {
|
|
||||||
return functions->StopListening(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError Accept(jlong accept_timeout, jlong handshake_timeout) {
|
|
||||||
return functions->Accept(this, accept_timeout, handshake_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
jboolean IsOpen(void) {
|
|
||||||
return functions->IsOpen(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError Close(void) {
|
|
||||||
return functions->Close(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError ReadPacket(jdwpPacket *pkt) {
|
|
||||||
return functions->ReadPacket(this, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError WritePacket(const jdwpPacket* pkt) {
|
|
||||||
return functions->WritePacket(this, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError GetLastError(char** error) {
|
|
||||||
return functions->GetLastError(this, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SetTransportConfiguration added in JDWPTRANSPORT_VERSION_1_1 */
|
|
||||||
jdwpTransportError SetTransportConfiguration(jdwpTransportEnv* env,
|
|
||||||
return functions->SetTransportConfiguration(this, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* JDWPTRANSPORT_H */
|
|
1987
jni/linux/jni.h
1987
jni/linux/jni.h
File diff suppressed because it is too large
Load Diff
2625
jni/linux/jvmti.h
2625
jni/linux/jvmti.h
File diff suppressed because it is too large
Load Diff
|
@ -1,115 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This header file defines the data structures sent by the VM
|
|
||||||
* through the JVMTI CompiledMethodLoad callback function via the
|
|
||||||
* "void * compile_info" parameter. The memory pointed to by the
|
|
||||||
* compile_info parameter may not be referenced after returning from
|
|
||||||
* the CompiledMethodLoad callback. These are VM implementation
|
|
||||||
* specific data structures that may evolve in future releases. A
|
|
||||||
* JVMTI agent should interpret a non-NULL compile_info as a pointer
|
|
||||||
* to a region of memory containing a list of records. In a typical
|
|
||||||
* usage scenario, a JVMTI agent would cast each record to a
|
|
||||||
* jvmtiCompiledMethodLoadRecordHeader, a struct that represents
|
|
||||||
* arbitrary information. This struct contains a kind field to indicate
|
|
||||||
* the kind of information being passed, and a pointer to the next
|
|
||||||
* record. If the kind field indicates inlining information, then the
|
|
||||||
* agent would cast the record to a jvmtiCompiledMethodLoadInlineRecord.
|
|
||||||
* This record contains an array of PCStackInfo structs, which indicate
|
|
||||||
* for every pc address what are the methods on the invocation stack.
|
|
||||||
* The "methods" and "bcis" fields in each PCStackInfo struct specify a
|
|
||||||
* 1-1 mapping between these inlined methods and their bytecode indices.
|
|
||||||
* This can be used to derive the proper source lines of the inlined
|
|
||||||
* methods.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JVMTI_CMLR_H_
|
|
||||||
#define _JVMTI_CMLR_H_
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVMTI_CMLR_MAJOR_VERSION_1 = 0x00000001,
|
|
||||||
JVMTI_CMLR_MINOR_VERSION_0 = 0x00000000,
|
|
||||||
|
|
||||||
JVMTI_CMLR_MAJOR_VERSION = 0x00000001,
|
|
||||||
JVMTI_CMLR_MINOR_VERSION = 0x00000000
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This comment is for the "JDK import from HotSpot" sanity check:
|
|
||||||
* version: 1.0.0
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
JVMTI_CMLR_DUMMY = 1,
|
|
||||||
JVMTI_CMLR_INLINE_INFO = 2
|
|
||||||
} jvmtiCMLRKind;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Record that represents arbitrary information passed through JVMTI
|
|
||||||
* CompiledMethodLoadEvent void pointer.
|
|
||||||
*/
|
|
||||||
typedef struct _jvmtiCompiledMethodLoadRecordHeader {
|
|
||||||
jvmtiCMLRKind kind; /* id for the kind of info passed in the record */
|
|
||||||
jint majorinfoversion; /* major and minor info version values. Init'ed */
|
|
||||||
jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */
|
|
||||||
|
|
||||||
struct _jvmtiCompiledMethodLoadRecordHeader* next;
|
|
||||||
} jvmtiCompiledMethodLoadRecordHeader;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Record that gives information about the methods on the compile-time
|
|
||||||
* stack at a specific pc address of a compiled method. Each element in
|
|
||||||
* the methods array maps to same element in the bcis array.
|
|
||||||
*/
|
|
||||||
typedef struct _PCStackInfo {
|
|
||||||
void* pc; /* the pc address for this compiled method */
|
|
||||||
jint numstackframes; /* number of methods on the stack */
|
|
||||||
jmethodID* methods; /* array of numstackframes method ids */
|
|
||||||
jint* bcis; /* array of numstackframes bytecode indices */
|
|
||||||
} PCStackInfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Record that contains inlining information for each pc address of
|
|
||||||
* an nmethod.
|
|
||||||
*/
|
|
||||||
typedef struct _jvmtiCompiledMethodLoadInlineRecord {
|
|
||||||
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
|
|
||||||
jint numpcs; /* number of pc descriptors in this nmethod */
|
|
||||||
PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
|
|
||||||
} jvmtiCompiledMethodLoadInlineRecord;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dummy record used to test that we can pass records with different
|
|
||||||
* information through the void pointer provided that they can be cast
|
|
||||||
* to a jvmtiCompiledMethodLoadRecordHeader.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct _jvmtiCompiledMethodLoadDummyRecord {
|
|
||||||
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
|
|
||||||
char message[50];
|
|
||||||
} jvmtiCompiledMethodLoadDummyRecord;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JAVASOFT_JAWT_MD_H_
|
|
||||||
#define _JAVASOFT_JAWT_MD_H_
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#include "jawt.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* X11-specific declarations for AWT native interface.
|
|
||||||
* See notes in jawt.h for an example of use.
|
|
||||||
*/
|
|
||||||
typedef struct jawt_X11DrawingSurfaceInfo {
|
|
||||||
Drawable drawable;
|
|
||||||
Display* display;
|
|
||||||
VisualID visualID;
|
|
||||||
Colormap colormapID;
|
|
||||||
int depth;
|
|
||||||
/*
|
|
||||||
* Since 1.4
|
|
||||||
* Returns a pixel value from a set of RGB values.
|
|
||||||
* This is useful for paletted color (256 color) modes.
|
|
||||||
*/
|
|
||||||
int (JNICALL *GetAWTColor)(JAWT_DrawingSurface* ds,
|
|
||||||
int r, int g, int b);
|
|
||||||
} JAWT_X11DrawingSurfaceInfo;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !_JAVASOFT_JAWT_MD_H_ */
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JAVASOFT_JNI_MD_H_
|
|
||||||
#define _JAVASOFT_JNI_MD_H_
|
|
||||||
|
|
||||||
#ifndef __has_attribute
|
|
||||||
#define __has_attribute(x) 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef JNIEXPORT
|
|
||||||
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
|
|
||||||
#ifdef ARM
|
|
||||||
#define JNIEXPORT __attribute__((externally_visible,visibility("default")))
|
|
||||||
#else
|
|
||||||
#define JNIEXPORT __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define JNIEXPORT
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
|
|
||||||
#ifdef ARM
|
|
||||||
#define JNIIMPORT __attribute__((externally_visible,visibility("default")))
|
|
||||||
#else
|
|
||||||
#define JNIIMPORT __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define JNIIMPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define JNICALL
|
|
||||||
|
|
||||||
typedef int jint;
|
|
||||||
#ifdef _LP64
|
|
||||||
typedef long jlong;
|
|
||||||
#else
|
|
||||||
typedef long long jlong;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef signed char jbyte;
|
|
||||||
|
|
||||||
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
|
|
@ -1,588 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CLASSFILE_CONSTANTS_H
|
|
||||||
#define CLASSFILE_CONSTANTS_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Classfile version number for this information */
|
|
||||||
#define JVM_CLASSFILE_MAJOR_VERSION 58
|
|
||||||
#define JVM_CLASSFILE_MINOR_VERSION 0
|
|
||||||
|
|
||||||
/* Flags */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_ACC_PUBLIC = 0x0001,
|
|
||||||
JVM_ACC_PRIVATE = 0x0002,
|
|
||||||
JVM_ACC_PROTECTED = 0x0004,
|
|
||||||
JVM_ACC_STATIC = 0x0008,
|
|
||||||
JVM_ACC_FINAL = 0x0010,
|
|
||||||
JVM_ACC_SYNCHRONIZED = 0x0020,
|
|
||||||
JVM_ACC_SUPER = 0x0020,
|
|
||||||
JVM_ACC_VOLATILE = 0x0040,
|
|
||||||
JVM_ACC_BRIDGE = 0x0040,
|
|
||||||
JVM_ACC_TRANSIENT = 0x0080,
|
|
||||||
JVM_ACC_VARARGS = 0x0080,
|
|
||||||
JVM_ACC_NATIVE = 0x0100,
|
|
||||||
JVM_ACC_INTERFACE = 0x0200,
|
|
||||||
JVM_ACC_ABSTRACT = 0x0400,
|
|
||||||
JVM_ACC_STRICT = 0x0800,
|
|
||||||
JVM_ACC_SYNTHETIC = 0x1000,
|
|
||||||
JVM_ACC_ANNOTATION = 0x2000,
|
|
||||||
JVM_ACC_ENUM = 0x4000,
|
|
||||||
JVM_ACC_MODULE = 0x8000
|
|
||||||
};
|
|
||||||
|
|
||||||
#define JVM_ACC_PUBLIC_BIT 0
|
|
||||||
#define JVM_ACC_PRIVATE_BIT 1
|
|
||||||
#define JVM_ACC_PROTECTED_BIT 2
|
|
||||||
#define JVM_ACC_STATIC_BIT 3
|
|
||||||
#define JVM_ACC_FINAL_BIT 4
|
|
||||||
#define JVM_ACC_SYNCHRONIZED_BIT 5
|
|
||||||
#define JVM_ACC_SUPER_BIT 5
|
|
||||||
#define JVM_ACC_VOLATILE_BIT 6
|
|
||||||
#define JVM_ACC_BRIDGE_BIT 6
|
|
||||||
#define JVM_ACC_TRANSIENT_BIT 7
|
|
||||||
#define JVM_ACC_VARARGS_BIT 7
|
|
||||||
#define JVM_ACC_NATIVE_BIT 8
|
|
||||||
#define JVM_ACC_INTERFACE_BIT 9
|
|
||||||
#define JVM_ACC_ABSTRACT_BIT 10
|
|
||||||
#define JVM_ACC_STRICT_BIT 11
|
|
||||||
#define JVM_ACC_SYNTHETIC_BIT 12
|
|
||||||
#define JVM_ACC_ANNOTATION_BIT 13
|
|
||||||
#define JVM_ACC_ENUM_BIT 14
|
|
||||||
|
|
||||||
/* Used in newarray instruction. */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_T_BOOLEAN = 4,
|
|
||||||
JVM_T_CHAR = 5,
|
|
||||||
JVM_T_FLOAT = 6,
|
|
||||||
JVM_T_DOUBLE = 7,
|
|
||||||
JVM_T_BYTE = 8,
|
|
||||||
JVM_T_SHORT = 9,
|
|
||||||
JVM_T_INT = 10,
|
|
||||||
JVM_T_LONG = 11
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Constant Pool Entries */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_CONSTANT_Utf8 = 1,
|
|
||||||
JVM_CONSTANT_Unicode = 2, /* unused */
|
|
||||||
JVM_CONSTANT_Integer = 3,
|
|
||||||
JVM_CONSTANT_Float = 4,
|
|
||||||
JVM_CONSTANT_Long = 5,
|
|
||||||
JVM_CONSTANT_Double = 6,
|
|
||||||
JVM_CONSTANT_Class = 7,
|
|
||||||
JVM_CONSTANT_String = 8,
|
|
||||||
JVM_CONSTANT_Fieldref = 9,
|
|
||||||
JVM_CONSTANT_Methodref = 10,
|
|
||||||
JVM_CONSTANT_InterfaceMethodref = 11,
|
|
||||||
JVM_CONSTANT_NameAndType = 12,
|
|
||||||
JVM_CONSTANT_MethodHandle = 15, // JSR 292
|
|
||||||
JVM_CONSTANT_MethodType = 16, // JSR 292
|
|
||||||
JVM_CONSTANT_Dynamic = 17,
|
|
||||||
JVM_CONSTANT_InvokeDynamic = 18,
|
|
||||||
JVM_CONSTANT_Module = 19,
|
|
||||||
JVM_CONSTANT_Package = 20,
|
|
||||||
JVM_CONSTANT_ExternalMax = 20
|
|
||||||
};
|
|
||||||
|
|
||||||
/* JVM_CONSTANT_MethodHandle subtypes */
|
|
||||||
enum {
|
|
||||||
JVM_REF_getField = 1,
|
|
||||||
JVM_REF_getStatic = 2,
|
|
||||||
JVM_REF_putField = 3,
|
|
||||||
JVM_REF_putStatic = 4,
|
|
||||||
JVM_REF_invokeVirtual = 5,
|
|
||||||
JVM_REF_invokeStatic = 6,
|
|
||||||
JVM_REF_invokeSpecial = 7,
|
|
||||||
JVM_REF_newInvokeSpecial = 8,
|
|
||||||
JVM_REF_invokeInterface = 9
|
|
||||||
};
|
|
||||||
|
|
||||||
/* StackMapTable type item numbers */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_ITEM_Top = 0,
|
|
||||||
JVM_ITEM_Integer = 1,
|
|
||||||
JVM_ITEM_Float = 2,
|
|
||||||
JVM_ITEM_Double = 3,
|
|
||||||
JVM_ITEM_Long = 4,
|
|
||||||
JVM_ITEM_Null = 5,
|
|
||||||
JVM_ITEM_UninitializedThis = 6,
|
|
||||||
JVM_ITEM_Object = 7,
|
|
||||||
JVM_ITEM_Uninitialized = 8
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Type signatures */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_SIGNATURE_SLASH = '/',
|
|
||||||
JVM_SIGNATURE_DOT = '.',
|
|
||||||
JVM_SIGNATURE_SPECIAL = '<',
|
|
||||||
JVM_SIGNATURE_ENDSPECIAL = '>',
|
|
||||||
JVM_SIGNATURE_ARRAY = '[',
|
|
||||||
JVM_SIGNATURE_BYTE = 'B',
|
|
||||||
JVM_SIGNATURE_CHAR = 'C',
|
|
||||||
JVM_SIGNATURE_CLASS = 'L',
|
|
||||||
JVM_SIGNATURE_ENDCLASS = ';',
|
|
||||||
JVM_SIGNATURE_ENUM = 'E',
|
|
||||||
JVM_SIGNATURE_FLOAT = 'F',
|
|
||||||
JVM_SIGNATURE_DOUBLE = 'D',
|
|
||||||
JVM_SIGNATURE_FUNC = '(',
|
|
||||||
JVM_SIGNATURE_ENDFUNC = ')',
|
|
||||||
JVM_SIGNATURE_INT = 'I',
|
|
||||||
JVM_SIGNATURE_LONG = 'J',
|
|
||||||
JVM_SIGNATURE_SHORT = 'S',
|
|
||||||
JVM_SIGNATURE_VOID = 'V',
|
|
||||||
JVM_SIGNATURE_BOOLEAN = 'Z'
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Opcodes */
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVM_OPC_nop = 0,
|
|
||||||
JVM_OPC_aconst_null = 1,
|
|
||||||
JVM_OPC_iconst_m1 = 2,
|
|
||||||
JVM_OPC_iconst_0 = 3,
|
|
||||||
JVM_OPC_iconst_1 = 4,
|
|
||||||
JVM_OPC_iconst_2 = 5,
|
|
||||||
JVM_OPC_iconst_3 = 6,
|
|
||||||
JVM_OPC_iconst_4 = 7,
|
|
||||||
JVM_OPC_iconst_5 = 8,
|
|
||||||
JVM_OPC_lconst_0 = 9,
|
|
||||||
JVM_OPC_lconst_1 = 10,
|
|
||||||
JVM_OPC_fconst_0 = 11,
|
|
||||||
JVM_OPC_fconst_1 = 12,
|
|
||||||
JVM_OPC_fconst_2 = 13,
|
|
||||||
JVM_OPC_dconst_0 = 14,
|
|
||||||
JVM_OPC_dconst_1 = 15,
|
|
||||||
JVM_OPC_bipush = 16,
|
|
||||||
JVM_OPC_sipush = 17,
|
|
||||||
JVM_OPC_ldc = 18,
|
|
||||||
JVM_OPC_ldc_w = 19,
|
|
||||||
JVM_OPC_ldc2_w = 20,
|
|
||||||
JVM_OPC_iload = 21,
|
|
||||||
JVM_OPC_lload = 22,
|
|
||||||
JVM_OPC_fload = 23,
|
|
||||||
JVM_OPC_dload = 24,
|
|
||||||
JVM_OPC_aload = 25,
|
|
||||||
JVM_OPC_iload_0 = 26,
|
|
||||||
JVM_OPC_iload_1 = 27,
|
|
||||||
JVM_OPC_iload_2 = 28,
|
|
||||||
JVM_OPC_iload_3 = 29,
|
|
||||||
JVM_OPC_lload_0 = 30,
|
|
||||||
JVM_OPC_lload_1 = 31,
|
|
||||||
JVM_OPC_lload_2 = 32,
|
|
||||||
JVM_OPC_lload_3 = 33,
|
|
||||||
JVM_OPC_fload_0 = 34,
|
|
||||||
JVM_OPC_fload_1 = 35,
|
|
||||||
JVM_OPC_fload_2 = 36,
|
|
||||||
JVM_OPC_fload_3 = 37,
|
|
||||||
JVM_OPC_dload_0 = 38,
|
|
||||||
JVM_OPC_dload_1 = 39,
|
|
||||||
JVM_OPC_dload_2 = 40,
|
|
||||||
JVM_OPC_dload_3 = 41,
|
|
||||||
JVM_OPC_aload_0 = 42,
|
|
||||||
JVM_OPC_aload_1 = 43,
|
|
||||||
JVM_OPC_aload_2 = 44,
|
|
||||||
JVM_OPC_aload_3 = 45,
|
|
||||||
JVM_OPC_iaload = 46,
|
|
||||||
JVM_OPC_laload = 47,
|
|
||||||
JVM_OPC_faload = 48,
|
|
||||||
JVM_OPC_daload = 49,
|
|
||||||
JVM_OPC_aaload = 50,
|
|
||||||
JVM_OPC_baload = 51,
|
|
||||||
JVM_OPC_caload = 52,
|
|
||||||
JVM_OPC_saload = 53,
|
|
||||||
JVM_OPC_istore = 54,
|
|
||||||
JVM_OPC_lstore = 55,
|
|
||||||
JVM_OPC_fstore = 56,
|
|
||||||
JVM_OPC_dstore = 57,
|
|
||||||
JVM_OPC_astore = 58,
|
|
||||||
JVM_OPC_istore_0 = 59,
|
|
||||||
JVM_OPC_istore_1 = 60,
|
|
||||||
JVM_OPC_istore_2 = 61,
|
|
||||||
JVM_OPC_istore_3 = 62,
|
|
||||||
JVM_OPC_lstore_0 = 63,
|
|
||||||
JVM_OPC_lstore_1 = 64,
|
|
||||||
JVM_OPC_lstore_2 = 65,
|
|
||||||
JVM_OPC_lstore_3 = 66,
|
|
||||||
JVM_OPC_fstore_0 = 67,
|
|
||||||
JVM_OPC_fstore_1 = 68,
|
|
||||||
JVM_OPC_fstore_2 = 69,
|
|
||||||
JVM_OPC_fstore_3 = 70,
|
|
||||||
JVM_OPC_dstore_0 = 71,
|
|
||||||
JVM_OPC_dstore_1 = 72,
|
|
||||||
JVM_OPC_dstore_2 = 73,
|
|
||||||
JVM_OPC_dstore_3 = 74,
|
|
||||||
JVM_OPC_astore_0 = 75,
|
|
||||||
JVM_OPC_astore_1 = 76,
|
|
||||||
JVM_OPC_astore_2 = 77,
|
|
||||||
JVM_OPC_astore_3 = 78,
|
|
||||||
JVM_OPC_iastore = 79,
|
|
||||||
JVM_OPC_lastore = 80,
|
|
||||||
JVM_OPC_fastore = 81,
|
|
||||||
JVM_OPC_dastore = 82,
|
|
||||||
JVM_OPC_aastore = 83,
|
|
||||||
JVM_OPC_bastore = 84,
|
|
||||||
JVM_OPC_castore = 85,
|
|
||||||
JVM_OPC_sastore = 86,
|
|
||||||
JVM_OPC_pop = 87,
|
|
||||||
JVM_OPC_pop2 = 88,
|
|
||||||
JVM_OPC_dup = 89,
|
|
||||||
JVM_OPC_dup_x1 = 90,
|
|
||||||
JVM_OPC_dup_x2 = 91,
|
|
||||||
JVM_OPC_dup2 = 92,
|
|
||||||
JVM_OPC_dup2_x1 = 93,
|
|
||||||
JVM_OPC_dup2_x2 = 94,
|
|
||||||
JVM_OPC_swap = 95,
|
|
||||||
JVM_OPC_iadd = 96,
|
|
||||||
JVM_OPC_ladd = 97,
|
|
||||||
JVM_OPC_fadd = 98,
|
|
||||||
JVM_OPC_dadd = 99,
|
|
||||||
JVM_OPC_isub = 100,
|
|
||||||
JVM_OPC_lsub = 101,
|
|
||||||
JVM_OPC_fsub = 102,
|
|
||||||
JVM_OPC_dsub = 103,
|
|
||||||
JVM_OPC_imul = 104,
|
|
||||||
JVM_OPC_lmul = 105,
|
|
||||||
JVM_OPC_fmul = 106,
|
|
||||||
JVM_OPC_dmul = 107,
|
|
||||||
JVM_OPC_idiv = 108,
|
|
||||||
JVM_OPC_ldiv = 109,
|
|
||||||
JVM_OPC_fdiv = 110,
|
|
||||||
JVM_OPC_ddiv = 111,
|
|
||||||
JVM_OPC_irem = 112,
|
|
||||||
JVM_OPC_lrem = 113,
|
|
||||||
JVM_OPC_frem = 114,
|
|
||||||
JVM_OPC_drem = 115,
|
|
||||||
JVM_OPC_ineg = 116,
|
|
||||||
JVM_OPC_lneg = 117,
|
|
||||||
JVM_OPC_fneg = 118,
|
|
||||||
JVM_OPC_dneg = 119,
|
|
||||||
JVM_OPC_ishl = 120,
|
|
||||||
JVM_OPC_lshl = 121,
|
|
||||||
JVM_OPC_ishr = 122,
|
|
||||||
JVM_OPC_lshr = 123,
|
|
||||||
JVM_OPC_iushr = 124,
|
|
||||||
JVM_OPC_lushr = 125,
|
|
||||||
JVM_OPC_iand = 126,
|
|
||||||
JVM_OPC_land = 127,
|
|
||||||
JVM_OPC_ior = 128,
|
|
||||||
JVM_OPC_lor = 129,
|
|
||||||
JVM_OPC_ixor = 130,
|
|
||||||
JVM_OPC_lxor = 131,
|
|
||||||
JVM_OPC_iinc = 132,
|
|
||||||
JVM_OPC_i2l = 133,
|
|
||||||
JVM_OPC_i2f = 134,
|
|
||||||
JVM_OPC_i2d = 135,
|
|
||||||
JVM_OPC_l2i = 136,
|
|
||||||
JVM_OPC_l2f = 137,
|
|
||||||
JVM_OPC_l2d = 138,
|
|
||||||
JVM_OPC_f2i = 139,
|
|
||||||
JVM_OPC_f2l = 140,
|
|
||||||
JVM_OPC_f2d = 141,
|
|
||||||
JVM_OPC_d2i = 142,
|
|
||||||
JVM_OPC_d2l = 143,
|
|
||||||
JVM_OPC_d2f = 144,
|
|
||||||
JVM_OPC_i2b = 145,
|
|
||||||
JVM_OPC_i2c = 146,
|
|
||||||
JVM_OPC_i2s = 147,
|
|
||||||
JVM_OPC_lcmp = 148,
|
|
||||||
JVM_OPC_fcmpl = 149,
|
|
||||||
JVM_OPC_fcmpg = 150,
|
|
||||||
JVM_OPC_dcmpl = 151,
|
|
||||||
JVM_OPC_dcmpg = 152,
|
|
||||||
JVM_OPC_ifeq = 153,
|
|
||||||
JVM_OPC_ifne = 154,
|
|
||||||
JVM_OPC_iflt = 155,
|
|
||||||
JVM_OPC_ifge = 156,
|
|
||||||
JVM_OPC_ifgt = 157,
|
|
||||||
JVM_OPC_ifle = 158,
|
|
||||||
JVM_OPC_if_icmpeq = 159,
|
|
||||||
JVM_OPC_if_icmpne = 160,
|
|
||||||
JVM_OPC_if_icmplt = 161,
|
|
||||||
JVM_OPC_if_icmpge = 162,
|
|
||||||
JVM_OPC_if_icmpgt = 163,
|
|
||||||
JVM_OPC_if_icmple = 164,
|
|
||||||
JVM_OPC_if_acmpeq = 165,
|
|
||||||
JVM_OPC_if_acmpne = 166,
|
|
||||||
JVM_OPC_goto = 167,
|
|
||||||
JVM_OPC_jsr = 168,
|
|
||||||
JVM_OPC_ret = 169,
|
|
||||||
JVM_OPC_tableswitch = 170,
|
|
||||||
JVM_OPC_lookupswitch = 171,
|
|
||||||
JVM_OPC_ireturn = 172,
|
|
||||||
JVM_OPC_lreturn = 173,
|
|
||||||
JVM_OPC_freturn = 174,
|
|
||||||
JVM_OPC_dreturn = 175,
|
|
||||||
JVM_OPC_areturn = 176,
|
|
||||||
JVM_OPC_return = 177,
|
|
||||||
JVM_OPC_getstatic = 178,
|
|
||||||
JVM_OPC_putstatic = 179,
|
|
||||||
JVM_OPC_getfield = 180,
|
|
||||||
JVM_OPC_putfield = 181,
|
|
||||||
JVM_OPC_invokevirtual = 182,
|
|
||||||
JVM_OPC_invokespecial = 183,
|
|
||||||
JVM_OPC_invokestatic = 184,
|
|
||||||
JVM_OPC_invokeinterface = 185,
|
|
||||||
JVM_OPC_invokedynamic = 186,
|
|
||||||
JVM_OPC_new = 187,
|
|
||||||
JVM_OPC_newarray = 188,
|
|
||||||
JVM_OPC_anewarray = 189,
|
|
||||||
JVM_OPC_arraylength = 190,
|
|
||||||
JVM_OPC_athrow = 191,
|
|
||||||
JVM_OPC_checkcast = 192,
|
|
||||||
JVM_OPC_instanceof = 193,
|
|
||||||
JVM_OPC_monitorenter = 194,
|
|
||||||
JVM_OPC_monitorexit = 195,
|
|
||||||
JVM_OPC_wide = 196,
|
|
||||||
JVM_OPC_multianewarray = 197,
|
|
||||||
JVM_OPC_ifnull = 198,
|
|
||||||
JVM_OPC_ifnonnull = 199,
|
|
||||||
JVM_OPC_goto_w = 200,
|
|
||||||
JVM_OPC_jsr_w = 201,
|
|
||||||
JVM_OPC_MAX = 201
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Opcode length initializer, use with something like:
|
|
||||||
* unsigned char opcode_length[JVM_OPC_MAX+1] = JVM_OPCODE_LENGTH_INITIALIZER;
|
|
||||||
*/
|
|
||||||
#define JVM_OPCODE_LENGTH_INITIALIZER { \
|
|
||||||
1, /* nop */ \
|
|
||||||
1, /* aconst_null */ \
|
|
||||||
1, /* iconst_m1 */ \
|
|
||||||
1, /* iconst_0 */ \
|
|
||||||
1, /* iconst_1 */ \
|
|
||||||
1, /* iconst_2 */ \
|
|
||||||
1, /* iconst_3 */ \
|
|
||||||
1, /* iconst_4 */ \
|
|
||||||
1, /* iconst_5 */ \
|
|
||||||
1, /* lconst_0 */ \
|
|
||||||
1, /* lconst_1 */ \
|
|
||||||
1, /* fconst_0 */ \
|
|
||||||
1, /* fconst_1 */ \
|
|
||||||
1, /* fconst_2 */ \
|
|
||||||
1, /* dconst_0 */ \
|
|
||||||
1, /* dconst_1 */ \
|
|
||||||
2, /* bipush */ \
|
|
||||||
3, /* sipush */ \
|
|
||||||
2, /* ldc */ \
|
|
||||||
3, /* ldc_w */ \
|
|
||||||
3, /* ldc2_w */ \
|
|
||||||
2, /* iload */ \
|
|
||||||
2, /* lload */ \
|
|
||||||
2, /* fload */ \
|
|
||||||
2, /* dload */ \
|
|
||||||
2, /* aload */ \
|
|
||||||
1, /* iload_0 */ \
|
|
||||||
1, /* iload_1 */ \
|
|
||||||
1, /* iload_2 */ \
|
|
||||||
1, /* iload_3 */ \
|
|
||||||
1, /* lload_0 */ \
|
|
||||||
1, /* lload_1 */ \
|
|
||||||
1, /* lload_2 */ \
|
|
||||||
1, /* lload_3 */ \
|
|
||||||
1, /* fload_0 */ \
|
|
||||||
1, /* fload_1 */ \
|
|
||||||
1, /* fload_2 */ \
|
|
||||||
1, /* fload_3 */ \
|
|
||||||
1, /* dload_0 */ \
|
|
||||||
1, /* dload_1 */ \
|
|
||||||
1, /* dload_2 */ \
|
|
||||||
1, /* dload_3 */ \
|
|
||||||
1, /* aload_0 */ \
|
|
||||||
1, /* aload_1 */ \
|
|
||||||
1, /* aload_2 */ \
|
|
||||||
1, /* aload_3 */ \
|
|
||||||
1, /* iaload */ \
|
|
||||||
1, /* laload */ \
|
|
||||||
1, /* faload */ \
|
|
||||||
1, /* daload */ \
|
|
||||||
1, /* aaload */ \
|
|
||||||
1, /* baload */ \
|
|
||||||
1, /* caload */ \
|
|
||||||
1, /* saload */ \
|
|
||||||
2, /* istore */ \
|
|
||||||
2, /* lstore */ \
|
|
||||||
2, /* fstore */ \
|
|
||||||
2, /* dstore */ \
|
|
||||||
2, /* astore */ \
|
|
||||||
1, /* istore_0 */ \
|
|
||||||
1, /* istore_1 */ \
|
|
||||||
1, /* istore_2 */ \
|
|
||||||
1, /* istore_3 */ \
|
|
||||||
1, /* lstore_0 */ \
|
|
||||||
1, /* lstore_1 */ \
|
|
||||||
1, /* lstore_2 */ \
|
|
||||||
1, /* lstore_3 */ \
|
|
||||||
1, /* fstore_0 */ \
|
|
||||||
1, /* fstore_1 */ \
|
|
||||||
1, /* fstore_2 */ \
|
|
||||||
1, /* fstore_3 */ \
|
|
||||||
1, /* dstore_0 */ \
|
|
||||||
1, /* dstore_1 */ \
|
|
||||||
1, /* dstore_2 */ \
|
|
||||||
1, /* dstore_3 */ \
|
|
||||||
1, /* astore_0 */ \
|
|
||||||
1, /* astore_1 */ \
|
|
||||||
1, /* astore_2 */ \
|
|
||||||
1, /* astore_3 */ \
|
|
||||||
1, /* iastore */ \
|
|
||||||
1, /* lastore */ \
|
|
||||||
1, /* fastore */ \
|
|
||||||
1, /* dastore */ \
|
|
||||||
1, /* aastore */ \
|
|
||||||
1, /* bastore */ \
|
|
||||||
1, /* castore */ \
|
|
||||||
1, /* sastore */ \
|
|
||||||
1, /* pop */ \
|
|
||||||
1, /* pop2 */ \
|
|
||||||
1, /* dup */ \
|
|
||||||
1, /* dup_x1 */ \
|
|
||||||
1, /* dup_x2 */ \
|
|
||||||
1, /* dup2 */ \
|
|
||||||
1, /* dup2_x1 */ \
|
|
||||||
1, /* dup2_x2 */ \
|
|
||||||
1, /* swap */ \
|
|
||||||
1, /* iadd */ \
|
|
||||||
1, /* ladd */ \
|
|
||||||
1, /* fadd */ \
|
|
||||||
1, /* dadd */ \
|
|
||||||
1, /* isub */ \
|
|
||||||
1, /* lsub */ \
|
|
||||||
1, /* fsub */ \
|
|
||||||
1, /* dsub */ \
|
|
||||||
1, /* imul */ \
|
|
||||||
1, /* lmul */ \
|
|
||||||
1, /* fmul */ \
|
|
||||||
1, /* dmul */ \
|
|
||||||
1, /* idiv */ \
|
|
||||||
1, /* ldiv */ \
|
|
||||||
1, /* fdiv */ \
|
|
||||||
1, /* ddiv */ \
|
|
||||||
1, /* irem */ \
|
|
||||||
1, /* lrem */ \
|
|
||||||
1, /* frem */ \
|
|
||||||
1, /* drem */ \
|
|
||||||
1, /* ineg */ \
|
|
||||||
1, /* lneg */ \
|
|
||||||
1, /* fneg */ \
|
|
||||||
1, /* dneg */ \
|
|
||||||
1, /* ishl */ \
|
|
||||||
1, /* lshl */ \
|
|
||||||
1, /* ishr */ \
|
|
||||||
1, /* lshr */ \
|
|
||||||
1, /* iushr */ \
|
|
||||||
1, /* lushr */ \
|
|
||||||
1, /* iand */ \
|
|
||||||
1, /* land */ \
|
|
||||||
1, /* ior */ \
|
|
||||||
1, /* lor */ \
|
|
||||||
1, /* ixor */ \
|
|
||||||
1, /* lxor */ \
|
|
||||||
3, /* iinc */ \
|
|
||||||
1, /* i2l */ \
|
|
||||||
1, /* i2f */ \
|
|
||||||
1, /* i2d */ \
|
|
||||||
1, /* l2i */ \
|
|
||||||
1, /* l2f */ \
|
|
||||||
1, /* l2d */ \
|
|
||||||
1, /* f2i */ \
|
|
||||||
1, /* f2l */ \
|
|
||||||
1, /* f2d */ \
|
|
||||||
1, /* d2i */ \
|
|
||||||
1, /* d2l */ \
|
|
||||||
1, /* d2f */ \
|
|
||||||
1, /* i2b */ \
|
|
||||||
1, /* i2c */ \
|
|
||||||
1, /* i2s */ \
|
|
||||||
1, /* lcmp */ \
|
|
||||||
1, /* fcmpl */ \
|
|
||||||
1, /* fcmpg */ \
|
|
||||||
1, /* dcmpl */ \
|
|
||||||
1, /* dcmpg */ \
|
|
||||||
3, /* ifeq */ \
|
|
||||||
3, /* ifne */ \
|
|
||||||
3, /* iflt */ \
|
|
||||||
3, /* ifge */ \
|
|
||||||
3, /* ifgt */ \
|
|
||||||
3, /* ifle */ \
|
|
||||||
3, /* if_icmpeq */ \
|
|
||||||
3, /* if_icmpne */ \
|
|
||||||
3, /* if_icmplt */ \
|
|
||||||
3, /* if_icmpge */ \
|
|
||||||
3, /* if_icmpgt */ \
|
|
||||||
3, /* if_icmple */ \
|
|
||||||
3, /* if_acmpeq */ \
|
|
||||||
3, /* if_acmpne */ \
|
|
||||||
3, /* goto */ \
|
|
||||||
3, /* jsr */ \
|
|
||||||
2, /* ret */ \
|
|
||||||
99, /* tableswitch */ \
|
|
||||||
99, /* lookupswitch */ \
|
|
||||||
1, /* ireturn */ \
|
|
||||||
1, /* lreturn */ \
|
|
||||||
1, /* freturn */ \
|
|
||||||
1, /* dreturn */ \
|
|
||||||
1, /* areturn */ \
|
|
||||||
1, /* return */ \
|
|
||||||
3, /* getstatic */ \
|
|
||||||
3, /* putstatic */ \
|
|
||||||
3, /* getfield */ \
|
|
||||||
3, /* putfield */ \
|
|
||||||
3, /* invokevirtual */ \
|
|
||||||
3, /* invokespecial */ \
|
|
||||||
3, /* invokestatic */ \
|
|
||||||
5, /* invokeinterface */ \
|
|
||||||
5, /* invokedynamic */ \
|
|
||||||
3, /* new */ \
|
|
||||||
2, /* newarray */ \
|
|
||||||
3, /* anewarray */ \
|
|
||||||
1, /* arraylength */ \
|
|
||||||
1, /* athrow */ \
|
|
||||||
3, /* checkcast */ \
|
|
||||||
3, /* instanceof */ \
|
|
||||||
1, /* monitorenter */ \
|
|
||||||
1, /* monitorexit */ \
|
|
||||||
0, /* wide */ \
|
|
||||||
4, /* multianewarray */ \
|
|
||||||
3, /* ifnull */ \
|
|
||||||
3, /* ifnonnull */ \
|
|
||||||
5, /* goto_w */ \
|
|
||||||
5 /* jsr_w */ \
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* CLASSFILE_CONSTANTS */
|
|
|
@ -1,356 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JAVASOFT_JAWT_H_
|
|
||||||
#define _JAVASOFT_JAWT_H_
|
|
||||||
|
|
||||||
#include "jni.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AWT native interface.
|
|
||||||
*
|
|
||||||
* The AWT native interface allows a native C or C++ application a means
|
|
||||||
* by which to access native structures in AWT. This is to facilitate moving
|
|
||||||
* legacy C and C++ applications to Java and to target the needs of the
|
|
||||||
* developers who need to do their own native rendering to canvases
|
|
||||||
* for performance or other reasons.
|
|
||||||
*
|
|
||||||
* Conversely it also provides mechanisms for an application which already
|
|
||||||
* has a native window to provide that to AWT for AWT rendering.
|
|
||||||
*
|
|
||||||
* Since every platform may be different in its native data structures
|
|
||||||
* and APIs for windowing systems the application must necessarily
|
|
||||||
* provided per-platform source and compile and deliver per-platform
|
|
||||||
* native code to use this API.
|
|
||||||
*
|
|
||||||
* These interfaces are not part of the Java SE specification and
|
|
||||||
* a VM is not required to implement this API. However it is strongly
|
|
||||||
* recommended that all implementations which support headful AWT
|
|
||||||
* also support these interfaces.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AWT Native Drawing Surface (JAWT_DrawingSurface).
|
|
||||||
*
|
|
||||||
* For each platform, there is a native drawing surface structure. This
|
|
||||||
* platform-specific structure can be found in jawt_md.h. It is recommended
|
|
||||||
* that additional platforms follow the same model. It is also recommended
|
|
||||||
* that VMs on all platforms support the existing structures in jawt_md.h.
|
|
||||||
*
|
|
||||||
*******************
|
|
||||||
* EXAMPLE OF USAGE:
|
|
||||||
*******************
|
|
||||||
*
|
|
||||||
* In Win32, a programmer wishes to access the HWND of a canvas to perform
|
|
||||||
* native rendering into it. The programmer has declared the paint() method
|
|
||||||
* for their canvas subclass to be native:
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* MyCanvas.java:
|
|
||||||
*
|
|
||||||
* import java.awt.*;
|
|
||||||
*
|
|
||||||
* public class MyCanvas extends Canvas {
|
|
||||||
*
|
|
||||||
* static {
|
|
||||||
* System.loadLibrary("mylib");
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public native void paint(Graphics g);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* myfile.c:
|
|
||||||
*
|
|
||||||
* #include "jawt_md.h"
|
|
||||||
* #include <assert.h>
|
|
||||||
*
|
|
||||||
* JNIEXPORT void JNICALL
|
|
||||||
* Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics)
|
|
||||||
* {
|
|
||||||
* JAWT awt;
|
|
||||||
* JAWT_DrawingSurface* ds;
|
|
||||||
* JAWT_DrawingSurfaceInfo* dsi;
|
|
||||||
* JAWT_Win32DrawingSurfaceInfo* dsi_win;
|
|
||||||
* jboolean result;
|
|
||||||
* jint lock;
|
|
||||||
*
|
|
||||||
* // Get the AWT. Request version 9 to access features in that release.
|
|
||||||
* awt.version = JAWT_VERSION_9;
|
|
||||||
* result = JAWT_GetAWT(env, &awt);
|
|
||||||
* assert(result != JNI_FALSE);
|
|
||||||
*
|
|
||||||
* // Get the drawing surface
|
|
||||||
* ds = awt.GetDrawingSurface(env, canvas);
|
|
||||||
* assert(ds != NULL);
|
|
||||||
*
|
|
||||||
* // Lock the drawing surface
|
|
||||||
* lock = ds->Lock(ds);
|
|
||||||
* assert((lock & JAWT_LOCK_ERROR) == 0);
|
|
||||||
*
|
|
||||||
* // Get the drawing surface info
|
|
||||||
* dsi = ds->GetDrawingSurfaceInfo(ds);
|
|
||||||
*
|
|
||||||
* // Get the platform-specific drawing info
|
|
||||||
* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
|
|
||||||
*
|
|
||||||
* //////////////////////////////
|
|
||||||
* // !!! DO PAINTING HERE !!! //
|
|
||||||
* //////////////////////////////
|
|
||||||
*
|
|
||||||
* // Free the drawing surface info
|
|
||||||
* ds->FreeDrawingSurfaceInfo(dsi);
|
|
||||||
*
|
|
||||||
* // Unlock the drawing surface
|
|
||||||
* ds->Unlock(ds);
|
|
||||||
*
|
|
||||||
* // Free the drawing surface
|
|
||||||
* awt.FreeDrawingSurface(ds);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JAWT_Rectangle
|
|
||||||
* Structure for a native rectangle.
|
|
||||||
*/
|
|
||||||
typedef struct jawt_Rectangle {
|
|
||||||
jint x;
|
|
||||||
jint y;
|
|
||||||
jint width;
|
|
||||||
jint height;
|
|
||||||
} JAWT_Rectangle;
|
|
||||||
|
|
||||||
struct jawt_DrawingSurface;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JAWT_DrawingSurfaceInfo
|
|
||||||
* Structure for containing the underlying drawing information of a component.
|
|
||||||
*/
|
|
||||||
typedef struct jawt_DrawingSurfaceInfo {
|
|
||||||
/*
|
|
||||||
* Pointer to the platform-specific information. This can be safely
|
|
||||||
* cast to a JAWT_Win32DrawingSurfaceInfo on Windows or a
|
|
||||||
* JAWT_X11DrawingSurfaceInfo on Linux and Solaris. On Mac OS X this is a
|
|
||||||
* pointer to a NSObject that conforms to the JAWT_SurfaceLayers
|
|
||||||
* protocol. See jawt_md.h for details.
|
|
||||||
*/
|
|
||||||
void* platformInfo;
|
|
||||||
/* Cached pointer to the underlying drawing surface */
|
|
||||||
struct jawt_DrawingSurface* ds;
|
|
||||||
/* Bounding rectangle of the drawing surface */
|
|
||||||
JAWT_Rectangle bounds;
|
|
||||||
/* Number of rectangles in the clip */
|
|
||||||
jint clipSize;
|
|
||||||
/* Clip rectangle array */
|
|
||||||
JAWT_Rectangle* clip;
|
|
||||||
} JAWT_DrawingSurfaceInfo;
|
|
||||||
|
|
||||||
#define JAWT_LOCK_ERROR 0x00000001
|
|
||||||
#define JAWT_LOCK_CLIP_CHANGED 0x00000002
|
|
||||||
#define JAWT_LOCK_BOUNDS_CHANGED 0x00000004
|
|
||||||
#define JAWT_LOCK_SURFACE_CHANGED 0x00000008
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JAWT_DrawingSurface
|
|
||||||
* Structure for containing the underlying drawing information of a component.
|
|
||||||
* All operations on a JAWT_DrawingSurface MUST be performed from the same
|
|
||||||
* thread as the call to GetDrawingSurface.
|
|
||||||
*/
|
|
||||||
typedef struct jawt_DrawingSurface {
|
|
||||||
/*
|
|
||||||
* Cached reference to the Java environment of the calling thread.
|
|
||||||
* If Lock(), Unlock(), GetDrawingSurfaceInfo() or
|
|
||||||
* FreeDrawingSurfaceInfo() are called from a different thread,
|
|
||||||
* this data member should be set before calling those functions.
|
|
||||||
*/
|
|
||||||
JNIEnv* env;
|
|
||||||
/* Cached reference to the target object */
|
|
||||||
jobject target;
|
|
||||||
/*
|
|
||||||
* Lock the surface of the target component for native rendering.
|
|
||||||
* When finished drawing, the surface must be unlocked with
|
|
||||||
* Unlock(). This function returns a bitmask with one or more of the
|
|
||||||
* following values:
|
|
||||||
*
|
|
||||||
* JAWT_LOCK_ERROR - When an error has occurred and the surface could not
|
|
||||||
* be locked.
|
|
||||||
*
|
|
||||||
* JAWT_LOCK_CLIP_CHANGED - When the clip region has changed.
|
|
||||||
*
|
|
||||||
* JAWT_LOCK_BOUNDS_CHANGED - When the bounds of the surface have changed.
|
|
||||||
*
|
|
||||||
* JAWT_LOCK_SURFACE_CHANGED - When the surface itself has changed
|
|
||||||
*/
|
|
||||||
jint (JNICALL *Lock)
|
|
||||||
(struct jawt_DrawingSurface* ds);
|
|
||||||
/*
|
|
||||||
* Get the drawing surface info.
|
|
||||||
* The value returned may be cached, but the values may change if
|
|
||||||
* additional calls to Lock() or Unlock() are made.
|
|
||||||
* Lock() must be called before this can return a valid value.
|
|
||||||
* Returns NULL if an error has occurred.
|
|
||||||
* When finished with the returned value, FreeDrawingSurfaceInfo must be
|
|
||||||
* called.
|
|
||||||
*/
|
|
||||||
JAWT_DrawingSurfaceInfo* (JNICALL *GetDrawingSurfaceInfo)
|
|
||||||
(struct jawt_DrawingSurface* ds);
|
|
||||||
/*
|
|
||||||
* Free the drawing surface info.
|
|
||||||
*/
|
|
||||||
void (JNICALL *FreeDrawingSurfaceInfo)
|
|
||||||
(JAWT_DrawingSurfaceInfo* dsi);
|
|
||||||
/*
|
|
||||||
* Unlock the drawing surface of the target component for native rendering.
|
|
||||||
*/
|
|
||||||
void (JNICALL *Unlock)
|
|
||||||
(struct jawt_DrawingSurface* ds);
|
|
||||||
} JAWT_DrawingSurface;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JAWT
|
|
||||||
* Structure for containing native AWT functions.
|
|
||||||
*/
|
|
||||||
typedef struct jawt {
|
|
||||||
/*
|
|
||||||
* Version of this structure. This must always be set before
|
|
||||||
* calling JAWT_GetAWT(). It affects the functions returned.
|
|
||||||
* Must be one of the known pre-defined versions.
|
|
||||||
*/
|
|
||||||
jint version;
|
|
||||||
/*
|
|
||||||
* Return a drawing surface from a target jobject. This value
|
|
||||||
* may be cached.
|
|
||||||
* Returns NULL if an error has occurred.
|
|
||||||
* Target must be a java.awt.Component (should be a Canvas
|
|
||||||
* or Window for native rendering).
|
|
||||||
* FreeDrawingSurface() must be called when finished with the
|
|
||||||
* returned JAWT_DrawingSurface.
|
|
||||||
*/
|
|
||||||
JAWT_DrawingSurface* (JNICALL *GetDrawingSurface)
|
|
||||||
(JNIEnv* env, jobject target);
|
|
||||||
/*
|
|
||||||
* Free the drawing surface allocated in GetDrawingSurface.
|
|
||||||
*/
|
|
||||||
void (JNICALL *FreeDrawingSurface)
|
|
||||||
(JAWT_DrawingSurface* ds);
|
|
||||||
/*
|
|
||||||
* Since 1.4
|
|
||||||
* Locks the entire AWT for synchronization purposes
|
|
||||||
*/
|
|
||||||
void (JNICALL *Lock)(JNIEnv* env);
|
|
||||||
/*
|
|
||||||
* Since 1.4
|
|
||||||
* Unlocks the entire AWT for synchronization purposes
|
|
||||||
*/
|
|
||||||
void (JNICALL *Unlock)(JNIEnv* env);
|
|
||||||
/*
|
|
||||||
* Since 1.4
|
|
||||||
* Returns a reference to a java.awt.Component from a native
|
|
||||||
* platform handle. On Windows, this corresponds to an HWND;
|
|
||||||
* on Solaris and Linux, this is a Drawable. For other platforms,
|
|
||||||
* see the appropriate machine-dependent header file for a description.
|
|
||||||
* The reference returned by this function is a local
|
|
||||||
* reference that is only valid in this environment.
|
|
||||||
* This function returns a NULL reference if no component could be
|
|
||||||
* found with matching platform information.
|
|
||||||
*/
|
|
||||||
jobject (JNICALL *GetComponent)(JNIEnv* env, void* platformInfo);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since 9
|
|
||||||
* Creates a java.awt.Frame placed in a native container. Container is
|
|
||||||
* referenced by the native platform handle. For example on Windows this
|
|
||||||
* corresponds to an HWND. For other platforms, see the appropriate
|
|
||||||
* machine-dependent header file for a description. The reference returned
|
|
||||||
* by this function is a local reference that is only valid in this
|
|
||||||
* environment. This function returns a NULL reference if no frame could be
|
|
||||||
* created with matching platform information.
|
|
||||||
*/
|
|
||||||
jobject (JNICALL *CreateEmbeddedFrame) (JNIEnv *env, void* platformInfo);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since 9
|
|
||||||
* Moves and resizes the embedded frame. The new location of the top-left
|
|
||||||
* corner is specified by x and y parameters relative to the native parent
|
|
||||||
* component. The new size is specified by width and height.
|
|
||||||
*
|
|
||||||
* The embedded frame should be created by CreateEmbeddedFrame() method, or
|
|
||||||
* this function will not have any effect.
|
|
||||||
*
|
|
||||||
* java.awt.Component.setLocation() and java.awt.Component.setBounds() for
|
|
||||||
* EmbeddedFrame really don't move it within the native parent. These
|
|
||||||
* methods always locate the embedded frame at (0, 0) for backward
|
|
||||||
* compatibility. To allow moving embedded frames this method was
|
|
||||||
* introduced, and it works just the same way as setLocation() and
|
|
||||||
* setBounds() for usual, non-embedded components.
|
|
||||||
*
|
|
||||||
* Using usual get/setLocation() and get/setBounds() together with this new
|
|
||||||
* method is not recommended.
|
|
||||||
*/
|
|
||||||
void (JNICALL *SetBounds) (JNIEnv *env, jobject embeddedFrame,
|
|
||||||
jint x, jint y, jint w, jint h);
|
|
||||||
/**
|
|
||||||
* Since 9
|
|
||||||
* Synthesize a native message to activate or deactivate an EmbeddedFrame
|
|
||||||
* window depending on the value of parameter doActivate, if "true"
|
|
||||||
* activates the window; otherwise, deactivates the window.
|
|
||||||
*
|
|
||||||
* The embedded frame should be created by CreateEmbeddedFrame() method, or
|
|
||||||
* this function will not have any effect.
|
|
||||||
*/
|
|
||||||
void (JNICALL *SynthesizeWindowActivation) (JNIEnv *env,
|
|
||||||
jobject embeddedFrame, jboolean doActivate);
|
|
||||||
} JAWT;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the AWT native structure. This function returns JNI_FALSE if
|
|
||||||
* an error occurs.
|
|
||||||
*/
|
|
||||||
_JNI_IMPORT_OR_EXPORT_
|
|
||||||
jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Specify one of these constants as the JAWT.version
|
|
||||||
* Specifying an earlier version will limit the available functions to
|
|
||||||
* those provided in that earlier version of JAWT.
|
|
||||||
* See the "Since" note on each API. Methods with no "Since"
|
|
||||||
* may be presumed to be present in JAWT_VERSION_1_3.
|
|
||||||
*/
|
|
||||||
#define JAWT_VERSION_1_3 0x00010003
|
|
||||||
#define JAWT_VERSION_1_4 0x00010004
|
|
||||||
#define JAWT_VERSION_1_7 0x00010007
|
|
||||||
#define JAWT_VERSION_9 0x00090000
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !_JAVASOFT_JAWT_H_ */
|
|
|
@ -1,276 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Java Debug Wire Protocol Transport Service Provider Interface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef JDWPTRANSPORT_H
|
|
||||||
#define JDWPTRANSPORT_H
|
|
||||||
|
|
||||||
#include "jni.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JDWPTRANSPORT_VERSION_1_0 = 0x00010000,
|
|
||||||
JDWPTRANSPORT_VERSION_1_1 = 0x00010001
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct jdwpTransportNativeInterface_;
|
|
||||||
|
|
||||||
struct _jdwpTransportEnv;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
typedef _jdwpTransportEnv jdwpTransportEnv;
|
|
||||||
#else
|
|
||||||
typedef const struct jdwpTransportNativeInterface_ *jdwpTransportEnv;
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Errors. Universal errors with JVMTI/JVMDI equivalents keep the
|
|
||||||
* values the same.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
JDWPTRANSPORT_ERROR_NONE = 0,
|
|
||||||
JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT = 103,
|
|
||||||
JDWPTRANSPORT_ERROR_OUT_OF_MEMORY = 110,
|
|
||||||
JDWPTRANSPORT_ERROR_INTERNAL = 113,
|
|
||||||
JDWPTRANSPORT_ERROR_ILLEGAL_STATE = 201,
|
|
||||||
JDWPTRANSPORT_ERROR_IO_ERROR = 202,
|
|
||||||
JDWPTRANSPORT_ERROR_TIMEOUT = 203,
|
|
||||||
JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE = 204
|
|
||||||
} jdwpTransportError;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structure to define capabilities
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int can_timeout_attach :1;
|
|
||||||
unsigned int can_timeout_accept :1;
|
|
||||||
unsigned int can_timeout_handshake :1;
|
|
||||||
unsigned int reserved3 :1;
|
|
||||||
unsigned int reserved4 :1;
|
|
||||||
unsigned int reserved5 :1;
|
|
||||||
unsigned int reserved6 :1;
|
|
||||||
unsigned int reserved7 :1;
|
|
||||||
unsigned int reserved8 :1;
|
|
||||||
unsigned int reserved9 :1;
|
|
||||||
unsigned int reserved10 :1;
|
|
||||||
unsigned int reserved11 :1;
|
|
||||||
unsigned int reserved12 :1;
|
|
||||||
unsigned int reserved13 :1;
|
|
||||||
unsigned int reserved14 :1;
|
|
||||||
unsigned int reserved15 :1;
|
|
||||||
} JDWPTransportCapabilities;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structures to define packet layout.
|
|
||||||
*
|
|
||||||
* See: http://java.sun.com/j2se/1.5/docs/guide/jpda/jdwp-spec.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define JDWP_HEADER_SIZE 11
|
|
||||||
|
|
||||||
enum {
|
|
||||||
/*
|
|
||||||
* If additional flags are added that apply to jdwpCmdPacket,
|
|
||||||
* then debugLoop.c: reader() will need to be updated to
|
|
||||||
* accept more than JDWPTRANSPORT_FLAGS_NONE.
|
|
||||||
*/
|
|
||||||
JDWPTRANSPORT_FLAGS_NONE = 0x0,
|
|
||||||
JDWPTRANSPORT_FLAGS_REPLY = 0x80
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
jint len;
|
|
||||||
jint id;
|
|
||||||
jbyte flags;
|
|
||||||
jbyte cmdSet;
|
|
||||||
jbyte cmd;
|
|
||||||
jbyte *data;
|
|
||||||
} jdwpCmdPacket;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
jint len;
|
|
||||||
jint id;
|
|
||||||
jbyte flags;
|
|
||||||
jshort errorCode;
|
|
||||||
jbyte *data;
|
|
||||||
} jdwpReplyPacket;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
union {
|
|
||||||
jdwpCmdPacket cmd;
|
|
||||||
jdwpReplyPacket reply;
|
|
||||||
} type;
|
|
||||||
} jdwpPacket;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JDWP functions called by the transport.
|
|
||||||
*/
|
|
||||||
typedef struct jdwpTransportCallback {
|
|
||||||
void *(*alloc)(jint numBytes); /* Call this for all allocations */
|
|
||||||
void (*free)(void *buffer); /* Call this for all deallocations */
|
|
||||||
} jdwpTransportCallback;
|
|
||||||
|
|
||||||
typedef jint (JNICALL *jdwpTransport_OnLoad_t)(JavaVM *jvm,
|
|
||||||
jdwpTransportCallback *callback,
|
|
||||||
jint version,
|
|
||||||
jdwpTransportEnv** env);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JDWP transport configuration from the agent.
|
|
||||||
*/
|
|
||||||
typedef struct jdwpTransportConfiguration {
|
|
||||||
/* Field added in JDWPTRANSPORT_VERSION_1_1: */
|
|
||||||
const char* allowed_peers; /* Peers allowed for connection */
|
|
||||||
} jdwpTransportConfiguration;
|
|
||||||
|
|
||||||
|
|
||||||
/* Function Interface */
|
|
||||||
|
|
||||||
struct jdwpTransportNativeInterface_ {
|
|
||||||
/* 1 : RESERVED */
|
|
||||||
void *reserved1;
|
|
||||||
|
|
||||||
/* 2 : Get Capabilities */
|
|
||||||
jdwpTransportError (JNICALL *GetCapabilities)(jdwpTransportEnv* env,
|
|
||||||
JDWPTransportCapabilities *capabilities_ptr);
|
|
||||||
|
|
||||||
/* 3 : Attach */
|
|
||||||
jdwpTransportError (JNICALL *Attach)(jdwpTransportEnv* env,
|
|
||||||
const char* address,
|
|
||||||
jlong attach_timeout,
|
|
||||||
jlong handshake_timeout);
|
|
||||||
|
|
||||||
/* 4: StartListening */
|
|
||||||
jdwpTransportError (JNICALL *StartListening)(jdwpTransportEnv* env,
|
|
||||||
const char* address,
|
|
||||||
char** actual_address);
|
|
||||||
|
|
||||||
/* 5: StopListening */
|
|
||||||
jdwpTransportError (JNICALL *StopListening)(jdwpTransportEnv* env);
|
|
||||||
|
|
||||||
/* 6: Accept */
|
|
||||||
jdwpTransportError (JNICALL *Accept)(jdwpTransportEnv* env,
|
|
||||||
jlong accept_timeout,
|
|
||||||
jlong handshake_timeout);
|
|
||||||
|
|
||||||
/* 7: IsOpen */
|
|
||||||
jboolean (JNICALL *IsOpen)(jdwpTransportEnv* env);
|
|
||||||
|
|
||||||
/* 8: Close */
|
|
||||||
jdwpTransportError (JNICALL *Close)(jdwpTransportEnv* env);
|
|
||||||
|
|
||||||
/* 9: ReadPacket */
|
|
||||||
jdwpTransportError (JNICALL *ReadPacket)(jdwpTransportEnv* env,
|
|
||||||
jdwpPacket *pkt);
|
|
||||||
|
|
||||||
/* 10: Write Packet */
|
|
||||||
jdwpTransportError (JNICALL *WritePacket)(jdwpTransportEnv* env,
|
|
||||||
const jdwpPacket* pkt);
|
|
||||||
|
|
||||||
/* 11: GetLastError */
|
|
||||||
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
|
|
||||||
char** error);
|
|
||||||
|
|
||||||
/* 12: SetTransportConfiguration added in JDWPTRANSPORT_VERSION_1_1 */
|
|
||||||
jdwpTransportError (JNICALL *SetTransportConfiguration)(jdwpTransportEnv* env,
|
|
||||||
jdwpTransportConfiguration *config);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use inlined functions so that C++ code can use syntax such as
|
|
||||||
* env->Attach("mymachine:5000", 10*1000, 0);
|
|
||||||
*
|
|
||||||
* rather than using C's :-
|
|
||||||
*
|
|
||||||
* (*env)->Attach(env, "mymachine:5000", 10*1000, 0);
|
|
||||||
*/
|
|
||||||
struct _jdwpTransportEnv {
|
|
||||||
const struct jdwpTransportNativeInterface_ *functions;
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
jdwpTransportError GetCapabilities(JDWPTransportCapabilities *capabilities_ptr) {
|
|
||||||
return functions->GetCapabilities(this, capabilities_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError Attach(const char* address, jlong attach_timeout,
|
|
||||||
jlong handshake_timeout) {
|
|
||||||
return functions->Attach(this, address, attach_timeout, handshake_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError StartListening(const char* address,
|
|
||||||
char** actual_address) {
|
|
||||||
return functions->StartListening(this, address, actual_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError StopListening(void) {
|
|
||||||
return functions->StopListening(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError Accept(jlong accept_timeout, jlong handshake_timeout) {
|
|
||||||
return functions->Accept(this, accept_timeout, handshake_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
jboolean IsOpen(void) {
|
|
||||||
return functions->IsOpen(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError Close(void) {
|
|
||||||
return functions->Close(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError ReadPacket(jdwpPacket *pkt) {
|
|
||||||
return functions->ReadPacket(this, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError WritePacket(const jdwpPacket* pkt) {
|
|
||||||
return functions->WritePacket(this, pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
jdwpTransportError GetLastError(char** error) {
|
|
||||||
return functions->GetLastError(this, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SetTransportConfiguration added in JDWPTRANSPORT_VERSION_1_1 */
|
|
||||||
jdwpTransportError SetTransportConfiguration(jdwpTransportEnv* env,
|
|
||||||
return functions->SetTransportConfiguration(this, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* JDWPTRANSPORT_H */
|
|
1987
jni/windows/jni.h
1987
jni/windows/jni.h
File diff suppressed because it is too large
Load Diff
2624
jni/windows/jvmti.h
2624
jni/windows/jvmti.h
File diff suppressed because it is too large
Load Diff
|
@ -1,115 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This header file defines the data structures sent by the VM
|
|
||||||
* through the JVMTI CompiledMethodLoad callback function via the
|
|
||||||
* "void * compile_info" parameter. The memory pointed to by the
|
|
||||||
* compile_info parameter may not be referenced after returning from
|
|
||||||
* the CompiledMethodLoad callback. These are VM implementation
|
|
||||||
* specific data structures that may evolve in future releases. A
|
|
||||||
* JVMTI agent should interpret a non-NULL compile_info as a pointer
|
|
||||||
* to a region of memory containing a list of records. In a typical
|
|
||||||
* usage scenario, a JVMTI agent would cast each record to a
|
|
||||||
* jvmtiCompiledMethodLoadRecordHeader, a struct that represents
|
|
||||||
* arbitrary information. This struct contains a kind field to indicate
|
|
||||||
* the kind of information being passed, and a pointer to the next
|
|
||||||
* record. If the kind field indicates inlining information, then the
|
|
||||||
* agent would cast the record to a jvmtiCompiledMethodLoadInlineRecord.
|
|
||||||
* This record contains an array of PCStackInfo structs, which indicate
|
|
||||||
* for every pc address what are the methods on the invocation stack.
|
|
||||||
* The "methods" and "bcis" fields in each PCStackInfo struct specify a
|
|
||||||
* 1-1 mapping between these inlined methods and their bytecode indices.
|
|
||||||
* This can be used to derive the proper source lines of the inlined
|
|
||||||
* methods.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JVMTI_CMLR_H_
|
|
||||||
#define _JVMTI_CMLR_H_
|
|
||||||
|
|
||||||
enum {
|
|
||||||
JVMTI_CMLR_MAJOR_VERSION_1 = 0x00000001,
|
|
||||||
JVMTI_CMLR_MINOR_VERSION_0 = 0x00000000,
|
|
||||||
|
|
||||||
JVMTI_CMLR_MAJOR_VERSION = 0x00000001,
|
|
||||||
JVMTI_CMLR_MINOR_VERSION = 0x00000000
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This comment is for the "JDK import from HotSpot" sanity check:
|
|
||||||
* version: 1.0.0
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
JVMTI_CMLR_DUMMY = 1,
|
|
||||||
JVMTI_CMLR_INLINE_INFO = 2
|
|
||||||
} jvmtiCMLRKind;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Record that represents arbitrary information passed through JVMTI
|
|
||||||
* CompiledMethodLoadEvent void pointer.
|
|
||||||
*/
|
|
||||||
typedef struct _jvmtiCompiledMethodLoadRecordHeader {
|
|
||||||
jvmtiCMLRKind kind; /* id for the kind of info passed in the record */
|
|
||||||
jint majorinfoversion; /* major and minor info version values. Init'ed */
|
|
||||||
jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */
|
|
||||||
|
|
||||||
struct _jvmtiCompiledMethodLoadRecordHeader* next;
|
|
||||||
} jvmtiCompiledMethodLoadRecordHeader;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Record that gives information about the methods on the compile-time
|
|
||||||
* stack at a specific pc address of a compiled method. Each element in
|
|
||||||
* the methods array maps to same element in the bcis array.
|
|
||||||
*/
|
|
||||||
typedef struct _PCStackInfo {
|
|
||||||
void* pc; /* the pc address for this compiled method */
|
|
||||||
jint numstackframes; /* number of methods on the stack */
|
|
||||||
jmethodID* methods; /* array of numstackframes method ids */
|
|
||||||
jint* bcis; /* array of numstackframes bytecode indices */
|
|
||||||
} PCStackInfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Record that contains inlining information for each pc address of
|
|
||||||
* an nmethod.
|
|
||||||
*/
|
|
||||||
typedef struct _jvmtiCompiledMethodLoadInlineRecord {
|
|
||||||
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
|
|
||||||
jint numpcs; /* number of pc descriptors in this nmethod */
|
|
||||||
PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
|
|
||||||
} jvmtiCompiledMethodLoadInlineRecord;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dummy record used to test that we can pass records with different
|
|
||||||
* information through the void pointer provided that they can be cast
|
|
||||||
* to a jvmtiCompiledMethodLoadRecordHeader.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct _jvmtiCompiledMethodLoadDummyRecord {
|
|
||||||
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
|
|
||||||
char message[50];
|
|
||||||
} jvmtiCompiledMethodLoadDummyRecord;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,92 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Header file defining callback typedefs for Windows routines
|
|
||||||
* which are called from Java (responding to events, etc.).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __AccessBridgeCallbacks_H__
|
|
||||||
#define __AccessBridgeCallbacks_H__
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
#include "AccessBridgePackages.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef void (*AccessBridge_PropertyChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
|
||||||
wchar_t *property, wchar_t *oldValue, wchar_t *newValue);
|
|
||||||
|
|
||||||
typedef void (*AccessBridge_JavaShutdownFP) (long vmID);
|
|
||||||
typedef void (*AccessBridge_JavaShutdownFP) (long vmID);
|
|
||||||
|
|
||||||
typedef void (*AccessBridge_FocusGainedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_FocusLostFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
|
|
||||||
typedef void (*AccessBridge_CaretUpdateFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
|
|
||||||
typedef void (*AccessBridge_MouseClickedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_MouseEnteredFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_MouseExitedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_MousePressedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_MouseReleasedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
|
|
||||||
typedef void (*AccessBridge_MenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_MenuDeselectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_MenuSelectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_PopupMenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_PopupMenuWillBecomeInvisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_PopupMenuWillBecomeVisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
|
|
||||||
typedef void (*AccessBridge_PropertyNameChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
|
||||||
wchar_t *oldName, wchar_t *newName);
|
|
||||||
typedef void (*AccessBridge_PropertyDescriptionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
|
||||||
wchar_t *oldDescription, wchar_t *newDescription);
|
|
||||||
typedef void (*AccessBridge_PropertyStateChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
|
||||||
wchar_t *oldState, wchar_t *newState);
|
|
||||||
typedef void (*AccessBridge_PropertyValueChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
|
||||||
wchar_t *oldValue, wchar_t *newValue);
|
|
||||||
typedef void (*AccessBridge_PropertySelectionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_PropertyTextChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_PropertyCaretChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
|
||||||
int oldPosition, int newPosition);
|
|
||||||
typedef void (*AccessBridge_PropertyVisibleDataChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
|
|
||||||
typedef void (*AccessBridge_PropertyChildChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
|
|
||||||
JOBJECT64 oldChild, JOBJECT64 newChild);
|
|
||||||
typedef void (*AccessBridge_PropertyActiveDescendentChangeFP) (long vmID, JOBJECT64 event,
|
|
||||||
JOBJECT64 source,
|
|
||||||
JOBJECT64 oldActiveDescendent,
|
|
||||||
JOBJECT64 newActiveDescendent);
|
|
||||||
|
|
||||||
typedef void (*AccessBridge_PropertyTableModelChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 src,
|
|
||||||
wchar_t *oldValue, wchar_t *newValue);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,725 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Note: In addition to this header file AccessBridgeCalls.c must be compiled and
|
|
||||||
* linked to your application. AccessBridgeCalls.c implements the Java Access
|
|
||||||
* Bridge API and also hides the complexities associated with interfacing to the
|
|
||||||
* associated Java Access Bridge DLL which is installed when Java is installed.
|
|
||||||
*
|
|
||||||
* AccessBridgeCalls.c is available for download from the OpenJDK repository using
|
|
||||||
* the following link:
|
|
||||||
*
|
|
||||||
* http://hg.openjdk.java.net/jdk9/jdk9/jdk/raw-file/tip/src/jdk.accessibility/windows/native/bridge/AccessBridgeCalls.c
|
|
||||||
*
|
|
||||||
* Also note that the API is used in the jaccessinspector and jaccesswalker tools.
|
|
||||||
* The source for those tools is available in the OpenJDK repository at these links:
|
|
||||||
*
|
|
||||||
* http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp
|
|
||||||
* http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalker.cpp
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wrapper functions around calls to the AccessBridge DLL
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <jni.h>
|
|
||||||
#include "AccessBridgeCallbacks.h"
|
|
||||||
#include "AccessBridgePackages.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define null NULL
|
|
||||||
|
|
||||||
typedef JOBJECT64 AccessibleContext;
|
|
||||||
typedef JOBJECT64 AccessibleText;
|
|
||||||
typedef JOBJECT64 AccessibleValue;
|
|
||||||
typedef JOBJECT64 AccessibleSelection;
|
|
||||||
typedef JOBJECT64 Java_Object;
|
|
||||||
typedef JOBJECT64 PropertyChangeEvent;
|
|
||||||
typedef JOBJECT64 FocusEvent;
|
|
||||||
typedef JOBJECT64 CaretEvent;
|
|
||||||
typedef JOBJECT64 MouseEvent;
|
|
||||||
typedef JOBJECT64 MenuEvent;
|
|
||||||
typedef JOBJECT64 AccessibleTable;
|
|
||||||
typedef JOBJECT64 AccessibleHyperlink;
|
|
||||||
typedef JOBJECT64 AccessibleHypertext;
|
|
||||||
|
|
||||||
|
|
||||||
typedef void (*Windows_runFP) ();
|
|
||||||
|
|
||||||
typedef void (*SetPropertyChangeFP) (AccessBridge_PropertyChangeFP fp);
|
|
||||||
|
|
||||||
typedef void (*SetJavaShutdownFP) (AccessBridge_JavaShutdownFP fp);
|
|
||||||
typedef void (*SetFocusGainedFP) (AccessBridge_FocusGainedFP fp);
|
|
||||||
typedef void (*SetFocusLostFP) (AccessBridge_FocusLostFP fp);
|
|
||||||
|
|
||||||
typedef void (*SetCaretUpdateFP) (AccessBridge_CaretUpdateFP fp);
|
|
||||||
|
|
||||||
typedef void (*SetMouseClickedFP) (AccessBridge_MouseClickedFP fp);
|
|
||||||
typedef void (*SetMouseEnteredFP) (AccessBridge_MouseEnteredFP fp);
|
|
||||||
typedef void (*SetMouseExitedFP) (AccessBridge_MouseExitedFP fp);
|
|
||||||
typedef void (*SetMousePressedFP) (AccessBridge_MousePressedFP fp);
|
|
||||||
typedef void (*SetMouseReleasedFP) (AccessBridge_MouseReleasedFP fp);
|
|
||||||
|
|
||||||
typedef void (*SetMenuCanceledFP) (AccessBridge_MenuCanceledFP fp);
|
|
||||||
typedef void (*SetMenuDeselectedFP) (AccessBridge_MenuDeselectedFP fp);
|
|
||||||
typedef void (*SetMenuSelectedFP) (AccessBridge_MenuSelectedFP fp);
|
|
||||||
typedef void (*SetPopupMenuCanceledFP) (AccessBridge_PopupMenuCanceledFP fp);
|
|
||||||
typedef void (*SetPopupMenuWillBecomeInvisibleFP) (AccessBridge_PopupMenuWillBecomeInvisibleFP fp);
|
|
||||||
typedef void (*SetPopupMenuWillBecomeVisibleFP) (AccessBridge_PopupMenuWillBecomeVisibleFP fp);
|
|
||||||
|
|
||||||
typedef void (*SetPropertyNameChangeFP) (AccessBridge_PropertyNameChangeFP fp);
|
|
||||||
typedef void (*SetPropertyDescriptionChangeFP) (AccessBridge_PropertyDescriptionChangeFP fp);
|
|
||||||
typedef void (*SetPropertyStateChangeFP) (AccessBridge_PropertyStateChangeFP fp);
|
|
||||||
typedef void (*SetPropertyValueChangeFP) (AccessBridge_PropertyValueChangeFP fp);
|
|
||||||
typedef void (*SetPropertySelectionChangeFP) (AccessBridge_PropertySelectionChangeFP fp);
|
|
||||||
typedef void (*SetPropertyTextChangeFP) (AccessBridge_PropertyTextChangeFP fp);
|
|
||||||
typedef void (*SetPropertyCaretChangeFP) (AccessBridge_PropertyCaretChangeFP fp);
|
|
||||||
typedef void (*SetPropertyVisibleDataChangeFP) (AccessBridge_PropertyVisibleDataChangeFP fp);
|
|
||||||
typedef void (*SetPropertyChildChangeFP) (AccessBridge_PropertyChildChangeFP fp);
|
|
||||||
typedef void (*SetPropertyActiveDescendentChangeFP) (AccessBridge_PropertyActiveDescendentChangeFP fp);
|
|
||||||
|
|
||||||
typedef void (*SetPropertyTableModelChangeFP) (AccessBridge_PropertyTableModelChangeFP fp);
|
|
||||||
|
|
||||||
typedef void (*ReleaseJavaObjectFP) (long vmID, Java_Object object);
|
|
||||||
|
|
||||||
typedef BOOL (*GetVersionInfoFP) (long vmID, AccessBridgeVersionInfo *info);
|
|
||||||
|
|
||||||
typedef BOOL (*IsJavaWindowFP) (HWND window);
|
|
||||||
typedef BOOL (*IsSameObjectFP) (long vmID, JOBJECT64 obj1, JOBJECT64 obj2);
|
|
||||||
typedef BOOL (*GetAccessibleContextFromHWNDFP) (HWND window, long *vmID, AccessibleContext *ac);
|
|
||||||
typedef HWND (*getHWNDFromAccessibleContextFP) (long vmID, AccessibleContext ac);
|
|
||||||
|
|
||||||
typedef BOOL (*GetAccessibleContextAtFP) (long vmID, AccessibleContext acParent,
|
|
||||||
jint x, jint y, AccessibleContext *ac);
|
|
||||||
typedef BOOL (*GetAccessibleContextWithFocusFP) (HWND window, long *vmID, AccessibleContext *ac);
|
|
||||||
typedef BOOL (*GetAccessibleContextInfoFP) (long vmID, AccessibleContext ac, AccessibleContextInfo *info);
|
|
||||||
typedef AccessibleContext (*GetAccessibleChildFromContextFP) (long vmID, AccessibleContext ac, jint i);
|
|
||||||
typedef AccessibleContext (*GetAccessibleParentFromContextFP) (long vmID, AccessibleContext ac);
|
|
||||||
|
|
||||||
/* begin AccessibleTable */
|
|
||||||
typedef BOOL (*getAccessibleTableInfoFP) (long vmID, AccessibleContext ac, AccessibleTableInfo *tableInfo);
|
|
||||||
typedef BOOL (*getAccessibleTableCellInfoFP) (long vmID, AccessibleTable accessibleTable,
|
|
||||||
jint row, jint column, AccessibleTableCellInfo *tableCellInfo);
|
|
||||||
|
|
||||||
typedef BOOL (*getAccessibleTableRowHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
|
||||||
typedef BOOL (*getAccessibleTableColumnHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
|
||||||
|
|
||||||
typedef AccessibleContext (*getAccessibleTableRowDescriptionFP) (long vmID, AccessibleContext acParent, jint row);
|
|
||||||
typedef AccessibleContext (*getAccessibleTableColumnDescriptionFP) (long vmID, AccessibleContext acParent, jint column);
|
|
||||||
|
|
||||||
typedef jint (*getAccessibleTableRowSelectionCountFP) (long vmID, AccessibleTable table);
|
|
||||||
typedef BOOL (*isAccessibleTableRowSelectedFP) (long vmID, AccessibleTable table, jint row);
|
|
||||||
typedef BOOL (*getAccessibleTableRowSelectionsFP) (long vmID, AccessibleTable table, jint count,
|
|
||||||
jint *selections);
|
|
||||||
|
|
||||||
typedef jint (*getAccessibleTableColumnSelectionCountFP) (long vmID, AccessibleTable table);
|
|
||||||
typedef BOOL (*isAccessibleTableColumnSelectedFP) (long vmID, AccessibleTable table, jint column);
|
|
||||||
typedef BOOL (*getAccessibleTableColumnSelectionsFP) (long vmID, AccessibleTable table, jint count,
|
|
||||||
jint *selections);
|
|
||||||
|
|
||||||
typedef jint (*getAccessibleTableRowFP) (long vmID, AccessibleTable table, jint index);
|
|
||||||
typedef jint (*getAccessibleTableColumnFP) (long vmID, AccessibleTable table, jint index);
|
|
||||||
typedef jint (*getAccessibleTableIndexFP) (long vmID, AccessibleTable table, jint row, jint column);
|
|
||||||
/* end AccessibleTable */
|
|
||||||
|
|
||||||
/* AccessibleRelationSet */
|
|
||||||
typedef BOOL (*getAccessibleRelationSetFP) (long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleRelationSetInfo *relationSetInfo);
|
|
||||||
|
|
||||||
/* AccessibleHypertext */
|
|
||||||
typedef BOOL (*getAccessibleHypertextFP)(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleHypertextInfo *hypertextInfo);
|
|
||||||
|
|
||||||
typedef BOOL (*activateAccessibleHyperlinkFP)(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleHyperlink accessibleHyperlink);
|
|
||||||
|
|
||||||
typedef jint (*getAccessibleHyperlinkCountFP)(const long vmID,
|
|
||||||
const AccessibleContext accessibleContext);
|
|
||||||
|
|
||||||
typedef BOOL (*getAccessibleHypertextExtFP) (const long vmID,
|
|
||||||
const AccessibleContext accessibleContext,
|
|
||||||
const jint nStartIndex,
|
|
||||||
AccessibleHypertextInfo *hypertextInfo);
|
|
||||||
|
|
||||||
typedef jint (*getAccessibleHypertextLinkIndexFP)(const long vmID,
|
|
||||||
const AccessibleHypertext hypertext,
|
|
||||||
const jint nIndex);
|
|
||||||
|
|
||||||
typedef BOOL (*getAccessibleHyperlinkFP)(const long vmID,
|
|
||||||
const AccessibleHypertext hypertext,
|
|
||||||
const jint nIndex,
|
|
||||||
AccessibleHyperlinkInfo *hyperlinkInfo);
|
|
||||||
|
|
||||||
|
|
||||||
/* Accessible KeyBindings, Icons and Actions */
|
|
||||||
typedef BOOL (*getAccessibleKeyBindingsFP)(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleKeyBindings *keyBindings);
|
|
||||||
|
|
||||||
typedef BOOL (*getAccessibleIconsFP)(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleIcons *icons);
|
|
||||||
|
|
||||||
typedef BOOL (*getAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleActions *actions);
|
|
||||||
|
|
||||||
typedef BOOL (*doAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleActionsToDo *actionsToDo, jint *failure);
|
|
||||||
|
|
||||||
|
|
||||||
/* AccessibleText */
|
|
||||||
|
|
||||||
typedef BOOL (*GetAccessibleTextInfoFP) (long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y);
|
|
||||||
typedef BOOL (*GetAccessibleTextItemsFP) (long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index);
|
|
||||||
typedef BOOL (*GetAccessibleTextSelectionInfoFP) (long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection);
|
|
||||||
typedef BOOL (*GetAccessibleTextAttributesFP) (long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes);
|
|
||||||
typedef BOOL (*GetAccessibleTextRectFP) (long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index);
|
|
||||||
typedef BOOL (*GetAccessibleTextLineBoundsFP) (long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex);
|
|
||||||
typedef BOOL (*GetAccessibleTextRangeFP) (long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len);
|
|
||||||
|
|
||||||
typedef BOOL (*GetCurrentAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
|
|
||||||
typedef BOOL (*GetMaximumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
|
|
||||||
typedef BOOL (*GetMinimumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
|
|
||||||
|
|
||||||
typedef void (*AddAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
|
|
||||||
typedef void (*ClearAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as);
|
|
||||||
typedef JOBJECT64 (*GetAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
|
|
||||||
typedef int (*GetAccessibleSelectionCountFromContextFP) (long vmID, AccessibleSelection as);
|
|
||||||
typedef BOOL (*IsAccessibleChildSelectedFromContextFP) (long vmID, AccessibleSelection as, int i);
|
|
||||||
typedef void (*RemoveAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
|
|
||||||
typedef void (*SelectAllAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as);
|
|
||||||
|
|
||||||
/* Utility methods */
|
|
||||||
|
|
||||||
typedef BOOL (*setTextContentsFP) (const long vmID, const AccessibleContext ac, const wchar_t *text);
|
|
||||||
typedef AccessibleContext (*getParentWithRoleFP) (const long vmID, const AccessibleContext ac, const wchar_t *role);
|
|
||||||
typedef AccessibleContext (*getParentWithRoleElseRootFP) (const long vmID, const AccessibleContext ac, const wchar_t *role);
|
|
||||||
typedef AccessibleContext (*getTopLevelObjectFP) (const long vmID, const AccessibleContext ac);
|
|
||||||
typedef int (*getObjectDepthFP) (const long vmID, const AccessibleContext ac);
|
|
||||||
typedef AccessibleContext (*getActiveDescendentFP) (const long vmID, const AccessibleContext ac);
|
|
||||||
|
|
||||||
|
|
||||||
typedef BOOL (*getVirtualAccessibleNameFP) (const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
wchar_t *name, int len);
|
|
||||||
|
|
||||||
typedef BOOL (*requestFocusFP) (const long vmID, const AccessibleContext accessibleContext);
|
|
||||||
|
|
||||||
typedef BOOL (*selectTextRangeFP) (const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
const int startIndex, const int endIndex);
|
|
||||||
|
|
||||||
typedef BOOL (*getTextAttributesInRangeFP) (const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
const int startIndex, const int endIndex,
|
|
||||||
AccessibleTextAttributesInfo *attributes, short *len);
|
|
||||||
|
|
||||||
typedef int (*getVisibleChildrenCountFP) (const long vmID, const AccessibleContext accessibleContext);
|
|
||||||
|
|
||||||
typedef BOOL (*getVisibleChildrenFP) (const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
const int startIndex, VisibleChildrenInfo *children);
|
|
||||||
|
|
||||||
typedef BOOL (*setCaretPositionFP) (const long vmID, const AccessibleContext accessibleContext, const int position);
|
|
||||||
|
|
||||||
typedef BOOL (*getCaretLocationFP) (long vmID, AccessibleContext ac, AccessibleTextRectInfo *rectInfo, jint index);
|
|
||||||
|
|
||||||
typedef int (*getEventsWaitingFP) ();
|
|
||||||
|
|
||||||
typedef struct AccessBridgeFPsTag {
|
|
||||||
Windows_runFP Windows_run;
|
|
||||||
|
|
||||||
SetPropertyChangeFP SetPropertyChange;
|
|
||||||
|
|
||||||
SetJavaShutdownFP SetJavaShutdown;
|
|
||||||
SetFocusGainedFP SetFocusGained;
|
|
||||||
SetFocusLostFP SetFocusLost;
|
|
||||||
|
|
||||||
SetCaretUpdateFP SetCaretUpdate;
|
|
||||||
|
|
||||||
SetMouseClickedFP SetMouseClicked;
|
|
||||||
SetMouseEnteredFP SetMouseEntered;
|
|
||||||
SetMouseExitedFP SetMouseExited;
|
|
||||||
SetMousePressedFP SetMousePressed;
|
|
||||||
SetMouseReleasedFP SetMouseReleased;
|
|
||||||
|
|
||||||
SetMenuCanceledFP SetMenuCanceled;
|
|
||||||
SetMenuDeselectedFP SetMenuDeselected;
|
|
||||||
SetMenuSelectedFP SetMenuSelected;
|
|
||||||
SetPopupMenuCanceledFP SetPopupMenuCanceled;
|
|
||||||
SetPopupMenuWillBecomeInvisibleFP SetPopupMenuWillBecomeInvisible;
|
|
||||||
SetPopupMenuWillBecomeVisibleFP SetPopupMenuWillBecomeVisible;
|
|
||||||
|
|
||||||
SetPropertyNameChangeFP SetPropertyNameChange;
|
|
||||||
SetPropertyDescriptionChangeFP SetPropertyDescriptionChange;
|
|
||||||
SetPropertyStateChangeFP SetPropertyStateChange;
|
|
||||||
SetPropertyValueChangeFP SetPropertyValueChange;
|
|
||||||
SetPropertySelectionChangeFP SetPropertySelectionChange;
|
|
||||||
SetPropertyTextChangeFP SetPropertyTextChange;
|
|
||||||
SetPropertyCaretChangeFP SetPropertyCaretChange;
|
|
||||||
SetPropertyVisibleDataChangeFP SetPropertyVisibleDataChange;
|
|
||||||
SetPropertyChildChangeFP SetPropertyChildChange;
|
|
||||||
SetPropertyActiveDescendentChangeFP SetPropertyActiveDescendentChange;
|
|
||||||
|
|
||||||
SetPropertyTableModelChangeFP SetPropertyTableModelChange;
|
|
||||||
|
|
||||||
ReleaseJavaObjectFP ReleaseJavaObject;
|
|
||||||
GetVersionInfoFP GetVersionInfo;
|
|
||||||
|
|
||||||
IsJavaWindowFP IsJavaWindow;
|
|
||||||
IsSameObjectFP IsSameObject;
|
|
||||||
GetAccessibleContextFromHWNDFP GetAccessibleContextFromHWND;
|
|
||||||
getHWNDFromAccessibleContextFP getHWNDFromAccessibleContext;
|
|
||||||
|
|
||||||
GetAccessibleContextAtFP GetAccessibleContextAt;
|
|
||||||
GetAccessibleContextWithFocusFP GetAccessibleContextWithFocus;
|
|
||||||
GetAccessibleContextInfoFP GetAccessibleContextInfo;
|
|
||||||
GetAccessibleChildFromContextFP GetAccessibleChildFromContext;
|
|
||||||
GetAccessibleParentFromContextFP GetAccessibleParentFromContext;
|
|
||||||
|
|
||||||
getAccessibleTableInfoFP getAccessibleTableInfo;
|
|
||||||
getAccessibleTableCellInfoFP getAccessibleTableCellInfo;
|
|
||||||
|
|
||||||
getAccessibleTableRowHeaderFP getAccessibleTableRowHeader;
|
|
||||||
getAccessibleTableColumnHeaderFP getAccessibleTableColumnHeader;
|
|
||||||
|
|
||||||
getAccessibleTableRowDescriptionFP getAccessibleTableRowDescription;
|
|
||||||
getAccessibleTableColumnDescriptionFP getAccessibleTableColumnDescription;
|
|
||||||
|
|
||||||
getAccessibleTableRowSelectionCountFP getAccessibleTableRowSelectionCount;
|
|
||||||
isAccessibleTableRowSelectedFP isAccessibleTableRowSelected;
|
|
||||||
getAccessibleTableRowSelectionsFP getAccessibleTableRowSelections;
|
|
||||||
|
|
||||||
getAccessibleTableColumnSelectionCountFP getAccessibleTableColumnSelectionCount;
|
|
||||||
isAccessibleTableColumnSelectedFP isAccessibleTableColumnSelected;
|
|
||||||
getAccessibleTableColumnSelectionsFP getAccessibleTableColumnSelections;
|
|
||||||
|
|
||||||
getAccessibleTableRowFP getAccessibleTableRow;
|
|
||||||
getAccessibleTableColumnFP getAccessibleTableColumn;
|
|
||||||
getAccessibleTableIndexFP getAccessibleTableIndex;
|
|
||||||
|
|
||||||
getAccessibleRelationSetFP getAccessibleRelationSet;
|
|
||||||
|
|
||||||
getAccessibleHypertextFP getAccessibleHypertext;
|
|
||||||
activateAccessibleHyperlinkFP activateAccessibleHyperlink;
|
|
||||||
getAccessibleHyperlinkCountFP getAccessibleHyperlinkCount;
|
|
||||||
getAccessibleHypertextExtFP getAccessibleHypertextExt;
|
|
||||||
getAccessibleHypertextLinkIndexFP getAccessibleHypertextLinkIndex;
|
|
||||||
getAccessibleHyperlinkFP getAccessibleHyperlink;
|
|
||||||
|
|
||||||
getAccessibleKeyBindingsFP getAccessibleKeyBindings;
|
|
||||||
getAccessibleIconsFP getAccessibleIcons;
|
|
||||||
getAccessibleActionsFP getAccessibleActions;
|
|
||||||
doAccessibleActionsFP doAccessibleActions;
|
|
||||||
|
|
||||||
GetAccessibleTextInfoFP GetAccessibleTextInfo;
|
|
||||||
GetAccessibleTextItemsFP GetAccessibleTextItems;
|
|
||||||
GetAccessibleTextSelectionInfoFP GetAccessibleTextSelectionInfo;
|
|
||||||
GetAccessibleTextAttributesFP GetAccessibleTextAttributes;
|
|
||||||
GetAccessibleTextRectFP GetAccessibleTextRect;
|
|
||||||
GetAccessibleTextLineBoundsFP GetAccessibleTextLineBounds;
|
|
||||||
GetAccessibleTextRangeFP GetAccessibleTextRange;
|
|
||||||
|
|
||||||
GetCurrentAccessibleValueFromContextFP GetCurrentAccessibleValueFromContext;
|
|
||||||
GetMaximumAccessibleValueFromContextFP GetMaximumAccessibleValueFromContext;
|
|
||||||
GetMinimumAccessibleValueFromContextFP GetMinimumAccessibleValueFromContext;
|
|
||||||
|
|
||||||
AddAccessibleSelectionFromContextFP AddAccessibleSelectionFromContext;
|
|
||||||
ClearAccessibleSelectionFromContextFP ClearAccessibleSelectionFromContext;
|
|
||||||
GetAccessibleSelectionFromContextFP GetAccessibleSelectionFromContext;
|
|
||||||
GetAccessibleSelectionCountFromContextFP GetAccessibleSelectionCountFromContext;
|
|
||||||
IsAccessibleChildSelectedFromContextFP IsAccessibleChildSelectedFromContext;
|
|
||||||
RemoveAccessibleSelectionFromContextFP RemoveAccessibleSelectionFromContext;
|
|
||||||
SelectAllAccessibleSelectionFromContextFP SelectAllAccessibleSelectionFromContext;
|
|
||||||
|
|
||||||
setTextContentsFP setTextContents;
|
|
||||||
getParentWithRoleFP getParentWithRole;
|
|
||||||
getTopLevelObjectFP getTopLevelObject;
|
|
||||||
getParentWithRoleElseRootFP getParentWithRoleElseRoot;
|
|
||||||
getObjectDepthFP getObjectDepth;
|
|
||||||
getActiveDescendentFP getActiveDescendent;
|
|
||||||
|
|
||||||
getVirtualAccessibleNameFP getVirtualAccessibleName;
|
|
||||||
requestFocusFP requestFocus;
|
|
||||||
selectTextRangeFP selectTextRange;
|
|
||||||
getTextAttributesInRangeFP getTextAttributesInRange;
|
|
||||||
getVisibleChildrenCountFP getVisibleChildrenCount;
|
|
||||||
getVisibleChildrenFP getVisibleChildren;
|
|
||||||
setCaretPositionFP setCaretPosition;
|
|
||||||
getCaretLocationFP getCaretLocation;
|
|
||||||
|
|
||||||
getEventsWaitingFP getEventsWaiting;
|
|
||||||
|
|
||||||
} AccessBridgeFPs;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the world
|
|
||||||
*/
|
|
||||||
BOOL initializeAccessBridge();
|
|
||||||
BOOL shutdownAccessBridge();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Window routines
|
|
||||||
*/
|
|
||||||
BOOL IsJavaWindow(HWND window);
|
|
||||||
|
|
||||||
// Returns the virtual machine ID and AccessibleContext for a top-level window
|
|
||||||
BOOL GetAccessibleContextFromHWND(HWND target, long *vmID, AccessibleContext *ac);
|
|
||||||
|
|
||||||
// Returns the HWND from the AccessibleContext of a top-level window
|
|
||||||
HWND getHWNDFromAccessibleContext(long vmID, AccessibleContext ac);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event handling routines
|
|
||||||
*/
|
|
||||||
void SetJavaShutdown(AccessBridge_JavaShutdownFP fp);
|
|
||||||
void SetFocusGained(AccessBridge_FocusGainedFP fp);
|
|
||||||
void SetFocusLost(AccessBridge_FocusLostFP fp);
|
|
||||||
|
|
||||||
void SetCaretUpdate(AccessBridge_CaretUpdateFP fp);
|
|
||||||
|
|
||||||
void SetMouseClicked(AccessBridge_MouseClickedFP fp);
|
|
||||||
void SetMouseEntered(AccessBridge_MouseEnteredFP fp);
|
|
||||||
void SetMouseExited(AccessBridge_MouseExitedFP fp);
|
|
||||||
void SetMousePressed(AccessBridge_MousePressedFP fp);
|
|
||||||
void SetMouseReleased(AccessBridge_MouseReleasedFP fp);
|
|
||||||
|
|
||||||
void SetMenuCanceled(AccessBridge_MenuCanceledFP fp);
|
|
||||||
void SetMenuDeselected(AccessBridge_MenuDeselectedFP fp);
|
|
||||||
void SetMenuSelected(AccessBridge_MenuSelectedFP fp);
|
|
||||||
void SetPopupMenuCanceled(AccessBridge_PopupMenuCanceledFP fp);
|
|
||||||
void SetPopupMenuWillBecomeInvisible(AccessBridge_PopupMenuWillBecomeInvisibleFP fp);
|
|
||||||
void SetPopupMenuWillBecomeVisible(AccessBridge_PopupMenuWillBecomeVisibleFP fp);
|
|
||||||
|
|
||||||
void SetPropertyNameChange(AccessBridge_PropertyNameChangeFP fp);
|
|
||||||
void SetPropertyDescriptionChange(AccessBridge_PropertyDescriptionChangeFP fp);
|
|
||||||
void SetPropertyStateChange(AccessBridge_PropertyStateChangeFP fp);
|
|
||||||
void SetPropertyValueChange(AccessBridge_PropertyValueChangeFP fp);
|
|
||||||
void SetPropertySelectionChange(AccessBridge_PropertySelectionChangeFP fp);
|
|
||||||
void SetPropertyTextChange(AccessBridge_PropertyTextChangeFP fp);
|
|
||||||
void SetPropertyCaretChange(AccessBridge_PropertyCaretChangeFP fp);
|
|
||||||
void SetPropertyVisibleDataChange(AccessBridge_PropertyVisibleDataChangeFP fp);
|
|
||||||
void SetPropertyChildChange(AccessBridge_PropertyChildChangeFP fp);
|
|
||||||
void SetPropertyActiveDescendentChange(AccessBridge_PropertyActiveDescendentChangeFP fp);
|
|
||||||
|
|
||||||
void SetPropertyTableModelChange(AccessBridge_PropertyTableModelChangeFP fp);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* General routines
|
|
||||||
*/
|
|
||||||
void ReleaseJavaObject(long vmID, Java_Object object);
|
|
||||||
BOOL GetVersionInfo(long vmID, AccessBridgeVersionInfo *info);
|
|
||||||
HWND GetHWNDFromAccessibleContext(long vmID, JOBJECT64 accesibleContext);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accessible Context routines
|
|
||||||
*/
|
|
||||||
BOOL GetAccessibleContextAt(long vmID, AccessibleContext acParent,
|
|
||||||
jint x, jint y, AccessibleContext *ac);
|
|
||||||
BOOL GetAccessibleContextWithFocus(HWND window, long *vmID, AccessibleContext *ac);
|
|
||||||
BOOL GetAccessibleContextInfo(long vmID, AccessibleContext ac, AccessibleContextInfo *info);
|
|
||||||
AccessibleContext GetAccessibleChildFromContext(long vmID, AccessibleContext ac, jint index);
|
|
||||||
AccessibleContext GetAccessibleParentFromContext(long vmID, AccessibleContext ac);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accessible Text routines
|
|
||||||
*/
|
|
||||||
BOOL GetAccessibleTextInfo(long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y);
|
|
||||||
BOOL GetAccessibleTextItems(long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index);
|
|
||||||
BOOL GetAccessibleTextSelectionInfo(long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection);
|
|
||||||
BOOL GetAccessibleTextAttributes(long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes);
|
|
||||||
BOOL GetAccessibleTextRect(long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index);
|
|
||||||
BOOL GetAccessibleTextLineBounds(long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex);
|
|
||||||
BOOL GetAccessibleTextRange(long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len);
|
|
||||||
|
|
||||||
/* begin AccessibleTable routines */
|
|
||||||
BOOL getAccessibleTableInfo(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
|
||||||
|
|
||||||
BOOL getAccessibleTableCellInfo(long vmID, AccessibleTable accessibleTable, jint row, jint column,
|
|
||||||
AccessibleTableCellInfo *tableCellInfo);
|
|
||||||
|
|
||||||
BOOL getAccessibleTableRowHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
|
||||||
BOOL getAccessibleTableColumnHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
|
|
||||||
|
|
||||||
AccessibleContext getAccessibleTableRowDescription(long vmID, AccessibleContext acParent, jint row);
|
|
||||||
AccessibleContext getAccessibleTableColumnDescription(long vmID, AccessibleContext acParent, jint column);
|
|
||||||
|
|
||||||
jint getAccessibleTableRowSelectionCount(long vmID, AccessibleTable table);
|
|
||||||
BOOL isAccessibleTableRowSelected(long vmID, AccessibleTable table, jint row);
|
|
||||||
BOOL getAccessibleTableRowSelections(long vmID, AccessibleTable table, jint count, jint *selections);
|
|
||||||
|
|
||||||
jint getAccessibleTableColumnSelectionCount(long vmID, AccessibleTable table);
|
|
||||||
BOOL isAccessibleTableColumnSelected(long vmID, AccessibleTable table, jint column);
|
|
||||||
BOOL getAccessibleTableColumnSelections(long vmID, AccessibleTable table, jint count, jint *selections);
|
|
||||||
|
|
||||||
jint getAccessibleTableRow(long vmID, AccessibleTable table, jint index);
|
|
||||||
jint getAccessibleTableColumn(long vmID, AccessibleTable table, jint index);
|
|
||||||
jint getAccessibleTableIndex(long vmID, AccessibleTable table, jint row, jint column);
|
|
||||||
/* end AccessibleTable */
|
|
||||||
|
|
||||||
/* ----- AccessibleRelationSet routines */
|
|
||||||
BOOL getAccessibleRelationSet(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleRelationSetInfo *relationSetInfo);
|
|
||||||
|
|
||||||
/* ----- AccessibleHypertext routines */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns hypertext information associated with a component.
|
|
||||||
*/
|
|
||||||
BOOL getAccessibleHypertext(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleHypertextInfo *hypertextInfo);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Requests that a hyperlink be activated.
|
|
||||||
*/
|
|
||||||
BOOL activateAccessibleHyperlink(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleHyperlink accessibleHyperlink);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the number of hyperlinks in a component
|
|
||||||
* Maps to AccessibleHypertext.getLinkCount.
|
|
||||||
* Returns -1 on error.
|
|
||||||
*/
|
|
||||||
jint getAccessibleHyperlinkCount(const long vmID,
|
|
||||||
const AccessibleHypertext hypertext);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This method is used to iterate through the hyperlinks in a component. It
|
|
||||||
* returns hypertext information for a component starting at hyperlink index
|
|
||||||
* nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will
|
|
||||||
* be returned for each call to this method.
|
|
||||||
* Returns FALSE on error.
|
|
||||||
*/
|
|
||||||
BOOL getAccessibleHypertextExt(const long vmID,
|
|
||||||
const AccessibleContext accessibleContext,
|
|
||||||
const jint nStartIndex,
|
|
||||||
/* OUT */ AccessibleHypertextInfo *hypertextInfo);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the index into an array of hyperlinks that is associated with
|
|
||||||
* a character index in document; maps to AccessibleHypertext.getLinkIndex
|
|
||||||
* Returns -1 on error.
|
|
||||||
*/
|
|
||||||
jint getAccessibleHypertextLinkIndex(const long vmID,
|
|
||||||
const AccessibleHypertext hypertext,
|
|
||||||
const jint nIndex);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the nth hyperlink in a document
|
|
||||||
* Maps to AccessibleHypertext.getLink.
|
|
||||||
* Returns FALSE on error
|
|
||||||
*/
|
|
||||||
BOOL getAccessibleHyperlink(const long vmID,
|
|
||||||
const AccessibleHypertext hypertext,
|
|
||||||
const jint nIndex,
|
|
||||||
/* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo);
|
|
||||||
|
|
||||||
/* Accessible KeyBindings, Icons and Actions */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a list of key bindings associated with a component.
|
|
||||||
*/
|
|
||||||
BOOL getAccessibleKeyBindings(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleKeyBindings *keyBindings);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a list of icons associate with a component.
|
|
||||||
*/
|
|
||||||
BOOL getAccessibleIcons(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleIcons *icons);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a list of actions that a component can perform.
|
|
||||||
*/
|
|
||||||
BOOL getAccessibleActions(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleActions *actions);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Request that a list of AccessibleActions be performed by a component.
|
|
||||||
* Returns TRUE if all actions are performed. Returns FALSE
|
|
||||||
* when the first requested action fails in which case "failure"
|
|
||||||
* contains the index of the action that failed.
|
|
||||||
*/
|
|
||||||
BOOL doAccessibleActions(long vmID, AccessibleContext accessibleContext,
|
|
||||||
AccessibleActionsToDo *actionsToDo, jint *failure);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Additional utility methods */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns whether two object references refer to the same object.
|
|
||||||
*/
|
|
||||||
BOOL IsSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets editable text contents. The AccessibleContext must implement AccessibleEditableText and
|
|
||||||
* be editable. The maximum text length that can be set is MAX_STRING_SIZE - 1.
|
|
||||||
* Returns whether successful
|
|
||||||
*/
|
|
||||||
BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Accessible Context with the specified role that is the
|
|
||||||
* ancestor of a given object. The role is one of the role strings
|
|
||||||
* defined in AccessBridgePackages.h
|
|
||||||
* If there is no ancestor object that has the specified role,
|
|
||||||
* returns (AccessibleContext)0.
|
|
||||||
*/
|
|
||||||
AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
const wchar_t *role);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Accessible Context with the specified role that is the
|
|
||||||
* ancestor of a given object. The role is one of the role strings
|
|
||||||
* defined in AccessBridgePackages.h. If an object with the specified
|
|
||||||
* role does not exist, returns the top level object for the Java Window.
|
|
||||||
* Returns (AccessibleContext)0 on error.
|
|
||||||
*/
|
|
||||||
AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
const wchar_t *role);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Accessible Context for the top level object in
|
|
||||||
* a Java Window. This is same Accessible Context that is obtained
|
|
||||||
* from GetAccessibleContextFromHWND for that window. Returns
|
|
||||||
* (AccessibleContext)0 on error.
|
|
||||||
*/
|
|
||||||
AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns how deep in the object hierarchy a given object is.
|
|
||||||
* The top most object in the object hierarchy has an object depth of 0.
|
|
||||||
* Returns -1 on error.
|
|
||||||
*/
|
|
||||||
int getObjectDepth (const long vmID, const AccessibleContext accessibleContext);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Accessible Context of the current ActiveDescendent of an object.
|
|
||||||
* This method assumes the ActiveDescendent is the component that is currently
|
|
||||||
* selected in a container object.
|
|
||||||
* Returns (AccessibleContext)0 on error or if there is no selection.
|
|
||||||
*/
|
|
||||||
AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext);
|
|
||||||
|
|
||||||
/**
|
|
||||||
/**
|
|
||||||
* Accessible Value routines
|
|
||||||
*/
|
|
||||||
BOOL GetCurrentAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
|
|
||||||
BOOL GetMaximumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
|
|
||||||
BOOL GetMinimumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accessible Selection routines
|
|
||||||
*/
|
|
||||||
void AddAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
|
|
||||||
void ClearAccessibleSelectionFromContext(long vmID, AccessibleSelection as);
|
|
||||||
JOBJECT64 GetAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
|
|
||||||
int GetAccessibleSelectionCountFromContext(long vmID, AccessibleSelection as);
|
|
||||||
BOOL IsAccessibleChildSelectedFromContext(long vmID, AccessibleSelection as, int i);
|
|
||||||
void RemoveAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
|
|
||||||
void SelectAllAccessibleSelectionFromContext(long vmID, AccessibleSelection as);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional methods for Teton
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the AccessibleName for a component based upon the JAWS algorithm. Returns
|
|
||||||
* whether successful.
|
|
||||||
*
|
|
||||||
* Bug ID 4916682 - Implement JAWS AccessibleName policy
|
|
||||||
*/
|
|
||||||
BOOL getVirtualAccessibleName(const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
wchar_t *name, int len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request focus for a component. Returns whether successful.
|
|
||||||
*
|
|
||||||
* Bug ID 4944757 - requestFocus method needed
|
|
||||||
*/
|
|
||||||
BOOL requestFocus(const long vmID, const AccessibleContext accessibleContext);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selects text between two indices. Selection includes the text at the start index
|
|
||||||
* and the text at the end index. Returns whether successful.
|
|
||||||
*
|
|
||||||
* Bug ID 4944758 - selectTextRange method needed
|
|
||||||
*/
|
|
||||||
BOOL selectTextRange(const long vmID, const AccessibleContext accessibleContext, const int startIndex,
|
|
||||||
const int endIndex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get text attributes between two indices. The attribute list includes the text at the
|
|
||||||
* start index and the text at the end index. Returns whether successful;
|
|
||||||
*
|
|
||||||
* Bug ID 4944761 - getTextAttributes between two indices method needed
|
|
||||||
*/
|
|
||||||
BOOL getTextAttributesInRange(const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
const int startIndex, const int endIndex,
|
|
||||||
AccessibleTextAttributesInfo *attributes, short *len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of visible children of a component. Returns -1 on error.
|
|
||||||
*
|
|
||||||
* Bug ID 4944762- getVisibleChildren for list-like components needed
|
|
||||||
*/
|
|
||||||
int getVisibleChildrenCount(const long vmID, const AccessibleContext accessibleContext);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the visible children of an AccessibleContext. Returns whether successful.
|
|
||||||
*
|
|
||||||
* Bug ID 4944762- getVisibleChildren for list-like components needed
|
|
||||||
*/
|
|
||||||
BOOL getVisibleChildren(const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
const int startIndex,
|
|
||||||
VisibleChildrenInfo *visibleChildrenInfo);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the caret to a text position. Returns whether successful.
|
|
||||||
*
|
|
||||||
* Bug ID 4944770 - setCaretPosition method needed
|
|
||||||
*/
|
|
||||||
BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext,
|
|
||||||
const int position);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the text caret location
|
|
||||||
*/
|
|
||||||
BOOL getCaretLocation(long vmID, AccessibleContext ac,
|
|
||||||
AccessibleTextRectInfo *rectInfo, jint index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number of events waiting to fire
|
|
||||||
*/
|
|
||||||
int getEventsWaiting();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JAVASOFT_JAWT_MD_H_
|
|
||||||
#define _JAVASOFT_JAWT_MD_H_
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include "jawt.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Win32-specific declarations for AWT native interface.
|
|
||||||
* See notes in jawt.h for an example of use.
|
|
||||||
*/
|
|
||||||
typedef struct jawt_Win32DrawingSurfaceInfo {
|
|
||||||
/* Native window, DDB, or DIB handle */
|
|
||||||
union {
|
|
||||||
HWND hwnd;
|
|
||||||
HBITMAP hbitmap;
|
|
||||||
void* pbits;
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
* This HDC should always be used instead of the HDC returned from
|
|
||||||
* BeginPaint() or any calls to GetDC().
|
|
||||||
*/
|
|
||||||
HDC hdc;
|
|
||||||
HPALETTE hpalette;
|
|
||||||
} JAWT_Win32DrawingSurfaceInfo;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* !_JAVASOFT_JAWT_MD_H_ */
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _JAVASOFT_JNI_MD_H_
|
|
||||||
#define _JAVASOFT_JNI_MD_H_
|
|
||||||
|
|
||||||
#define JNIEXPORT __declspec(dllexport)
|
|
||||||
#define JNIIMPORT __declspec(dllimport)
|
|
||||||
#define JNICALL __stdcall
|
|
||||||
|
|
||||||
// 'long' is always 32 bit on windows so this matches what jdk expects
|
|
||||||
typedef long jint;
|
|
||||||
typedef __int64 jlong;
|
|
||||||
typedef signed char jbyte;
|
|
||||||
|
|
||||||
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
|
|
@ -1,4 +1,4 @@
|
||||||
Copyright (C) 2020 Planet Virtual Boy
|
Copyright (C) 2021 Planet Virtual Boy
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
|
151
locale/en-US.txt
151
locale/en-US.txt
|
@ -1,151 +0,0 @@
|
||||||
# Locale
|
|
||||||
locale {
|
|
||||||
id en-US
|
|
||||||
name English (United States)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main window
|
|
||||||
app {
|
|
||||||
|
|
||||||
debug {
|
|
||||||
(menu) Debug
|
|
||||||
breakpoints Breakpoints
|
|
||||||
console Console
|
|
||||||
cpu CPU
|
|
||||||
memory Memory
|
|
||||||
# VIP section
|
|
||||||
bg_maps BG Maps
|
|
||||||
characters Characters
|
|
||||||
frame_buffers Frame buffers
|
|
||||||
objects Objects
|
|
||||||
worlds Worlds
|
|
||||||
}
|
|
||||||
|
|
||||||
file {
|
|
||||||
(menu) File
|
|
||||||
debug_mode Debug mode
|
|
||||||
exit Exit
|
|
||||||
game_mode Game mode
|
|
||||||
load_rom Load ROM...
|
|
||||||
new_window New window
|
|
||||||
}
|
|
||||||
|
|
||||||
title {
|
|
||||||
default PVB Emulator
|
|
||||||
mixed {ctrl.number} {ctrl.filename} - {app.title.default}
|
|
||||||
number {ctrl.number} {app.title.default}
|
|
||||||
rom {ctrl.filename} - {app.title.default}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# BG Maps window
|
|
||||||
bg_maps {
|
|
||||||
address Address
|
|
||||||
cell Cell
|
|
||||||
character Character
|
|
||||||
generic Generic
|
|
||||||
grid Grid
|
|
||||||
hflip H-Flip
|
|
||||||
index Index
|
|
||||||
map Map
|
|
||||||
palette Palette
|
|
||||||
scale Scale
|
|
||||||
title BG Maps
|
|
||||||
vflip V-Flip
|
|
||||||
}
|
|
||||||
|
|
||||||
# Breakpoints window
|
|
||||||
breakpoints {
|
|
||||||
address Address
|
|
||||||
condition Condition
|
|
||||||
default_name New breakpoint
|
|
||||||
delete Delete
|
|
||||||
enabled Enabled
|
|
||||||
exception Exception
|
|
||||||
execute Execute
|
|
||||||
name Name
|
|
||||||
new New
|
|
||||||
read Read
|
|
||||||
title Breakpoints
|
|
||||||
type Type
|
|
||||||
write Write
|
|
||||||
|
|
||||||
error {
|
|
||||||
badliteral_a Error:{err.position}: Unable to process address "{err.text}"
|
|
||||||
badliteral_c Error:{err.position}: Unable to process literal "{err.text}"
|
|
||||||
badoperand Error:{err.position}: Invalid operand to operator "{err.text}"
|
|
||||||
badtoken Error:{err.position}: Unrecognized token "{err.text}"
|
|
||||||
earlyeof Error:{err.position}: Unexpected end of input
|
|
||||||
invalid Error:{err.position}: Token "{err.text}" cannot appear here
|
|
||||||
nesting Error:{err.position}: Expected "{err.other}", but found "{err.text}"
|
|
||||||
unexpected Error:{err.position}: Unexpected "{err.text}"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# Characters window
|
|
||||||
characters {
|
|
||||||
address Address
|
|
||||||
grid Grid
|
|
||||||
index Index
|
|
||||||
mirror Mirror
|
|
||||||
Palette Palette
|
|
||||||
scale Scale
|
|
||||||
title Characters
|
|
||||||
wide Wide
|
|
||||||
}
|
|
||||||
|
|
||||||
# Console window
|
|
||||||
console {
|
|
||||||
title Console
|
|
||||||
}
|
|
||||||
|
|
||||||
# Emulation core
|
|
||||||
core {
|
|
||||||
java Java
|
|
||||||
linux-x86 Linux (32-bit)
|
|
||||||
linux-x86_64 Linux (64-bit)
|
|
||||||
native Native
|
|
||||||
windows-x86 Windows (32-bit)
|
|
||||||
windows-x86_64 Windows (64-bit)
|
|
||||||
}
|
|
||||||
|
|
||||||
# CPU window
|
|
||||||
cpu {
|
|
||||||
float Float
|
|
||||||
hex Hex
|
|
||||||
jump_from From
|
|
||||||
jump_to To
|
|
||||||
signed Signed
|
|
||||||
title CPU
|
|
||||||
unsigned Unsigned
|
|
||||||
}
|
|
||||||
|
|
||||||
# File dialog
|
|
||||||
dialog {
|
|
||||||
ext_isx ISX modules (*.isx)
|
|
||||||
ext_vb Virtual Boy ROMs (*.vb)
|
|
||||||
load Load
|
|
||||||
load_rom Load ROM
|
|
||||||
load_rom_error Unable to load the selected ROM file.
|
|
||||||
load_rom_notvb The selected file does not appear to be a Virtual Boy ROM.
|
|
||||||
}
|
|
||||||
|
|
||||||
# Memory window
|
|
||||||
memory {
|
|
||||||
title Memory
|
|
||||||
}
|
|
||||||
|
|
||||||
# Palettes
|
|
||||||
palette {
|
|
||||||
Generic Generic
|
|
||||||
gplt0 BG 0
|
|
||||||
gplt1 BG 1
|
|
||||||
gplt2 BG 2
|
|
||||||
gplt3 BG 3
|
|
||||||
jplt0 OBJ 0
|
|
||||||
jplt1 OBJ 1
|
|
||||||
jplt2 OBJ 2
|
|
||||||
jplt3 OBJ 3
|
|
||||||
}
|
|
167
makefile
167
makefile
|
@ -1,167 +0,0 @@
|
||||||
# Java include directory pathnames
|
|
||||||
# The Windows files need to be copied from a Windows JDK installation
|
|
||||||
include_linux = jni/linux
|
|
||||||
include_windows = jni/windows
|
|
||||||
|
|
||||||
# Default goal
|
|
||||||
.PHONY: default
|
|
||||||
default:
|
|
||||||
@echo $(include_linux)
|
|
||||||
@echo "Planet Virtual Boy Emulator"
|
|
||||||
@echo " https://www.planetvb.com/"
|
|
||||||
@echo " December 26, 2020"
|
|
||||||
@echo
|
|
||||||
@echo "Intended build environment: Debian i386 or amd64"
|
|
||||||
@echo " gcc-multilib"
|
|
||||||
@echo " mingw-w64"
|
|
||||||
@echo " openjdk-15-jdk"
|
|
||||||
@echo
|
|
||||||
@echo "Usage: make <recipe>"
|
|
||||||
@echo " Package recipes:"
|
|
||||||
@echo " build Compiles the native modules and desktop application"
|
|
||||||
@echo " clean Deletes all output files"
|
|
||||||
@echo " core Check the native core library for style errors"
|
|
||||||
@echo " desktop Compiles the Java desktop application"
|
|
||||||
@echo " native Builds all native modules"
|
|
||||||
@echo " pack Bundles everything in a .jar file"
|
|
||||||
@echo " release Produces a .jar and deletes all intermediate files"
|
|
||||||
@echo " Native recipes:"
|
|
||||||
@echo " lin32 Builds native module linux_x86"
|
|
||||||
@echo " lin64 Builds native module linux_x86-64"
|
|
||||||
@echo " win32 Builds native module windows_x86"
|
|
||||||
@echo " win64 Builds native module windows_x86-64"
|
|
||||||
@echo
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Package Recipes #
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
# Perform a full build process of the native modules and desktop application
|
|
||||||
.PHONY: build
|
|
||||||
build:
|
|
||||||
@make -s core
|
|
||||||
@make -s desktop
|
|
||||||
@make -s native
|
|
||||||
|
|
||||||
# Delete all output files
|
|
||||||
.PHONY: clean
|
|
||||||
clean: clean_most
|
|
||||||
@rm -f pvbemu_*.jar
|
|
||||||
|
|
||||||
# Check the native core library for style errors
|
|
||||||
.PHONY: core
|
|
||||||
core:
|
|
||||||
@echo " Checking native core library for style errors"
|
|
||||||
$(eval coreargs = -c -Isrc/core/include -Werror -Wall -Wextra -Wpedantic \
|
|
||||||
-fno-strict-aliasing -fsyntax-only src/core/vue.c)
|
|
||||||
@gcc -std=c90 $(coreargs)
|
|
||||||
@gcc -std=c90 -D VUE_BIGENDIAN $(coreargs)
|
|
||||||
@gcc -std=c99 $(coreargs)
|
|
||||||
@gcc -std=c99 -D VUE_BIGENDIAN $(coreargs)
|
|
||||||
@gcc -std=c11 $(coreargs)
|
|
||||||
@gcc -std=c11 -D VUE_BIGENDIAN $(coreargs)
|
|
||||||
|
|
||||||
# Compile the Java desktop application
|
|
||||||
.PHONY: desktop
|
|
||||||
desktop: clean_desktop
|
|
||||||
@echo " Compiling Java desktop application"
|
|
||||||
@javac -sourcepath src/desktop --release 10 -Xlint:unchecked \
|
|
||||||
-Xlint:deprecation -h src/desktop/vue -d . src/desktop/Main.java
|
|
||||||
|
|
||||||
# Build all native modules
|
|
||||||
.PHONY: native
|
|
||||||
native:
|
|
||||||
@make -s lin32
|
|
||||||
@make -s lin64
|
|
||||||
@make -s win32
|
|
||||||
@make -s win64
|
|
||||||
|
|
||||||
# Package the release into a .jar file
|
|
||||||
.PHONY: pack
|
|
||||||
pack:
|
|
||||||
$(eval jarname = "pvbemu_`date +%Y%m%d`.jar")
|
|
||||||
@echo " Bundling into $(jarname)"
|
|
||||||
@jar -cfe $(jarname) Main *.class license.txt \
|
|
||||||
app images locale native util vue
|
|
||||||
|
|
||||||
# Performs a full build and packages it into a .jar
|
|
||||||
.PHONY: release
|
|
||||||
release:
|
|
||||||
@make -s build
|
|
||||||
@make -s pack
|
|
||||||
@echo " Removing temporary files"
|
|
||||||
@make -s clean_most
|
|
||||||
|
|
||||||
# Delete only Java .class files
|
|
||||||
.PHONY: clean_desktop
|
|
||||||
clean_desktop:
|
|
||||||
@rm -r -f *.class app util vue
|
|
||||||
|
|
||||||
# Delete everything but the .jar
|
|
||||||
.PHONY: clean_most
|
|
||||||
clean_most: clean_desktop
|
|
||||||
@rm -f src/desktop/vue/vue_NativeVue.h native/*.dll native/*.so
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Native Recipes #
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
# JNI header file
|
|
||||||
src/desktop/vue/vue_NativeVue.h: src/desktop/vue/NativeVue.java
|
|
||||||
@javac -h src/desktop/vue -sourcepath src/desktop -d . \
|
|
||||||
src/desktop/vue/NativeVue.java
|
|
||||||
@sleep 3
|
|
||||||
|
|
||||||
# linux_x86
|
|
||||||
.PHONY: lin32_pre
|
|
||||||
lin32_pre: src/desktop/vue/vue_NativeVue.h
|
|
||||||
$(eval name = linux_x86)
|
|
||||||
$(eval prefix = `uname -m`-linux-gnu-)
|
|
||||||
$(eval include = -I$(include_linux) -I$(include_linux)/linux)
|
|
||||||
$(eval gccargs = -m32 -lm)
|
|
||||||
$(eval ext = .so)
|
|
||||||
.PHONY: lin32
|
|
||||||
lin32: lin32_pre native_common
|
|
||||||
|
|
||||||
# linux_x86-64
|
|
||||||
.PHONY: lin64_pre
|
|
||||||
lin64_pre: src/desktop/vue/vue_NativeVue.h
|
|
||||||
$(eval name = linux_x86-64)
|
|
||||||
$(eval prefix = `uname -m`-linux-gnu-)
|
|
||||||
$(eval include = -I$(include_linux) -I$(include_linux)/linux)
|
|
||||||
$(eval gccargs = -m64 -lm)
|
|
||||||
$(eval ext = .so)
|
|
||||||
.PHONY: lin64
|
|
||||||
lin64: lin64_pre native_common
|
|
||||||
|
|
||||||
# windows_x86
|
|
||||||
.PHONY: win32_pre
|
|
||||||
win32_pre: src/desktop/vue/vue_NativeVue.h
|
|
||||||
$(eval name = windows_x86)
|
|
||||||
$(eval prefix = i686-w64-mingw32-)
|
|
||||||
$(eval include = -I$(include_windows) -I$(include_windows)/win32)
|
|
||||||
$(eval ext = .dll)
|
|
||||||
.PHONY: win32
|
|
||||||
win32: win32_pre native_common
|
|
||||||
|
|
||||||
# windows_x86-64
|
|
||||||
.PHONY: win64_pre
|
|
||||||
win64_pre: src/desktop/vue/vue_NativeVue.h
|
|
||||||
$(eval name = windows_x86-64)
|
|
||||||
$(eval prefix = x86_64-w64-mingw32-)
|
|
||||||
$(eval include = -I$(include_windows) -I$(include_windows)/win32)
|
|
||||||
$(eval ext = .dll)
|
|
||||||
.PHONY: win64
|
|
||||||
win64: win64_pre native_common
|
|
||||||
|
|
||||||
# Common recipe for building native modules
|
|
||||||
.PHONY: native_common
|
|
||||||
native_common:
|
|
||||||
@echo " Building native module $(name)"
|
|
||||||
@$(prefix)gcc $(include) -Isrc/core/include $(gccargs) -s -shared -O2 \
|
|
||||||
-fno-strict-aliasing -fPIC -Werror \
|
|
||||||
-o native/$(name)$(ext) src/desktop/vue/NativeVue.c src/core/vue.c
|
|
1261
src/core/cpu.c
1261
src/core/cpu.c
File diff suppressed because it is too large
Load Diff
|
@ -1,14 +0,0 @@
|
||||||
/* This file is included through vue.c and cannot be built directly. */
|
|
||||||
#ifdef VUEAPI
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Module Functions *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/* System reset */
|
|
||||||
static void pakReset(Vue *vue) {
|
|
||||||
vue->pak.wcr_exp1w = 0;
|
|
||||||
vue->pak.wcr_rom1w = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,295 +0,0 @@
|
||||||
#ifndef __VUE_H__
|
|
||||||
#define __VUE_H__
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* API management */
|
|
||||||
#ifndef VUEAPI
|
|
||||||
#define VUEAPI extern
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Header includes */
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Constants *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/* Boolean values */
|
|
||||||
#define VUE_FALSE 0
|
|
||||||
#define VUE_TRUE 1
|
|
||||||
|
|
||||||
/* Memory access types */
|
|
||||||
#define VUE_S8 0
|
|
||||||
#define VUE_U8 1
|
|
||||||
#define VUE_S16 2
|
|
||||||
#define VUE_U16 3
|
|
||||||
#define VUE_S32 4
|
|
||||||
#define VUE_CANCEL 5
|
|
||||||
|
|
||||||
/* System register indexes */
|
|
||||||
#define VUE_ADTRE 25
|
|
||||||
#define VUE_CHCW 24
|
|
||||||
#define VUE_ECR 4
|
|
||||||
#define VUE_EIPC 0
|
|
||||||
#define VUE_EIPSW 1
|
|
||||||
#define VUE_FEPC 2
|
|
||||||
#define VUE_FEPSW 3
|
|
||||||
#define VUE_PIR 6
|
|
||||||
#define VUE_PSW 5
|
|
||||||
#define VUE_TKCW 7
|
|
||||||
|
|
||||||
/* Non-standard register indexes */
|
|
||||||
#define VUE_PC -1
|
|
||||||
#define VUE_JUMP_FROM -2
|
|
||||||
#define VUE_JUMP_TO -3
|
|
||||||
|
|
||||||
/* Program register indexes */
|
|
||||||
#define VUE_GP 4
|
|
||||||
#define VUE_HP 2
|
|
||||||
#define VUE_LP 31
|
|
||||||
#define VUE_SP 3
|
|
||||||
#define VUE_TP 5
|
|
||||||
|
|
||||||
/* Instruction IDs */
|
|
||||||
#define VUE_ILLEGAL -1
|
|
||||||
#define VUE_ADD_IMM 0
|
|
||||||
#define VUE_ADD_REG 1
|
|
||||||
#define VUE_ADDF_S 2
|
|
||||||
#define VUE_ADDI 3
|
|
||||||
#define VUE_AND 4
|
|
||||||
#define VUE_ANDBSU 5
|
|
||||||
#define VUE_ANDI 6
|
|
||||||
#define VUE_ANDNBSU 7
|
|
||||||
#define VUE_BCOND 8
|
|
||||||
#define VUE_CAXI 9
|
|
||||||
#define VUE_CLI 10
|
|
||||||
#define VUE_CMP_IMM 11
|
|
||||||
#define VUE_CMP_REG 12
|
|
||||||
#define VUE_CMPF_S 13
|
|
||||||
#define VUE_CVT_SW 14
|
|
||||||
#define VUE_CVT_WS 15
|
|
||||||
#define VUE_DIV 16
|
|
||||||
#define VUE_DIVF_S 17
|
|
||||||
#define VUE_DIVU 18
|
|
||||||
#define VUE_HALT 19
|
|
||||||
#define VUE_IN_B 20
|
|
||||||
#define VUE_IN_H 21
|
|
||||||
#define VUE_IN_W 22
|
|
||||||
#define VUE_JAL 23
|
|
||||||
#define VUE_JMP 24
|
|
||||||
#define VUE_JR 25
|
|
||||||
#define VUE_LD_B 26
|
|
||||||
#define VUE_LD_H 27
|
|
||||||
#define VUE_LD_W 28
|
|
||||||
#define VUE_LDSR 29
|
|
||||||
#define VUE_MOV_IMM 30
|
|
||||||
#define VUE_MOV_REG 31
|
|
||||||
#define VUE_MOVBSU 32
|
|
||||||
#define VUE_MOVEA 33
|
|
||||||
#define VUE_MOVHI 34
|
|
||||||
#define VUE_MPYHW 35
|
|
||||||
#define VUE_MUL 36
|
|
||||||
#define VUE_MULF_S 37
|
|
||||||
#define VUE_MULU 38
|
|
||||||
#define VUE_NOT 39
|
|
||||||
#define VUE_NOTBSU 40
|
|
||||||
#define VUE_OR 41
|
|
||||||
#define VUE_ORBSU 42
|
|
||||||
#define VUE_ORI 43
|
|
||||||
#define VUE_ORNBSU 44
|
|
||||||
#define VUE_OUT_B 45
|
|
||||||
#define VUE_OUT_H 46
|
|
||||||
#define VUE_OUT_W 47
|
|
||||||
#define VUE_RETI 48
|
|
||||||
#define VUE_REV 49
|
|
||||||
#define VUE_SAR_IMM 50
|
|
||||||
#define VUE_SAR_REG 51
|
|
||||||
#define VUE_SCH0BSD 52
|
|
||||||
#define VUE_SCH0BSU 53
|
|
||||||
#define VUE_SCH1BSD 54
|
|
||||||
#define VUE_SCH1BSU 55
|
|
||||||
#define VUE_SEI 56
|
|
||||||
#define VUE_SETF 57
|
|
||||||
#define VUE_SHL_IMM 58
|
|
||||||
#define VUE_SHL_REG 59
|
|
||||||
#define VUE_SHR_IMM 60
|
|
||||||
#define VUE_SHR_REG 61
|
|
||||||
#define VUE_ST_B 62
|
|
||||||
#define VUE_ST_H 63
|
|
||||||
#define VUE_ST_W 64
|
|
||||||
#define VUE_STSR 65
|
|
||||||
#define VUE_SUB 66
|
|
||||||
#define VUE_SUBF_S 67
|
|
||||||
#define VUE_TRAP 68
|
|
||||||
#define VUE_TRNC_SW 69
|
|
||||||
#define VUE_XB 70
|
|
||||||
#define VUE_XH 71
|
|
||||||
#define VUE_XOR 72
|
|
||||||
#define VUE_XORBSU 73
|
|
||||||
#define VUE_XORI 74
|
|
||||||
#define VUE_XORNBSU 75
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Types *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/* Forward references */
|
|
||||||
typedef struct Vue Vue;
|
|
||||||
|
|
||||||
/* Boolean */
|
|
||||||
typedef int vbool;
|
|
||||||
|
|
||||||
/* Access state */
|
|
||||||
typedef struct {
|
|
||||||
uint32_t address; /* CPU bus address */
|
|
||||||
int32_t value; /* Value read/to write */
|
|
||||||
int8_t fetch; /* Index of machine code unit */
|
|
||||||
int8_t type; /* Data type */
|
|
||||||
} VueAccess;
|
|
||||||
|
|
||||||
/* Instruction state */
|
|
||||||
typedef struct {
|
|
||||||
int32_t bits; /* Binary encoding */
|
|
||||||
int32_t disp; /* Displacement for jumps and branches */
|
|
||||||
int32_t imm; /* Immediate operand */
|
|
||||||
uint8_t cond; /* Condition for Bcond */
|
|
||||||
int8_t format; /* Binary format */
|
|
||||||
int8_t id; /* Library-specific identifier */
|
|
||||||
uint8_t opcode; /* Instruction opcode */
|
|
||||||
uint8_t reg1; /* Source/right register */
|
|
||||||
uint8_t reg2; /* Destination/left register */
|
|
||||||
uint8_t size; /* Number of bytes in encoding */
|
|
||||||
uint8_t subopcode; /* Instruction subopcode */
|
|
||||||
} VueInstruction;
|
|
||||||
|
|
||||||
/* Breakpoint handler callbacks */
|
|
||||||
typedef int32_t (*VueOnAccess )(Vue *, VueAccess *);
|
|
||||||
typedef int32_t (*VueOnException)(Vue *, uint16_t );
|
|
||||||
typedef int32_t (*VueOnExecute )(Vue *, VueInstruction *);
|
|
||||||
typedef int32_t (*VueOnFrame )(Vue * );
|
|
||||||
|
|
||||||
/* Emulation state */
|
|
||||||
struct Vue {
|
|
||||||
void *tag; /* Application reference */
|
|
||||||
int32_t breakCode; /* Application break code */
|
|
||||||
uint8_t wram[0x10000]; /* System memory */
|
|
||||||
|
|
||||||
/* Breakpoint handlers */
|
|
||||||
VueOnException onException;
|
|
||||||
VueOnExecute onExecute;
|
|
||||||
VueOnFrame onFrame;
|
|
||||||
VueOnAccess onRead;
|
|
||||||
VueOnAccess onWrite;
|
|
||||||
|
|
||||||
/* CPU state */
|
|
||||||
struct {
|
|
||||||
VueAccess access; /* Access state */
|
|
||||||
VueInstruction inst; /* Instruction state */
|
|
||||||
uint32_t cycles; /* Cycles until next stage */
|
|
||||||
int32_t jumpFrom[3]; /* Source 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 */
|
|
||||||
int fetch; /* Fetch unit index */
|
|
||||||
int stage; /* Current processing stage */
|
|
||||||
|
|
||||||
/* Program registers */
|
|
||||||
int32_t program[32];
|
|
||||||
|
|
||||||
/* System registers */
|
|
||||||
int32_t adtre; /* Address Trap Register for Execution */
|
|
||||||
int32_t eipc; /* Exception/interrupt PC */
|
|
||||||
int32_t eipsw; /* Exception/interrupt PSW */
|
|
||||||
int32_t fepc; /* Duplexed exception PC */
|
|
||||||
int32_t fepsw; /* Duplexed exception PSW */
|
|
||||||
int32_t pc; /* Program Counter */
|
|
||||||
int32_t sr29; /* System register 29 */
|
|
||||||
int32_t sr31; /* System register 31 */
|
|
||||||
|
|
||||||
/* Program Status Word */
|
|
||||||
int8_t psw_ae; /* Address Trap Enable */
|
|
||||||
int8_t psw_ep; /* Exception Pending */
|
|
||||||
int8_t psw_id; /* Interrupt Disable */
|
|
||||||
int8_t psw_cy; /* Carry */
|
|
||||||
int8_t psw_fiv; /* Floating Reserved Operand */
|
|
||||||
int8_t psw_fov; /* Floating Overflow */
|
|
||||||
int8_t psw_fpr; /* Floating Precision */
|
|
||||||
int8_t psw_fro; /* Floating Reserved Operand */
|
|
||||||
int8_t psw_fud; /* Floating Underflow */
|
|
||||||
int8_t psw_fzd; /* Floating Zero Divide */
|
|
||||||
int8_t psw_i; /* Interrupt Level */
|
|
||||||
int8_t psw_np; /* NMI Pending */
|
|
||||||
int8_t psw_ov; /* Overflow */
|
|
||||||
int8_t psw_s; /* Sign */
|
|
||||||
int8_t psw_z; /* Zero */
|
|
||||||
|
|
||||||
/* Cache Control Word */
|
|
||||||
uint16_t chcw_cec; /* Clear Entry Count */
|
|
||||||
uint16_t chcw_cen; /* Clear Entry Number */
|
|
||||||
int8_t chcw_icc; /* Instruction Cache Clear */
|
|
||||||
int8_t chcw_icd; /* Instruction Cache Dump */
|
|
||||||
int8_t chcw_ice; /* Instruction Cache Enable */
|
|
||||||
int8_t chcw_icr; /* Instruction Cache Restore */
|
|
||||||
int32_t chcw_sa; /* Spill-Out Base Address */
|
|
||||||
|
|
||||||
/* Exception Cause Register */
|
|
||||||
uint16_t ecr_eicc; /* Exception/Interrupt Cause Code */
|
|
||||||
uint16_t ecr_fecc; /* Fatal Error Cause Code */
|
|
||||||
} cpu;
|
|
||||||
|
|
||||||
/* Game pak state */
|
|
||||||
struct {
|
|
||||||
uint8_t *ram; /* Cartridge SRAM */
|
|
||||||
uint32_t ramSize; /* Number of bytes in cartridge SRAM */
|
|
||||||
uint8_t *rom; /* Cartridge ROM */
|
|
||||||
uint32_t romSize; /* Number of bytes in cartridge ROM */
|
|
||||||
int8_t wcr_exp1w; /* Expansion one-wait mode */
|
|
||||||
int8_t wcr_rom1w; /* ROM one-wait mode */
|
|
||||||
} pak;
|
|
||||||
|
|
||||||
/* VIP state */
|
|
||||||
struct {
|
|
||||||
uint8_t vram[0x40000]; /* Video memory */
|
|
||||||
} vip;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Function Prototypes *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
VUEAPI uint32_t vueEmulate (Vue *vue, uint32_t maxCycles);
|
|
||||||
VUEAPI int32_t vueGetBreakCode (Vue *vue);
|
|
||||||
VUEAPI uint16_t vueGetExceptionCode (Vue *vue);
|
|
||||||
VUEAPI int32_t vueGetRegister (Vue *vue, int32_t index, vbool system);
|
|
||||||
VUEAPI void* vueGetTag (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 vbool vueReadBytes (Vue *vue, uint32_t address, uint8_t *dest, uint32_t length);
|
|
||||||
VUEAPI void vueReset (Vue *vue);
|
|
||||||
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 void* vueSetTag (Vue *vue, void *tag);
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif /* __VUE_H__ */
|
|
298
src/core/vip.c
298
src/core/vip.c
|
@ -1,298 +0,0 @@
|
||||||
/* This file is included through vue.c and cannot be built directly. */
|
|
||||||
#ifdef VUEAPI
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Internal Functions *
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/* Process the simulation */
|
|
||||||
static void vipEmulate(Vue *vue, uint32_t cycles) {
|
|
||||||
vue = vue;
|
|
||||||
cycles = cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read an I/O register */
|
|
||||||
static int32_t vipReadRegister(Vue *vue, int32_t address) {
|
|
||||||
vue=vue;
|
|
||||||
/* Process by register */
|
|
||||||
switch (address & ~1) {
|
|
||||||
case 0x0005F800: break; /* INTPND */
|
|
||||||
case 0x0005F802: break; /* INTENB */
|
|
||||||
case 0x0005F804: break; /* INTCLR */
|
|
||||||
case 0x0005F820: break; /* DPSTTS */
|
|
||||||
case 0x0005F822: break; /* DPCTRL */
|
|
||||||
case 0x0005F824: break; /* BRTA */
|
|
||||||
case 0x0005F826: break; /* BRTB */
|
|
||||||
case 0x0005F828: break; /* BRTC */
|
|
||||||
case 0x0005F82A: break; /* REST */
|
|
||||||
case 0x0005F82E: break; /* FRMCYC */
|
|
||||||
case 0x0005F830: break; /* CTA */
|
|
||||||
case 0x0005F840: break; /* XPSTTS */
|
|
||||||
case 0x0005F842: break; /* XPCTRL */
|
|
||||||
case 0x0005F844: break; /* VER */
|
|
||||||
case 0x0005F848: break; /* SPT0 */
|
|
||||||
case 0x0005F84A: break; /* SPT1 */
|
|
||||||
case 0x0005F84C: break; /* SPT2 */
|
|
||||||
case 0x0005F84E: break; /* SPT3 */
|
|
||||||
case 0x0005F860: break; /* GPLT0 */
|
|
||||||
case 0x0005F862: break; /* GPLT1 */
|
|
||||||
case 0x0005F864: break; /* GPLT2 */
|
|
||||||
case 0x0005F866: break; /* GPLT3 */
|
|
||||||
case 0x0005F868: break; /* JPLT0 */
|
|
||||||
case 0x0005F86A: break; /* JPLT1 */
|
|
||||||
case 0x0005F86C: break; /* JPLT2 */
|
|
||||||
case 0x0005F86E: break; /* JPLT3 */
|
|
||||||
case 0x0005F870: break; /* BKCOL */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unmapped */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read an I/O register */
|
|
||||||
static void vipWriteRegister(Vue *vue, int32_t address, int32_t value) {
|
|
||||||
vue=vue;
|
|
||||||
value=value;
|
|
||||||
/* Process by register */
|
|
||||||
switch (address & ~1) {
|
|
||||||
case 0x0005F800: break; /* INTPND */
|
|
||||||
case 0x0005F802: break; /* INTENB */
|
|
||||||
case 0x0005F804: break; /* INTCLR */
|
|
||||||
case 0x0005F820: break; /* DPSTTS */
|
|
||||||
case 0x0005F822: break; /* DPCTRL */
|
|
||||||
case 0x0005F824: break; /* BRTA */
|
|
||||||
case 0x0005F826: break; /* BRTB */
|
|
||||||
case 0x0005F828: break; /* BRTC */
|
|
||||||
case 0x0005F82A: break; /* REST */
|
|
||||||
case 0x0005F82E: break; /* FRMCYC */
|
|
||||||
case 0x0005F830: break; /* CTA */
|
|
||||||
case 0x0005F840: break; /* XPSTTS */
|
|
||||||
case 0x0005F842: break; /* XPCTRL */
|
|
||||||
case 0x0005F844: break; /* VER */
|
|
||||||
case 0x0005F848: break; /* SPT0 */
|
|
||||||
case 0x0005F84A: break; /* SPT1 */
|
|
||||||
case 0x0005F84C: break; /* SPT2 */
|
|
||||||
case 0x0005F84E: break; /* SPT3 */
|
|
||||||
case 0x0005F860: break; /* GPLT0 */
|
|
||||||
case 0x0005F862: break; /* GPLT1 */
|
|
||||||
case 0x0005F864: break; /* GPLT2 */
|
|
||||||
case 0x0005F866: break; /* GPLT3 */
|
|
||||||
case 0x0005F868: break; /* JPLT0 */
|
|
||||||
case 0x0005F86A: break; /* JPLT1 */
|
|
||||||
case 0x0005F86C: break; /* JPLT2 */
|
|
||||||
case 0x0005F86E: break; /* JPLT3 */
|
|
||||||
case 0x0005F870: break; /* BKCOL */
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a value from the CPU bus */
|
|
||||||
static int32_t vipRead(Vue *vue, int32_t address, int32_t type) {
|
|
||||||
int32_t value; /* Register value */
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
/* VRAM */
|
|
||||||
if (address < 0x00040000)
|
|
||||||
return readBuffer(vue->vip.vram, 0x40000, address, type);
|
|
||||||
|
|
||||||
/* Mirrors of character memory */
|
|
||||||
if (address >= 0x00078000)
|
|
||||||
return readBuffer(vue->vip.vram, 0x40000,
|
|
||||||
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
|
|
||||||
(address & 0x00001FFF),
|
|
||||||
type);
|
|
||||||
|
|
||||||
/* I/O register or unmapped */
|
|
||||||
value = vipReadRegister(vue, address);
|
|
||||||
if (type < 2 && (address & 1) == 1)
|
|
||||||
value >>= 8;
|
|
||||||
switch (type) {
|
|
||||||
case VUE_S8 : return SIGN_EXTEND(value, 8);
|
|
||||||
case VUE_U8 : return value & 0x000000FF;
|
|
||||||
case VUE_S16: return SIGN_EXTEND(value, 16);
|
|
||||||
case VUE_S32: return value | vipReadRegister(vue, address + 2) << 16;
|
|
||||||
}
|
|
||||||
return value; /* U16 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read bytes from the CPU bus */
|
|
||||||
static void vipReadBytes(Vue *vue, int address, uint8_t *dest, int length) {
|
|
||||||
int32_t count, size, value; /* Working variables */
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
/* Perform the operation */
|
|
||||||
while (length > 0) {
|
|
||||||
|
|
||||||
/* VRAM */
|
|
||||||
if (address < 0x00040000) {
|
|
||||||
count = 0x00040000 - address;
|
|
||||||
if (length < count)
|
|
||||||
count = length;
|
|
||||||
readBytes(vue->vip.vram, 0x40000, address, dest, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mirrors of character memory */
|
|
||||||
else if (address >= 0x00078000) {
|
|
||||||
count = 0x2000 - (address & 0x1FFF);
|
|
||||||
if (length < count)
|
|
||||||
count = length;
|
|
||||||
readBytes(vue->vip.vram, 0x40000,
|
|
||||||
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
|
|
||||||
(address & 0x00001FFF),
|
|
||||||
dest, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* I/O register or unmapped */
|
|
||||||
else {
|
|
||||||
count = 0x00078000 - address;
|
|
||||||
if (length < count)
|
|
||||||
count = length;
|
|
||||||
|
|
||||||
/* Read all registers in the range */
|
|
||||||
while (count > 0) {
|
|
||||||
value = vipReadRegister(vue, address);
|
|
||||||
|
|
||||||
/* Odd address */
|
|
||||||
if ((address & 1) == 1) {
|
|
||||||
*dest = value >> 8;
|
|
||||||
address++;
|
|
||||||
count --;
|
|
||||||
length --;
|
|
||||||
dest ++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Even address */
|
|
||||||
size = count == 1 ? 1 : 2;
|
|
||||||
*dest = value;
|
|
||||||
if (size == 2)
|
|
||||||
dest[1] = value >> 8;
|
|
||||||
address += size;
|
|
||||||
count -= size;
|
|
||||||
length -= size;
|
|
||||||
dest += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Advance to the next region */
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
dest += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* System reset */
|
|
||||||
static void vipReset(Vue *vue) {
|
|
||||||
vue = vue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine the number of CPU cycles until a breakpoint could trigger */
|
|
||||||
static uint32_t vipUntil(Vue *vue, uint32_t cycles) {
|
|
||||||
vue = vue;
|
|
||||||
return cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a value to the CPU bus */
|
|
||||||
static void vipWrite(Vue *vue, int32_t address, int32_t type, int32_t value) {
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
/* VRAM */
|
|
||||||
if (address < 0x00040000) {
|
|
||||||
writeBuffer(vue->vip.vram, 0x40000, address, type, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mirrors of character memory */
|
|
||||||
if (address >= 0x00078000) {
|
|
||||||
writeBuffer(vue->vip.vram, 0x40000,
|
|
||||||
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
|
|
||||||
(address & 0x00001FFF),
|
|
||||||
type, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* I/O register or unmapped */
|
|
||||||
if (type < 2 && (address & 1) == 1)
|
|
||||||
value <<= 8;
|
|
||||||
vipWriteRegister(vue, address, value);
|
|
||||||
if (type == VUE_S32)
|
|
||||||
vipWriteRegister(vue, address + 2, value >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write bytes to the CPU bus */
|
|
||||||
static void vipWriteBytes(Vue *vue, int address, uint8_t *src, int length) {
|
|
||||||
int32_t count, size, value; /* Working variables */
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
/* Perform the operation */
|
|
||||||
while (length > 0) {
|
|
||||||
|
|
||||||
/* VRAM */
|
|
||||||
if (address < 0x00040000) {
|
|
||||||
count = 0x00040000 - address;
|
|
||||||
if (length < count)
|
|
||||||
count = length;
|
|
||||||
writeBytes(vue->vip.vram, 0x40000, address, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mirrors of character memory */
|
|
||||||
else if (address >= 0x00078000) {
|
|
||||||
count = 0x2000 - (address & 0x1FFF);
|
|
||||||
if (length < count)
|
|
||||||
count = length;
|
|
||||||
writeBytes(vue->vip.vram, 0x40000,
|
|
||||||
(address - 0x00078000) >> 13 << 15 | 0x00006000 |
|
|
||||||
(address & 0x00001FFF),
|
|
||||||
src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* I/O register or unmapped */
|
|
||||||
else {
|
|
||||||
count = 0x00078000 - address;
|
|
||||||
if (length < count)
|
|
||||||
count = length;
|
|
||||||
|
|
||||||
/* Read all registers in the range */
|
|
||||||
while (count > 0) {
|
|
||||||
value = *src;
|
|
||||||
|
|
||||||
/* Odd address */
|
|
||||||
if ((address & 1) == 1) {
|
|
||||||
vipWriteRegister(vue, address, value << 8);
|
|
||||||
address++;
|
|
||||||
count --;
|
|
||||||
length --;
|
|
||||||
src ++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Even address */
|
|
||||||
size = count == 1 ? 1 : 2;
|
|
||||||
if (size == 2)
|
|
||||||
value |= src[1] << 8;
|
|
||||||
vipWriteRegister(vue, address, value);
|
|
||||||
address += size;
|
|
||||||
count -= size;
|
|
||||||
length -= size;
|
|
||||||
src += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Advance to the next region */
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
src += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
458
src/core/vue.c
458
src/core/vue.c
|
@ -1,458 +0,0 @@
|
||||||
#define VUEAPI
|
|
||||||
#include <vue.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Macros *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/* Sign-extend a value */
|
|
||||||
#define SIGN_EXTEND(bits, value) \
|
|
||||||
((value) & 1 << (bits - 1) ? (value) | (~(1 << bits) + 1) : (value))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Constants *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/* Memory access type sizes */
|
|
||||||
static const uint32_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Module Functions *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/* Read a value from a byte buffer */
|
|
||||||
static int32_t readBuffer(uint8_t *data, uint32_t datlen, uint32_t address,
|
|
||||||
int32_t type) {
|
|
||||||
uint32_t size = TYPE_SIZES[type]; /* Size of data type */
|
|
||||||
int32_t value = 0;
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (data == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Common processing */
|
|
||||||
address &= (~size + 1) & (datlen - 1);
|
|
||||||
|
|
||||||
/* The host is little-endian */
|
|
||||||
#ifndef VUE_BIGENDIAN
|
|
||||||
switch (type) {
|
|
||||||
case VUE_S8 : value = *( int8_t *)&data[address]; break;
|
|
||||||
case VUE_U8 : value = *(uint8_t *)&data[address]; break;
|
|
||||||
case VUE_S16: value = *( int16_t *)&data[address]; break;
|
|
||||||
case VUE_U16: value = *(uint16_t *)&data[address]; break;
|
|
||||||
case VUE_S32: value = *( int32_t *)&data[address]; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The host is big-endian */
|
|
||||||
#else
|
|
||||||
switch (type) {
|
|
||||||
case VUE_S32: value =
|
|
||||||
data[address + 3] << 24 |
|
|
||||||
(data[address + 2] & 0xFF) << 16;
|
|
||||||
/* Fallthrough */
|
|
||||||
case VUE_S16: /* Fallthrough */
|
|
||||||
case VUE_U16: value |=
|
|
||||||
(data[address + 1] & 0xFF) << 8;
|
|
||||||
/* Fallthrough */
|
|
||||||
case VUE_S8 : /* Fallthrough */
|
|
||||||
case VUE_U8 : value |=
|
|
||||||
data[address ] & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sign-extend the value if appropriate */
|
|
||||||
if ((type & 1) == 0) {
|
|
||||||
size <<= 3;
|
|
||||||
value = SIGN_EXTEND(size, value);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read bytes from a byte buffer */
|
|
||||||
static void readBytes(uint8_t *data, uint32_t datlen, uint32_t address,
|
|
||||||
uint8_t *dest, uint32_t length) {
|
|
||||||
|
|
||||||
/* The source does not exist */
|
|
||||||
if (data == NULL) {
|
|
||||||
while (length--)
|
|
||||||
*dest++ = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Transfer bytes from the source as a circular buffer */
|
|
||||||
while (length--)
|
|
||||||
*dest++ = data[address++ & (datlen - 1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a value to a byte buffer */
|
|
||||||
static void writeBuffer(uint8_t *data, uint32_t datlen, uint32_t address,
|
|
||||||
int32_t type, int32_t value) {
|
|
||||||
uint32_t size = TYPE_SIZES[type]; /* Size of data type */
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (data == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Common processing */
|
|
||||||
address &= (~size + 1) & (datlen - 1);
|
|
||||||
|
|
||||||
/* The host is big-endian */
|
|
||||||
#ifdef VUE_BIGENDIAN
|
|
||||||
switch (type) {
|
|
||||||
case VUE_S32:
|
|
||||||
value = (value >> 16 & 0x0000FFFF) | value << 16;
|
|
||||||
/* Fallthrough */
|
|
||||||
case VUE_S16: /* Fallthrough */
|
|
||||||
case VUE_U16:
|
|
||||||
value = (value >> 8 & 0x00FF00FF) | (value << 8 & 0xFF00FF00);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Processing by data type */
|
|
||||||
switch (type) {
|
|
||||||
case VUE_S8 : /* Fallthrough */
|
|
||||||
case VUE_U8 : *(int8_t *)&data[address] = (int8_t ) value; break;
|
|
||||||
case VUE_S16: /* Fallthrough */
|
|
||||||
case VUE_U16: *(int16_t *)&data[address] = (int16_t ) value; break;
|
|
||||||
case VUE_S32: *(int32_t *)&data[address] = (int32_t ) value; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write bytes to a byte buffer */
|
|
||||||
static void writeBytes(uint8_t *data, uint32_t datlen, uint32_t address,
|
|
||||||
uint8_t *src, uint32_t length) {
|
|
||||||
|
|
||||||
/* The destination does not exist */
|
|
||||||
if (data == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Transfer bytes to the destination as a circular buffer */
|
|
||||||
while (length--)
|
|
||||||
data[address++ & (datlen - 1)] = *src++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Component Includes *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include "cpu.c"
|
|
||||||
#include "gamepak.c"
|
|
||||||
#include "vip.c"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Library Functions *
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/* Process the simulation */
|
|
||||||
uint32_t vueEmulate(Vue *vue, uint32_t maxCycles) {
|
|
||||||
uint32_t cycles; /* Number of cycles to process */
|
|
||||||
|
|
||||||
/* Process up to the given number of cycles */
|
|
||||||
do {
|
|
||||||
|
|
||||||
/* Determine the number of cycles where no breakpoint will occur */
|
|
||||||
cycles = maxCycles; /* min(maxCycles, nextFrameCycles) */
|
|
||||||
cycles = cpuUntil (vue, cycles);
|
|
||||||
/*cycles = padUntil (vue, cycles);*/
|
|
||||||
/*cycles = linkUntil (vue, cycles);*/
|
|
||||||
/*cycles = timerUntil(vue, cycles);*/
|
|
||||||
cycles = vipUntil (vue, cycles);
|
|
||||||
|
|
||||||
/* Process all system components */
|
|
||||||
vue->breakCode = 0;
|
|
||||||
cpuEmulate (vue, cycles);
|
|
||||||
/*padEmulate (vue, cycles);*/
|
|
||||||
/*pakEmulate (vue, cycles);*/
|
|
||||||
/*linkEmulate (vue, cycles);*/
|
|
||||||
/*timerEmulate(vue, cycles);*/
|
|
||||||
vipEmulate (vue, cycles);
|
|
||||||
/*vsuEmulate (vue, cycles);*/
|
|
||||||
maxCycles -= cycles;
|
|
||||||
} while (vue->breakCode == 0 && maxCycles != 0);
|
|
||||||
|
|
||||||
/* A break condition has occurred */
|
|
||||||
return maxCycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve the most recent applicaiton break code */
|
|
||||||
int32_t vueGetBreakCode(Vue *vue) {
|
|
||||||
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 */
|
|
||||||
int32_t vueGetRegister(Vue *vue, int32_t index, vbool system) {
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (vue == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Non-indexed registers */
|
|
||||||
if (system && index < 0) switch (index) {
|
|
||||||
case VUE_JUMP_FROM:
|
|
||||||
return vue->cpu.jumpFrom[vue->cpu.psw_np ? 2 : vue->cpu.psw_ep];
|
|
||||||
case VUE_JUMP_TO :
|
|
||||||
return vue->cpu.jumpTo [vue->cpu.psw_np ? 2 : vue->cpu.psw_ep];
|
|
||||||
case VUE_PC : return vue->cpu.pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Indexed registers */
|
|
||||||
return
|
|
||||||
index < 0 || index > 31 ? 0 :
|
|
||||||
system ? cpuGetSystemRegister(vue, index) :
|
|
||||||
vue->cpu.program[index]
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve the application reference */
|
|
||||||
void* vueGetTag(Vue *vue) {
|
|
||||||
return vue == NULL ? NULL : vue->tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare an emulation state context for use */
|
|
||||||
void vueInitialize(Vue *vue) {
|
|
||||||
if (vue == NULL)
|
|
||||||
return;
|
|
||||||
vue->onException = NULL;
|
|
||||||
vue->onExecute = NULL;
|
|
||||||
vue->onFrame = NULL;
|
|
||||||
vue->onRead = NULL;
|
|
||||||
vue->onWrite = NULL;
|
|
||||||
vue->pak.ram = 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 vueOnRead(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 */
|
|
||||||
int32_t vueRead(Vue *vue, uint32_t address, int32_t type) {
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (vue == NULL || type < 0 || type > 4)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Perform the operation */
|
|
||||||
switch (address >> 24 & 7) {
|
|
||||||
case 0: return vipRead (vue , address,type);
|
|
||||||
case 5: return readBuffer(vue->wram , 0x10000,address,type);
|
|
||||||
case 6: return readBuffer(vue->pak.ram,vue->pak.ramSize,address,type);
|
|
||||||
case 7: return readBuffer(vue->pak.rom,vue->pak.romSize,address,type);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read bytes from the CPU bus */
|
|
||||||
vbool vueReadBytes(Vue *vue, uint32_t address, uint8_t *dest, uint32_t length){
|
|
||||||
uint32_t count; /* Bytes to read in one iteration */
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (vue == NULL || dest == NULL)
|
|
||||||
return VUE_FALSE;
|
|
||||||
|
|
||||||
/* Perform the operation */
|
|
||||||
while (length > 0) {
|
|
||||||
count = 0x01000000 - (address & 0x00FFFFFF);
|
|
||||||
if (length < count)
|
|
||||||
count = length;
|
|
||||||
switch (address >> 24 & 7) {
|
|
||||||
case 0: vipReadBytes(vue ,
|
|
||||||
address, dest, count); break;
|
|
||||||
case 5: readBytes(vue->wram , 0x10000,
|
|
||||||
address, dest, count); break;
|
|
||||||
case 6: readBytes(vue->pak.ram, vue->pak.ramSize,
|
|
||||||
address, dest, count); break;
|
|
||||||
case 7: readBytes(vue->pak.rom, vue->pak.romSize,
|
|
||||||
address, dest, count); break;
|
|
||||||
default:
|
|
||||||
for (address += count, length -= count; count--;)
|
|
||||||
*dest++ = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
dest += count;
|
|
||||||
}
|
|
||||||
return VUE_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize all system components */
|
|
||||||
void vueReset(Vue *vue) {
|
|
||||||
uint32_t x; /* Iterator */
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (vue == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Reset state */
|
|
||||||
cpuReset(vue);
|
|
||||||
pakReset(vue);
|
|
||||||
for (x = 0; x < 0x10000; x++)
|
|
||||||
vue->wram[x] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Specify a value for a register */
|
|
||||||
int32_t vueSetRegister(Vue *vue, int32_t index, vbool system, int32_t value) {
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (vue == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* PC */
|
|
||||||
if (index == VUE_PC && system) {
|
|
||||||
if (vue->cpu.stage == CPU_EXECUTE || vue->cpu.stage == CPU_FETCH) {
|
|
||||||
vue->cpu.fetch = -1;
|
|
||||||
vue->cpu.stage = CPU_FETCH;
|
|
||||||
}
|
|
||||||
return vue->cpu.pc = value & 0xFFFFFFFE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Other */
|
|
||||||
return
|
|
||||||
index < 0 || index > 31 ? 0 :
|
|
||||||
system ? cpuSetSystemRegister(vue, index, value, VUE_TRUE) :
|
|
||||||
index == 0 ? 0 : (vue->cpu.program[index] = value)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Specify a new ROM buffer */
|
|
||||||
vbool vueSetROM(Vue *vue, uint8_t *rom, uint32_t size) {
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (
|
|
||||||
vue == NULL ||
|
|
||||||
rom == NULL ||
|
|
||||||
size < 1024 || size > 0x01000000 ||
|
|
||||||
(size & (size - 1)) != 0
|
|
||||||
) return VUE_FALSE;
|
|
||||||
|
|
||||||
/* Accept the new ROM buffer */
|
|
||||||
vue->pak.rom = rom;
|
|
||||||
vue->pak.romSize = size;
|
|
||||||
return VUE_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Specify a new application reference */
|
|
||||||
void* vueSetTag(Vue *vue, void *tag) {
|
|
||||||
void *ret;
|
|
||||||
if (vue == NULL)
|
|
||||||
return NULL;
|
|
||||||
ret = vue->tag;
|
|
||||||
vue->tag = tag;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a value to the CPU bus */
|
|
||||||
void vueWrite(Vue *vue, uint32_t address, int32_t type, int32_t value) {
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (vue == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Perform the operation */
|
|
||||||
switch (address >> 24 & 7) {
|
|
||||||
case 0: vipWrite(vue ,
|
|
||||||
address, type, value); break;
|
|
||||||
case 5: writeBuffer(vue->wram , 0x10000,
|
|
||||||
address, type, value); break;
|
|
||||||
case 6: writeBuffer(vue->pak.ram, vue->pak.ramSize,
|
|
||||||
address, type, value); break;
|
|
||||||
case 7: writeBuffer(vue->pak.rom, vue->pak.romSize,
|
|
||||||
address, type, value); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write bytes to the CPU bus */
|
|
||||||
vbool vueWriteBytes(Vue *vue, uint32_t address, uint8_t *src, uint32_t length){
|
|
||||||
uint32_t count; /* Bytes to write in one iteration */
|
|
||||||
|
|
||||||
/* Error checking */
|
|
||||||
if (vue == NULL || src == NULL)
|
|
||||||
return VUE_FALSE;
|
|
||||||
|
|
||||||
/* Perform the operation */
|
|
||||||
while (length > 0) {
|
|
||||||
count = 0x01000000 - (address & 0x00FFFFFF);
|
|
||||||
if (length < count)
|
|
||||||
count = length;
|
|
||||||
switch (address >> 24 & 7) {
|
|
||||||
case 0: vipWriteBytes(vue ,
|
|
||||||
address, src, count); break;
|
|
||||||
case 5: writeBytes(vue->wram , 0x10000,
|
|
||||||
address, src, count); break;
|
|
||||||
case 6: writeBytes(vue->pak.ram, vue->pak.ramSize,
|
|
||||||
address, src, count); break;
|
|
||||||
case 7: writeBytes(vue->pak.rom, vue->pak.ramSize,
|
|
||||||
address, src, count); break;
|
|
||||||
}
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
src += count;
|
|
||||||
}
|
|
||||||
return VUE_TRUE;
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Java imports
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import app.*;
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// Desktop application primary class
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
// Program entry point
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// Configure Swing look-and-feel
|
|
||||||
Util.setSystemLAF();
|
|
||||||
|
|
||||||
// Load the native module, if available
|
|
||||||
for (String filename : Util.listFiles("native")) {
|
|
||||||
File file = null;
|
|
||||||
|
|
||||||
// Skip any file that isn't a shared object library
|
|
||||||
if (!filename.endsWith(".dll") && !filename.endsWith(".so"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Write the contents of the native object file
|
|
||||||
FileOutputStream stream = null;
|
|
||||||
try {
|
|
||||||
file = File.createTempFile("native", "." + filename);
|
|
||||||
stream = new FileOutputStream(file);
|
|
||||||
stream.write(Util.fileRead("native/" + filename));
|
|
||||||
} catch (Exception e) { file = null; }
|
|
||||||
try { stream.close(); } catch (Exception e) { }
|
|
||||||
|
|
||||||
// Load the native object file into the JVM
|
|
||||||
try {
|
|
||||||
System.load(file.getAbsolutePath());
|
|
||||||
Vue.setNativeID(filename.substring(0,
|
|
||||||
filename.lastIndexOf(".")));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (Error e) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the native module
|
|
||||||
boolean useNative = false;
|
|
||||||
for (String arg : args)
|
|
||||||
if (arg.trim().toLowerCase().equals("native"))
|
|
||||||
useNative = true;
|
|
||||||
|
|
||||||
// Begin application operations
|
|
||||||
new App(useNative);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,174 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// Top-level software state manager
|
|
||||||
public class App {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private boolean useNative; // Produce native core contexts
|
|
||||||
private Localizer.Locale[] locales; // Language translations
|
|
||||||
private ArrayList<MainWindow> windows; // Application windows
|
|
||||||
|
|
||||||
// Configuration fields
|
|
||||||
Util.Font fntDialog; // Dialog font
|
|
||||||
Util.Font fntMono; // Monospaced font
|
|
||||||
int hexDigitWidth; // Width in pixels of one hex digit
|
|
||||||
Localizer localizer; // UI localization manager
|
|
||||||
int[][] rgbBase; // Base anaglyph filter colors
|
|
||||||
int rgbClear; // Transparent pixel color
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Anaglyph presets
|
|
||||||
static final int[] RED = { 0xFF, 0x00, 0x00 };
|
|
||||||
static final int[] CYAN = { 0x00, 0xC6, 0xF0 };
|
|
||||||
static final int[] GREEN = { 0x00, 0xB4, 0x00 };
|
|
||||||
static final int[] MAGENTA = { 0xC8, 0x00, 0xFF };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
public App(boolean useNative) {
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
localizer = new Localizer();
|
|
||||||
windows = new ArrayList<MainWindow>();
|
|
||||||
|
|
||||||
// Configure config fields
|
|
||||||
fntDialog = new Util.Font(new JLabel().getFont());
|
|
||||||
fntMono = new Util.Font(new Font(Util.fontFamily(new String[]
|
|
||||||
{ "Consolas", Font.MONOSPACED } ), Font.PLAIN, 14));
|
|
||||||
hexDigitWidth = hexDigitWidth();
|
|
||||||
rgbBase = new int[][] {
|
|
||||||
Arrays.copyOf(GREEN , 4),
|
|
||||||
Arrays.copyOf(MAGENTA, 4),
|
|
||||||
Arrays.copyOf(RED , 4)
|
|
||||||
};
|
|
||||||
rgbClear = 0x555555;
|
|
||||||
|
|
||||||
// Additional processing
|
|
||||||
setUseNative(useNative);
|
|
||||||
initLocales();
|
|
||||||
addWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a new program window
|
|
||||||
void addWindow() {
|
|
||||||
windows.add(new MainWindow(this));
|
|
||||||
windowsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine whether the native module is in use
|
|
||||||
boolean getUseNative() {
|
|
||||||
return useNative;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a list of registered locales
|
|
||||||
Localizer.Locale[] listLocales() {
|
|
||||||
var ret = new Localizer.Locale[locales.length];
|
|
||||||
System.arraycopy(locales, 0, ret, 0, locales.length);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the number of a window in the collection
|
|
||||||
int numberOf(MainWindow window) {
|
|
||||||
return windows.indexOf(window) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a program window
|
|
||||||
void removeWindow(MainWindow window) {
|
|
||||||
windows.remove(window);
|
|
||||||
windowsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify whether using the native module
|
|
||||||
boolean setUseNative(boolean useNative) {
|
|
||||||
return this.useNative = useNative && Vue.getNativeID() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Calculate the maximum hexadecimal digit width
|
|
||||||
private int hexDigitWidth() {
|
|
||||||
int width = 0;
|
|
||||||
for (var digit : "0123456789ABCDEFabcdef".toCharArray())
|
|
||||||
width = Math.max(width, fntMono.metrics.charWidth(digit));
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load and parse all locale translations
|
|
||||||
private void initLocales() {
|
|
||||||
|
|
||||||
// Process all locale files
|
|
||||||
var locales = new HashMap<String, Localizer.Locale>();
|
|
||||||
for (String file : Util.listFiles("locale")) {
|
|
||||||
|
|
||||||
// Process the file
|
|
||||||
try {
|
|
||||||
var locale = Localizer.parse(Util.textRead("locale/" + file));
|
|
||||||
String key = locale.id.toLowerCase();
|
|
||||||
|
|
||||||
// Register the locale
|
|
||||||
if (locales.containsKey(key)) throw new RuntimeException(
|
|
||||||
"Locale with ID '" + locale.id + "' already registered");
|
|
||||||
locales.put(key, locale);
|
|
||||||
|
|
||||||
// The locale matches the one in the config
|
|
||||||
if (key.equals("en-us"))
|
|
||||||
localizer.setLocale(locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Could not process the file
|
|
||||||
catch (Exception e) {
|
|
||||||
System.err.println("Error parsing locale " +
|
|
||||||
file + ": " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce the list of registered locales
|
|
||||||
this.locales = locales.values().toArray(
|
|
||||||
new Localizer.Locale[locales.size()]);
|
|
||||||
Arrays.sort(this.locales);
|
|
||||||
|
|
||||||
// Select a default locale
|
|
||||||
if (localizer.getLocale() != null || this.locales.length == 0)
|
|
||||||
return;
|
|
||||||
var locale = locales.get("en-us");
|
|
||||||
localizer.setLocale(locale != null ? locale : this.locales[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A window has been added to or removed from the program state
|
|
||||||
private void windowsChanged() {
|
|
||||||
int count = windows.size();
|
|
||||||
for (int x = 0; x < count; x++)
|
|
||||||
windows.get(x).windowsChanged(x + 1, count == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,512 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.awt.image.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.border.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// VIP backgrounds window
|
|
||||||
class BGMapsWindow extends ChildWindow {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private int cellIndex; // Current cell index
|
|
||||||
private int character; // Cell character index
|
|
||||||
private Point dragging; // Most recent pattern mouse position
|
|
||||||
private boolean generic; // Use the generic palette
|
|
||||||
private boolean grid; // Draw a grid around characters
|
|
||||||
private boolean hFlip; // Cell is flipped horizontally
|
|
||||||
private int mapIndex; // Current BG map index
|
|
||||||
private int palette; // Palette index
|
|
||||||
private int[] pix; // Image buffer
|
|
||||||
private int scale; // Display scale
|
|
||||||
private boolean vFlip; // Cell is flipped vertically
|
|
||||||
private BufferedImage image; // BG map graphic
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
private JCheckBox chkGeneric; // Generic colors check box
|
|
||||||
private JCheckBox chkGrid; // Grid check box
|
|
||||||
private JCheckBox chkHFlip; // H-flip check box
|
|
||||||
private JCheckBox chkVFlip; // V-flip check box
|
|
||||||
private UComboBox cmbPalette; // Palette drop-down
|
|
||||||
private UPanel client; // Client area
|
|
||||||
private UPanel panCell; // Cell panel
|
|
||||||
private UPanel panMap; // BG map panel
|
|
||||||
private JScrollPane scrControls; // Controls panel
|
|
||||||
private JScrollPane scrMap; // BG map container
|
|
||||||
private JSlider sldScale; // Scale slider
|
|
||||||
private JSpinner spnCellIndex; // Cell index spinner
|
|
||||||
private JSpinner spnCharacter; // Character spinner
|
|
||||||
private JSpinner spnMapIndex; // BG map index spinner
|
|
||||||
private JTextField txtCellAddress; // Cell address text box
|
|
||||||
private JTextField txtMapAddress; // BG map address text box
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
BGMapsWindow(MainWindow parent) {
|
|
||||||
super(parent, "bg_maps.title");
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
generic = false;
|
|
||||||
image = new BufferedImage(512, 512, BufferedImage.TYPE_INT_RGB);
|
|
||||||
pix = new int[512 * 512];
|
|
||||||
scale = 2;
|
|
||||||
|
|
||||||
// Configure client area
|
|
||||||
client = new UPanel(new BorderLayout());
|
|
||||||
client.setBackground(SystemColor.control);
|
|
||||||
client.setFocusable(true);
|
|
||||||
client.setPreferredSize(new Dimension(480, 360));
|
|
||||||
client.addComponentListener(Util.onResize(e->onResize()));
|
|
||||||
|
|
||||||
// Configure controls panel
|
|
||||||
var ctrls = new UPanel(new GridBagLayout());
|
|
||||||
ctrls.setBackground(SystemColor.control);
|
|
||||||
ctrls.addMouseListener(
|
|
||||||
Util.onMouse(e->client.requestFocus(), null));
|
|
||||||
scrControls = new JScrollPane(ctrls,
|
|
||||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
|
||||||
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
|
||||||
scrControls.setBorder(null);
|
|
||||||
scrControls.getVerticalScrollBar().setUnitIncrement(20);
|
|
||||||
client.add(scrControls, BorderLayout.WEST);
|
|
||||||
|
|
||||||
// BG Map controls
|
|
||||||
label(ctrls, "bg_maps.map", true);
|
|
||||||
spnMapIndex = spinner(ctrls, 0, 15, 0, true);
|
|
||||||
spnMapIndex.addChangeListener(e->
|
|
||||||
setMap((Integer) spnMapIndex.getValue()));
|
|
||||||
label(ctrls, "bg_maps.address", false);
|
|
||||||
txtMapAddress = textBox(ctrls);
|
|
||||||
txtMapAddress.addFocusListener(Util.onFocus(null,
|
|
||||||
e->onAddress(txtMapAddress)));
|
|
||||||
|
|
||||||
// Cell controls container
|
|
||||||
var cell = new UPanel(new GridBagLayout());
|
|
||||||
cell.setBorder(new TitledBorder(""));
|
|
||||||
parent.app.localizer.add(cell, "bg_maps.cell");
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 2, 2, 2);
|
|
||||||
ctrls.add(cell, gbc);
|
|
||||||
|
|
||||||
// Cell controls
|
|
||||||
label(cell, "bg_maps.index", true);
|
|
||||||
spnCellIndex = spinner(cell, 0, 4095, 0, true);
|
|
||||||
spnCellIndex.addChangeListener(e->
|
|
||||||
setCell((Integer) spnCellIndex.getValue()));
|
|
||||||
label(cell, "bg_maps.address", false);
|
|
||||||
txtCellAddress = textBox(cell);
|
|
||||||
txtCellAddress.addFocusListener(Util.onFocus(null,
|
|
||||||
e->onAddress(txtCellAddress)));
|
|
||||||
label(cell, "bg_maps.character", false);
|
|
||||||
spnCharacter = spinner(cell, 0, 2047, 0, false);
|
|
||||||
spnCharacter.addChangeListener(e->onEdit());
|
|
||||||
label(cell, "bg_maps.palette", false);
|
|
||||||
cmbPalette = select(cell, new String[] {
|
|
||||||
"palette.gplt0", "palette.gplt1", "palette.gplt2", "palette.gplt3"
|
|
||||||
});
|
|
||||||
cmbPalette.addActionListener(e->onEdit());
|
|
||||||
label(cell, "bg_maps.hflip", false);
|
|
||||||
chkHFlip = checkBox(cell);
|
|
||||||
chkHFlip.addActionListener(e->onEdit());
|
|
||||||
label(cell, "bg_maps.vflip", false);
|
|
||||||
chkVFlip = checkBox(cell);
|
|
||||||
chkVFlip.addActionListener(e->onEdit());
|
|
||||||
|
|
||||||
// Cell panel
|
|
||||||
panCell = new UPanel();
|
|
||||||
panCell.setOpaque(false);
|
|
||||||
panCell.setPreferredSize(new Dimension(96, 96));
|
|
||||||
panCell.addPaintListener((g,w,h)->onPaintCell(g, w, h));
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.CENTER;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(2, 2, 2, 2);
|
|
||||||
cell.add(panCell, gbc);
|
|
||||||
terminator(cell);
|
|
||||||
|
|
||||||
// Fill the extra space above the view controls
|
|
||||||
var spacer = new UPanel();
|
|
||||||
spacer.setOpaque(false);
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.weighty = 1;
|
|
||||||
ctrls.add(spacer, gbc);
|
|
||||||
|
|
||||||
// View controls
|
|
||||||
label(ctrls, "bg_maps.grid", false);
|
|
||||||
chkGrid = checkBox(ctrls);
|
|
||||||
chkGrid.addActionListener(e->{
|
|
||||||
grid = chkGrid.isSelected(); onView(); });
|
|
||||||
label(ctrls, "bg_maps.generic", false);
|
|
||||||
chkGeneric = checkBox(ctrls);
|
|
||||||
chkGeneric.setSelected(generic);
|
|
||||||
chkGeneric.addActionListener(e->{
|
|
||||||
generic = chkGeneric.isSelected(); refresh(); });
|
|
||||||
label(ctrls, "bg_maps.scale", false);
|
|
||||||
sldScale = slider(ctrls, 1, 10, scale);
|
|
||||||
sldScale.addChangeListener(e->{
|
|
||||||
scale = sldScale.getValue(); onView(); });
|
|
||||||
terminator(ctrls);
|
|
||||||
|
|
||||||
// Configure BG map panel
|
|
||||||
panMap = new UPanel();
|
|
||||||
panMap.setBackground(SystemColor.control);
|
|
||||||
panMap.addMouseListener(
|
|
||||||
Util.onMouse(e->onMouse(e), e->onMouse(e)));
|
|
||||||
panMap.addMouseMotionListener(
|
|
||||||
Util.onMouseMove(null, e->onMouse(e)));
|
|
||||||
panMap.addPaintListener((g,w,h)->onPaintMap(g, w, h));
|
|
||||||
scrMap = new JScrollPane(panMap);
|
|
||||||
client.add(scrMap, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
setContentPane(client);
|
|
||||||
setCell(0);
|
|
||||||
onView();
|
|
||||||
pack();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
void refresh() {
|
|
||||||
|
|
||||||
// Update BG map graphic
|
|
||||||
int src = 0x00020000 | mapIndex << 13;
|
|
||||||
for (int index = 0; index < 4096; index++, src += 2) {
|
|
||||||
int bits = parent.vram[src] & 0xFF | parent.vram[src + 1] << 8;
|
|
||||||
var pal = parent.palettes[generic ? MainWindow.GENERIC :
|
|
||||||
MainWindow.GPLT0 + (bits >> 14 & 3)][MainWindow.RED];
|
|
||||||
parent.drawCharacter(
|
|
||||||
bits & 0x07FF, (bits & 0x2000) != 0, (bits & 0x1000) != 0, pal,
|
|
||||||
pix, index >> 6 << 12 | (index & 63) << 3, 512
|
|
||||||
);
|
|
||||||
}
|
|
||||||
image.setRGB(0, 0, 512, 512, pix, 0, 512);
|
|
||||||
|
|
||||||
// Update display;
|
|
||||||
panCell.repaint();
|
|
||||||
panMap .repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Event Handlers //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Address text boxes commit
|
|
||||||
private void onAddress(JTextField src) {
|
|
||||||
int address;
|
|
||||||
|
|
||||||
// Parse the given address
|
|
||||||
try { address = (int) Long.parseLong(src.getText(), 16); }
|
|
||||||
catch (Exception e) {
|
|
||||||
setMap(mapIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restrict address range
|
|
||||||
if ((address >> 24 & 7) != 0) {
|
|
||||||
setMap(mapIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
// Check if the address is in BG map memory
|
|
||||||
if (address < 0x00020000 || address >= 0x00040000) {
|
|
||||||
setMap(mapIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the map and character indexes
|
|
||||||
address -= 0x00020000;
|
|
||||||
mapIndex = address >> 13;
|
|
||||||
setCell((address & 0x00001FFE) >> 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A cell value has changed
|
|
||||||
private void onEdit() {
|
|
||||||
|
|
||||||
// Process cell properties
|
|
||||||
character = (Integer) spnCharacter.getValue();
|
|
||||||
hFlip = chkHFlip.isSelected();
|
|
||||||
palette = cmbPalette.getSelectedIndex();
|
|
||||||
vFlip = chkVFlip.isSelected();
|
|
||||||
|
|
||||||
// Update VRAM state
|
|
||||||
parent.vue.write(
|
|
||||||
0x00020000 | mapIndex << 13 | cellIndex << 1, Vue.U16,
|
|
||||||
palette << 14 | (hFlip ? 0x2000 : 0) |
|
|
||||||
(vFlip ? 0x1000 : 0) | character
|
|
||||||
);
|
|
||||||
parent.refreshDebug(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BG map panel mouse
|
|
||||||
private void onMouse(MouseEvent e) {
|
|
||||||
int id = e.getID();
|
|
||||||
|
|
||||||
// Mouse release
|
|
||||||
if (id == MouseEvent.MOUSE_RELEASED) {
|
|
||||||
if (e.getButton() == MouseEvent.BUTTON1)
|
|
||||||
dragging = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse press
|
|
||||||
if (id == MouseEvent.MOUSE_PRESSED) {
|
|
||||||
client.requestFocus();
|
|
||||||
if (e.getButton() != MouseEvent.BUTTON1)
|
|
||||||
return;
|
|
||||||
dragging = e.getPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not dragging
|
|
||||||
if (dragging == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Working variables
|
|
||||||
int grid = this.grid ? 1 : 0;
|
|
||||||
int size = 8 * scale + grid;
|
|
||||||
int col = e.getX() / size;
|
|
||||||
int row = e.getY() / size;
|
|
||||||
|
|
||||||
// The pixel is not within a cell
|
|
||||||
if (col >= 64 || row >= 64)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Calculate the index of the selected cell
|
|
||||||
setCell(row << 6 | col);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cell panel paint
|
|
||||||
private void onPaintCell(Graphics2D g, int width, int height) {
|
|
||||||
int scale = Math.max(1, Math.min(width >> 3, height >> 3));
|
|
||||||
int x = (width - (scale << 3) + 1) >> 1;
|
|
||||||
int y = (height - (scale << 3) + 1) >> 1;
|
|
||||||
int ix = (cellIndex & 63) << 3;
|
|
||||||
int iy = cellIndex >> 6 << 3;
|
|
||||||
g.drawImage(image,
|
|
||||||
x, y, x + scale * 8, y + scale * 8,
|
|
||||||
ix, iy, ix + 8 , iy + 8 ,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BG map panel paint
|
|
||||||
private void onPaintMap(Graphics2D g, int width, int height) {
|
|
||||||
|
|
||||||
// Drawing with a grid
|
|
||||||
if (grid) {
|
|
||||||
|
|
||||||
int scale = 8 * this.scale;
|
|
||||||
for (int y = 0, z = 0; y < 64; y++)
|
|
||||||
for (int x = 0; x < 64; x++, z++) {
|
|
||||||
int ix = (z & 63) << 3;
|
|
||||||
int iy = z >> 6 << 3;
|
|
||||||
int ox = x * (scale + 1);
|
|
||||||
int oy = y * (scale + 1);
|
|
||||||
g.drawImage(image,
|
|
||||||
ox, oy, ox + scale, oy + scale,
|
|
||||||
ix, iy, ix + 8 , iy + 8 ,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not drawing with a grid
|
|
||||||
else g.drawImage(image, 0, 0, 512 * scale, 512 * scale, null);
|
|
||||||
|
|
||||||
// Highlight the selected cell
|
|
||||||
int size = 8 * scale + (grid ? 1 : 0);
|
|
||||||
int X = (cellIndex & 63) * size;
|
|
||||||
int Y = (cellIndex >> 6) * size;
|
|
||||||
int light = SystemColor.textHighlight.getRGB() & 0x00FFFFFF;
|
|
||||||
g.setColor(new Color(0xD0000000 | light, true));
|
|
||||||
g.drawRect(X , Y , 8 * scale - 1, 8 * scale - 1);
|
|
||||||
g.setColor(new Color(0x90000000 | light, true));
|
|
||||||
g.drawRect(X + 1, Y + 1, 8 * scale - 3, 8 * scale - 3);
|
|
||||||
g.setColor(new Color(0x50000000 | light, true));
|
|
||||||
g.fillRect(X + 2, Y + 2, 8 * scale - 4, 8 * scale - 4);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window resize
|
|
||||||
private void onResize() {
|
|
||||||
var viewport = scrControls.getViewport();
|
|
||||||
int inner = viewport.getView().getPreferredSize().width;
|
|
||||||
int outer = viewport.getExtentSize().width;
|
|
||||||
|
|
||||||
// Size the controls container to match the inner component
|
|
||||||
if (inner != outer) {
|
|
||||||
scrControls.setPreferredSize(new Dimension(
|
|
||||||
scrControls.getPreferredSize().width + inner - outer, 0));
|
|
||||||
scrControls.revalidate();
|
|
||||||
scrControls.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// View control changed
|
|
||||||
private void onView() {
|
|
||||||
int grid = this.grid ? 1 : 0;
|
|
||||||
int size = 8 * scale + grid;
|
|
||||||
int pref = size * 64 - grid;
|
|
||||||
scrMap.getVerticalScrollBar().setUnitIncrement(8 * scale + grid);
|
|
||||||
panMap.setPreferredSize(new Dimension(pref, pref));
|
|
||||||
panMap.revalidate();
|
|
||||||
panMap.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a check box to the controls panel
|
|
||||||
private JCheckBox checkBox(UPanel panel) {
|
|
||||||
var chk = new JCheckBox();
|
|
||||||
chk.setBorder(null);
|
|
||||||
chk.setFocusable(false);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, 2);
|
|
||||||
panel.add(chk, gbc);
|
|
||||||
return chk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a label to the controls panel
|
|
||||||
private void label(UPanel panel, String key, boolean top) {
|
|
||||||
var lbl = new JLabel();
|
|
||||||
parent.app.localizer.add(lbl, key);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.insets = new Insets(top ? 2 : 0, 2, 2, 2);
|
|
||||||
panel.add(lbl, gbc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update controls
|
|
||||||
private void refreshLite() {
|
|
||||||
int mapAddr = mapIndex << 13 | 0x00020000;
|
|
||||||
int cellAddr = mapAddr | cellIndex << 1;
|
|
||||||
|
|
||||||
int bits = parent.vram[cellAddr] & 0xFF | parent.vram[cellAddr+1] << 8;
|
|
||||||
character = bits & 0x07FF;
|
|
||||||
hFlip = (bits & 0x2000) != 0;
|
|
||||||
palette = bits >> 14 & 3;
|
|
||||||
vFlip = (bits & 0x1000) != 0;
|
|
||||||
|
|
||||||
chkHFlip .setSelected(hFlip);
|
|
||||||
chkVFlip .setSelected(vFlip);
|
|
||||||
cmbPalette .setSelectedIndex(palette);
|
|
||||||
spnCellIndex .setValue(cellIndex);
|
|
||||||
spnCharacter .setValue(character);
|
|
||||||
spnMapIndex .setValue(mapIndex);
|
|
||||||
txtMapAddress .setText(String.format("%08X", mapAddr ));
|
|
||||||
txtCellAddress.setText(String.format("%08X", cellAddr));
|
|
||||||
|
|
||||||
panCell.repaint();
|
|
||||||
panMap .repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a combo box to the controls panel
|
|
||||||
private UComboBox select(UPanel panel, String[] options) {
|
|
||||||
var cmb = new UComboBox();
|
|
||||||
parent.app.localizer.add(cmb, options);
|
|
||||||
cmb.setSelectedIndex(0);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, 2);
|
|
||||||
panel.add(cmb, gbc);
|
|
||||||
return cmb;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the current cell index
|
|
||||||
private void setCell(int index) {
|
|
||||||
cellIndex = index;
|
|
||||||
refreshLite();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the current BG map index
|
|
||||||
private void setMap(int index) {
|
|
||||||
mapIndex = index;
|
|
||||||
refreshLite();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a slider to the controls panel
|
|
||||||
private JSlider slider(UPanel panel, int min, int max, int value) {
|
|
||||||
var sld = new JSlider(min, max, value);
|
|
||||||
sld.setFocusable(false);
|
|
||||||
sld.setPreferredSize(new Dimension(0, sld.getPreferredSize().height));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 1, 2);
|
|
||||||
panel.add(sld, gbc);
|
|
||||||
return sld;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a spinner to the controls panel
|
|
||||||
private JSpinner spinner(UPanel panel, int min, int max, int value,
|
|
||||||
boolean top) {
|
|
||||||
var spn = new JSpinner(new SpinnerNumberModel(value, min, max, 1));
|
|
||||||
var txt = new JSpinner.NumberEditor(spn, "#");
|
|
||||||
txt.getTextField().addActionListener(e->client.requestFocus());
|
|
||||||
spn.setEditor(txt);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(top ? 2 : 0, 0, 2, 2);
|
|
||||||
gbc.weightx = 1;
|
|
||||||
panel.add(spn, gbc);
|
|
||||||
return spn;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate a controls container
|
|
||||||
private void terminator(UPanel panel) {
|
|
||||||
var spacer = new UPanel();
|
|
||||||
spacer.setOpaque(false);
|
|
||||||
spacer.setPreferredSize(new Dimension(0, 0));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.gridheight = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
panel.add(spacer, gbc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a text box to the controls panel
|
|
||||||
private JTextField textBox(UPanel panel) {
|
|
||||||
var txt = new JTextField();
|
|
||||||
txt.setFont(parent.app.fntMono);
|
|
||||||
txt.addActionListener(e->client.requestFocus());
|
|
||||||
var size = txt.getPreferredSize();
|
|
||||||
txt.setPreferredSize(new Dimension(
|
|
||||||
parent.app.hexDigitWidth * 8 + 2 + size.width, size.height));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, 2);
|
|
||||||
panel.add(txt, gbc);
|
|
||||||
return txt;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,613 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// Memory viewer and hex editor window
|
|
||||||
class BreakpointsWindow extends ChildWindow {
|
|
||||||
|
|
||||||
// Private fields
|
|
||||||
private ArrayList<Item> items; // List items
|
|
||||||
private int selectedIndex; // Selected list item
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
private JButton btnDelete; // Delete button
|
|
||||||
private JButton btnNew; // New button
|
|
||||||
private JCheckBox chkEnabled; // Enabled check box
|
|
||||||
private JCheckBox chkException; // Exception check box
|
|
||||||
private JCheckBox chkExecute; // Execute check box
|
|
||||||
private JCheckBox chkRead; // Read check box
|
|
||||||
private JCheckBox chkWrite; // Write check box
|
|
||||||
private UPanel client; // Client area
|
|
||||||
private JLabel errAddress; // Address error text
|
|
||||||
private JLabel errCondition; // Condition error text
|
|
||||||
private UPanel lstBreakpoints; // Breakpoint list
|
|
||||||
private UPanel spacer; // List termination spacer
|
|
||||||
private JTextField txtAddress; // Address text box
|
|
||||||
private JTextField txtCondition; // Condition text box
|
|
||||||
private JTextField txtName; // Name text box
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Address error keys
|
|
||||||
private static final String[] KEYS_ADDRESS = {
|
|
||||||
null , // NONE
|
|
||||||
"breakpoints.error.badliteral_a", // BADLITERAL
|
|
||||||
null , // BADOPERAND
|
|
||||||
null , // BADTOKEN
|
|
||||||
"breakpoints.error.earlyeof" , // EARLYEOF
|
|
||||||
null , // INVALID
|
|
||||||
null , // NESTING
|
|
||||||
"breakpoints.error.unexpected" // UNEXPECTED
|
|
||||||
};
|
|
||||||
|
|
||||||
// Condition error keys
|
|
||||||
private static final String[] KEYS_CONDITION = {
|
|
||||||
null , // NONE
|
|
||||||
"breakpoints.error.badliteral_c", // BADLITERAL
|
|
||||||
"breakpoints.error.badoperand" , // BADOPERAND
|
|
||||||
"breakpoints.error.badtoken" , // BADTOKEN
|
|
||||||
"breakpoints.error.earlyeof" , // EARLYEOF
|
|
||||||
"breakpoints.error.invalid" , // INVALID
|
|
||||||
"breakpoints.error.nesting" , // NESTING
|
|
||||||
"breakpoints.error.unexpected" // UNEXPECTED
|
|
||||||
};
|
|
||||||
|
|
||||||
// List constraints
|
|
||||||
private static final GridBagConstraints ENABLED;
|
|
||||||
private static final GridBagConstraints NAME;
|
|
||||||
private static final GridBagConstraints SPACER;
|
|
||||||
private static final GridBagConstraints STATUS;
|
|
||||||
|
|
||||||
// Static initializer
|
|
||||||
static {
|
|
||||||
ENABLED = new GridBagConstraints();
|
|
||||||
ENABLED.anchor = GridBagConstraints.CENTER;
|
|
||||||
ENABLED.insets = new Insets(1, 2, 1, 2);
|
|
||||||
NAME = new GridBagConstraints();
|
|
||||||
NAME.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
NAME.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
NAME.insets = new Insets(1, 0, 1, 2);
|
|
||||||
NAME.weightx = 1;
|
|
||||||
SPACER = new GridBagConstraints();
|
|
||||||
SPACER.fill = GridBagConstraints.BOTH;
|
|
||||||
SPACER.gridheight = GridBagConstraints.REMAINDER;
|
|
||||||
SPACER.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
SPACER.weighty = 1;
|
|
||||||
STATUS = new GridBagConstraints();
|
|
||||||
STATUS.fill = GridBagConstraints.BOTH;
|
|
||||||
STATUS.insets = new Insets(0, 0, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Classes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Text box commit
|
|
||||||
private interface Commit {
|
|
||||||
void run();
|
|
||||||
}
|
|
||||||
|
|
||||||
// List item
|
|
||||||
private class Item {
|
|
||||||
Breakpoint breakpoint;
|
|
||||||
JCheckBox chkEnabled;
|
|
||||||
JLabel lblName;
|
|
||||||
JLabel lblStatus;
|
|
||||||
|
|
||||||
// Constructor
|
|
||||||
Item(Breakpoint brk) {
|
|
||||||
var that = this;
|
|
||||||
breakpoint = brk;
|
|
||||||
brk.setFetch(false);
|
|
||||||
chkEnabled = new JCheckBox();
|
|
||||||
chkEnabled.setBorder(null);
|
|
||||||
chkEnabled.setFocusable(false);
|
|
||||||
chkEnabled.addActionListener(e->onEnabled(that));
|
|
||||||
parent.app.localizer.add(chkEnabled,"null","breakpoints.enabled");
|
|
||||||
lblName = new JLabel(brk.getName());
|
|
||||||
lblStatus = new JLabel("", SwingConstants.CENTER);
|
|
||||||
refresh(null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
void refresh(Instruction inst, Access acc) {
|
|
||||||
if (
|
|
||||||
breakpoint.getAddressError ().code != Breakpoint.NONE ||
|
|
||||||
breakpoint.getConditionError().code != Breakpoint.NONE
|
|
||||||
) lblStatus.setText("\u00d7"); // Times symbol
|
|
||||||
else if (breakpoint.any() && breakpoint.evaluate(inst, acc))
|
|
||||||
lblStatus.setText("\u2605"); // Star
|
|
||||||
else lblStatus.setText(" ");
|
|
||||||
int lineHeight = parent.app.fntDialog.metrics.getHeight();
|
|
||||||
lblStatus.setPreferredSize(new Dimension(lineHeight, lineHeight));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify whether or not the item has focus
|
|
||||||
void setFocused(boolean focused) {
|
|
||||||
var color = focused ? SystemColor.textHighlightText :
|
|
||||||
SystemColor.windowText;
|
|
||||||
lblStatus.setForeground(color);
|
|
||||||
lblName .setForeground(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
BreakpointsWindow(MainWindow parent) {
|
|
||||||
super(parent, "breakpoints.title");
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
items = new ArrayList<Item>();
|
|
||||||
selectedIndex = -1;
|
|
||||||
|
|
||||||
// Configure client area
|
|
||||||
client = new UPanel(new BorderLayout());
|
|
||||||
client.setBackground(SystemColor.control);
|
|
||||||
client.setFocusable(true);
|
|
||||||
client.setPreferredSize(new Dimension(320, 240));
|
|
||||||
|
|
||||||
// Configure breakpoint list
|
|
||||||
lstBreakpoints = new UPanel(new GridBagLayout());
|
|
||||||
lstBreakpoints.setFocusable(true);
|
|
||||||
lstBreakpoints.setBackground(SystemColor.window);
|
|
||||||
lstBreakpoints.addFocusListener(Util.onFocus(
|
|
||||||
e->lstBreakpoints.repaint(), e->lstBreakpoints.repaint()));
|
|
||||||
lstBreakpoints.addMouseListener(Util.onMouse(e->onMouseDown(e), null));
|
|
||||||
lstBreakpoints.addPaintListener((g,w,h)->onPaint(g, w, h));
|
|
||||||
var scr = new JScrollPane(lstBreakpoints);
|
|
||||||
scr.getVerticalScrollBar().setUnitIncrement(
|
|
||||||
parent.app.fntDialog.metrics.getHeight());
|
|
||||||
client.add(scr, BorderLayout.CENTER);
|
|
||||||
spacer = new UPanel();
|
|
||||||
spacer.setOpaque(false);
|
|
||||||
lstBreakpoints.add(spacer, SPACER);
|
|
||||||
|
|
||||||
// Configure properties pane
|
|
||||||
var props = new UPanel(new GridBagLayout());
|
|
||||||
props.setBackground(SystemColor.control);
|
|
||||||
props.addMouseListener(
|
|
||||||
Util.onMouse(e->client.requestFocus(), null));
|
|
||||||
client.add(props, BorderLayout.SOUTH);
|
|
||||||
|
|
||||||
// Configure properties
|
|
||||||
label(props, "breakpoints.name", 2);
|
|
||||||
txtName = textBox(props, false, 2, ()->onName());
|
|
||||||
//label(props, "breakpoints.enabled", 0);
|
|
||||||
//chkEnabled = checkBox(props, null, true);
|
|
||||||
chkEnabled = new JCheckBox();
|
|
||||||
chkEnabled.addActionListener(e->onEnabled(null));
|
|
||||||
label(props, "breakpoints.type", 0);
|
|
||||||
chkExecute = checkBox(props, "breakpoints.execute" , false);
|
|
||||||
chkExecute .addActionListener(e->onType(chkExecute ));
|
|
||||||
chkRead = checkBox(props, "breakpoints.read" , false);
|
|
||||||
chkRead .addActionListener(e->onType(chkRead ));
|
|
||||||
chkWrite = checkBox(props, "breakpoints.write" , false);
|
|
||||||
chkWrite .addActionListener(e->onType(chkWrite ));
|
|
||||||
chkException = checkBox(props, "breakpoints.exception", true );
|
|
||||||
chkException.addActionListener(e->onType(chkException));
|
|
||||||
label(props, "breakpoints.address", 0);
|
|
||||||
txtAddress = textBox(props, true, 0, ()->onAddress());
|
|
||||||
errAddress = error(props);
|
|
||||||
label(props, "breakpoints.condition", 0);
|
|
||||||
txtCondition = textBox(props, true, 0, ()->onCondition());
|
|
||||||
errCondition = error(props);
|
|
||||||
|
|
||||||
// Configure buttons
|
|
||||||
var buttons = new UPanel(new GridBagLayout());
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
props.add(buttons, gbc);
|
|
||||||
var fill = new UPanel();
|
|
||||||
fill.setOpaque(false);
|
|
||||||
fill.addMouseListener(Util.onMouse(e->onDebug(e), null));
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.weightx = 1;
|
|
||||||
buttons.add(fill, gbc);
|
|
||||||
btnDelete = button(buttons, "breakpoints.delete", false);
|
|
||||||
btnDelete.setEnabled(false);
|
|
||||||
btnDelete.addActionListener(e->onDelete());
|
|
||||||
btnNew = button(buttons, "breakpoints.new", true);
|
|
||||||
btnNew.addActionListener(e->onNew());
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
setContentPane(client);
|
|
||||||
pack();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
void refresh() {
|
|
||||||
var inst = new Instruction(parent.vue.read(
|
|
||||||
parent.vue.getRegister(Vue.PC, true), Vue.S32));
|
|
||||||
var acc = inst.access(parent.vue);
|
|
||||||
for (var item : items)
|
|
||||||
item.refresh(inst, acc);
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Event Handlers //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Address text box commit
|
|
||||||
private void onAddress() {
|
|
||||||
if (selectedIndex == -1)
|
|
||||||
return;
|
|
||||||
var item = items.get(selectedIndex);
|
|
||||||
item.breakpoint.setAddresses(txtAddress.getText());
|
|
||||||
checkErrors(item);
|
|
||||||
item.refresh(null, null);
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Condition text box commit
|
|
||||||
private void onCondition() {
|
|
||||||
if (selectedIndex == -1)
|
|
||||||
return;
|
|
||||||
var item = items.get(selectedIndex);
|
|
||||||
item.breakpoint.setCondition(txtCondition.getText());
|
|
||||||
checkErrors(item);
|
|
||||||
item.refresh(null, null);
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug interaction
|
|
||||||
private void onDebug(MouseEvent e) {
|
|
||||||
client.requestFocus();
|
|
||||||
if (
|
|
||||||
selectedIndex == -1 ||
|
|
||||||
e.getButton() != MouseEvent.BUTTON1 ||
|
|
||||||
(e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == 0
|
|
||||||
) return;
|
|
||||||
var brk = items.get(selectedIndex).breakpoint;
|
|
||||||
System.out.println("Address");
|
|
||||||
System.out.println(brk.getAddresses());
|
|
||||||
System.out.println(brk.debugRanges());
|
|
||||||
System.out.println("Condition");
|
|
||||||
System.out.println(brk.getCondition());
|
|
||||||
System.out.println(brk.debugTokens());
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete button click
|
|
||||||
private void onDelete() {
|
|
||||||
var item = items.remove(selectedIndex);
|
|
||||||
parent.vue.remove(item.breakpoint);
|
|
||||||
lstBreakpoints.remove(item.chkEnabled);
|
|
||||||
lstBreakpoints.remove(item.lblName);
|
|
||||||
lstBreakpoints.remove(item.lblStatus);
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
selectedIndex = -1;
|
|
||||||
select(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enabled check box toggle
|
|
||||||
private void onEnabled(Item item) {
|
|
||||||
boolean enabled;
|
|
||||||
|
|
||||||
// Clicked from the properties pane
|
|
||||||
if (item == null) {
|
|
||||||
enabled = chkEnabled.isSelected();
|
|
||||||
item = items.get(selectedIndex);
|
|
||||||
item.chkEnabled.setSelected(enabled);
|
|
||||||
client.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clicked from the breakpoints list
|
|
||||||
else {
|
|
||||||
enabled = item.chkEnabled.isSelected();
|
|
||||||
if (items.indexOf(item) == selectedIndex)
|
|
||||||
chkEnabled.setSelected(enabled);
|
|
||||||
lstBreakpoints.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Common processing
|
|
||||||
item.breakpoint.setEnabled(enabled);
|
|
||||||
item.refresh(null, null);
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// List mouse press
|
|
||||||
private void onMouseDown(MouseEvent e) {
|
|
||||||
int count = items.size();
|
|
||||||
|
|
||||||
// Left clicking
|
|
||||||
if (count > 0 && e.getButton() == MouseEvent.BUTTON1) {
|
|
||||||
int newIndex = e.getY() / items.get(0).lblStatus.getHeight();
|
|
||||||
if (newIndex < count)
|
|
||||||
select(newIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update layout
|
|
||||||
lstBreakpoints.requestFocus();
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name text box commit
|
|
||||||
private void onName() {
|
|
||||||
if (selectedIndex == -1)
|
|
||||||
return;
|
|
||||||
var item = items.get(selectedIndex);
|
|
||||||
item.lblName.setText(item.breakpoint.setName(txtName.getText()));
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
item.refresh(null, null);
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// New button click
|
|
||||||
private void onNew() {
|
|
||||||
|
|
||||||
var brk = parent.vue.breakpoint();
|
|
||||||
brk.setEnabled(true);
|
|
||||||
brk.setName (parent.app.localizer.get("breakpoints.default_name"));
|
|
||||||
|
|
||||||
var item = new Item(brk);
|
|
||||||
item.chkEnabled.setSelected(true);
|
|
||||||
item.lblName .setText(brk.getName());
|
|
||||||
items.add(item);
|
|
||||||
|
|
||||||
int count = items.size();
|
|
||||||
boolean first = count == 1;
|
|
||||||
lstBreakpoints.remove(spacer);
|
|
||||||
lstBreakpoints.add(item.chkEnabled, ENABLED);
|
|
||||||
lstBreakpoints.add(item.lblStatus , STATUS );
|
|
||||||
lstBreakpoints.add(item.lblName , NAME );
|
|
||||||
lstBreakpoints.add(spacer , SPACER );
|
|
||||||
|
|
||||||
select(count - 1);
|
|
||||||
lstBreakpoints.requestFocus();
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// List paint
|
|
||||||
private void onPaint(Graphics2D g, int width, int height) {
|
|
||||||
|
|
||||||
// There is no selected item
|
|
||||||
if (selectedIndex == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Select the display colors
|
|
||||||
var item = items.get(selectedIndex);
|
|
||||||
if (lstBreakpoints.isFocusOwner()) {
|
|
||||||
g.setColor(SystemColor.textHighlight);
|
|
||||||
item.setFocused(true);
|
|
||||||
} else {
|
|
||||||
g.setColor(SystemColor.control);
|
|
||||||
item.setFocused(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the selection background
|
|
||||||
height = item.lblStatus.getHeight();
|
|
||||||
g.fillRect(0, selectedIndex * height, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type check box toggle
|
|
||||||
private void onType(JCheckBox chk) {
|
|
||||||
var item = items.get(selectedIndex);
|
|
||||||
var brk = item.breakpoint;
|
|
||||||
boolean selected = chk.isSelected();
|
|
||||||
|
|
||||||
// Configure controls
|
|
||||||
if (chk == chkException)
|
|
||||||
brk.setException(selected);
|
|
||||||
else if (chk == chkExecute )
|
|
||||||
brk.setExecute (selected);
|
|
||||||
else if (chk == chkRead )
|
|
||||||
brk.setRead (selected);
|
|
||||||
else if (chk == chkWrite )
|
|
||||||
brk.setWrite (selected);
|
|
||||||
|
|
||||||
// Common processing
|
|
||||||
item.refresh(null, null);
|
|
||||||
client.requestFocus();
|
|
||||||
lstBreakpoints.revalidate();
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a button to the form
|
|
||||||
private JButton button(UPanel panel, String key, boolean last) {
|
|
||||||
var btn = new JButton();
|
|
||||||
if (key != null)
|
|
||||||
parent.app.localizer.add(btn, key);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, 2);
|
|
||||||
if (last)
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
panel.add(btn, gbc);
|
|
||||||
return btn;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a check box to the form
|
|
||||||
private JCheckBox checkBox(UPanel panel, String key, boolean last) {
|
|
||||||
var chk = new JCheckBox();
|
|
||||||
if (key != null)
|
|
||||||
parent.app.localizer.add(chk, key);
|
|
||||||
chk.setBorder(null);
|
|
||||||
chk.setEnabled(false);
|
|
||||||
chk.setFocusable(false);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, last ? 2 : 6);
|
|
||||||
if (last)
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
panel.add(chk, gbc);
|
|
||||||
return chk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for errors in the selected breakpoint
|
|
||||||
private void checkErrors(Item item) {
|
|
||||||
var brk = item.breakpoint;
|
|
||||||
var loc = parent.app.localizer;
|
|
||||||
|
|
||||||
// Check for address errors
|
|
||||||
var err = brk.getAddressError();
|
|
||||||
if (err.code != Breakpoint.NONE) {
|
|
||||||
loc.add(errAddress, KEYS_ADDRESS[err.code]);
|
|
||||||
loc.put(errAddress, "err.position",
|
|
||||||
Integer.toString(err.position));
|
|
||||||
loc.put(errAddress, "err.text", err.text);
|
|
||||||
errAddress.setVisible(true);
|
|
||||||
} else errAddress.setVisible(false);
|
|
||||||
|
|
||||||
// Check for condition errors
|
|
||||||
err = brk.getConditionError();
|
|
||||||
if (err.code != Breakpoint.NONE) {
|
|
||||||
loc.add(errCondition, KEYS_CONDITION[err.code]);
|
|
||||||
loc.put(errCondition, "err.position",
|
|
||||||
Integer.toString(err.position));
|
|
||||||
loc.put(errCondition, "err.text", err.text);
|
|
||||||
if (err.code == Breakpoint.NESTING)
|
|
||||||
loc.put(errCondition, "err.other",
|
|
||||||
err.text.equals(")") ? "]" : ")");
|
|
||||||
errCondition.setVisible(true);
|
|
||||||
} else errCondition.setVisible(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an error label to the form
|
|
||||||
private JLabel error(UPanel panel) {
|
|
||||||
var lbl = new JLabel();
|
|
||||||
lbl.setForeground(Color.red);
|
|
||||||
lbl.setVisible(false);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.CENTER;
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridx = 1;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, 2);
|
|
||||||
panel.add(lbl, gbc);
|
|
||||||
return lbl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a label to the form
|
|
||||||
private void label(UPanel panel, String key, int top) {
|
|
||||||
var lbl = new JLabel();
|
|
||||||
if (key != null)
|
|
||||||
parent.app.localizer.add(lbl, key);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.insets = new Insets(top, 2, 2, 4);
|
|
||||||
panel.add(lbl, gbc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select a particular list item
|
|
||||||
private void select(int newIndex) {
|
|
||||||
boolean enabled = newIndex != -1;
|
|
||||||
|
|
||||||
// The existing selection was de-selected
|
|
||||||
if (selectedIndex != -1 && newIndex != selectedIndex)
|
|
||||||
items.get(selectedIndex).setFocused(false);
|
|
||||||
|
|
||||||
// Selecting a new list item
|
|
||||||
if (newIndex != -1)
|
|
||||||
items.get(newIndex).setFocused(true);
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
selectedIndex = newIndex;
|
|
||||||
|
|
||||||
// Update control properties
|
|
||||||
if (enabled) {
|
|
||||||
var brk = items.get(selectedIndex).breakpoint;
|
|
||||||
chkEnabled .setSelected(brk.isEnabled ());
|
|
||||||
chkExecute .setSelected(brk.getExecute ());
|
|
||||||
chkRead .setSelected(brk.getRead ());
|
|
||||||
chkWrite .setSelected(brk.getWrite ());
|
|
||||||
chkException.setSelected(brk.getException());
|
|
||||||
txtAddress .setText (brk.getAddresses());
|
|
||||||
txtCondition.setText (brk.getCondition());
|
|
||||||
txtName .setText (brk.getName ());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear control properties
|
|
||||||
else {
|
|
||||||
chkEnabled .setSelected(false);
|
|
||||||
chkExecute .setSelected(false);
|
|
||||||
chkRead .setSelected(false);
|
|
||||||
chkWrite .setSelected(false);
|
|
||||||
chkException.setSelected(false);
|
|
||||||
errAddress .setText(""); errAddress .setVisible(false);
|
|
||||||
errCondition.setText(""); errCondition.setVisible(false);
|
|
||||||
txtAddress .setText("");
|
|
||||||
txtCondition.setText("");
|
|
||||||
txtName .setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable or disable controls
|
|
||||||
btnDelete .setEnabled(enabled);
|
|
||||||
chkEnabled .setEnabled(enabled);
|
|
||||||
chkExecute .setEnabled(enabled);
|
|
||||||
chkException.setEnabled(enabled);
|
|
||||||
chkRead .setEnabled(enabled);
|
|
||||||
chkWrite .setEnabled(enabled);
|
|
||||||
txtAddress .setEnabled(enabled);
|
|
||||||
txtCondition.setEnabled(enabled);
|
|
||||||
txtName .setEnabled(enabled);
|
|
||||||
|
|
||||||
// Common processing
|
|
||||||
if (selectedIndex != -1)
|
|
||||||
checkErrors(items.get(selectedIndex));
|
|
||||||
lstBreakpoints.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a text box to the form
|
|
||||||
private JTextField textBox(UPanel panel, boolean mono, int top,
|
|
||||||
Commit handler) {
|
|
||||||
var txt = new JTextField();
|
|
||||||
txt.setEnabled(false);
|
|
||||||
if (mono)
|
|
||||||
txt.setFont(parent.app.fntMono);
|
|
||||||
txt.addActionListener(e->client.requestFocus());
|
|
||||||
txt.addFocusListener (Util.onFocus(null, e->handler.run()));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.CENTER;
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(top, 0, 2, 2);
|
|
||||||
gbc.weightx = 1;
|
|
||||||
panel.add(txt, gbc);
|
|
||||||
return txt;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// CPU window
|
|
||||||
class CPUWindow extends ChildWindow {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
MainWindow parent; // Containing window
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
private DisassemblerPane panDasm; // Disassembler client
|
|
||||||
private RegisterList lstProgram; // Program register list
|
|
||||||
private RegisterList lstSystem; // System register list
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
CPUWindow(MainWindow parent) {
|
|
||||||
super(parent, "cpu.title");
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
this.parent = parent;
|
|
||||||
|
|
||||||
// Configure child panes
|
|
||||||
panDasm = new DisassemblerPane(this);
|
|
||||||
lstSystem = new RegisterList(this, true);
|
|
||||||
lstProgram = new RegisterList(this, false);
|
|
||||||
|
|
||||||
// Configure layout
|
|
||||||
var inner = Util.splitPane(JSplitPane.VERTICAL_SPLIT);
|
|
||||||
inner.setTopComponent(lstSystem);
|
|
||||||
inner.setBottomComponent(lstProgram);
|
|
||||||
var outer = Util.splitPane(JSplitPane.HORIZONTAL_SPLIT);
|
|
||||||
outer.setLeftComponent(panDasm);
|
|
||||||
outer.setRightComponent(inner);
|
|
||||||
outer.setResizeWeight(1);
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
var client = getContentPane();
|
|
||||||
client.add(outer);
|
|
||||||
client.setPreferredSize(new Dimension(480, 300));
|
|
||||||
pack();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
void refresh(boolean seekToPC) {
|
|
||||||
panDasm .refresh(seekToPC);
|
|
||||||
lstSystem .refresh();
|
|
||||||
lstProgram.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,612 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.awt.image.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
|
|
||||||
// VIP characters window
|
|
||||||
class CharactersWindow extends ChildWindow {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private int color; // Selected color index
|
|
||||||
private Point dragging; // Most recent pattern mouse position
|
|
||||||
private int index; // Current character index
|
|
||||||
private boolean grid; // Draw a grid around characters
|
|
||||||
private int palette; // Palette index
|
|
||||||
private int[] pix; // Image buffer
|
|
||||||
private int scale; // Display scale
|
|
||||||
private int wide; // Number of characters per row
|
|
||||||
private BufferedImage image; // Character graphics
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
private JCheckBox chkGrid; // Grid check box
|
|
||||||
private UPanel client; // Client area
|
|
||||||
private UComboBox cmbPalette; // Palette drop-down
|
|
||||||
private UPanel panCharacters; // Characters panel
|
|
||||||
private UPanel panPalette; // Palette panel
|
|
||||||
private UPanel panPattern; // Pattern panel
|
|
||||||
private JScrollPane scrCharacters; // Characters container
|
|
||||||
private JScrollPane scrControls; // Controls panel
|
|
||||||
private JScrollBar scrWidth; // Width template scroll bar
|
|
||||||
private JSlider sldScale; // Scale slider
|
|
||||||
private JSpinner spnIndex; // Index spinner
|
|
||||||
private JSpinner spnWide; // Wide spinner
|
|
||||||
private JTextField txtAddress; // Address text box
|
|
||||||
private JTextField txtMirror; // Mirror text box
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
CharactersWindow(MainWindow parent) {
|
|
||||||
super(parent, "characters.title");
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
color = 0;
|
|
||||||
grid = true;
|
|
||||||
image = new BufferedImage(256, 512, BufferedImage.TYPE_INT_RGB);
|
|
||||||
pix = new int[256 * 512];
|
|
||||||
scale = 3;
|
|
||||||
|
|
||||||
// Template scroll bar to check control width in the current LAF
|
|
||||||
scrWidth = new JScrollBar(JScrollBar.VERTICAL);
|
|
||||||
|
|
||||||
// Configure client area
|
|
||||||
client = new UPanel(new BorderLayout());
|
|
||||||
client.setBackground(SystemColor.control);
|
|
||||||
client.setFocusable(true);
|
|
||||||
client.setPreferredSize(new Dimension(480, 360));
|
|
||||||
client.addComponentListener(Util.onResize(e->onResize()));
|
|
||||||
|
|
||||||
// Configure controls panel
|
|
||||||
var ctrls = new UPanel(new GridBagLayout());
|
|
||||||
ctrls.setBackground(SystemColor.control);
|
|
||||||
ctrls.addMouseListener(
|
|
||||||
Util.onMouse(e->client.requestFocus(), null));
|
|
||||||
scrControls = new JScrollPane(ctrls,
|
|
||||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
|
||||||
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
|
||||||
scrControls.setBorder(null);
|
|
||||||
scrControls.getVerticalScrollBar().setUnitIncrement(20);
|
|
||||||
client.add(scrControls, BorderLayout.WEST);
|
|
||||||
|
|
||||||
// Character controls
|
|
||||||
label(ctrls, "characters.index", true);
|
|
||||||
spnIndex = spinner(ctrls, 0, 2047, 0, true);
|
|
||||||
spnIndex.addChangeListener(e->
|
|
||||||
setIndex((Integer) spnIndex.getValue()));
|
|
||||||
label(ctrls, "characters.address", false);
|
|
||||||
txtAddress = textBox(ctrls);
|
|
||||||
txtAddress.addFocusListener(Util.onFocus(null,
|
|
||||||
e->onAddress(txtAddress)));
|
|
||||||
label(ctrls, "characters.mirror", false);
|
|
||||||
txtMirror = textBox(ctrls);
|
|
||||||
txtMirror.addFocusListener(Util.onFocus(null,
|
|
||||||
e->onAddress(txtMirror)));
|
|
||||||
|
|
||||||
// Pattern panel
|
|
||||||
panPattern = new UPanel();
|
|
||||||
panPattern.setOpaque(false);
|
|
||||||
panPattern.setPreferredSize(new Dimension(96, 96));
|
|
||||||
panPattern.addMouseListener(
|
|
||||||
Util.onMouse(e->onMousePattern(e), e->onMousePattern(e)));
|
|
||||||
panPattern.addMouseMotionListener(
|
|
||||||
Util.onMouseMove(null, e->onMousePattern(e)));
|
|
||||||
panPattern.addPaintListener((g,w,h)->onPaintPattern(g, w, h));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.CENTER;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(4, 2, 2, 2);
|
|
||||||
ctrls.add(panPattern, gbc);
|
|
||||||
|
|
||||||
// Palette panel
|
|
||||||
panPalette = new UPanel();
|
|
||||||
panPalette.setOpaque(false);
|
|
||||||
panPalette.setPreferredSize(new Dimension(0, 20 + 6));
|
|
||||||
panPalette.addMouseListener(
|
|
||||||
Util.onMouse(e->onMouseDownPalette(e), null));
|
|
||||||
panPalette.addPaintListener((g,w,h)->onPaintPalette(g, w, h));
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 2, 4, 2);
|
|
||||||
ctrls.add(panPalette, gbc);
|
|
||||||
|
|
||||||
// Fill the extra space above the view controls
|
|
||||||
var spacer = new UPanel();
|
|
||||||
spacer.setOpaque(false);
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.weighty = 1;
|
|
||||||
ctrls.add(spacer, gbc);
|
|
||||||
|
|
||||||
// View controls
|
|
||||||
label(ctrls, "characters.grid", false);
|
|
||||||
chkGrid = checkBox(ctrls);
|
|
||||||
chkGrid.setSelected(grid);
|
|
||||||
chkGrid.addActionListener(e->{
|
|
||||||
grid = chkGrid.isSelected(); onView(); });
|
|
||||||
label(ctrls, "characters.wide", false);
|
|
||||||
spnWide = spinner(ctrls, 0, 2048, 0, false);
|
|
||||||
spnWide.addChangeListener(e->{
|
|
||||||
wide = (Integer) spnWide.getValue(); onView(); });
|
|
||||||
label(ctrls, "characters.palette", false);
|
|
||||||
cmbPalette = select(ctrls, new String[] { "palette.generic",
|
|
||||||
"palette.gplt0", "palette.gplt1", "palette.gplt2", "palette.gplt3",
|
|
||||||
"palette.jplt0", "palette.jplt1", "palette.jplt2", "palette.jplt3"
|
|
||||||
});
|
|
||||||
cmbPalette.addActionListener(e->{
|
|
||||||
palette = cmbPalette.getSelectedIndex(); repaint(); });
|
|
||||||
label(ctrls, "characters.scale", false);
|
|
||||||
sldScale = slider(ctrls, 1, 10, scale);
|
|
||||||
sldScale.addChangeListener(e->{
|
|
||||||
scale = sldScale.getValue(); onView(); });
|
|
||||||
|
|
||||||
// Terminate the list of controls
|
|
||||||
spacer = new UPanel();
|
|
||||||
spacer.setOpaque(false);
|
|
||||||
spacer.setPreferredSize(new Dimension(0, 0));
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.gridheight = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
ctrls.add(spacer, gbc);
|
|
||||||
|
|
||||||
// Configure characters panel
|
|
||||||
panCharacters = new UPanel();
|
|
||||||
panCharacters.setBackground(SystemColor.control);
|
|
||||||
panCharacters.addMouseListener(
|
|
||||||
Util.onMouse(e->onMouseCharacters(e), e->onMouseCharacters(e)));
|
|
||||||
panCharacters.addMouseMotionListener(
|
|
||||||
Util.onMouseMove(null, e->onMouseCharacters(e)));
|
|
||||||
panCharacters.addPaintListener((g,w,h)->onPaintCharacters(g, w, h));
|
|
||||||
scrCharacters = new JScrollPane(panCharacters);
|
|
||||||
client.add(scrCharacters, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
setContentPane(client);
|
|
||||||
setIndex(0);
|
|
||||||
onView();
|
|
||||||
pack();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
void refresh() {
|
|
||||||
|
|
||||||
// Update characters graphic
|
|
||||||
var pal = parent.palettes[palette][MainWindow.RED];
|
|
||||||
for (int index = 0; index < 2048; index++)
|
|
||||||
parent.drawCharacter(index, false, false, pal, pix,
|
|
||||||
index >> 5 << 11 | (index & 31) << 3, 256);
|
|
||||||
image.setRGB(0, 0, 256, 512, pix, 0, 256);
|
|
||||||
|
|
||||||
// Update display;
|
|
||||||
panCharacters.repaint();
|
|
||||||
panPattern .repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Event Handlers //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Address and Mirror text box commit
|
|
||||||
private void onAddress(JTextField src) {
|
|
||||||
int address;
|
|
||||||
|
|
||||||
// Parse the given address
|
|
||||||
try { address = (int) Long.parseLong(src.getText(), 16); }
|
|
||||||
catch (Exception e) {
|
|
||||||
setIndex(index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restrict address range
|
|
||||||
if ((address >> 24 & 7) != 0) {
|
|
||||||
setIndex(index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
// Character memory
|
|
||||||
if ((address & 0x00066000) == 0x00006000)
|
|
||||||
index = address >> 15 << 9 | address >> 4 & 511;
|
|
||||||
|
|
||||||
// Mirror of character memory
|
|
||||||
else if (address >= 0x00078000)
|
|
||||||
index = address - 0x00078000 >> 4;
|
|
||||||
|
|
||||||
// Common processing
|
|
||||||
setIndex(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Characters mouse
|
|
||||||
private void onMouseCharacters(MouseEvent e) {
|
|
||||||
int id = e.getID();
|
|
||||||
|
|
||||||
// Mouse release
|
|
||||||
if (id == MouseEvent.MOUSE_RELEASED) {
|
|
||||||
if (e.getButton() == MouseEvent.BUTTON1)
|
|
||||||
dragging = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse press
|
|
||||||
if (id == MouseEvent.MOUSE_PRESSED) {
|
|
||||||
client.requestFocus();
|
|
||||||
if (e.getButton() != MouseEvent.BUTTON1)
|
|
||||||
return;
|
|
||||||
dragging = e.getPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not dragging
|
|
||||||
if (dragging == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Working variables
|
|
||||||
int grid = this.grid ? 1 : 0;
|
|
||||||
int size = 8 * scale + grid;
|
|
||||||
int wide = this.wide != 0 ? this.wide :
|
|
||||||
Math.max(1, (panCharacters.getWidth() + grid) / size);
|
|
||||||
int col = e.getX() / size;
|
|
||||||
int row = e.getY() / size;
|
|
||||||
|
|
||||||
// The pixel is not within a character
|
|
||||||
if (col >= wide || row >= (2047 + wide) / wide)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Calculate the index of the selected character
|
|
||||||
int index = row * wide + col;
|
|
||||||
if (index < 2048)
|
|
||||||
setIndex(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Palette mouse button press
|
|
||||||
private void onMouseDownPalette(MouseEvent e) {
|
|
||||||
|
|
||||||
// Common processing
|
|
||||||
client.requestFocus();
|
|
||||||
|
|
||||||
// Only consider left clicks
|
|
||||||
if (e.getButton() != MouseEvent.BUTTON1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Working variables
|
|
||||||
int height = panPalette.getHeight();
|
|
||||||
int width = panPalette.getWidth();
|
|
||||||
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
|
||||||
int left = (width - size * 4 - 18) / 2;
|
|
||||||
int top = (height - size - 6) / 2;
|
|
||||||
int x = e.getX() - left - 3;
|
|
||||||
int y = e.getY() - top - 3;
|
|
||||||
|
|
||||||
// The click was not on top of a color
|
|
||||||
if (
|
|
||||||
x < 0 || x >= (size + 4) * 4 ||
|
|
||||||
x % (size + 4) >= size ||
|
|
||||||
y < 0 || y >= size
|
|
||||||
) return;
|
|
||||||
|
|
||||||
// Select the clicked color
|
|
||||||
color = x / (size + 4);
|
|
||||||
panPalette.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pattern mouse
|
|
||||||
private void onMousePattern(MouseEvent e) {
|
|
||||||
int id = e.getID();
|
|
||||||
int scale = Math.max(1, Math.min(
|
|
||||||
panPattern.getWidth () >> 3,
|
|
||||||
panPattern.getHeight() >> 3
|
|
||||||
));
|
|
||||||
|
|
||||||
// Mouse release
|
|
||||||
if (id == MouseEvent.MOUSE_RELEASED) {
|
|
||||||
if (e.getButton() == MouseEvent.BUTTON1)
|
|
||||||
dragging = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse press
|
|
||||||
if (id == MouseEvent.MOUSE_PRESSED) {
|
|
||||||
client.requestFocus();
|
|
||||||
if (e.getButton() != MouseEvent.BUTTON1)
|
|
||||||
return;
|
|
||||||
dragging = e.getPoint();
|
|
||||||
dragging.x = dragging.x / scale - (dragging.x < 0 ? 1 : 0);
|
|
||||||
dragging.y = dragging.y / scale - (dragging.y < 0 ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not dragging
|
|
||||||
if (dragging == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Retrieve the current point
|
|
||||||
var pos = e.getPoint();
|
|
||||||
pos.x = pos.x / scale - (pos.x < 0 ? 1 : 0);
|
|
||||||
pos.y = pos.y / scale - (pos.y < 0 ? 1 : 0);
|
|
||||||
|
|
||||||
// Draw a line segment (adapted from Wikipedia)
|
|
||||||
int dx = Math.abs(pos.x - dragging.x);
|
|
||||||
int sx = dragging.x < pos.x ? 1 : -1;
|
|
||||||
int dy = -Math.abs(pos.y - dragging.y);
|
|
||||||
int sy = dragging.y < pos.y ? 1 : -1;
|
|
||||||
int err = dx + dy;
|
|
||||||
int addr = index >> 9 << 15 | 0x00006000 | (index & 511) << 4;
|
|
||||||
for (;;) {
|
|
||||||
|
|
||||||
// Draw the current pixel
|
|
||||||
if ((dragging.x&7) == dragging.x && (dragging.y&7) == dragging.y) {
|
|
||||||
int b = addr | dragging.y << 1 | dragging.x >> 2;
|
|
||||||
int bit = (dragging.x & 3) << 1;
|
|
||||||
parent.vram[b] = (byte)
|
|
||||||
(parent.vram[b] & ~(3 << bit) | color << bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The last pixel has been drawn
|
|
||||||
if (dragging.x == pos.x && dragging.y == pos.y)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Advance to the next pixel
|
|
||||||
int e2 = err << 1;
|
|
||||||
if (e2 >= dy)
|
|
||||||
{ err += dy; dragging.x += sx; }
|
|
||||||
if (e2 <= dx)
|
|
||||||
{ err += dx; dragging.y += sy; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update VRAM state
|
|
||||||
parent.vue.writeBytes(addr, parent.vram, addr, 16);
|
|
||||||
parent.refreshDebug(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Characters paint
|
|
||||||
private void onPaintCharacters(Graphics2D g, int width, int height) {
|
|
||||||
int grid = this.grid ? 1 : 0;
|
|
||||||
int size = scale * 8 + grid;
|
|
||||||
int wide = this.wide != 0 ? this.wide :
|
|
||||||
Math.max(1, (width + grid) / size);
|
|
||||||
int tall = (2047 + wide) / wide;
|
|
||||||
|
|
||||||
// Draw all characters
|
|
||||||
for (int Y = 0, y = 0, z = 0; y < tall; y++, Y += size)
|
|
||||||
for (int X = 0, x = 0; x < wide; x++, z++, X += size) {
|
|
||||||
if (z == 2048)
|
|
||||||
break;
|
|
||||||
int ix = (z & 31) << 3;
|
|
||||||
int iy = z >> 5 << 3;
|
|
||||||
g.drawImage(image,
|
|
||||||
X, Y, X + size - grid, Y + size - grid,
|
|
||||||
ix, iy, ix + 8 , iy + 8 ,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Highlight the selected character
|
|
||||||
int X = index % wide * size;
|
|
||||||
int Y = index / wide * size;
|
|
||||||
int light = SystemColor.textHighlight.getRGB() & 0x00FFFFFF;
|
|
||||||
g.setColor(new Color(0xD0000000 | light, true));
|
|
||||||
g.drawRect(X , Y , 8 * scale - 1, 8 * scale - 1);
|
|
||||||
g.setColor(new Color(0x90000000 | light, true));
|
|
||||||
g.drawRect(X + 1, Y + 1, 8 * scale - 3, 8 * scale - 3);
|
|
||||||
g.setColor(new Color(0x50000000 | light, true));
|
|
||||||
g.fillRect(X + 2, Y + 2, 8 * scale - 4, 8 * scale - 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Palette paint
|
|
||||||
private void onPaintPalette(Graphics2D g, int width, int height) {
|
|
||||||
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
|
||||||
int left = (width - size * 4 - 18) / 2;
|
|
||||||
var pal = parent.palettes[palette][MainWindow.RED];
|
|
||||||
int top = (height - size - 6) / 2;
|
|
||||||
|
|
||||||
// Draw the color picker
|
|
||||||
for (int x = 0; x < 4; x++, left += size + 4) {
|
|
||||||
|
|
||||||
// The current color is selected
|
|
||||||
if (x == color) {
|
|
||||||
g.setColor(SystemColor.textHighlight);
|
|
||||||
g.fillRect(left , top , size + 6, size + 6);
|
|
||||||
g.setColor(SystemColor.control);
|
|
||||||
g.fillRect(left + 2, top + 2, size + 2, size + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the color area
|
|
||||||
g.setColor(new Color(pal[x]));
|
|
||||||
g.fillRect(left + 3, top + 3, size , size );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pattern paint
|
|
||||||
private void onPaintPattern(Graphics2D g, int width, int height) {
|
|
||||||
int scale = Math.max(1, Math.min(width >> 3, height >> 3));
|
|
||||||
int x = (width - (scale << 3) + 1) >> 1;
|
|
||||||
int y = (height - (scale << 3) + 1) >> 1;
|
|
||||||
int ix = (index & 31) << 3;
|
|
||||||
int iy = index >> 5 << 3;
|
|
||||||
g.drawImage(image,
|
|
||||||
x, y, x + scale * 8, y + scale * 8,
|
|
||||||
ix, iy, ix + 8 , iy + 8 ,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window resize
|
|
||||||
private void onResize() {
|
|
||||||
var viewport = scrControls.getViewport();
|
|
||||||
int inner = viewport.getView().getPreferredSize().width;
|
|
||||||
int outer = viewport.getExtentSize().width;
|
|
||||||
|
|
||||||
// Size the controls container to match the inner component
|
|
||||||
if (inner != outer) {
|
|
||||||
scrControls.setPreferredSize(new Dimension(
|
|
||||||
scrControls.getPreferredSize().width + inner - outer, 0));
|
|
||||||
scrControls.revalidate();
|
|
||||||
scrControls.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The number of characters per row is dynamic
|
|
||||||
if (wide == 0) {
|
|
||||||
var bar = scrWidth.getPreferredSize().width;
|
|
||||||
var border = scrCharacters.getBorder();
|
|
||||||
int grid = this.grid ? 1 : 0;
|
|
||||||
var insets = border == null ? new Insets(0, 0, 0, 0) :
|
|
||||||
border.getBorderInsets(scrCharacters);
|
|
||||||
var size = new Dimension(
|
|
||||||
scrCharacters.getWidth () - insets.left - insets.right,
|
|
||||||
scrCharacters.getHeight() - insets.top - insets.bottom
|
|
||||||
);
|
|
||||||
|
|
||||||
// Calculate the dimensions without the vertical scroll bar
|
|
||||||
int wide = Math.max(1, (size.width + grid) / (8 * scale + grid));
|
|
||||||
int height = (2047 + wide) / wide * (8 * scale + grid) - grid;
|
|
||||||
|
|
||||||
// Calculate the dimensions with the vertical scroll bar
|
|
||||||
if (height > size.height) {
|
|
||||||
wide = Math.max(1, (size.width-bar+grid) / (8 * scale + grid));
|
|
||||||
height = (2047 + wide) / wide * (8 * scale + grid) - grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the component
|
|
||||||
panCharacters.setPreferredSize(
|
|
||||||
new Dimension(wide * (8 * scale + grid) - grid, height));
|
|
||||||
panCharacters.revalidate();
|
|
||||||
panCharacters.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// View control changed
|
|
||||||
private void onView() {
|
|
||||||
|
|
||||||
// Number of characters per row is dynamic: defer to resize processing
|
|
||||||
if (wide == 0) {
|
|
||||||
onResize();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the space occupied by the character images
|
|
||||||
int grid = this.grid ? 1 : 0;
|
|
||||||
panCharacters.setPreferredSize(new Dimension(
|
|
||||||
wide * (scale * 8 + grid) - grid,
|
|
||||||
(2047 + wide) / wide * (scale * 8 + grid) - grid
|
|
||||||
));
|
|
||||||
scrCharacters.getVerticalScrollBar().setUnitIncrement(8*scale+grid);
|
|
||||||
panCharacters.revalidate();
|
|
||||||
panCharacters.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a check box to the controls panel
|
|
||||||
private JCheckBox checkBox(UPanel panel) {
|
|
||||||
var chk = new JCheckBox();
|
|
||||||
chk.setBorder(null);
|
|
||||||
chk.setFocusable(false);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, 2);
|
|
||||||
panel.add(chk, gbc);
|
|
||||||
return chk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a label to the controls panel
|
|
||||||
private void label(UPanel panel, String key, boolean top) {
|
|
||||||
var lbl = new JLabel();
|
|
||||||
parent.app.localizer.add(lbl, key);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
gbc.insets = new Insets(top ? 2 : 0, 2, 2, 2);
|
|
||||||
panel.add(lbl, gbc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a combo box to the controls panel
|
|
||||||
private UComboBox select(UPanel panel, String[] options) {
|
|
||||||
var cmb = new UComboBox();
|
|
||||||
parent.app.localizer.add(cmb, options);
|
|
||||||
cmb.setSelectedIndex(0);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, 2);
|
|
||||||
panel.add(cmb, gbc);
|
|
||||||
return cmb;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the current character index
|
|
||||||
private void setIndex(int index) {
|
|
||||||
this.index = index;
|
|
||||||
spnIndex.setValue(index);
|
|
||||||
txtAddress.setText(String.format("%08X",
|
|
||||||
index >> 9 << 15 | 0x00006000 | (index & 511) << 4));
|
|
||||||
txtMirror .setText(String.format("%08X",
|
|
||||||
index << 4 | 0x00078000));
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a slider to the controls panel
|
|
||||||
private JSlider slider(UPanel panel, int min, int max, int value) {
|
|
||||||
var sld = new JSlider(min, max, value);
|
|
||||||
sld.setFocusable(false);
|
|
||||||
sld.setPreferredSize(new Dimension(0, sld.getPreferredSize().height));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 1, 2);
|
|
||||||
panel.add(sld, gbc);
|
|
||||||
return sld;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a spinner to the controls panel
|
|
||||||
private JSpinner spinner(UPanel panel, int min, int max, int value,
|
|
||||||
boolean top) {
|
|
||||||
var spn = new JSpinner(new SpinnerNumberModel(value, min, max, 1));
|
|
||||||
var txt = new JSpinner.NumberEditor(spn, "#");
|
|
||||||
txt.getTextField().addActionListener(e->client.requestFocus());
|
|
||||||
spn.setEditor(txt);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(top ? 2 : 0, 0, 2, 2);
|
|
||||||
gbc.weightx = 1;
|
|
||||||
panel.add(spn, gbc);
|
|
||||||
return spn;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a text box to the controls panel
|
|
||||||
private JTextField textBox(UPanel panel) {
|
|
||||||
var txt = new JTextField();
|
|
||||||
txt.setFont(parent.app.fntMono);
|
|
||||||
txt.addActionListener(e->client.requestFocus());
|
|
||||||
var size = txt.getPreferredSize();
|
|
||||||
txt.setPreferredSize(new Dimension(
|
|
||||||
parent.app.hexDigitWidth * 8 + 2 + size.width, size.height));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.fill = GridBagConstraints.BOTH;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 0, 2, 2);
|
|
||||||
panel.add(txt, gbc);
|
|
||||||
return txt;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
|
|
||||||
// Child window
|
|
||||||
class ChildWindow extends JInternalFrame {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
MainWindow parent; // Parent application window
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
ChildWindow(MainWindow parent, String key) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
// Configure instanece fields
|
|
||||||
this.parent = parent;
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
parent.app.localizer.add(this, key);
|
|
||||||
addInternalFrameListener(Util.onClose2(e->setVisible(false)));
|
|
||||||
setClosable(true);
|
|
||||||
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
|
||||||
setMaximizable(true);
|
|
||||||
setResizable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Show or hide the component
|
|
||||||
public void setVisible(boolean visible) {
|
|
||||||
|
|
||||||
// Making visible
|
|
||||||
if (visible) {
|
|
||||||
|
|
||||||
// Not currently visible: center in parent
|
|
||||||
if (!isVisible()) {
|
|
||||||
var parent = getParent().getParent();
|
|
||||||
setLocation(
|
|
||||||
Math.max(0, (parent.getWidth () - getWidth ()) / 2),
|
|
||||||
Math.max(0, (parent.getHeight() - getHeight()) / 2)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Already visible: bring to front
|
|
||||||
else {
|
|
||||||
moveToFront();
|
|
||||||
try { setSelected(true); } catch (Exception e) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change visibility
|
|
||||||
super.setVisible(visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Console window
|
|
||||||
class ConsoleWindow extends ChildWindow {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private boolean shown; // Component has been visible
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
ConsoleWindow(MainWindow parent) {
|
|
||||||
super(parent, "console.title");
|
|
||||||
getContentPane().setPreferredSize(new Dimension(384, 224));
|
|
||||||
pack();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Show the component on the first transition to debug mode
|
|
||||||
void firstShow() {
|
|
||||||
if (!shown)
|
|
||||||
setVisible(shown = true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,386 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// Instruction disassembler
|
|
||||||
class Disassembler {
|
|
||||||
private Disassembler() { } // Cannot be instantiated
|
|
||||||
static { setDefaults(); } // Initialize to default settings
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Global Settings //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static boolean bcondCombine; // Merge Bcond condition into mnemonic
|
|
||||||
static boolean bcondNames; // Use symbolic condition names for Bcond
|
|
||||||
static boolean condCaps; // Uppercase condition mnemonics
|
|
||||||
static boolean destLast; // Destination register last
|
|
||||||
static boolean dispDest; // Resolve jump destination addresses
|
|
||||||
static boolean dispInside; // Load/store displacement inside brackets
|
|
||||||
static boolean hexCaps; // Upercase hexadecimal
|
|
||||||
static int hexMode; // Hexadecimal decoration
|
|
||||||
static boolean immNumber; // Use number sign with immediate values
|
|
||||||
static boolean jmpBrackets; // Square brackets around JMP
|
|
||||||
static boolean jumpAddress; // Use jump destination addresses
|
|
||||||
static boolean lower; // Use L instead of C in conditions
|
|
||||||
static boolean mnemonicCaps; // Uppercase mnemonics
|
|
||||||
static boolean programCaps; // Uppercase program register names
|
|
||||||
static boolean programNames; // Use symbolic program register names
|
|
||||||
static boolean setfCombine; // Merge SETF condition into mnemonic
|
|
||||||
static boolean setfNames; // Use symbolic condition names for SETF
|
|
||||||
static boolean systemCaps; // Uppercase system register names
|
|
||||||
static boolean systemNames; // Use symbolic system register names
|
|
||||||
static boolean zero; // Use Z instead of E in conditions
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Hexadecimal decorations
|
|
||||||
static final int DOLLAR = 0;
|
|
||||||
static final int H = 1;
|
|
||||||
static final int ZEROX = 2;
|
|
||||||
|
|
||||||
// Condition mneonics
|
|
||||||
static final String[] CONDITIONS = {
|
|
||||||
"V" , "C" , "E" , "NH", "N", "T", "LT", "LE",
|
|
||||||
"NV", "NC", "NE", "H" , "P", "F", "GE", "GT"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Mnemonics
|
|
||||||
static final String[] MNEMONICS = {
|
|
||||||
"---" , "ADD" , "ADD" , "ADDF.S", "ADDI" , "AND" ,
|
|
||||||
"ANDBSU" , "ANDI" , "ANDNBSU", "Bcond" , "CAXI" , "CLI" ,
|
|
||||||
"CMP" , "CMP" , "CMPF.S" , "CVT.SW", "CVT.WS" , "DIV" ,
|
|
||||||
"DIVF.S" , "DIVU" , "HALT" , "IN.B" , "IN.H" , "IN.W" ,
|
|
||||||
"JAL" , "JMP" , "JR" , "LD.B" , "LD.H" , "LD.W" ,
|
|
||||||
"LDSR" , "MOV" , "MOV" , "MOVBSU", "MOVEA" , "MOVHI" ,
|
|
||||||
"MPYHW" , "MUL" , "MULF.S" , "MULU" , "NOT" , "NOTBSU" ,
|
|
||||||
"OR" , "ORBSU" , "ORI" , "ORNBSU", "OUT.B" , "OUT.H" ,
|
|
||||||
"OUT.W" , "RETI" , "REV" , "SAR" , "SAR" , "SCH0BSD",
|
|
||||||
"SCH0BSU", "SCH1BSD", "SCH1BSU", "SEI" , "SETF" , "SHL" ,
|
|
||||||
"SHL" , "SHR" , "SHR" , "ST.B" , "ST.H" , "ST.W" ,
|
|
||||||
"STSR" , "SUB" , "SUBF.S" , "TRAP" , "TRNC.SW", "XB" ,
|
|
||||||
"XH" , "XOR" , "XORBSU" , "XORI" , "XORNBSU"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Program register names
|
|
||||||
private static final String[] PROGRAMS = {
|
|
||||||
null, null, "hp", "sp", "gp", "tp", null, null,
|
|
||||||
null, null, null, null, null, null, null, null,
|
|
||||||
null, null, null, null, null, null, null, null,
|
|
||||||
null, null, null, null, null, null, null, "lp"
|
|
||||||
};
|
|
||||||
|
|
||||||
// System register names
|
|
||||||
private static final String[] SYSTEMS = {
|
|
||||||
"EIPC", "EIPSW", "FEPC", "FEPSW", "ECR", "PSW", "PIR", "TKCW",
|
|
||||||
null , null , null , null , null , null , null , null ,
|
|
||||||
null , null , null , null , null , null , null , null ,
|
|
||||||
"CHCW", "ADTRE", null , null , null , null , null , null
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Classes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// One row of output
|
|
||||||
static class Row {
|
|
||||||
String address; // Bus address
|
|
||||||
String bytes; // Encoded bytes in bus order
|
|
||||||
String mnemonic; // Instruction mnemonic
|
|
||||||
String operands; // Instruction operands, if any
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Static Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Reset all settings to their default values
|
|
||||||
static void setDefaults() {
|
|
||||||
bcondCombine = true;
|
|
||||||
bcondNames = true;
|
|
||||||
condCaps = true;
|
|
||||||
destLast = true;
|
|
||||||
dispDest = true;
|
|
||||||
dispInside = false;
|
|
||||||
hexCaps = true;
|
|
||||||
hexMode = ZEROX;
|
|
||||||
immNumber = false;
|
|
||||||
jmpBrackets = true;
|
|
||||||
jumpAddress = true;
|
|
||||||
lower = true;
|
|
||||||
mnemonicCaps = true;
|
|
||||||
programCaps = false;
|
|
||||||
programNames = true;
|
|
||||||
setfCombine = false;
|
|
||||||
setfNames = true;
|
|
||||||
systemCaps = true;
|
|
||||||
systemNames = true;
|
|
||||||
zero = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Represent an instruction as text fields
|
|
||||||
static void disassemble(int address, Instruction inst, Row row) {
|
|
||||||
|
|
||||||
// Address
|
|
||||||
String x = hexCaps ? "X" : "x";
|
|
||||||
row.address = String.format("%08" + x, address);
|
|
||||||
|
|
||||||
// Bytes
|
|
||||||
x = "%02" + x;
|
|
||||||
row.bytes = inst.size == 2 ?
|
|
||||||
String.format(x + " " + x,
|
|
||||||
inst.bits >> 16 & 0xFF,
|
|
||||||
inst.bits >> 24 & 0xFF
|
|
||||||
) : String.format(x + " " + x + " " + x + " " + x,
|
|
||||||
inst.bits >> 16 & 0xFF,
|
|
||||||
inst.bits >> 24 & 0xFF,
|
|
||||||
inst.bits & 0xFF,
|
|
||||||
inst.bits >> 8 & 0xFF
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
// Bcond mnemonic
|
|
||||||
if (inst.id == Vue.BCOND && bcondCombine) {
|
|
||||||
row.mnemonic = "B" + CONDITIONS[inst.cond];
|
|
||||||
if (lower && (inst.cond & 7) == 1)
|
|
||||||
row.mnemonic = inst.cond == 1 ? "BL" : "BNL";
|
|
||||||
if (zero && (inst.cond & 7) == 2)
|
|
||||||
row.mnemonic = inst.cond == 2 ? "BZ" : "BNZ";
|
|
||||||
if ( (inst.cond & 7) == 5)
|
|
||||||
row.mnemonic = inst.cond == 5 ? "BR" : "NOP";
|
|
||||||
}
|
|
||||||
|
|
||||||
// SETF mnemonic
|
|
||||||
else if (inst.id == Vue.SETF && setfCombine)
|
|
||||||
row.mnemonic = "SETF" + CONDITIONS[inst.imm];
|
|
||||||
|
|
||||||
// All other mnemonics
|
|
||||||
else row.mnemonic = MNEMONICS[inst.id + 1];
|
|
||||||
|
|
||||||
// Adjust mnemonic case
|
|
||||||
if (!mnemonicCaps)
|
|
||||||
row.mnemonic = row.mnemonic.toLowerCase();
|
|
||||||
|
|
||||||
// Operands by format
|
|
||||||
row.operands = null;
|
|
||||||
if (inst.id != Vue.ILLEGAL) switch (inst.format) {
|
|
||||||
case 1: // Fallthrough
|
|
||||||
case 7: row.operands = formatI_VII(inst ); break;
|
|
||||||
case 2: row.operands = formatII (inst ); break;
|
|
||||||
case 3: row.operands = formatIII (inst, address); break;
|
|
||||||
case 4: row.operands = destination(inst, address); break;
|
|
||||||
case 5: row.operands = formatV (inst ); break;
|
|
||||||
case 6: row.operands = formatVI (inst ); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Format the destination of a branch or jump
|
|
||||||
private static String destination(Instruction inst, int address) {
|
|
||||||
return !dispDest ? toHex(inst.disp, 1, false) :
|
|
||||||
String.format("%08" + (hexCaps ? "X" : "x"), address + inst.disp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operands for Format I and Format VII
|
|
||||||
private static String formatI_VII(Instruction inst) {
|
|
||||||
String reg1 = program(inst.reg1);
|
|
||||||
String reg2 = program(inst.reg2);
|
|
||||||
|
|
||||||
// One-operand instructions
|
|
||||||
switch (inst.id) {
|
|
||||||
case Vue.JMP:
|
|
||||||
return String.format(jmpBrackets ? "[%s]" : "%s", reg1);
|
|
||||||
case Vue.XB: // Fallthrough
|
|
||||||
case Vue.XH:
|
|
||||||
return reg2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic
|
|
||||||
return String.format("%s, %s",
|
|
||||||
destLast ? reg1 : reg2,
|
|
||||||
destLast ? reg2 : reg1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operands for Format II
|
|
||||||
private static String formatII(Instruction inst) {
|
|
||||||
|
|
||||||
// Bit string
|
|
||||||
if (inst.opcode == 0b011111)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Zero- or one-operand instructions
|
|
||||||
switch (inst.id) {
|
|
||||||
|
|
||||||
// Zero-operand
|
|
||||||
case Vue.CLI : // Fallthrough
|
|
||||||
case Vue.HALT: // Fallthrough
|
|
||||||
case Vue.RETI: // Fallthrough
|
|
||||||
case Vue.SEI :
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// One-operand
|
|
||||||
case Vue.TRAP:
|
|
||||||
return Integer.toString(inst.imm);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combined SETF
|
|
||||||
String reg2 = program(inst.reg2);
|
|
||||||
if (inst.id == Vue.SETF && setfCombine)
|
|
||||||
return reg2;
|
|
||||||
|
|
||||||
// Two-operand instructions
|
|
||||||
String imm = String.format("%s%d", immNumber ? "#" : "", inst.imm);
|
|
||||||
switch (inst.id) {
|
|
||||||
case Vue.LDSR: // Fallthrough
|
|
||||||
case Vue.STSR:
|
|
||||||
if (!systemNames || SYSTEMS[inst.imm] == null)
|
|
||||||
break;
|
|
||||||
imm = SYSTEMS[inst.imm];
|
|
||||||
if (!systemCaps)
|
|
||||||
imm = imm.toLowerCase();
|
|
||||||
break;
|
|
||||||
case Vue.SETF:
|
|
||||||
if (!setfNames)
|
|
||||||
break;
|
|
||||||
imm = CONDITIONS[inst.imm];
|
|
||||||
if (!condCaps)
|
|
||||||
imm = imm.toLowerCase();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// LDSR
|
|
||||||
if (inst.id == Vue.LDSR) {
|
|
||||||
String temp = imm;
|
|
||||||
imm = reg2;
|
|
||||||
reg2 = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic
|
|
||||||
return String.format("%s, %s",
|
|
||||||
destLast ? imm : reg2,
|
|
||||||
destLast ? reg2 : imm
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operands for Format III
|
|
||||||
private static String formatIII(Instruction inst, int address) {
|
|
||||||
|
|
||||||
// NOP
|
|
||||||
if (bcondCombine && inst.cond == 13)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Format destination
|
|
||||||
String dest = destination(inst, address);
|
|
||||||
|
|
||||||
// One-operand notation
|
|
||||||
if (bcondCombine)
|
|
||||||
return dest;
|
|
||||||
|
|
||||||
// Two-operand notation
|
|
||||||
String cond = bcondNames ?
|
|
||||||
CONDITIONS[inst.cond] : Integer.toString(inst.cond);
|
|
||||||
if (bcondNames && !condCaps)
|
|
||||||
cond = cond.toLowerCase();
|
|
||||||
return String.format("%s, %s", cond, dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operands for Format V
|
|
||||||
private static String formatV(Instruction inst) {
|
|
||||||
String reg1 = program(inst.reg1);
|
|
||||||
String reg2 = program(inst.reg2);
|
|
||||||
String imm = toHex(
|
|
||||||
inst.id == Vue.MOVEA ? inst.imm & 0xFFFF : inst.imm,
|
|
||||||
inst.id == Vue.ADDI ? 1 : 4,
|
|
||||||
immNumber
|
|
||||||
);
|
|
||||||
return String.format("%s, %s, %s",
|
|
||||||
destLast ? imm : reg2,
|
|
||||||
reg1,
|
|
||||||
destLast ? reg2 : imm
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operands for Format VI
|
|
||||||
private static String formatVI(Instruction inst) {
|
|
||||||
String src = program(inst.reg1);
|
|
||||||
String dest = program(inst.reg2);
|
|
||||||
|
|
||||||
// Data operand
|
|
||||||
src = inst.disp == 0 ? String.format("[%s]", src) :
|
|
||||||
dispInside ? String.format(
|
|
||||||
"[%s %s %s]",
|
|
||||||
src,
|
|
||||||
inst.disp < 0 ? "-" : "+",
|
|
||||||
toHex(Math.abs(inst.disp), 1, false)
|
|
||||||
) : String.format(
|
|
||||||
"%s[%s]",
|
|
||||||
toHex(inst.disp, 1, false),
|
|
||||||
src
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
// Write instruction
|
|
||||||
switch (inst.id) {
|
|
||||||
case Vue.OUT_B: // Fallthrough
|
|
||||||
case Vue.OUT_H: // Fallthrough
|
|
||||||
case Vue.OUT_W: // Fallthrough
|
|
||||||
case Vue.ST_B : // Fallthrough
|
|
||||||
case Vue.ST_H : // Fallthrough
|
|
||||||
case Vue.ST_W :
|
|
||||||
String temp = src;
|
|
||||||
src = dest;
|
|
||||||
dest = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format operands
|
|
||||||
return String.format("%s, %s",
|
|
||||||
destLast ? src : dest,
|
|
||||||
destLast ? dest : src
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format a program register
|
|
||||||
private static String program(int index) {
|
|
||||||
String ret = programNames ? PROGRAMS[index] : null;
|
|
||||||
if (ret == null)
|
|
||||||
ret = "r" + index;
|
|
||||||
return programCaps ? ret.toUpperCase() : ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Represent an immediate value as hexadecimal
|
|
||||||
private static String toHex(int value, int digits, boolean number) {
|
|
||||||
return String.format(
|
|
||||||
"%s%s%s%0" + digits + (hexCaps ? "X" : "x") + "%s",
|
|
||||||
number ? "#" : "",
|
|
||||||
value < 0 ? "-" : "",
|
|
||||||
hexMode == DOLLAR ? "$" : hexMode == ZEROX ? "0x" : "",
|
|
||||||
value < 0 ? -value : value,
|
|
||||||
hexMode == H ? "h" : ""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,405 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// Disassembler UI
|
|
||||||
class DisassemblerPane extends JScrollPane {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private int address; // Address of top row of output
|
|
||||||
private CPUWindow parent; // Containing CPU window
|
|
||||||
private boolean showBytes; // Display the bytes column
|
|
||||||
private boolean shown; // Component has been shown
|
|
||||||
private int[] widths; // Column widths
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
private UPanel client; // Client area
|
|
||||||
private ArrayList<Row> rows; // Disassembler output
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Classes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// One row of disassembler output
|
|
||||||
private class Row extends Disassembler.Row {
|
|
||||||
Instruction inst; // Decoded instruction
|
|
||||||
JLabel[] labels; // Display text
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
DisassemblerPane(CPUWindow parent) {
|
|
||||||
super(VERTICAL_SCROLLBAR_NEVER, HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
this.parent = parent;
|
|
||||||
rows = new ArrayList<Row>();
|
|
||||||
showBytes = true;
|
|
||||||
widths = new int[5];
|
|
||||||
|
|
||||||
// Configure client area
|
|
||||||
client = new UPanel();
|
|
||||||
client.setBackground(SystemColor.window);
|
|
||||||
client.setFocusable(true);
|
|
||||||
client.addFocusListener(
|
|
||||||
Util.onFocus(e->client.repaint(), e->client.repaint()));
|
|
||||||
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
|
|
||||||
client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
|
|
||||||
client.addMouseWheelListener(e->onMouseWheel(e));
|
|
||||||
client.addPaintListener((g,w,h)->onPaint(g, w, h));
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
setViewportView(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
void refresh(boolean seekToPC) {
|
|
||||||
if (seekToPC) {
|
|
||||||
int pc = parent.parent.vue.getRegister(Vue.PC, true);
|
|
||||||
if (!isVisible(pc))
|
|
||||||
seek(pc, tall(false) / 3);
|
|
||||||
}
|
|
||||||
client.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Event Handlers //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Key down
|
|
||||||
private void onKeyDown(KeyEvent e) {
|
|
||||||
int code = e.getKeyCode();
|
|
||||||
int count = tall(false);
|
|
||||||
int mods = e.getModifiersEx();
|
|
||||||
var vue = parent.parent.vue;
|
|
||||||
boolean alt = (mods & InputEvent.ALT_DOWN_MASK ) != 0;
|
|
||||||
boolean ctrl = (mods & InputEvent.CTRL_DOWN_MASK) != 0;
|
|
||||||
|
|
||||||
// No Alt combinations
|
|
||||||
if (alt) return;
|
|
||||||
|
|
||||||
// Goto
|
|
||||||
if (ctrl && code == KeyEvent.VK_G) {
|
|
||||||
String text = JOptionPane.showInputDialog(
|
|
||||||
this, "Goto:", "Goto", JOptionPane.PLAIN_MESSAGE);
|
|
||||||
Object eval = vue.evaluate(text);
|
|
||||||
int addr = 0;
|
|
||||||
if (eval instanceof Integer)
|
|
||||||
addr = (Integer) eval;
|
|
||||||
else if (eval instanceof Long)
|
|
||||||
addr = (int) (long) (Long) eval;
|
|
||||||
else return;
|
|
||||||
if (!isVisible(addr))
|
|
||||||
seek(addr, count / 3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processing by key code
|
|
||||||
int pc = vue.getRegister(Vue.PC, true);
|
|
||||||
var step = parent.parent.brkStep;
|
|
||||||
switch (code) {
|
|
||||||
case KeyEvent.VK_UP : 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_DOWN: seek(address, -count); break;
|
|
||||||
|
|
||||||
// Single Step
|
|
||||||
case KeyEvent.VK_F11:
|
|
||||||
step.setCondition("!fetch&&pc!=" + pc);
|
|
||||||
step.setEnabled(true);
|
|
||||||
vue.emulate(20000000);
|
|
||||||
if (step.evaluate())
|
|
||||||
step.setEnabled(false);
|
|
||||||
parent.parent.refreshDebug(true);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Run to Next
|
|
||||||
case KeyEvent.VK_F12:
|
|
||||||
step.setCondition("!fetch&&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(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse wheel
|
|
||||||
private void onMouseWheel(MouseWheelEvent e) {
|
|
||||||
seek(address, -e.getUnitsToScroll());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client paint
|
|
||||||
private void onPaint(Graphics2D g, int width, int height) {
|
|
||||||
var vue = parent.parent.vue;
|
|
||||||
int pc = vue.getRegister(Vue.PC, true);
|
|
||||||
|
|
||||||
// The view is being shown for the first time
|
|
||||||
if (!shown) {
|
|
||||||
shown = true;
|
|
||||||
seek(pc, tall(false) / 3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure working variables
|
|
||||||
int address = this.address;
|
|
||||||
int count = tall(true);
|
|
||||||
var data = new byte[count * 4];
|
|
||||||
int lineHeight = parent.parent.app.fntMono.metrics.getHeight();
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
// Disassemble from the current address
|
|
||||||
vue.readBytes(address, data, 0, data.length);
|
|
||||||
widths[3] = widths[4] = 0;
|
|
||||||
for (int y = 0; y < count; y++) {
|
|
||||||
var row = y < rows.size() ? rows.get(y) : addRow();
|
|
||||||
var color = SystemColor.windowText;
|
|
||||||
|
|
||||||
// Disassemble the instruction
|
|
||||||
row.inst.decode(data, offset);
|
|
||||||
Disassembler.disassemble(address, row.inst, row);
|
|
||||||
updateRow(row);
|
|
||||||
|
|
||||||
// Highlight PC
|
|
||||||
if (address == pc) {
|
|
||||||
Color bg = SystemColor.control;
|
|
||||||
if (client.isFocusOwner()) {
|
|
||||||
bg = SystemColor.textHighlight;
|
|
||||||
color = SystemColor.textHighlightText;
|
|
||||||
}
|
|
||||||
g.setColor(bg);
|
|
||||||
g.fillRect(
|
|
||||||
0, y * lineHeight,
|
|
||||||
width, lineHeight
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure label text color
|
|
||||||
for (var label : row.labels)
|
|
||||||
label.setForeground(color);
|
|
||||||
|
|
||||||
// Advance to the next instruction
|
|
||||||
int size = address + 2 == pc ? 2 : row.inst.size;
|
|
||||||
address += size;
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure all rows
|
|
||||||
for (int y = 0; y < rows.size(); y++) {
|
|
||||||
var row = rows.get(y);
|
|
||||||
int top = y * lineHeight;
|
|
||||||
|
|
||||||
// Configure all labels
|
|
||||||
for (int z = 0, x = 0; z < 5; z++) {
|
|
||||||
var label = row.labels[z];
|
|
||||||
|
|
||||||
// The label is not part of the output
|
|
||||||
if (y >= count || widths[z] == 0) {
|
|
||||||
label.setVisible(false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the label
|
|
||||||
label.setLocation(x, top);
|
|
||||||
label.setSize(label.getPreferredSize());
|
|
||||||
x += widths[z] + lineHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the client's size
|
|
||||||
var size = client.getPreferredSize();
|
|
||||||
width = -lineHeight + 1;
|
|
||||||
for (int x = 0; x < 5; x++)
|
|
||||||
if (widths[x] != 0 && (x != 2 || showBytes))
|
|
||||||
width += lineHeight + widths[x];
|
|
||||||
if (width == size.width)
|
|
||||||
return;
|
|
||||||
client.setPreferredSize(new Dimension(width, 0));
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Create a new row object
|
|
||||||
private Row addRow() {
|
|
||||||
var row = new Row();
|
|
||||||
row.inst = new Instruction();
|
|
||||||
row.labels = new JLabel[5];
|
|
||||||
|
|
||||||
// Initialize columns
|
|
||||||
for (int x = 0; x < 5; x++) {
|
|
||||||
var label = row.labels[x] = new JLabel();
|
|
||||||
if (x != 4)
|
|
||||||
label.setFont(parent.parent.app.fntMono);
|
|
||||||
client.add(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.add(row);
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine whether the instruction at an address is in the client view
|
|
||||||
private boolean isVisible(int target) {
|
|
||||||
int count = Math.max(1, tall(false));
|
|
||||||
var data = new byte[count * 4];
|
|
||||||
int offset = 0;
|
|
||||||
var vue = parent.parent.vue;
|
|
||||||
int pc = vue.getRegister(Vue.PC, true);
|
|
||||||
target &= 0xFFFFFFFE;
|
|
||||||
|
|
||||||
// Load enough bytes to represent every fully visible instruction
|
|
||||||
vue.readBytes(address, data, 0, data.length);
|
|
||||||
|
|
||||||
// Iterate through instructions
|
|
||||||
for (int x = 0, address = this.address; x < count; x++) {
|
|
||||||
|
|
||||||
// Determine the instruction's size
|
|
||||||
int size = address + 2 == pc ? 2 :
|
|
||||||
Instruction.size(data[offset + 1] >> 2 & 0x3F);
|
|
||||||
|
|
||||||
// The current instruction is the target
|
|
||||||
if (address == target || size == 4 && address + 2 == target)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Advance to the next instruction
|
|
||||||
address += size;
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The instruction is not visible in the view
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the address of the top row of output
|
|
||||||
private void seek(int target, int row) {
|
|
||||||
var data = new byte[(Math.abs(row) + 9) * 4];
|
|
||||||
int offset = 0;
|
|
||||||
var vue = parent.parent.vue;
|
|
||||||
int pc = vue.getRegister(Vue.PC, true);
|
|
||||||
target &= 0xFFFFFFFE;
|
|
||||||
|
|
||||||
// Scrolling down
|
|
||||||
if (row <= 0) {
|
|
||||||
|
|
||||||
// Load bytes starting up to 8 instructions prior to the target
|
|
||||||
address = target - 32;
|
|
||||||
vue.readBytes(address, data, 0, data.length);
|
|
||||||
|
|
||||||
// Iterate through instructions
|
|
||||||
for (boolean found = false;;) {
|
|
||||||
|
|
||||||
// Determine the instruction's size
|
|
||||||
int size = address + 2 == pc ? 2 :
|
|
||||||
Instruction.size(data[offset + 1] >> 2 & 0x3F);
|
|
||||||
|
|
||||||
// The current instruction is the target
|
|
||||||
if (address == target || size == 4 && address + 2 == target)
|
|
||||||
found = true;
|
|
||||||
if (found && row++ == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Advance to the next instruction
|
|
||||||
address += size;
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scrolling up
|
|
||||||
else {
|
|
||||||
|
|
||||||
// Load bytes starting up to 8 instructions prior to the top row
|
|
||||||
address = target - data.length + 4;
|
|
||||||
vue.readBytes(address, data, 0, data.length);
|
|
||||||
|
|
||||||
// Iterate through instructions
|
|
||||||
var addresses = new int[row]; // Circular buffer
|
|
||||||
for (int index = 0;;) {
|
|
||||||
|
|
||||||
// Determine the instruction's size
|
|
||||||
int size = pc == address + 2 ? 2 :
|
|
||||||
Instruction.size(data[offset + 1] >> 2 & 63);
|
|
||||||
|
|
||||||
// The current instruction is the target
|
|
||||||
if (address == target || size == 4 && address + 2 == target) {
|
|
||||||
address = addresses[index];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance to the next instruction
|
|
||||||
addresses[index] = address;
|
|
||||||
if (++index == row)
|
|
||||||
index = 0;
|
|
||||||
address += size;
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Common processing
|
|
||||||
client.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine how many rows of output are visible
|
|
||||||
private int tall(boolean partial) {
|
|
||||||
int lineHeight = parent.parent.app.fntMono.metrics.getHeight();
|
|
||||||
return Math.max(1, (client.getHeight() +
|
|
||||||
(partial ? lineHeight - 1 : 0)
|
|
||||||
) / lineHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update a row with its text and measure the column widths
|
|
||||||
private void updateRow(Row row) {
|
|
||||||
|
|
||||||
for (int x = 0; x < 5; x++) {
|
|
||||||
var label = row.labels[x];
|
|
||||||
|
|
||||||
String text = null;
|
|
||||||
switch (x) {
|
|
||||||
case 0: text = row.address ; break;
|
|
||||||
case 1: text = row.bytes ; break;
|
|
||||||
case 2: text = row.mnemonic; break;
|
|
||||||
case 3: text = row.operands; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text != null) {
|
|
||||||
label.setText(text);
|
|
||||||
label.setVisible(x == 1 ? showBytes : true);
|
|
||||||
widths[x] = Math.max(widths[x],label.getPreferredSize().width);
|
|
||||||
} else label.setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,477 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.image.*;
|
|
||||||
import java.io.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.filechooser.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// Main application window
|
|
||||||
class MainWindow extends JFrame {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
App app; // Containing application
|
|
||||||
Breakpoint brkStep; // Single step internal breakpoint
|
|
||||||
int[][][] palettes; // Raster palettes
|
|
||||||
byte[] vram; // Snapshot of VIP memory
|
|
||||||
Vue vue; // Emulation core context
|
|
||||||
|
|
||||||
// Private fields
|
|
||||||
private boolean debugMode; // Window is in debug mode
|
|
||||||
private int number; // Window number within application
|
|
||||||
private boolean only; // This is the only application window
|
|
||||||
private File pwd; // Most recent working directory
|
|
||||||
private ROM rom; // Currently loaded ROM
|
|
||||||
private File romFile; // Currently loaded ROM file
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
private UPanel client; // Common client container
|
|
||||||
private JDesktopPane desktop; // Container for child windows
|
|
||||||
private JMenu mnuDebug; // Debug menu
|
|
||||||
private UPanel video; // Video output
|
|
||||||
private JMenuItem mnuFileDebugMode; // File -> Debug mode
|
|
||||||
private JMenuItem mnuFileGameMode; // File -> Game mode
|
|
||||||
|
|
||||||
// Child windows
|
|
||||||
private BGMapsWindow bgMaps;
|
|
||||||
private BreakpointsWindow breakpoints;
|
|
||||||
private CharactersWindow characters;
|
|
||||||
private ConsoleWindow console;
|
|
||||||
private CPUWindow cpu;
|
|
||||||
private MemoryWindow memory;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Palette indexes
|
|
||||||
static final int GENERIC = 0;
|
|
||||||
static final int GPLT0 = 1;
|
|
||||||
static final int GPLT1 = 2;
|
|
||||||
static final int GPLT2 = 3;
|
|
||||||
static final int GPLT3 = 4;
|
|
||||||
static final int JPLT0 = 5;
|
|
||||||
static final int JPLT1 = 6;
|
|
||||||
static final int JPLT2 = 7;
|
|
||||||
static final int JPLT3 = 8;
|
|
||||||
static final int LEFT = 0;
|
|
||||||
static final int RIGHT = 1;
|
|
||||||
static final int RED = 2;
|
|
||||||
|
|
||||||
// Application icon
|
|
||||||
private static final BufferedImage APPICON;
|
|
||||||
|
|
||||||
// Static initializer
|
|
||||||
static {
|
|
||||||
APPICON = Util.imageRead("images/app_icon.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
MainWindow(App app) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
this.app = app;
|
|
||||||
palettes = new int[9][3][4];
|
|
||||||
pwd = Util.PWD;
|
|
||||||
vram = new byte[0x40000];
|
|
||||||
vue = Vue.create(app.getUseNative());
|
|
||||||
System.out.println("Native: " +
|
|
||||||
(vue.isNative() ? Vue.getNativeID() : "No"));
|
|
||||||
|
|
||||||
// Configure video pane
|
|
||||||
video = new UPanel();
|
|
||||||
video.setPreferredSize(new Dimension(384, 224));
|
|
||||||
video.setFocusable(true);
|
|
||||||
video.addPaintListener((g,w,h)->onPaintVideo(g, w, h));
|
|
||||||
|
|
||||||
// Configure client area
|
|
||||||
client = new UPanel(new BorderLayout());
|
|
||||||
client.add(video, BorderLayout.CENTER);
|
|
||||||
|
|
||||||
// Configure window
|
|
||||||
addWindowListener(Util.onClose(e->onClose()));
|
|
||||||
setContentPane(client);
|
|
||||||
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
|
||||||
setIconImage(APPICON);
|
|
||||||
setJMenuBar(initMenus());
|
|
||||||
app.localizer.add(this, "app.title.default");
|
|
||||||
|
|
||||||
// Configure child windows
|
|
||||||
desktop = new JDesktopPane();
|
|
||||||
desktop.setBackground(SystemColor.controlShadow);
|
|
||||||
desktop.add(bgMaps = new BGMapsWindow (this));
|
|
||||||
desktop.add(breakpoints = new BreakpointsWindow(this));
|
|
||||||
desktop.add(characters = new CharactersWindow (this));
|
|
||||||
desktop.add(console = new ConsoleWindow (this));
|
|
||||||
desktop.add(cpu = new CPUWindow (this));
|
|
||||||
desktop.add(memory = new MemoryWindow (this));
|
|
||||||
|
|
||||||
// Configure internal breakpoints
|
|
||||||
brkStep = vue.breakpoint();
|
|
||||||
brkStep.setRead(true);
|
|
||||||
|
|
||||||
// Display window
|
|
||||||
refreshDebug(true);
|
|
||||||
pack();
|
|
||||||
setLocationRelativeTo(null);
|
|
||||||
setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Menu Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Produce the window's menu bar
|
|
||||||
private JMenuBar initMenus() {
|
|
||||||
var bar = new JMenuBar();
|
|
||||||
var loc = app.localizer;
|
|
||||||
bar.add(initMenuFile (loc));
|
|
||||||
bar.add(initMenuDebug(loc));
|
|
||||||
return bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the Debug menu
|
|
||||||
private JMenu initMenuDebug(Localizer loc) {
|
|
||||||
mnuDebug = new JMenu();
|
|
||||||
loc.add(mnuDebug, "app.debug.(menu)");
|
|
||||||
mnuDebug.setVisible(false);
|
|
||||||
|
|
||||||
var mnuDebugBreakpoints = new JMenuItem();
|
|
||||||
loc.add(mnuDebugBreakpoints, "app.debug.breakpoints");
|
|
||||||
mnuDebugBreakpoints.addActionListener(e->breakpoints.setVisible(true));
|
|
||||||
mnuDebug.add(mnuDebugBreakpoints);
|
|
||||||
|
|
||||||
var mnuDebugConsole = new JMenuItem();
|
|
||||||
loc.add(mnuDebugConsole, "app.debug.console");
|
|
||||||
mnuDebugConsole.addActionListener(e->console.setVisible(true));
|
|
||||||
mnuDebug.add(mnuDebugConsole);
|
|
||||||
|
|
||||||
var mnuDebugCPU = new JMenuItem();
|
|
||||||
loc.add(mnuDebugCPU, "app.debug.cpu");
|
|
||||||
mnuDebugCPU.addActionListener(e->cpu.setVisible(true));
|
|
||||||
mnuDebug.add(mnuDebugCPU);
|
|
||||||
|
|
||||||
var mnuDebugMemory = new JMenuItem();
|
|
||||||
loc.add(mnuDebugMemory, "app.debug.memory");
|
|
||||||
mnuDebugMemory.addActionListener(e->memory.setVisible(true));
|
|
||||||
mnuDebug.add(mnuDebugMemory);
|
|
||||||
|
|
||||||
mnuDebug.addSeparator();
|
|
||||||
|
|
||||||
var mnuDebugBGMaps = new JMenuItem();
|
|
||||||
loc.add(mnuDebugBGMaps, "app.debug.bg_maps");
|
|
||||||
mnuDebugBGMaps.addActionListener(e->bgMaps.setVisible(true));
|
|
||||||
mnuDebug.add(mnuDebugBGMaps);
|
|
||||||
|
|
||||||
var mnuDebugCharacters = new JMenuItem();
|
|
||||||
loc.add(mnuDebugCharacters, "app.debug.characters");
|
|
||||||
mnuDebugCharacters.addActionListener(e->characters.setVisible(true));
|
|
||||||
mnuDebug.add(mnuDebugCharacters);
|
|
||||||
|
|
||||||
var mnuDebugFrameBuffers = new JMenuItem();
|
|
||||||
mnuDebugFrameBuffers.setEnabled(false);
|
|
||||||
loc.add(mnuDebugFrameBuffers, "app.debug.frame_buffers");
|
|
||||||
mnuDebug.add(mnuDebugFrameBuffers);
|
|
||||||
|
|
||||||
var mnuDebugObjects = new JMenuItem();
|
|
||||||
mnuDebugObjects.setEnabled(false);
|
|
||||||
loc.add(mnuDebugObjects, "app.debug.objects");
|
|
||||||
mnuDebug.add(mnuDebugObjects);
|
|
||||||
|
|
||||||
var mnuDebugWorlds = new JMenuItem();
|
|
||||||
mnuDebugWorlds.setEnabled(false);
|
|
||||||
loc.add(mnuDebugWorlds, "app.debug.worlds");
|
|
||||||
mnuDebug.add(mnuDebugWorlds);
|
|
||||||
|
|
||||||
return mnuDebug;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the File menu
|
|
||||||
private JMenu initMenuFile(Localizer loc) {
|
|
||||||
var mnuFile = new JMenu();
|
|
||||||
loc.add(mnuFile, "app.file.(menu)");
|
|
||||||
|
|
||||||
var mnuFileLoadRom = new JMenuItem();
|
|
||||||
loc.add(mnuFileLoadRom, "app.file.load_rom");
|
|
||||||
mnuFileLoadRom.addActionListener(e->onLoadROM());
|
|
||||||
mnuFile.add(mnuFileLoadRom);
|
|
||||||
|
|
||||||
mnuFileDebugMode = new JMenuItem();
|
|
||||||
loc.add(mnuFileDebugMode, "app.file.debug_mode");
|
|
||||||
mnuFileDebugMode.addActionListener(e->onDebugMode(true));
|
|
||||||
mnuFile.add(mnuFileDebugMode);
|
|
||||||
|
|
||||||
mnuFileGameMode = new JMenuItem();
|
|
||||||
loc.add(mnuFileGameMode, "app.file.game_mode");
|
|
||||||
mnuFileGameMode.addActionListener(e->onDebugMode(false));
|
|
||||||
mnuFileGameMode.setVisible(false);
|
|
||||||
mnuFile.add(mnuFileGameMode);
|
|
||||||
|
|
||||||
mnuFile.addSeparator();
|
|
||||||
|
|
||||||
var mnuFileNewWindow = new JMenuItem();
|
|
||||||
loc.add(mnuFileNewWindow, "app.file.new_window");
|
|
||||||
mnuFileNewWindow.addActionListener(e->onNewWindow());
|
|
||||||
mnuFile.add(mnuFileNewWindow);
|
|
||||||
|
|
||||||
var mnuFileExit = new JMenuItem();
|
|
||||||
loc.add(mnuFileExit, "app.file.exit");
|
|
||||||
mnuFileExit.addActionListener(e->onClose());
|
|
||||||
mnuFile.add(mnuFileExit);
|
|
||||||
|
|
||||||
return mnuFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Draw a character into a pixel buffer
|
|
||||||
void drawCharacter(int index, boolean hFlip, boolean vFlip, int[] palette,
|
|
||||||
int[] buffer, int offset, int stride) {
|
|
||||||
int addr = index >> 9 << 15 | 0x00006000 | (index & 511) << 4;
|
|
||||||
|
|
||||||
for (int y = 0; y < 8; y++, offset += stride - 8)
|
|
||||||
for (int x = 0; x < 8; x++, offset += 1 ) {
|
|
||||||
int ix = hFlip ? 7 - x : x;
|
|
||||||
int iy = vFlip ? 7 - y : y;
|
|
||||||
int b = addr | iy << 1 | ix >> 2;
|
|
||||||
int bit = (ix & 3) << 1;
|
|
||||||
buffer[offset] = palette[vram[b] >> bit & 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh all debug views
|
|
||||||
void refreshDebug(boolean seekToPC) {
|
|
||||||
vue.readBytes(0x00000000, vram, 0, vram.length);
|
|
||||||
refreshPalettes();
|
|
||||||
refreshDebugLite(seekToPC);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh all debug views without retrieving video memory
|
|
||||||
void refreshDebugLite(boolean seekToPC) {
|
|
||||||
bgMaps .refresh();
|
|
||||||
breakpoints.refresh();
|
|
||||||
characters .refresh();
|
|
||||||
cpu .refresh(seekToPC);
|
|
||||||
memory .refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
// A window has been added to or removed from the program state
|
|
||||||
void windowsChanged(int number, boolean only) {
|
|
||||||
this.number = number;
|
|
||||||
this.only = only;
|
|
||||||
app.localizer.put(this, "ctrl.number", "" + number);
|
|
||||||
updateTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Event Handlers //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Window close, File -> Exit
|
|
||||||
private void onClose() {
|
|
||||||
app.removeWindow(this);
|
|
||||||
cpu.dispose();
|
|
||||||
dispose();
|
|
||||||
vue.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// File -> Debug mode, File -> Game mode
|
|
||||||
private void onDebugMode(boolean debugMode) {
|
|
||||||
this.debugMode = debugMode;
|
|
||||||
mnuFileDebugMode.setVisible(!debugMode);
|
|
||||||
mnuFileGameMode .setVisible( debugMode);
|
|
||||||
|
|
||||||
// Transition to debug mode
|
|
||||||
if (debugMode) {
|
|
||||||
client.remove(video);
|
|
||||||
client.add(desktop, BorderLayout.CENTER);
|
|
||||||
console.setContentPane(video);
|
|
||||||
console.firstShow();
|
|
||||||
mnuDebug.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transition to game mode
|
|
||||||
else {
|
|
||||||
client.remove(desktop);
|
|
||||||
client.add(video, BorderLayout.CENTER);
|
|
||||||
mnuDebug.setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
client.revalidate();
|
|
||||||
client.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// File -> Load ROM
|
|
||||||
private void onLoadROM() {
|
|
||||||
var loc = app.localizer;
|
|
||||||
|
|
||||||
// Prompt the user to select a file
|
|
||||||
var dlgFile = new JFileChooser(pwd);
|
|
||||||
dlgFile.addChoosableFileFilter(new FileNameExtensionFilter(
|
|
||||||
loc.get("dialog.ext_vb"), "vb"));
|
|
||||||
dlgFile.addChoosableFileFilter(new FileNameExtensionFilter(
|
|
||||||
loc.get("dialog.ext_isx"), "isx"));
|
|
||||||
dlgFile.setAcceptAllFileFilterUsed(true);
|
|
||||||
dlgFile.setDialogTitle(loc.get("dialog.load_rom"));
|
|
||||||
int option = dlgFile.showDialog(this, loc.get("dialog.load"));
|
|
||||||
|
|
||||||
// The user did not select a file
|
|
||||||
var file = dlgFile.getSelectedFile();
|
|
||||||
if (option != JFileChooser.APPROVE_OPTION || file == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Update the current directory
|
|
||||||
pwd = file.getParentFile();
|
|
||||||
|
|
||||||
// Read the file
|
|
||||||
var data = Util.fileRead(file);
|
|
||||||
if (data == null) {
|
|
||||||
JOptionPane.showMessageDialog(this,
|
|
||||||
loc.get("dialog.load_rom_error"),
|
|
||||||
loc.get("dialog.load_rom"),
|
|
||||||
JOptionPane.ERROR_MESSAGE
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the ROM
|
|
||||||
ROM rom = null;
|
|
||||||
try { rom = new ROM(data); }
|
|
||||||
catch (Exception e) {
|
|
||||||
JOptionPane.showMessageDialog(this,
|
|
||||||
loc.get("dialog.load_rom_notvb"),
|
|
||||||
loc.get("dialog.load_rom"),
|
|
||||||
JOptionPane.ERROR_MESSAGE
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update instance fields
|
|
||||||
this.rom = rom;
|
|
||||||
romFile = file;
|
|
||||||
loc.put(this, "ctrl.filename", file.getName());
|
|
||||||
updateTitle();
|
|
||||||
|
|
||||||
// Update the emulation state
|
|
||||||
var bytes = rom.toByteArray();
|
|
||||||
// Pause emulation
|
|
||||||
vue.setROM(bytes, 0, bytes.length);
|
|
||||||
vue.reset();
|
|
||||||
refreshDebug(true);
|
|
||||||
// Resume emulation
|
|
||||||
}
|
|
||||||
|
|
||||||
// File -> New window
|
|
||||||
private void onNewWindow() {
|
|
||||||
app.addWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Video paint
|
|
||||||
private void onPaintVideo(Graphics2D g, int width, int height) {
|
|
||||||
int scale = Math.max(1, Math.min(width / 384, height / 224));
|
|
||||||
|
|
||||||
g.translate(
|
|
||||||
Math.max(0, (width - scale * 384) / 2),
|
|
||||||
Math.max(0, (height - scale * 224) / 2)
|
|
||||||
);
|
|
||||||
g.scale(scale, scale);
|
|
||||||
|
|
||||||
g.setColor(Color.black);
|
|
||||||
g.fillRect(0, 0, 384, 224);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Update the palette composites
|
|
||||||
private void refreshPalettes() {
|
|
||||||
|
|
||||||
// Process brightness levels
|
|
||||||
int[] brt = { 0,
|
|
||||||
vue.read(0x0005F824, Vue.U8),
|
|
||||||
vue.read(0x0005F826, Vue.U8),
|
|
||||||
vue.read(0x0005F828, Vue.U8)
|
|
||||||
};
|
|
||||||
brt[3] += brt[0] + brt[1];
|
|
||||||
for (int x = 1; x < 4; x++)
|
|
||||||
brt[x] = (Math.min(127, brt[x]) * 510 + 127) / 254 << 1;
|
|
||||||
|
|
||||||
// Process all palettes
|
|
||||||
var pal = new int[4];
|
|
||||||
for (int x = 0; x < 9; x++) {
|
|
||||||
|
|
||||||
// Generic palette
|
|
||||||
if (x == GENERIC) {
|
|
||||||
pal[1] = 0x55 << 1;
|
|
||||||
pal[2] = 0xAA << 1;
|
|
||||||
pal[3] = 0xFF << 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Palette from emulation state
|
|
||||||
else {
|
|
||||||
int bits = vue.read(0x0005F860 + (x - 1 << 1), Vue.U8);
|
|
||||||
pal[1] = brt[bits >> 2 & 3];
|
|
||||||
pal[2] = brt[bits >> 4 & 3];
|
|
||||||
pal[3] = brt[bits >> 6 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process colors
|
|
||||||
for (int y = 0; y < 3; y++) {
|
|
||||||
var base = app.rgbBase[y];
|
|
||||||
var dest = palettes[x][y];
|
|
||||||
dest[0] = 0xFF000000 | app.rgbClear;
|
|
||||||
for (int z = 1; z < 4; z++) {
|
|
||||||
dest[z] = 0xFF000000;
|
|
||||||
for (int w = 0, bits = 16; w < 3; w++, bits -= 8)
|
|
||||||
dest[z] |= (pal[z] * base[w] + 255) / 510 << bits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Separate the RGB components of a color
|
|
||||||
private static int[] split(int rgb) {
|
|
||||||
return new int[] { rgb >> 16 & 0xFF, rgb >> 8 & 0xFF, rgb & 0xFF };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the window title
|
|
||||||
private void updateTitle() {
|
|
||||||
app.localizer.add(this,
|
|
||||||
only ? romFile != null ?
|
|
||||||
"app.title.rom" :
|
|
||||||
"app.title.default"
|
|
||||||
: romFile != null ?
|
|
||||||
"app.title.mixed" :
|
|
||||||
"app.title.number"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,248 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
|
|
||||||
// Memory viewer and hex editor window
|
|
||||||
class MemoryWindow extends ChildWindow {
|
|
||||||
|
|
||||||
// Private fields
|
|
||||||
private int address; // Address of top row
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
private UPanel client; // Client area
|
|
||||||
private ArrayList<Row> rows; // Rows of text
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Classes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// One row of output
|
|
||||||
private class Row {
|
|
||||||
JLabel address; // Address (row header)
|
|
||||||
JLabel[] bytes; // Hexadecimal bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
MemoryWindow(MainWindow parent) {
|
|
||||||
super(parent, "memory.title");
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
address = 0x00000000;
|
|
||||||
rows = new ArrayList<Row>();
|
|
||||||
|
|
||||||
// Configure client area
|
|
||||||
client = new UPanel();
|
|
||||||
client.addComponentListener(Util.onResize(e->onResize()));
|
|
||||||
client.addKeyListener(Util.onKey(e->onKeyDown(e), null));
|
|
||||||
client.addMouseWheelListener(e->onWheel(e));
|
|
||||||
client.setBackground(SystemColor.window);
|
|
||||||
client.setFocusable(true);
|
|
||||||
client.setPreferredSize(new Dimension(480, 360));
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
var content = new UPanel(new BorderLayout());
|
|
||||||
content.setBorder(new JScrollPane().getBorder());
|
|
||||||
content.add(client, BorderLayout.CENTER);
|
|
||||||
setContentPane(content);
|
|
||||||
pack();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
void refresh() {
|
|
||||||
|
|
||||||
// The element is not ready
|
|
||||||
if (client == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Configure working variables
|
|
||||||
int height = client.getHeight();
|
|
||||||
int lineHeight = parent.app.fntMono.metrics.getHeight();
|
|
||||||
int count = (height + lineHeight - 1) / lineHeight;
|
|
||||||
var data = new byte[count * 16];
|
|
||||||
|
|
||||||
// Retrieve all visible bytes from the emulation context
|
|
||||||
parent.vue.readBytes(address, data, 0, data.length);
|
|
||||||
|
|
||||||
// Update visible rows
|
|
||||||
for (int x = 0; x < count; x++) {
|
|
||||||
Row row;
|
|
||||||
if (x < rows.size())
|
|
||||||
row = rows.get(x); // Retrieve row from collection
|
|
||||||
else row = createRow(); // Produce a new row
|
|
||||||
update(row, x * lineHeight, address + x * 16, data, x * 16);
|
|
||||||
setVisible(row, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide any rows that are not visible
|
|
||||||
for (int x = count; x < rows.size(); x++)
|
|
||||||
setVisible(rows.get(x), false);
|
|
||||||
|
|
||||||
// Finalize layout
|
|
||||||
client.revalidate();
|
|
||||||
client.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Event Handlers //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Key down
|
|
||||||
private void onKeyDown(KeyEvent e) {
|
|
||||||
int code = e.getKeyCode();
|
|
||||||
int mods = e.getModifiersEx();
|
|
||||||
boolean alt = (mods & InputEvent.ALT_DOWN_MASK ) != 0;
|
|
||||||
boolean ctrl = (mods & InputEvent.CTRL_DOWN_MASK) != 0;
|
|
||||||
int tall = Math.max(1, tall(false));
|
|
||||||
|
|
||||||
// No Alt combinations
|
|
||||||
if (alt) return;
|
|
||||||
|
|
||||||
// Goto
|
|
||||||
if (ctrl && code == KeyEvent.VK_G) {
|
|
||||||
String text = JOptionPane.showInputDialog(
|
|
||||||
this, "Goto:", "Goto", JOptionPane.PLAIN_MESSAGE);
|
|
||||||
Object eval = parent.vue.evaluate(text);
|
|
||||||
int addr = 0;
|
|
||||||
if (eval instanceof Integer)
|
|
||||||
addr = (Integer) eval;
|
|
||||||
else if (eval instanceof Long)
|
|
||||||
addr = (int) (long) (Long) eval;
|
|
||||||
else return;
|
|
||||||
setAddress(addr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seek
|
|
||||||
switch (code) {
|
|
||||||
case KeyEvent.VK_UP : setAddress(address - 16); break;
|
|
||||||
case KeyEvent.VK_DOWN : setAddress(address + 16); break;
|
|
||||||
case KeyEvent.VK_PAGE_UP : setAddress(address - tall * 16); break;
|
|
||||||
case KeyEvent.VK_PAGE_DOWN: setAddress(address + tall * 16); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client resize
|
|
||||||
private void onResize() {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse wheel
|
|
||||||
private void onWheel(MouseWheelEvent e) {
|
|
||||||
int amount = e.getUnitsToScroll();
|
|
||||||
int mods = e.getModifiersEx();
|
|
||||||
boolean alt = (mods & InputEvent.ALT_DOWN_MASK ) != 0;
|
|
||||||
boolean ctrl = (mods & InputEvent.CTRL_DOWN_MASK) != 0;
|
|
||||||
|
|
||||||
// No Alt or Ctrl combinations
|
|
||||||
if (amount == 0 || alt || ctrl)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Seek
|
|
||||||
setAddress(address + 16 * amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a new row of output
|
|
||||||
private Row createRow() {
|
|
||||||
var font = parent.app.fntMono;
|
|
||||||
var row = new Row();
|
|
||||||
|
|
||||||
// Address label
|
|
||||||
row.address = new JLabel();
|
|
||||||
row.address.setFont(font);
|
|
||||||
row.address.setForeground(SystemColor.windowText);
|
|
||||||
row.address.setVisible(false);
|
|
||||||
client.add(row.address);
|
|
||||||
|
|
||||||
// Byte labels
|
|
||||||
row.bytes = new JLabel[16];
|
|
||||||
for (int x = 0; x < row.bytes.length; x++) {
|
|
||||||
var label = row.bytes[x] = new JLabel();
|
|
||||||
label.setFont(font);
|
|
||||||
label.setForeground(SystemColor.windowText);
|
|
||||||
label.setHorizontalAlignment(SwingConstants.CENTER);
|
|
||||||
label.setVisible(false);
|
|
||||||
client.add(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the row to the collection
|
|
||||||
rows.add(row);
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Measure the minimum column widths for a row
|
|
||||||
private void measure(Row row, int[] widths) {
|
|
||||||
widths[0] = Math.max(widths[0], row.address.getPreferredSize().width);
|
|
||||||
for (int x = 0; x < 16; x++)
|
|
||||||
widths[1] = Math.max(widths[1],
|
|
||||||
row.bytes[x].getPreferredSize().width);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the address of the top row of output
|
|
||||||
private void setAddress(int address) {
|
|
||||||
this.address = address & 0xFFFFFFF0;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show or hide a row
|
|
||||||
private void setVisible(Row row, boolean visible) {
|
|
||||||
row.address.setVisible(visible);
|
|
||||||
for (var label : row.bytes)
|
|
||||||
label.setVisible(visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine how many rows of output are visible
|
|
||||||
private int tall(boolean partial) {
|
|
||||||
int lineHeight = parent.app.fntMono.metrics.getHeight();
|
|
||||||
return (client.getHeight() + (partial?lineHeight-1:0)) / lineHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the text of a row
|
|
||||||
private void update(Row row, int y, int address, byte[] data, int offset) {
|
|
||||||
int hexDigitWidth = parent.app.hexDigitWidth;
|
|
||||||
int lineHeight = parent.app.fntMono.metrics.getHeight();
|
|
||||||
|
|
||||||
// Update address
|
|
||||||
row.address.setBounds(0, y, 8 * hexDigitWidth, lineHeight);
|
|
||||||
row.address.setText(String.format("%08X", address));
|
|
||||||
|
|
||||||
// Update bytes
|
|
||||||
for (int z = 0, x = 10 * hexDigitWidth; z < 16; z++) {
|
|
||||||
var label = row.bytes[z];
|
|
||||||
label.setBounds(x, y, 2 * hexDigitWidth, lineHeight);
|
|
||||||
label.setText(String.format("%02X", data[offset++] & 0xFF));
|
|
||||||
x += hexDigitWidth * (z == 7 ? 4 : 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,254 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.nio.charset.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
// Cartridge ROM module
|
|
||||||
public class ROM {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private byte[] data; // Binary data
|
|
||||||
private int format; // File format of loaded file
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Formats
|
|
||||||
public static final int RAW = 0;
|
|
||||||
public static final int ISX = 1;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Classes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// ISX code segments
|
|
||||||
private static class Code {
|
|
||||||
int address; // CPU address
|
|
||||||
int offset; // Position within file
|
|
||||||
int size; // Number of bytes
|
|
||||||
Code(int o, int a, int s) { address = a; offset = o; size = s; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
ROM(byte[] data) {
|
|
||||||
|
|
||||||
// Attempt to decode as ISX
|
|
||||||
try { isxDecode(data); return; } catch (Exception e) { }
|
|
||||||
|
|
||||||
// Attempt to decode as raw
|
|
||||||
try { rawDecode(data); return; } catch (Exception e) { }
|
|
||||||
|
|
||||||
// Unable to identify the file contents
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Retrieve the game code from the ROM header
|
|
||||||
public String getGameCode() {
|
|
||||||
var bytes = new byte[4];
|
|
||||||
System.arraycopy(data, data.length - 517, bytes, 0, 4);
|
|
||||||
return new String(bytes, StandardCharsets.ISO_8859_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the file format of the loaded ROM file
|
|
||||||
public int getFormat() {
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the maker code from the ROM header
|
|
||||||
public String getMaker() {
|
|
||||||
var bytes = new byte[2];
|
|
||||||
System.arraycopy(data, data.length - 519, bytes, 0, 2);
|
|
||||||
return new String(bytes, StandardCharsets.ISO_8859_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the number of bytes in the ROM data
|
|
||||||
public int getSize() {
|
|
||||||
return data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the game title from the ROM header
|
|
||||||
public String getTitle() {
|
|
||||||
return ShiftJIS.decode(data, data.length - 544, 20).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the version number from the ROM header
|
|
||||||
public int getVersion() {
|
|
||||||
return data[data.length - 513] & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a byte array containing the ROM contents
|
|
||||||
public byte[] toByteArray() {
|
|
||||||
var ret = new byte[data.length];
|
|
||||||
System.arraycopy(data, 0, ret, 0, data.length);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Decode the file data as ISX
|
|
||||||
private void isxDecode(byte[] data) {
|
|
||||||
var codes = isxParse(data); // ISX code segments
|
|
||||||
int head = -1; // Latest address in bottom half of ROM address space
|
|
||||||
int tail = -1; // Earliest address in upper half of ROM address space
|
|
||||||
|
|
||||||
// Process all code segments
|
|
||||||
for (var code : codes) {
|
|
||||||
int end = code.address + code.size - 1;
|
|
||||||
int start = code.address;
|
|
||||||
boolean isHead = end >= 0; // Lower half of CPU address range
|
|
||||||
boolean isTail = start < 0; // Upper half of CPU address range
|
|
||||||
|
|
||||||
// The segment spans the middle of the ROM address space
|
|
||||||
if (isHead && isTail) {
|
|
||||||
head = 0x7FFFFF;
|
|
||||||
tail = 0x800000;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Track the segment's position within the ROM address space
|
|
||||||
end &= 0x00FFFFFF;
|
|
||||||
start &= 0x00FFFFFF;
|
|
||||||
if (isHead && (head == -1 || head < end )) head = end;
|
|
||||||
if (isTail && (tail == -1 || tail > start)) tail = start;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the required ROM size
|
|
||||||
int size = 1024;
|
|
||||||
int minSize = (head == -1 ? 0 : head + 1) +
|
|
||||||
(tail == -1 ? 0 : 0x01000000 - tail);
|
|
||||||
if (minSize == 0 || tail == -1 &&
|
|
||||||
(minSize < 1024 || (minSize - 1 & minSize) != 0))
|
|
||||||
throw new RuntimeException();
|
|
||||||
for (; size < minSize; size <<= 1);
|
|
||||||
|
|
||||||
// Transfer the code segments into the ROM buffer
|
|
||||||
this.data = new byte[size];
|
|
||||||
for (var code : codes)
|
|
||||||
System.arraycopy(
|
|
||||||
data , code.offset,
|
|
||||||
this.data, code.address & size - 1,
|
|
||||||
code.size
|
|
||||||
);
|
|
||||||
|
|
||||||
// The ROM is valid
|
|
||||||
format = ISX;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the code records from the ISX data
|
|
||||||
private Code[] isxParse(byte[] data) {
|
|
||||||
int count;
|
|
||||||
int offset = 0;
|
|
||||||
var ret = new ArrayList<Code>();
|
|
||||||
|
|
||||||
// Check for an extended ISX header
|
|
||||||
if (readInt(data, 0, 3) == 0x585349) // ASCII "ISX"
|
|
||||||
offset = 32;
|
|
||||||
|
|
||||||
// Process records
|
|
||||||
while (offset != data.length)
|
|
||||||
switch (data[offset++] & 0xFF) {
|
|
||||||
|
|
||||||
// SNES code
|
|
||||||
case 0x01:
|
|
||||||
if ((data[offset++] & 0xFF) >= 0x80) // Bank
|
|
||||||
offset++; // BankHigh
|
|
||||||
offset += 2; // Address
|
|
||||||
offset += 2 + readInt(data, offset, 2); // Data
|
|
||||||
break;
|
|
||||||
|
|
||||||
// SNES range
|
|
||||||
case 0x03:
|
|
||||||
// Count, { Bank, StartAddress, EndAddress, Type }
|
|
||||||
offset += 2 + readInt(data, offset, 2) * 6;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// SNES symbol
|
|
||||||
case 0x04:
|
|
||||||
count = readInt(data, offset, 2); offset += 2;
|
|
||||||
for (; count > 0; count--) // Name, Flags, Bank, Address
|
|
||||||
offset += 5 + readInt(data, offset, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Virtual Boy code
|
|
||||||
case 0x11:
|
|
||||||
int address = readInt(data, offset, 4); offset += 4;
|
|
||||||
int size = readInt(data, offset, 4); offset += 4;
|
|
||||||
if ((address & 0x07000000) != 0x07000000 || size < 0 ||
|
|
||||||
(address & 0x00FFFFFF) + size > 0x01000000)
|
|
||||||
throw new RuntimeException();
|
|
||||||
ret.add(new Code(offset, address, size));
|
|
||||||
offset += size;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Virtual Boy range
|
|
||||||
case 0x13:
|
|
||||||
// Count, { StartAddress, EndAddress, Type }
|
|
||||||
offset += 2 + readInt(data, offset, 2) * 9;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Virtual Boy symbol
|
|
||||||
case 0x14:
|
|
||||||
count = readInt(data, offset, 2); offset += 2;
|
|
||||||
for (; count > 0; count--) // Name, Flags, Address
|
|
||||||
offset += 7 + readInt(data, offset, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// System
|
|
||||||
case 0x20: case 0x21: case 0x22:
|
|
||||||
offset += 4 + readInt(data, offset, 4); // Debug, undocumented
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Invalid record type
|
|
||||||
default:
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret.toArray(new Code[ret.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode the file as raw
|
|
||||||
private void rawDecode(byte[] data) {
|
|
||||||
|
|
||||||
// Validate length
|
|
||||||
if (
|
|
||||||
data.length < 1024 || // Exception handlers and ROM header
|
|
||||||
data.length > 0x00FFFFFF || // 24-bit bus width
|
|
||||||
(data.length & data.length - 1) != 0 // Must be a power of 2
|
|
||||||
) throw new RuntimeException();
|
|
||||||
|
|
||||||
// The ROM is valid
|
|
||||||
this.data = data;
|
|
||||||
format = RAW;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read an integer from a byte array
|
|
||||||
private static int readInt(byte[] data, int offset, int size) {
|
|
||||||
int ret = 0;
|
|
||||||
for (size--; size >= 0; size--)
|
|
||||||
ret = ret << 8 | data[offset + size] & 0xFF;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,521 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// Register list item
|
|
||||||
class Register {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private boolean expandable; // The expansion area can be shown
|
|
||||||
private boolean expanded; // The expanded area is being shown
|
|
||||||
private int index; // Register index
|
|
||||||
private int mode; // Display mode for program registers
|
|
||||||
private String name; // Register name
|
|
||||||
private RegisterList parent; // Containing register list
|
|
||||||
private int type; // Expansion controls type
|
|
||||||
private int value; // Current register value
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
UPanel expansion; // Expansion container
|
|
||||||
JLabel btnExpand; // Expand button
|
|
||||||
UPanel indent; // Expansion area indentation
|
|
||||||
JLabel lblName; // Register name
|
|
||||||
JTextField txtValue; // Register value
|
|
||||||
ArrayList<JComponent> controls; // Expansion controls
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Modes
|
|
||||||
static final int FLOAT = 3;
|
|
||||||
static final int HEX = 0;
|
|
||||||
static final int SIGNED = 1;
|
|
||||||
static final int UNSIGNED = 2;
|
|
||||||
|
|
||||||
// Types
|
|
||||||
static final int PLAIN = -2;
|
|
||||||
static final int PROGRAM = -3;
|
|
||||||
|
|
||||||
// Expand button labels
|
|
||||||
static final String COLLAPSE = "-";
|
|
||||||
static final String EXPAND = "+";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
Register(RegisterList parent, String name, int index, int type) {
|
|
||||||
parent.add(index, this);
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
controls = new ArrayList<JComponent>();
|
|
||||||
expandable = type != PLAIN && index != 0;
|
|
||||||
this.index = index;
|
|
||||||
mode = HEX;
|
|
||||||
this.name = name;
|
|
||||||
this.parent = parent;
|
|
||||||
this.type = type;
|
|
||||||
|
|
||||||
// Click handler for expand and name controls
|
|
||||||
MouseListener expand = !expandable ? null : Util.onMouse(e->{
|
|
||||||
if (e.getButton() == 1) setExpanded(!expanded); }, null);
|
|
||||||
|
|
||||||
// Expand button
|
|
||||||
btnExpand = new JLabel(expandable ? EXPAND : "");
|
|
||||||
btnExpand.setHorizontalAlignment(SwingConstants.CENTER);
|
|
||||||
if (expandable)
|
|
||||||
btnExpand.addMouseListener(expand);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.NORTH;
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
parent.add(gbc, btnExpand);
|
|
||||||
|
|
||||||
// Name label
|
|
||||||
lblName = new JLabel(" ");
|
|
||||||
if (expandable)
|
|
||||||
lblName.addMouseListener(expand);
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.NORTH;
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
gbc.weightx = 1;
|
|
||||||
parent.add(gbc, lblName);
|
|
||||||
|
|
||||||
// Value text box
|
|
||||||
txtValue = new JTextField();
|
|
||||||
txtValue.setBorder(null);
|
|
||||||
txtValue.setOpaque(false);
|
|
||||||
txtValue.setText("00000000");
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 4, 0, 0);
|
|
||||||
parent.add(gbc, txtValue);
|
|
||||||
|
|
||||||
// Value changed
|
|
||||||
txtValue.addActionListener(e->parent.requestFocus());
|
|
||||||
txtValue.addFocusListener(Util.onFocus(null, e->{
|
|
||||||
String text = txtValue.getText();
|
|
||||||
int val = value;
|
|
||||||
try { switch (mode) {
|
|
||||||
case HEX : val = (int) Long.parseLong(text, 16); break;
|
|
||||||
case SIGNED : // Fallthrough
|
|
||||||
case UNSIGNED: val = (int) Long.parseLong(text, 10); break;
|
|
||||||
case FLOAT : val =
|
|
||||||
Float.floatToIntBits(Float.parseFloat(text) ); break;
|
|
||||||
}} catch (Exception x) { }
|
|
||||||
setValue(val);
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Expansion controls
|
|
||||||
switch (type) {
|
|
||||||
case PROGRAM : initProgram(); break;
|
|
||||||
case Vue.CHCW: initCHCW (); break;
|
|
||||||
case Vue.ECR : initECR (); break;
|
|
||||||
case Vue.PC : initPC (); break;
|
|
||||||
case Vue.PIR : initPIR (); break;
|
|
||||||
case Vue.PSW : initPSW (); break;
|
|
||||||
case Vue.TKCW: initTKCW (); break;
|
|
||||||
default: configure(); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expansion indentation
|
|
||||||
if (index != Vue.PC) {
|
|
||||||
indent = new UPanel();
|
|
||||||
indent.setOpaque(false);
|
|
||||||
indent.setPreferredSize(new Dimension(0, 0));
|
|
||||||
indent.setVisible(false);
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
parent.add(gbc, indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expansion area
|
|
||||||
expansion.setOpaque(false);
|
|
||||||
expansion.setVisible(false);
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.WEST;
|
|
||||||
if (index == Vue.PC)
|
|
||||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 4, 0, 0);
|
|
||||||
gbc.weightx = 1;
|
|
||||||
parent.add(gbc, expansion);
|
|
||||||
|
|
||||||
// Handling for PSW
|
|
||||||
if (index == Vue.PSW && type == Vue.PSW)
|
|
||||||
setExpanded(true);
|
|
||||||
|
|
||||||
// Apply application settings
|
|
||||||
configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Expansion Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Expansion controls for CHCW
|
|
||||||
private void initCHCW() {
|
|
||||||
expansion = new UPanel(new GridBagLayout());
|
|
||||||
addCheckBox("ICE", 1, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expansion controls for ECR
|
|
||||||
private void initECR() {
|
|
||||||
expansion = new UPanel(new GridBagLayout());
|
|
||||||
addTextBox("EICC", 0, 16, false, true);
|
|
||||||
addTextBox("FECC", 16, 16, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expansion controls for program registers
|
|
||||||
private void initProgram() {
|
|
||||||
expansion = new UPanel(new GridBagLayout());
|
|
||||||
var group = new ButtonGroup();
|
|
||||||
group.add(addRadioButton("cpu.hex" , HEX ));
|
|
||||||
group.add(addRadioButton("cpu.signed" , SIGNED ));
|
|
||||||
group.add(addRadioButton("cpu.unsigned", UNSIGNED));
|
|
||||||
group.add(addRadioButton("cpu.float" , FLOAT ));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expansion controls for PC
|
|
||||||
private void initPC() {
|
|
||||||
expansion = new UPanel(new GridBagLayout());
|
|
||||||
|
|
||||||
// Configure controls
|
|
||||||
for (int x = 0; x < 2; x++) {
|
|
||||||
|
|
||||||
// Indentation
|
|
||||||
indent = new UPanel();
|
|
||||||
indent.setOpaque(false);
|
|
||||||
indent.setPreferredSize(new Dimension(0, 0));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.weightx = 1;
|
|
||||||
expansion.add(indent, gbc);
|
|
||||||
|
|
||||||
// Name label
|
|
||||||
var label = new JLabel();
|
|
||||||
parent.parent.parent.app.localizer.add(label,
|
|
||||||
x == 0 ? "cpu.jump_from" : "cpu.jump_to" );
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.NORTHWEST;
|
|
||||||
expansion.add(label, gbc);
|
|
||||||
controls.add(label);
|
|
||||||
|
|
||||||
// Value text box
|
|
||||||
var txt = new JTextField();
|
|
||||||
txt.addActionListener(e->parent.requestFocus());
|
|
||||||
txt.addFocusListener(Util.onFocus(null,
|
|
||||||
e->txt.setText((String) txt.getClientProperty("text"))));
|
|
||||||
txt.putClientProperty("index",
|
|
||||||
x == 0 ? Vue.JUMP_FROM : Vue.JUMP_TO);
|
|
||||||
txt.setBorder(null);
|
|
||||||
txt.setOpaque(false);
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 4, 0, 0);
|
|
||||||
expansion.add(txt, gbc);
|
|
||||||
controls.add(txt);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expansion controls for PSW
|
|
||||||
private void initPSW() {
|
|
||||||
expansion = new UPanel(new GridBagLayout());
|
|
||||||
addCheckBox("Z" , 0, false, false);
|
|
||||||
addCheckBox("FRO", 9, false, true );
|
|
||||||
addCheckBox("S" , 1, false, false);
|
|
||||||
addCheckBox("FIV", 8, false, true );
|
|
||||||
addCheckBox("OV" , 2, false, false);
|
|
||||||
addCheckBox("FZD", 7, false, true );
|
|
||||||
addCheckBox("CY" , 3, false, false);
|
|
||||||
addCheckBox("FOV", 6, false, true );
|
|
||||||
addCheckBox("EP" , 14, false, false);
|
|
||||||
addCheckBox("FUD", 5, false, true );
|
|
||||||
addCheckBox("NP" , 15, false, false);
|
|
||||||
addCheckBox("FPR", 4, false, true );
|
|
||||||
addCheckBox("AE" , 13, false, true );
|
|
||||||
addCheckBox("ID" , 12, false, false);
|
|
||||||
addTextBox ("I" , 16, 4, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expansion controls for PIR
|
|
||||||
private void initPIR() {
|
|
||||||
expansion = new UPanel(new GridBagLayout());
|
|
||||||
addTextBox("PT", 0, 16, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expansion controls for TKCW
|
|
||||||
private void initTKCW() {
|
|
||||||
expansion = new UPanel(new GridBagLayout());
|
|
||||||
addCheckBox("OTM", 8, true, false);
|
|
||||||
addCheckBox("FVT", 5, true, true );
|
|
||||||
addCheckBox("FIT", 7, true, false);
|
|
||||||
addCheckBox("FUT", 4, true, true );
|
|
||||||
addCheckBox("FZT", 6, true, false);
|
|
||||||
addCheckBox("FPT", 3, true, true );
|
|
||||||
addCheckBox("RDI", 2, true, false);
|
|
||||||
addTextBox ("RD", 0, 2, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Apply configuration settings
|
|
||||||
void configure() {
|
|
||||||
String name = null;
|
|
||||||
|
|
||||||
// System register
|
|
||||||
if (type != PROGRAM) {
|
|
||||||
name = this.name;
|
|
||||||
if (!Disassembler.systemCaps)
|
|
||||||
name = name.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Program register
|
|
||||||
else {
|
|
||||||
if (Disassembler.programNames)
|
|
||||||
name = this.name;
|
|
||||||
if (name == null)
|
|
||||||
name = "r" + index;
|
|
||||||
if (Disassembler.programCaps)
|
|
||||||
name = name.toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name label
|
|
||||||
lblName.setText(name);
|
|
||||||
|
|
||||||
// Expand button
|
|
||||||
var size = btnExpand.getPreferredSize();
|
|
||||||
var metrics = parent.parent.parent.app.fntDialog.metrics;
|
|
||||||
size.width = 4 + Math.max(
|
|
||||||
metrics.stringWidth(EXPAND), metrics.stringWidth(COLLAPSE));
|
|
||||||
btnExpand.setPreferredSize(size);
|
|
||||||
|
|
||||||
// Value text box
|
|
||||||
var fntMono = parent.parent.parent.app.fntMono;
|
|
||||||
int hexDigitWidth = parent.parent.parent.app.hexDigitWidth;
|
|
||||||
txtValue.setFont(fntMono);
|
|
||||||
txtValue.setPreferredSize(new Dimension(
|
|
||||||
hexDigitWidth * 8 + 4, fntMono.metrics.getHeight()));
|
|
||||||
|
|
||||||
// Expansion controls
|
|
||||||
for (var ctrl : controls) {
|
|
||||||
if (!(ctrl instanceof JTextField))
|
|
||||||
continue;
|
|
||||||
if (type == Vue.PC || (Boolean) ctrl.getClientProperty("hex"))
|
|
||||||
((JTextField) ctrl).setFont(fntMono);
|
|
||||||
int digits = type == Vue.PC ? 8 :
|
|
||||||
(Integer) ctrl.getClientProperty("digits");
|
|
||||||
size = ctrl.getPreferredSize();
|
|
||||||
size.width = digits * hexDigitWidth + 4;
|
|
||||||
ctrl.setPreferredSize(size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh controls
|
|
||||||
void refresh() {
|
|
||||||
var vue = parent.parent.parent.vue;
|
|
||||||
|
|
||||||
// Value text box
|
|
||||||
value = vue.getRegister(index, type != PROGRAM);
|
|
||||||
txtValue.setText(
|
|
||||||
type != PROGRAM || mode == HEX ?
|
|
||||||
String.format("%08X", value) :
|
|
||||||
mode == SIGNED ? Integer.toString(value) :
|
|
||||||
mode == UNSIGNED ? Long.toString(value & 0xFFFFFFFFL) :
|
|
||||||
Float.toString(Float.intBitsToFloat(value))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Expansion controls
|
|
||||||
for (var control : controls) {
|
|
||||||
|
|
||||||
// Check box
|
|
||||||
if (control instanceof JCheckBox) {
|
|
||||||
var ctrl = (JCheckBox) control;
|
|
||||||
int bit = (Integer) ctrl.getClientProperty("bit");
|
|
||||||
ctrl.setSelected((value & 1 << bit) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text box
|
|
||||||
if (control instanceof JTextField) {
|
|
||||||
var ctrl = (JTextField) control;
|
|
||||||
int digits; // Maximum digits that can be displayed
|
|
||||||
boolean hex; // The value is hexadecimal
|
|
||||||
int val; // The value to be displayed
|
|
||||||
|
|
||||||
// Jump history
|
|
||||||
if (type == Vue.PC) {
|
|
||||||
digits = 8;
|
|
||||||
hex = true;
|
|
||||||
val = vue.getRegister((Integer)
|
|
||||||
ctrl.getClientProperty("index"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// All other values
|
|
||||||
else {
|
|
||||||
int bit = (Integer) ctrl.getClientProperty("bit" );
|
|
||||||
digits = (Integer) ctrl.getClientProperty("digits");
|
|
||||||
hex = (Boolean) ctrl.getClientProperty("hex");
|
|
||||||
int width = (Integer) ctrl.getClientProperty("width");
|
|
||||||
val = value >> bit & (1 << width) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the text
|
|
||||||
String text = !hex ? Integer.toString(val) : String.format(
|
|
||||||
"%0" + digits + (Disassembler.hexCaps ? "X" : "x"), val);
|
|
||||||
ctrl.putClientProperty("text", text);
|
|
||||||
ctrl.setText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify whether the expansion area is expanded
|
|
||||||
void setExpanded(boolean expanded) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (!expandable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Update controls
|
|
||||||
this.expanded = expanded;
|
|
||||||
btnExpand.setText(expanded ? "-" : "+");
|
|
||||||
if (type != Vue.PC)
|
|
||||||
indent.setVisible(expanded);
|
|
||||||
expansion.setVisible(expanded);
|
|
||||||
parent.revalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change the display mode of a program register
|
|
||||||
void setMode(int mode) {
|
|
||||||
this.mode = mode;
|
|
||||||
txtValue.setFont(mode!=HEX ? null : parent.parent.parent.app.fntMono);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a check box to the expansion area
|
|
||||||
private void addCheckBox(String name, int bit, boolean readOnly,
|
|
||||||
boolean last) {
|
|
||||||
int mask = 1 << bit;
|
|
||||||
|
|
||||||
// Configure control
|
|
||||||
var ctrl = new JCheckBox(name);
|
|
||||||
ctrl.putClientProperty("bit", bit);
|
|
||||||
ctrl.setBorder(null);
|
|
||||||
ctrl.setEnabled(!readOnly);
|
|
||||||
ctrl.setFocusable(false);
|
|
||||||
ctrl.setOpaque(false);
|
|
||||||
controls.add(ctrl);
|
|
||||||
|
|
||||||
// Event handler
|
|
||||||
ctrl.addItemListener(e->setValue(
|
|
||||||
e.getStateChange() == ItemEvent.SELECTED ?
|
|
||||||
value | mask : value & ~mask
|
|
||||||
));
|
|
||||||
|
|
||||||
// Configure expansion area
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.NORTHWEST;
|
|
||||||
gbc.gridwidth = last ? GridBagConstraints.REMAINDER : 2;
|
|
||||||
gbc.insets = new Insets(0, 4, 0, 4);
|
|
||||||
expansion.add(ctrl, gbc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a radio button to the expansion area
|
|
||||||
private JRadioButton addRadioButton(String key, int mode) {
|
|
||||||
|
|
||||||
// Configure control
|
|
||||||
var ctrl = new JRadioButton();
|
|
||||||
parent.parent.parent.app.localizer.add(ctrl, key);
|
|
||||||
ctrl.setBorder(null);
|
|
||||||
ctrl.setFocusable(false);
|
|
||||||
ctrl.setOpaque(false);
|
|
||||||
ctrl.setSelected(mode == HEX);
|
|
||||||
controls.add(ctrl);
|
|
||||||
|
|
||||||
// Event handler
|
|
||||||
ctrl.addItemListener(e->{
|
|
||||||
if (e.getStateChange() == ItemEvent.SELECTED) setMode(mode); });
|
|
||||||
|
|
||||||
// Configure expansion area
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.NORTHWEST;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 4, 0, 0);
|
|
||||||
expansion.add(ctrl, gbc);
|
|
||||||
|
|
||||||
return ctrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a text box to the expansion area
|
|
||||||
private void addTextBox(String name, int bit, int width, boolean readOnly,
|
|
||||||
boolean hex) {
|
|
||||||
int mask = (1 << width) - 1;
|
|
||||||
|
|
||||||
// Configure control
|
|
||||||
var ctrl = new JTextField();
|
|
||||||
ctrl.putClientProperty("bit", bit);
|
|
||||||
ctrl.putClientProperty("digits",
|
|
||||||
Integer.toString(mask, hex ? 16 : 10).length());
|
|
||||||
ctrl.putClientProperty("hex", hex);
|
|
||||||
ctrl.putClientProperty("width", width);
|
|
||||||
ctrl.setBorder(null);
|
|
||||||
ctrl.setEnabled(!readOnly);
|
|
||||||
ctrl.setOpaque(false);
|
|
||||||
controls.add(ctrl);
|
|
||||||
|
|
||||||
// Event handlers
|
|
||||||
ctrl.addActionListener(e->parent.requestFocus());
|
|
||||||
ctrl.addFocusListener(Util.onFocus(null, e->{
|
|
||||||
int val = value >> bit & mask;
|
|
||||||
try { val = Integer.parseInt(ctrl.getText(), hex ? 16 : 10); }
|
|
||||||
catch (Exception x) { }
|
|
||||||
setValue(value & ~(mask << bit) | (val & mask) << bit);
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Configure expansion area
|
|
||||||
var label = new JLabel(name);
|
|
||||||
label.setEnabled(!readOnly);
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.anchor = GridBagConstraints.NORTHWEST;
|
|
||||||
gbc.insets = new Insets(0, 4, 0, 4);
|
|
||||||
expansion.add(label, gbc);
|
|
||||||
gbc = new GridBagConstraints();
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.insets = new Insets(0, 4, 0, 4);
|
|
||||||
expansion.add(ctrl , gbc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the register value
|
|
||||||
private void setValue(int value) {
|
|
||||||
parent.parent.parent.vue.setRegister(index, type != PROGRAM, value);
|
|
||||||
refresh();
|
|
||||||
if (index == Vue.PSW && type == Vue.PSW)
|
|
||||||
parent.registers.get(Vue.PC).refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,203 +0,0 @@
|
||||||
package app;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Project imports
|
|
||||||
import util.*;
|
|
||||||
import vue.*;
|
|
||||||
|
|
||||||
// List of CPU registers
|
|
||||||
class RegisterList extends JScrollPane {
|
|
||||||
|
|
||||||
// Package fields
|
|
||||||
CPUWindow parent; // Containing CPU window
|
|
||||||
HashMap<Integer, Register> registers; // Register items
|
|
||||||
|
|
||||||
// Private fields
|
|
||||||
private boolean shown; // Component has been shown
|
|
||||||
|
|
||||||
// UI components
|
|
||||||
private UPanel client; // Client area
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
RegisterList(CPUWindow parent, boolean system) {
|
|
||||||
super(VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
this.parent = parent;
|
|
||||||
registers = new HashMap<Integer, Register>();
|
|
||||||
shown = true;
|
|
||||||
|
|
||||||
// Configure client area
|
|
||||||
client = new UPanel(new GridBagLayout()) {
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
var ret = super.getPreferredSize();
|
|
||||||
if (!shown) ret.height = system ? getInitialHeight() : 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
public void paintComponent(Graphics g) {
|
|
||||||
shown = true;
|
|
||||||
super.paintComponent(g);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
client.addMouseListener(Util.onMouse(e->client.requestFocus(), null));
|
|
||||||
client.setBackground(SystemColor.window);
|
|
||||||
client.setFocusable(true);
|
|
||||||
|
|
||||||
// Initialize system registers
|
|
||||||
if (system) {
|
|
||||||
new Register(this, "PC" , Vue.PC , Vue.PC );
|
|
||||||
new Register(this, "PSW" , Vue.PSW , Vue.PSW );
|
|
||||||
new Register(this, "EIPC" , Vue.EIPC , Register.PLAIN);
|
|
||||||
new Register(this, "EIPSW", Vue.EIPSW, Vue.PSW );
|
|
||||||
new Register(this, "FEPC" , Vue.FEPC , Register.PLAIN);
|
|
||||||
new Register(this, "FEPSW", Vue.FEPSW, Vue.PSW );
|
|
||||||
new Register(this, "ECR" , Vue.ECR , Vue.ECR );
|
|
||||||
new Register(this, "ADTRE", Vue.ADTRE, Register.PLAIN);
|
|
||||||
new Register(this, "CHCW" , Vue.CHCW , Vue.CHCW );
|
|
||||||
new Register(this, "PIR" , Vue.PIR , Vue.PIR );
|
|
||||||
new Register(this, "TKCW" , Vue.TKCW , Vue.TKCW );
|
|
||||||
new Register(this, "29" , 29, Register.PLAIN);
|
|
||||||
new Register(this, "30" , 30, Register.PLAIN);
|
|
||||||
new Register(this, "31" , 31, Register.PLAIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize program registers
|
|
||||||
else for (int x = 0; x < 32; x++) {
|
|
||||||
String name = null;
|
|
||||||
switch (x) {
|
|
||||||
case Vue.GP: name = "gp"; break;
|
|
||||||
case Vue.HP: name = "hp"; break;
|
|
||||||
case Vue.LP: name = "lp"; break;
|
|
||||||
case Vue.SP: name = "sp"; break;
|
|
||||||
case Vue.TP: name = "tp"; break;
|
|
||||||
}
|
|
||||||
new Register(this, name, x, Register.PROGRAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
// List terminator
|
|
||||||
var spacer = new UPanel();
|
|
||||||
spacer.setOpaque(false);
|
|
||||||
spacer.setPreferredSize(new Dimension(0, 0));
|
|
||||||
var gbc = new GridBagConstraints();
|
|
||||||
gbc.gridheight = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
||||||
gbc.weighty = 1;
|
|
||||||
client.add(spacer, gbc);
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
shown = false;
|
|
||||||
setViewportView(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Draw the component
|
|
||||||
public void paintComponent(Graphics g) {
|
|
||||||
if (!shown) {
|
|
||||||
shown = true;
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
super.paintComponent(g);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfer focus to the client area
|
|
||||||
public void requestFocus() {
|
|
||||||
client.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recalculate layout
|
|
||||||
public void revalidate() {
|
|
||||||
if (client != null)
|
|
||||||
client.revalidate();
|
|
||||||
super.revalidate();
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a register component to the client area
|
|
||||||
void add(GridBagConstraints gbc, JComponent comp) {
|
|
||||||
client.add(comp, gbc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Associate a register with its index
|
|
||||||
void add(int index, Register register) {
|
|
||||||
registers.put(index, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply configuration settings
|
|
||||||
void configure2() {
|
|
||||||
|
|
||||||
// Configure registers
|
|
||||||
for (var reg : registers.values())
|
|
||||||
reg.configure();
|
|
||||||
|
|
||||||
// Configure component
|
|
||||||
getVerticalScrollBar().setUnitIncrement(
|
|
||||||
parent.parent.app.fntMono.metrics.getHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the display
|
|
||||||
void refresh() {
|
|
||||||
for (var reg : registers.values())
|
|
||||||
reg.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Determine the initial height upon first show
|
|
||||||
private int getInitialHeight() {
|
|
||||||
int height = 0;
|
|
||||||
var layout = (GridBagLayout) client.getLayout();
|
|
||||||
int ret = 0;
|
|
||||||
int row = 0;
|
|
||||||
|
|
||||||
// Process controls until the target row is found
|
|
||||||
for (var control : client.getComponents()) {
|
|
||||||
var ctrl = (JComponent) control;
|
|
||||||
|
|
||||||
// Track the tallest control on the row
|
|
||||||
if (ctrl.isVisible())
|
|
||||||
height = Math.max(height, ctrl.getPreferredSize().height);
|
|
||||||
|
|
||||||
// This is not the last control on the row
|
|
||||||
if (layout.getConstraints(control).gridwidth !=
|
|
||||||
GridBagConstraints.REMAINDER)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Advance to the next row
|
|
||||||
ret += height;
|
|
||||||
height = 0;
|
|
||||||
row++;
|
|
||||||
|
|
||||||
// The target row has been reached
|
|
||||||
if (row == 4)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,585 +0,0 @@
|
||||||
package util;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.util.concurrent.locks.*;
|
|
||||||
import javax.sound.sampled.*;
|
|
||||||
|
|
||||||
// Background timer using either a realtime clock or audio for timing
|
|
||||||
public class FrameTimer {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private Callback callback; // Event handler
|
|
||||||
private double rate; // Frame rate in seconds
|
|
||||||
private int source; // Timing source
|
|
||||||
private int state; // Operation state
|
|
||||||
|
|
||||||
// Audio fields
|
|
||||||
private int block; // Current byte buffer index
|
|
||||||
private byte[][] blocks; // Reusable byte buffers
|
|
||||||
private double buffer; // Buffer length in seconds
|
|
||||||
private int channels; // Number channels
|
|
||||||
private double delay; // Delay in seconds
|
|
||||||
private int frames; // Audio frames per timer frame
|
|
||||||
private SourceDataLine line; // Output line
|
|
||||||
private int sampleRate; // Rate in samples per second
|
|
||||||
private boolean written; // Samples have been written this frame
|
|
||||||
private LinkedBlockingQueue<byte[]> queue; // Sample queue
|
|
||||||
|
|
||||||
// Threading fields
|
|
||||||
private Thread audio; // Background audio processing
|
|
||||||
private CyclicBarrier cycAudio; // Synchronization with audio thread
|
|
||||||
private CyclicBarrier cycTimer; // Synchronization with timer thread
|
|
||||||
private ReentrantLock lock; // Allows callback to control the timer
|
|
||||||
private Thread timer; // Background timer processing
|
|
||||||
|
|
||||||
// Type for timer event handler
|
|
||||||
public interface Callback {
|
|
||||||
void onFrame(FrameTimer source);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Sources
|
|
||||||
public static final int CLOCK = 0;
|
|
||||||
public static final int AUDIO = 1;
|
|
||||||
|
|
||||||
// States
|
|
||||||
public static final int STOPPED = 0;
|
|
||||||
public static final int RUNNING = 1;
|
|
||||||
public static final int PAUSED = 2;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
public FrameTimer() {
|
|
||||||
buffer = 0.05;
|
|
||||||
cycAudio = new CyclicBarrier(2);
|
|
||||||
cycTimer = new CyclicBarrier(2);
|
|
||||||
channels = 2;
|
|
||||||
delay = 0.1;
|
|
||||||
lock = new ReentrantLock();
|
|
||||||
queue = new LinkedBlockingQueue<byte[]>();
|
|
||||||
rate = 1;
|
|
||||||
sampleRate = 44100;
|
|
||||||
state = STOPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Retrieve the audio buffer size
|
|
||||||
public synchronized double getBuffer() {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the number of audio channels
|
|
||||||
public synchronized int getChannels() {
|
|
||||||
return channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the audio delay
|
|
||||||
public synchronized double getDelay() {
|
|
||||||
return delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the number of audio frames per timer frame
|
|
||||||
public synchronized int getFrames() {
|
|
||||||
return audioFrames(rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the frame rate
|
|
||||||
public synchronized double getRate() {
|
|
||||||
return rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the audio sampling rate
|
|
||||||
public synchronized int getSampleRate() {
|
|
||||||
return sampleRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the timing source
|
|
||||||
public synchronized int getSource() {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the operation state
|
|
||||||
public synchronized int getState() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pause the timer
|
|
||||||
public synchronized boolean pause() {
|
|
||||||
boolean isTimer = Thread.currentThread() == timer;
|
|
||||||
|
|
||||||
// The timer thread already owns the lock
|
|
||||||
if (isTimer && lock.isHeldByCurrentThread()) {
|
|
||||||
if (state == RUNNING)
|
|
||||||
state = PAUSED;
|
|
||||||
return state == PAUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the lock
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
// Invalid state
|
|
||||||
if (state != RUNNING) {
|
|
||||||
lock.unlock();
|
|
||||||
return state == PAUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure state
|
|
||||||
state = PAUSED;
|
|
||||||
|
|
||||||
// Pause timer thread
|
|
||||||
if (!isTimer) try {
|
|
||||||
timer.interrupt();
|
|
||||||
lock.unlock();
|
|
||||||
cycTimer.await();
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume running the paused timer
|
|
||||||
public synchronized boolean resume() {
|
|
||||||
boolean isTimer = Thread.currentThread() == timer;
|
|
||||||
|
|
||||||
// The timer thread already owns the lock
|
|
||||||
if (isTimer && lock.isHeldByCurrentThread()) {
|
|
||||||
if (state == PAUSED)
|
|
||||||
state = RUNNING;
|
|
||||||
return state == RUNNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the lock
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
// Invalid state
|
|
||||||
if (state != PAUSED) {
|
|
||||||
lock.unlock();
|
|
||||||
return state == RUNNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure state
|
|
||||||
state = RUNNING;
|
|
||||||
|
|
||||||
// Resume timer thread
|
|
||||||
if (!isTimer) try {
|
|
||||||
lock.unlock();
|
|
||||||
cycTimer.await();
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the audio buffer length
|
|
||||||
public synchronized double setBuffer(double buffer) {
|
|
||||||
return this.buffer = state == STOPPED && buffer > 0 ?
|
|
||||||
buffer : this.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the callback handler
|
|
||||||
public synchronized boolean setCallback(Callback callback) {
|
|
||||||
if (state != STOPPED)
|
|
||||||
return false;
|
|
||||||
this.callback = callback;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the number of audio channels
|
|
||||||
public synchronized int setChannels(int channels) {
|
|
||||||
return this.channels = state == STOPPED && (channels - 1 & ~1) != 0 ?
|
|
||||||
channels : this.channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the audio delay
|
|
||||||
public synchronized double setDelay(double delay) {
|
|
||||||
return this.delay = state == STOPPED && delay > 0 ? delay : this.delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the frame rate
|
|
||||||
public synchronized double setRate(double rate) {
|
|
||||||
return this.rate = state == STOPPED && rate > 0 ? rate : this.rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the audio sampling rate
|
|
||||||
public synchronized int setSampleRate(int sampleRate) {
|
|
||||||
return this.sampleRate = state == STOPPED && sampleRate > 0 ?
|
|
||||||
sampleRate : this.sampleRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin timer operations
|
|
||||||
public synchronized boolean start(int source) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (source != CLOCK && source != AUDIO || state != STOPPED ||
|
|
||||||
callback == null || Thread.currentThread() == timer ||
|
|
||||||
source == AUDIO && buffer > delay) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audio processing
|
|
||||||
if (source == AUDIO) try {
|
|
||||||
|
|
||||||
// Open the output line
|
|
||||||
AudioFormat fmt =
|
|
||||||
new AudioFormat(sampleRate, 16, channels, true, false);
|
|
||||||
line = AudioSystem.getSourceDataLine(fmt);
|
|
||||||
line.open(fmt);
|
|
||||||
|
|
||||||
// Configure audio fields
|
|
||||||
frames = audioFrames(rate);
|
|
||||||
block = 0;
|
|
||||||
blocks = new byte[(int) Math.ceil(delay / rate)]
|
|
||||||
[frames * channels * 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Could not open the audio line
|
|
||||||
catch (Exception e) {
|
|
||||||
line = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure state
|
|
||||||
this.source = source;
|
|
||||||
state = RUNNING;
|
|
||||||
|
|
||||||
// Spawn and start timer thread
|
|
||||||
cycTimer.reset();
|
|
||||||
timer = new Thread(()->timer());
|
|
||||||
timer.setDaemon(true);
|
|
||||||
timer.start();
|
|
||||||
|
|
||||||
// Spawn and start audio thread
|
|
||||||
if (source == AUDIO) {
|
|
||||||
cycAudio.reset();
|
|
||||||
audio = new Thread(()->audio());
|
|
||||||
audio.setDaemon(true);
|
|
||||||
audio.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Synchronize with timer thread
|
|
||||||
try { cycTimer.await(); } catch (Exception e) { }
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End timer operations
|
|
||||||
public synchronized boolean stop() {
|
|
||||||
boolean isTimer = Thread.currentThread() == timer;
|
|
||||||
|
|
||||||
// The timer thread already owns the lock
|
|
||||||
if (isTimer && lock.isHeldByCurrentThread())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Obtain the lock
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
// Invalid state
|
|
||||||
if (state == STOPPED) {
|
|
||||||
lock.unlock();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure state
|
|
||||||
boolean paused = state == PAUSED;
|
|
||||||
state = STOPPED;
|
|
||||||
|
|
||||||
// Stop timer thread
|
|
||||||
if (!isTimer) try {
|
|
||||||
if (!paused) timer.interrupt();
|
|
||||||
lock.unlock();
|
|
||||||
if ( paused) cycTimer.await();
|
|
||||||
cycTimer.await();
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write audio samples as bytes to output
|
|
||||||
public boolean write(byte[] samples, int offset) {
|
|
||||||
int size = frames * channels * 2;
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (Thread.currentThread() != timer || state == STOPPED || written ||
|
|
||||||
samples == null || offset < 0 || samples.length < offset + size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Add a new sample block to the queue
|
|
||||||
block = (block + 1) % blocks.length;
|
|
||||||
byte[] block = blocks[this.block];
|
|
||||||
System.arraycopy(samples, offset, block, 0, size);
|
|
||||||
queue.offer(block);
|
|
||||||
return written = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write audio samples as shorts to output
|
|
||||||
public boolean write(short[] samples, int offset) {
|
|
||||||
int size = frames * channels;
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (Thread.currentThread() != timer || state == STOPPED || written ||
|
|
||||||
samples == null || offset < 0 || samples.length < offset + size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Encode the samples as bytes
|
|
||||||
block = (block + 1) % blocks.length;
|
|
||||||
byte[] block = blocks[this.block];
|
|
||||||
for (int src = 0, dest = 0; src < size; src++) {
|
|
||||||
short sample = samples[offset + src];
|
|
||||||
block[dest++] = (byte) sample;
|
|
||||||
block[dest++] = (byte) (sample >> 8);
|
|
||||||
}
|
|
||||||
queue.offer(block);
|
|
||||||
return written = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write audio samples as floats to output (range -1 to +1)
|
|
||||||
public boolean write(float[] samples, int offset) {
|
|
||||||
int size = frames * channels;
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (Thread.currentThread() != timer || state == STOPPED || written ||
|
|
||||||
samples == null || offset < 0 || samples.length < offset + size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Encode the samples as bytes
|
|
||||||
block = (block + 1) % blocks.length;
|
|
||||||
byte[] block = blocks[this.block];
|
|
||||||
for (int src = 0, dest = 0; src < size; src++) {
|
|
||||||
short sample = (short) Math.round(32767 *
|
|
||||||
Math.min(1, Math.max(-1, samples[offset + src])) );
|
|
||||||
block[dest++] = (byte) sample;
|
|
||||||
block[dest++] = (byte) (sample >> 8);
|
|
||||||
}
|
|
||||||
queue.offer(block);
|
|
||||||
return written = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methds //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Calculate the number of audio sampling frames in some number of seconds
|
|
||||||
private int audioFrames(double seconds) {
|
|
||||||
return Math.max(1, (int) Math.round(seconds * sampleRate));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handler for pause operations -- invoked by timer thread
|
|
||||||
private long onPause(long reference, boolean isCallback) {
|
|
||||||
|
|
||||||
// Track the current time
|
|
||||||
if (source == CLOCK)
|
|
||||||
reference = System.nanoTime() - reference;
|
|
||||||
|
|
||||||
// Pause audio thread
|
|
||||||
else try {
|
|
||||||
audio.interrupt();
|
|
||||||
line.stop();
|
|
||||||
cycAudio.await();
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
// Synchronization
|
|
||||||
try {
|
|
||||||
if (!isCallback)
|
|
||||||
cycTimer.await(); // Synchronize with invoking thread
|
|
||||||
else lock.unlock();
|
|
||||||
cycTimer.await(); // Wait for resume() or stop()
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
// Calculate a new reference time
|
|
||||||
if (source == CLOCK)
|
|
||||||
reference = System.nanoTime() - reference;
|
|
||||||
|
|
||||||
// Unpause audio thread
|
|
||||||
else try { cycAudio.await(); } catch (Exception e) { }
|
|
||||||
|
|
||||||
return reference;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handler for stop operations -- invoked by timer thread
|
|
||||||
private int onStop(boolean paused, boolean isCallback) {
|
|
||||||
|
|
||||||
// Stop the audio thread
|
|
||||||
if (source == AUDIO) try {
|
|
||||||
audio.interrupt();
|
|
||||||
line.stop();
|
|
||||||
cycAudio.await();
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
// Synchronization
|
|
||||||
try {
|
|
||||||
if (!isCallback || paused)
|
|
||||||
cycTimer.await(); // Synchronize with invoking thread
|
|
||||||
else lock.unlock();
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
blocks = null;
|
|
||||||
timer = null;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Thread Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Audio thread entry point
|
|
||||||
private void audio() {
|
|
||||||
|
|
||||||
// Synchronize with timer thread
|
|
||||||
try { cycAudio.await(); } catch (Exception e) { }
|
|
||||||
|
|
||||||
// Initialize working variables
|
|
||||||
byte[] block = new byte[audioFrames(delay ) * channels * 2];
|
|
||||||
byte[] buffer = new byte[audioFrames(this.buffer) * channels * 2];
|
|
||||||
int blockPos = 0;
|
|
||||||
int bufferPos = -buffer.length; // Less than 0 means not full
|
|
||||||
|
|
||||||
// Audio processing
|
|
||||||
line.start();
|
|
||||||
for (;;) {
|
|
||||||
|
|
||||||
// Fill the buffer with samples, blocking until full
|
|
||||||
while (bufferPos < 0) {
|
|
||||||
|
|
||||||
// Load bytes from the current block
|
|
||||||
if (blockPos < block.length) {
|
|
||||||
int size = Math.min(block.length - blockPos, -bufferPos);
|
|
||||||
System.arraycopy(block, blockPos, buffer,
|
|
||||||
bufferPos + buffer.length, size);
|
|
||||||
blockPos += size;
|
|
||||||
bufferPos += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch a new sample block, blocking until one is available
|
|
||||||
else try {
|
|
||||||
block = queue.take();
|
|
||||||
blockPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The timer state has changed
|
|
||||||
catch (Exception e) {
|
|
||||||
audio.interrupt(); // take() clears interrupt status
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send samples to the output, blocking until sent
|
|
||||||
if (!audio.isInterrupted()) {
|
|
||||||
bufferPos +=
|
|
||||||
line.write(buffer, bufferPos, buffer.length - bufferPos);
|
|
||||||
if (bufferPos == buffer.length)
|
|
||||||
bufferPos = -buffer.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for changes to the timer state
|
|
||||||
if (state == RUNNING)
|
|
||||||
continue;
|
|
||||||
Thread.interrupted();
|
|
||||||
|
|
||||||
// Timer has paused
|
|
||||||
if (state == PAUSED) try {
|
|
||||||
cycAudio.await(); // Synchronize with timer thread
|
|
||||||
cycAudio.await(); // Wait for resume() or stop()
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
// Timer has stopped
|
|
||||||
if (state == STOPPED) {
|
|
||||||
try { line.close(); } catch (Exception e) { }
|
|
||||||
try { cycAudio.await(); } catch (Exception e) { }
|
|
||||||
audio = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume playback
|
|
||||||
line.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timer thread entry point
|
|
||||||
private int timer() {
|
|
||||||
|
|
||||||
// Synchronize with other threads
|
|
||||||
try {
|
|
||||||
if (source == AUDIO)
|
|
||||||
cycAudio.await(); // Synchronize with audio thread
|
|
||||||
cycTimer.await(); // Synchronize with parent thread
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
// Initialize working variables
|
|
||||||
byte[] empty = new byte[frames * channels * 2];
|
|
||||||
long reference = source == AUDIO ? 0 : System.nanoTime();
|
|
||||||
long target = source == AUDIO ? audioFrames(rate) :
|
|
||||||
Math.max(1, (long) Math.round(rate * 1000000000L));
|
|
||||||
|
|
||||||
// Timer processing
|
|
||||||
for (boolean first = true;; first = false) {
|
|
||||||
long current = source == CLOCK ? System.nanoTime() :
|
|
||||||
line.getLongFramePosition();
|
|
||||||
long remain = target - current + reference;
|
|
||||||
|
|
||||||
// Processing on all frames but the first
|
|
||||||
if (!first) {
|
|
||||||
|
|
||||||
// Wait until the next frame interval
|
|
||||||
if (remain > 0) try {
|
|
||||||
if (source == AUDIO)
|
|
||||||
remain = remain * 1000000000L / sampleRate;
|
|
||||||
remain = Math.max(1000000, remain);
|
|
||||||
Thread.sleep(remain / 1000000, (int) (remain % 1000000));
|
|
||||||
continue;
|
|
||||||
} catch (Exception e) { timer.interrupt(); }
|
|
||||||
|
|
||||||
// Another thread configured the timer state
|
|
||||||
if (Thread.interrupted()) {
|
|
||||||
if (state == PAUSED)
|
|
||||||
reference = onPause(reference, false);
|
|
||||||
if (state == STOPPED)
|
|
||||||
return onStop(false, false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke the event callback
|
|
||||||
written = false;
|
|
||||||
callback.onFrame(this);
|
|
||||||
if (source == AUDIO && !written)
|
|
||||||
queue.offer(empty);
|
|
||||||
|
|
||||||
// The callback configured the timer state
|
|
||||||
if (lock.isHeldByCurrentThread()) {
|
|
||||||
boolean paused = state == PAUSED;
|
|
||||||
if (state == PAUSED)
|
|
||||||
reference = onPause(reference, true);
|
|
||||||
if (state == STOPPED)
|
|
||||||
return onStop(paused, true);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Track processed frame time
|
|
||||||
reference = current + remain;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,249 +0,0 @@
|
||||||
package util;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
// Little-endian implementation of DataInputStream
|
|
||||||
public class LEDataInputStream extends FilterInputStream {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private DataInputStream data; // Data-decoding stream
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
public LEDataInputStream(InputStream stream) {
|
|
||||||
super(stream = stream instanceof LEDataInputStream ?
|
|
||||||
((LEDataInputStream) stream).in : stream);
|
|
||||||
data = stream instanceof DataInputStream ?
|
|
||||||
(DataInputStream) stream : new DataInputStream(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Byte array constructor
|
|
||||||
public LEDataInputStream(byte[] data) {
|
|
||||||
this(new ByteArrayInputStream(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Reads a boolean from the underlying input stream
|
|
||||||
public boolean readBoolean() throws IOException {
|
|
||||||
return data.readByte() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of booleans from the underlying input stream
|
|
||||||
public boolean[] readBooleans(int count) throws IOException {
|
|
||||||
return readBooleans(new boolean[count], 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of booleans from the underlying input stream
|
|
||||||
public boolean[] readBooleans(boolean[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
v[offset + x] = readBoolean();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a byte from the underlying input stream
|
|
||||||
public byte readByte() throws IOException {
|
|
||||||
return data.readByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of bytes from the underlying input stream
|
|
||||||
public byte[] readBytes(int count) throws IOException {
|
|
||||||
return readBytes(new byte[count], 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of bytes from the underlying input stream
|
|
||||||
public byte[] readBytes(byte[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
data.read(v, offset, length);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a character from the underlying input stream
|
|
||||||
public char readChar() throws IOException {
|
|
||||||
return (char) Short.reverseBytes(data.readShort());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of characters from the underlying input stream
|
|
||||||
public char[] readChars(int count) throws IOException {
|
|
||||||
return readChars(new char[count], 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of characters from the underlying input stream
|
|
||||||
public char[] readChars(char[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
v[offset + x] = readChar();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a double from the underlying input stream
|
|
||||||
public double readDouble() throws IOException {
|
|
||||||
return readDouble(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a double from the underlying input stream
|
|
||||||
public double readDouble(boolean finite) throws IOException {
|
|
||||||
long bits = readLong();
|
|
||||||
double ret = Double.longBitsToDouble(bits);
|
|
||||||
if (finite && !Double.isFinite(ret)) throw new RuntimeException(
|
|
||||||
String.format("Non-finite double value 0x%016X", bits));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of doubles from the underlying input stream
|
|
||||||
public double[] readDoubles(int count) throws IOException {
|
|
||||||
return readDoubles(new double[count], 0, count, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of doubles from the underlying input stream
|
|
||||||
public double[] readDoubles(int count, boolean finite) throws IOException {
|
|
||||||
return readDoubles(new double[count], 0, count, finite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of doubles from the underlying input stream
|
|
||||||
public double[] readDoubles(double[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
return readDoubles(v, offset, length, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of doubles from the underlying input stream
|
|
||||||
public double[] readDoubles(double[] v, int offset, int length,
|
|
||||||
boolean finite) throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
v[offset + x] = readDouble(finite);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a float from the underlying input stream
|
|
||||||
public float readFloat() throws IOException {
|
|
||||||
return readFloat(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a float from the underlying input stream
|
|
||||||
public float readFloat(boolean finite) throws IOException {
|
|
||||||
int bits = readInt();
|
|
||||||
float ret = Float.intBitsToFloat(bits);
|
|
||||||
if (finite && !Float.isFinite(ret)) throw new RuntimeException(
|
|
||||||
String.format("Non-finite float value 0x%08X", bits));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of floats from the underlying input stream
|
|
||||||
public float[] readFloats(int count) throws IOException {
|
|
||||||
return readFloats(new float[count], 0, count, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of floats from the underlying input stream
|
|
||||||
public float[] readFloats(int count, boolean finite) throws IOException {
|
|
||||||
return readFloats(new float[count], 0, count, finite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of floats from the underlying input stream
|
|
||||||
public float[] readFloats(float[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
return readFloats(v, offset, length, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of floats from the underlying input stream
|
|
||||||
public float[] readFloats(float[] v, int offset, int length,
|
|
||||||
boolean finite) throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
v[offset + x] = readFloat(finite);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an int from the underlying input stream
|
|
||||||
public int readInt() throws IOException {
|
|
||||||
return Integer.reverseBytes(data.readInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of ints from the underlying input stream
|
|
||||||
public int[] readInts(int count) throws IOException {
|
|
||||||
return readInts(new int[count], 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of ints from the underlying input stream
|
|
||||||
public int[] readInts(int[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
v[offset + x] = readInt();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a long from the underlying input stream
|
|
||||||
public long readLong() throws IOException {
|
|
||||||
return Long.reverseBytes(data.readLong());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of longs from the underlying input stream
|
|
||||||
public long[] readLongs(int count) throws IOException {
|
|
||||||
return readLongs(new long[count], 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of longs from the underlying input stream
|
|
||||||
public long[] readLongs(long[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
v[offset + x] = readLong();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a 24-bit integer from the underlying input stream
|
|
||||||
public int readMiddle() throws IOException {
|
|
||||||
int v = readShort() & 0xFFFF;
|
|
||||||
return readByte() << 16 | v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of 24-bit integers from the underlying input stream
|
|
||||||
public int[] readMiddles(int count) throws IOException {
|
|
||||||
return readMiddles(new int[count], 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of 24-bit integers from the underlying input stream
|
|
||||||
public int[] readMiddles(int[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
v[offset + x] = readMiddle();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads a short from the underlying input stream
|
|
||||||
public short readShort() throws IOException {
|
|
||||||
return Short.reverseBytes(data.readShort());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of shorts from the underlying input stream
|
|
||||||
public short[] readShorts(int count) throws IOException {
|
|
||||||
return readShorts(new short[count], 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads an array of shorts from the underlying input stream
|
|
||||||
public short[] readShorts(short[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
v[offset + x] = readShort();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads from the stream in a modified UTF-8 string
|
|
||||||
public String readUTF() throws IOException {
|
|
||||||
return data.readUTF();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advances forward in the stream some number of bytes
|
|
||||||
public int skipBytes(int n) throws IOException {
|
|
||||||
return data.skipBytes(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,218 +0,0 @@
|
||||||
package util;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.*;
|
|
||||||
|
|
||||||
// Little-endian implementation of DataOutputStream
|
|
||||||
public class LEDataOutputStream extends FilterOutputStream {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private DataOutputStream data; // Data-encoding stream
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
public LEDataOutputStream() {
|
|
||||||
this(new ByteArrayOutputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stream constructor
|
|
||||||
public LEDataOutputStream(OutputStream stream) {
|
|
||||||
super(stream = stream instanceof LEDataOutputStream ?
|
|
||||||
((LEDataOutputStream) stream).out : stream);
|
|
||||||
data = stream instanceof DataOutputStream ?
|
|
||||||
(DataOutputStream) stream : new DataOutputStream(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Returns the current value of the underlying buffer
|
|
||||||
public int size() {
|
|
||||||
return out instanceof ByteArrayOutputStream ?
|
|
||||||
((ByteArrayOutputStream) out).size() : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a byte array containing this stream's data
|
|
||||||
public byte[] toByteArray() throws IOException {
|
|
||||||
return out instanceof ByteArrayOutputStream ?
|
|
||||||
((ByteArrayOutputStream) out).toByteArray() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a boolean to the underlying output stream as a 1-byte value
|
|
||||||
public void writeBoolean(boolean v) throws IOException {
|
|
||||||
data.writeBoolean(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of booleans to the underlying output stream
|
|
||||||
public void writeBooleans(boolean[] v) throws IOException {
|
|
||||||
writeBooleans(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of booleans to the underlying output stream
|
|
||||||
public void writeBooleans(boolean[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
writeBoolean(v[offset + x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes out a byte to the underlying output stream as a 1-byte value
|
|
||||||
public void writeByte(int v) throws IOException {
|
|
||||||
data.writeByte(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes out the string to the underlying output stream
|
|
||||||
public void writeBytes(String s) throws IOException {
|
|
||||||
data.writeBytes(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of bytes to the underlying output stream
|
|
||||||
public void writeBytes(byte[] v) throws IOException {
|
|
||||||
writeBytes(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of bytes to the underlying output stream
|
|
||||||
public void writeBytes(byte[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
data.write(v, offset, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a character to the underlying output stream as a 2-byte value
|
|
||||||
public void writeChar(int v) throws IOException {
|
|
||||||
data.writeChar(Short.reverseBytes((short) v));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a string to the underlying output stream
|
|
||||||
public void writeChars(String s) throws IOException {
|
|
||||||
writeChars(s.toCharArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of characters to the underlying output stream
|
|
||||||
public void writeChars(char[] v) throws IOException {
|
|
||||||
writeChars(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of characters to the underlying output stream
|
|
||||||
public void writeChars(char[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
writeChar(v[offset + x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts the double argument to a long using doubleToLongBits
|
|
||||||
public void writeDouble(double v) throws IOException {
|
|
||||||
data.writeLong(Long.reverseBytes(Double.doubleToLongBits(v)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of doubles to the underlying output stream
|
|
||||||
public void writeDoubles(double[] v) throws IOException {
|
|
||||||
writeDoubles(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of doubles to the underlying output stream
|
|
||||||
public void writeDoubles(double[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
writeDouble(v[offset + x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts the float argument to an int using floatToIntBits
|
|
||||||
public void writeFloat(float v) throws IOException {
|
|
||||||
data.writeInt(Integer.reverseBytes(Float.floatToIntBits(v)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of floats to the underlying output stream
|
|
||||||
public void writeFloats(float[] v) throws IOException {
|
|
||||||
writeFloats(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of floats to the underlying output stream
|
|
||||||
public void writeFloats(float[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
writeFloat(v[offset + x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an int to the underlying output stream as four bytes
|
|
||||||
public void writeInt(int v) throws IOException {
|
|
||||||
data.writeInt(Integer.reverseBytes(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of ints to the underlying output stream
|
|
||||||
public void writeInts(int[] v) throws IOException {
|
|
||||||
writeInts(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of ints to the underlying output stream
|
|
||||||
public void writeInts(int[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
writeInt(v[offset + x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an int to the underlying output stream as three bytes
|
|
||||||
public void writeMiddle(int v) throws IOException {
|
|
||||||
writeShort((short) v );
|
|
||||||
writeByte ((byte ) (v >> 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of 24-bit integers to the underlying output stream
|
|
||||||
public void writeMiddles(int[] v) throws IOException {
|
|
||||||
writeMiddles(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of 24-bit integers to the underlying output stream
|
|
||||||
public void writeMiddles(int[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
writeMiddle(v[offset + x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a long to the underlying output stream as eight bytes
|
|
||||||
public void writeLong(long v) throws IOException {
|
|
||||||
data.writeLong(Long.reverseBytes(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of longs to the underlying output stream
|
|
||||||
public void writeLong(long[] v) throws IOException {
|
|
||||||
writeLongs(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of longs to the underlying output stream
|
|
||||||
public void writeLongs(long[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
writeLong(v[offset + x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a short to the underlying output stream as two bytes
|
|
||||||
public void writeShort(int v) throws IOException {
|
|
||||||
data.writeShort(Short.reverseBytes((short) v));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of shorts to the underlying output stream
|
|
||||||
public void writeShorts(short[] v) throws IOException {
|
|
||||||
writeShorts(v, 0, v.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes an array of shorts to the underlying output stream
|
|
||||||
public void writeShorts(short[] v, int offset, int length)
|
|
||||||
throws IOException {
|
|
||||||
for (int x = 0; x < length; x++)
|
|
||||||
writeShort(v[offset + x]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes a string to the underlying output stream using modified UTF-8
|
|
||||||
public void writeUTF(String str) throws IOException {
|
|
||||||
data.writeUTF(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,538 +0,0 @@
|
||||||
package util;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.border.*;
|
|
||||||
import javax.swing.text.*;
|
|
||||||
|
|
||||||
// UI display text manager
|
|
||||||
public class Localizer {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private HashMap<Object, Control> controls; // Control mapping
|
|
||||||
private Locale locale; // Current message store
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Class reference for JComboBox<String>
|
|
||||||
JComboBox<String> JCOMBOBOX = new JComboBox<String>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Classes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Control settings
|
|
||||||
private static class Control {
|
|
||||||
String key; // Single-string dictionary key
|
|
||||||
String[] keys; // Multiple-string dictionary key
|
|
||||||
String tipKey; // Tooltip dictionary key
|
|
||||||
HashMap<String, String> tags; // Message overrides
|
|
||||||
Control(String tipKey) {
|
|
||||||
tags = new HashMap<String, String>();
|
|
||||||
this.tipKey = tipKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Locale container
|
|
||||||
public static class Locale implements Comparable<Locale> {
|
|
||||||
|
|
||||||
// Public fields
|
|
||||||
public final String id; // Unique identifier
|
|
||||||
public final String name; // Display name
|
|
||||||
|
|
||||||
// Private fields
|
|
||||||
private HashMap<String, String> messages; // Message dictionary
|
|
||||||
|
|
||||||
// Constructor
|
|
||||||
private Locale(HashMap<String, String> messages) {
|
|
||||||
id = messages.get("locale.id");
|
|
||||||
this.messages = messages;
|
|
||||||
name = messages.get("locale.name");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparator
|
|
||||||
public int compareTo(Locale o) {
|
|
||||||
return id.compareTo(o.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Represent this object as a string
|
|
||||||
public String toString() {
|
|
||||||
return id + " - " + name;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Static Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Parse a text file to produce a Locale object
|
|
||||||
public static Locale parse(String text) {
|
|
||||||
var chars = text.replaceAll("\\r\\n?", "\n").toCharArray();
|
|
||||||
var ret = new HashMap<String, String>(); // Output dictionary
|
|
||||||
int start = 0; // Position of first character in key or value
|
|
||||||
var stack = new Stack<String>(); // Nested key chain
|
|
||||||
int state = 0; // Current parsing context
|
|
||||||
|
|
||||||
// Process all characters
|
|
||||||
for (int x = 0, line = 1, col = 1; x < chars.length; x++, col++) {
|
|
||||||
char c = chars[x];
|
|
||||||
boolean end = x == chars.length - 1;
|
|
||||||
String pos = line + ":" + col + ": ";
|
|
||||||
boolean white = c == ' ' || c == '\t';
|
|
||||||
|
|
||||||
// Processing for newline
|
|
||||||
if (c == '\n') {
|
|
||||||
col = 0;
|
|
||||||
line++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comment
|
|
||||||
if (state == -1) {
|
|
||||||
if (c == '\n' || end)
|
|
||||||
state = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pre-key
|
|
||||||
else if (state == 0) {
|
|
||||||
|
|
||||||
// Ignore leading whitespace
|
|
||||||
if (white)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// The line is a comment
|
|
||||||
if (c == '#') {
|
|
||||||
state = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of input has been reached
|
|
||||||
if (end)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The line is empty
|
|
||||||
if (c == '\n')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Proceed to key
|
|
||||||
start = x;
|
|
||||||
state = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key
|
|
||||||
else if (state == 1) {
|
|
||||||
|
|
||||||
// Any non-whitespace character is valid in a key
|
|
||||||
if (!white && c != '\n' && !end)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Produce the key as a string
|
|
||||||
String key = new String(chars, start, x - start).trim();
|
|
||||||
|
|
||||||
// Close a key group
|
|
||||||
if (key.equals("}")) {
|
|
||||||
|
|
||||||
// Nesting error
|
|
||||||
if (stack.size() == 0) throw new RuntimeException(
|
|
||||||
pos + "Unexpected '}'");
|
|
||||||
|
|
||||||
// Syntax error
|
|
||||||
outer: for (int y = x; y < chars.length; y++) {
|
|
||||||
char h = chars[y];
|
|
||||||
if (h == '\n') break;
|
|
||||||
if (h != ' ' && h != '\t') throw new RuntimeException(
|
|
||||||
pos + "Newline expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proceed to key
|
|
||||||
state = 0;
|
|
||||||
stack.pop();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Curly braces are not valid in keys
|
|
||||||
if (key.contains("{") || key.contains("}"))
|
|
||||||
throw new RuntimeException(
|
|
||||||
line + ": Curly braces are not allowed in keys");
|
|
||||||
|
|
||||||
// Proceed to interim
|
|
||||||
stack.push(key);
|
|
||||||
state = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post-key, pre-value
|
|
||||||
if (state == 2) {
|
|
||||||
|
|
||||||
// Ignore any whitespace between key and value
|
|
||||||
if (white)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// No value is present
|
|
||||||
if (c == '\n') throw new RuntimeException(
|
|
||||||
pos + "Unexpected newline");
|
|
||||||
if (end) throw new RuntimeException(
|
|
||||||
pos + "Unexpected end of input");
|
|
||||||
|
|
||||||
// Proceed to value
|
|
||||||
start = x;
|
|
||||||
state = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value
|
|
||||||
if (state == 3) {
|
|
||||||
|
|
||||||
// Escape sequence
|
|
||||||
if (c == '\\') {
|
|
||||||
|
|
||||||
// EOF
|
|
||||||
if (x == chars.length - 1)
|
|
||||||
throw new RuntimeException(
|
|
||||||
pos + "Unexpected end of input");
|
|
||||||
|
|
||||||
// Cannot escape a newline
|
|
||||||
if (chars[x + 1] == '\n')
|
|
||||||
throw new RuntimeException(
|
|
||||||
pos + "Unexpected newline");
|
|
||||||
|
|
||||||
// Skip the next character
|
|
||||||
x++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The end of the value has not yet been reached
|
|
||||||
if (c != '\n' && !end)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Produce the value as a string
|
|
||||||
if (end)
|
|
||||||
x++;
|
|
||||||
String value = new String(chars, start, x - start).trim();
|
|
||||||
state = 0;
|
|
||||||
|
|
||||||
// Open a key group
|
|
||||||
if (value.equals("{")) {
|
|
||||||
state = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for nesting errors
|
|
||||||
int depth = 0;
|
|
||||||
for (int y = start; y < x; y++) {
|
|
||||||
switch (chars[y]) {
|
|
||||||
case '\\': y++; continue;
|
|
||||||
case '{' : depth++; continue;
|
|
||||||
case '}' : if (--depth == -1)
|
|
||||||
throw new RuntimeException(
|
|
||||||
(line - 1) + ": Unexpected '}'"
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (depth != 0) throw new RuntimeException(
|
|
||||||
pos + "'}' expected");
|
|
||||||
|
|
||||||
// Produce the full key as a string
|
|
||||||
var pkey = new StringBuilder();
|
|
||||||
for (String item : stack)
|
|
||||||
pkey.append((pkey.length() != 0 ? "." : "") + item);
|
|
||||||
String key = pkey.toString();
|
|
||||||
|
|
||||||
// Check for duplicate keys
|
|
||||||
String lkey = key.toLowerCase();
|
|
||||||
if (ret.get(lkey) != null) throw new RuntimeException(
|
|
||||||
(line-1)+ ": Key '" + key + "' has already been defined.");
|
|
||||||
|
|
||||||
// Add the pair to the dictionary
|
|
||||||
ret.put(lkey, value);
|
|
||||||
stack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform post-processing error checks
|
|
||||||
if (state != 0 || !stack.empty()) throw new RuntimeException(
|
|
||||||
"Unexpected end of input");
|
|
||||||
if (!ret.containsKey("locale.id")) throw new RuntimeException(
|
|
||||||
"Required key not found: 'locale.id'");
|
|
||||||
if (!ret.containsKey("locale.name")) throw new RuntimeException(
|
|
||||||
"Required key not found: 'locale.name'");
|
|
||||||
ret.put("null", "");
|
|
||||||
return new Locale(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
public Localizer() {
|
|
||||||
controls = new HashMap<Object, Control>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parsing constructor
|
|
||||||
public Localizer(String text) {
|
|
||||||
this();
|
|
||||||
setLocale(parse(text));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a control to the collection
|
|
||||||
public boolean add(Object control, Object key) {
|
|
||||||
return add(control, key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a control with a tooltip to the collection
|
|
||||||
public boolean add(Object control, Object key, String tipKey) {
|
|
||||||
var ctrl = controls.get(control);
|
|
||||||
if (ctrl == null)
|
|
||||||
ctrl = new Control(tipKey);
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (control == null || key == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Control takes a single string
|
|
||||||
if (key instanceof String) {
|
|
||||||
|
|
||||||
// Type validation
|
|
||||||
if (!(
|
|
||||||
control instanceof AbstractButton ||
|
|
||||||
control instanceof JFrame ||
|
|
||||||
control instanceof JInternalFrame ||
|
|
||||||
control instanceof JLabel ||
|
|
||||||
control instanceof JPanel || // TitledBorder
|
|
||||||
control instanceof JTextComponent
|
|
||||||
)) return false;
|
|
||||||
|
|
||||||
// Configure key
|
|
||||||
ctrl.key = (String) key;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Control takes an array of strings
|
|
||||||
else if (key instanceof String[]) {
|
|
||||||
|
|
||||||
// Type validation
|
|
||||||
if (!(
|
|
||||||
JCOMBOBOX.getClass().isAssignableFrom(control.getClass())
|
|
||||||
)) return false;
|
|
||||||
|
|
||||||
// Configure keys
|
|
||||||
String[] keys = (String[]) key;
|
|
||||||
ctrl.keys = new String[keys.length];
|
|
||||||
System.arraycopy(keys, 0, ctrl.keys, 0, keys.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invalid control type
|
|
||||||
else return false;
|
|
||||||
|
|
||||||
// Add the control to the collection
|
|
||||||
controls.put(control, ctrl);
|
|
||||||
update(control);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove all controls from being managed
|
|
||||||
public void clearControls() {
|
|
||||||
controls.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate the message for a given key
|
|
||||||
public String get(String key) {
|
|
||||||
return key == null ? null : evaluate(null, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the currently loaded locale
|
|
||||||
public Locale getLocale() {
|
|
||||||
return locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure a control tag
|
|
||||||
public String put(Object control, String key, String value) {
|
|
||||||
var ctrl = controls.get(control);
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (ctrl == null || key == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Update the control's tags
|
|
||||||
key = key.toLowerCase();
|
|
||||||
String ret = value == null ?
|
|
||||||
ctrl.tags.remove(key) :
|
|
||||||
ctrl.tags.put(key, value)
|
|
||||||
;
|
|
||||||
|
|
||||||
// Refresh the text on the control
|
|
||||||
update(control);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a control from the collection
|
|
||||||
public boolean remove(Object control) {
|
|
||||||
return controls.remove(control) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify a message dictionary
|
|
||||||
public void setLocale(Locale locale) {
|
|
||||||
this.locale = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Process substitutions and escapes on a message for a given key
|
|
||||||
private String evaluate(Control control, String key) {
|
|
||||||
|
|
||||||
// No locale is loaded
|
|
||||||
if (locale == null)
|
|
||||||
return key;
|
|
||||||
|
|
||||||
// Check that the key exists
|
|
||||||
String ret = locale.messages.get(key.toLowerCase());
|
|
||||||
if (ret == null)
|
|
||||||
return key;
|
|
||||||
|
|
||||||
// Perform all substitutions
|
|
||||||
outer: for (;;) {
|
|
||||||
var chars = ret.toCharArray();
|
|
||||||
int start = 0;
|
|
||||||
|
|
||||||
// Look for the first complete substitution
|
|
||||||
for (int x = 0; x < chars.length; x++) {
|
|
||||||
char c = chars[x];
|
|
||||||
|
|
||||||
// Escape sequence
|
|
||||||
if (c == '\\') {
|
|
||||||
x++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin substitution
|
|
||||||
if (c == '{')
|
|
||||||
start = x + 1;
|
|
||||||
|
|
||||||
// Substitution has not yet ended
|
|
||||||
if (c != '}')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Determine the substitution
|
|
||||||
key = new String(chars, start, x - start);
|
|
||||||
String lkey = key.toLowerCase();
|
|
||||||
String value = control == null ? null : control.tags.get(lkey);
|
|
||||||
if (value == null)
|
|
||||||
value = locale.messages.get(lkey);
|
|
||||||
if (value == null)
|
|
||||||
value = "\\{" + key + "\\}";
|
|
||||||
|
|
||||||
// Apply the substitution to the message
|
|
||||||
ret =
|
|
||||||
new String(chars, 0, start - 1) +
|
|
||||||
value +
|
|
||||||
new String(chars, x + 1, chars.length - x - 1)
|
|
||||||
;
|
|
||||||
continue outer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No further substitutions
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unescape all escape sequences
|
|
||||||
var chars = ret.toCharArray();
|
|
||||||
int length = 0;
|
|
||||||
for (int x = 0; x < chars.length; x++, length++) {
|
|
||||||
char c = chars[x];
|
|
||||||
if (c == '\\') switch (c = chars[++x]) {
|
|
||||||
case 'n': c = '\n'; break;
|
|
||||||
case 't': c = '\t'; break;
|
|
||||||
}
|
|
||||||
chars[length] = c;
|
|
||||||
}
|
|
||||||
return new String(chars, 0, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the text for all controls
|
|
||||||
private void update() {
|
|
||||||
for (var control : controls.keySet())
|
|
||||||
update(control);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the text for a control
|
|
||||||
private void update(Object control) {
|
|
||||||
var ctrl = controls.get(control);
|
|
||||||
String[] keys = ctrl.key==null ? ctrl.keys : new String[]{ctrl.key};
|
|
||||||
String[] values = new String[keys.length];
|
|
||||||
|
|
||||||
// Evaluate all messages
|
|
||||||
for (int x = 0; x < keys.length; x++)
|
|
||||||
values[x] = evaluate(ctrl, keys[x]);
|
|
||||||
|
|
||||||
// Update the control's text
|
|
||||||
if (control instanceof AbstractButton)
|
|
||||||
((AbstractButton) control).setText (values[0]);
|
|
||||||
if (control instanceof JFrame)
|
|
||||||
((JFrame ) control).setTitle(values[0]);
|
|
||||||
if (control instanceof JInternalFrame)
|
|
||||||
((JInternalFrame) control).setTitle(values[0]);
|
|
||||||
if (control instanceof JLabel )
|
|
||||||
((JLabel ) control).setText (values[0]);
|
|
||||||
if (control instanceof JTextComponent)
|
|
||||||
((JTextComponent) control).setText (values[0]);
|
|
||||||
|
|
||||||
// JPanel must be wrapped in a TitledBorder
|
|
||||||
if (control instanceof JPanel) {
|
|
||||||
var border = ((JPanel) control).getBorder();
|
|
||||||
if (border instanceof TitledBorder)
|
|
||||||
((TitledBorder) border).setTitle(values[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace the contents of a JComboBox without firing events
|
|
||||||
if (JCOMBOBOX.getClass().isAssignableFrom(control.getClass())) {
|
|
||||||
|
|
||||||
// The type is explicitly verified above
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
var box = (JComboBox<String>) control;
|
|
||||||
|
|
||||||
// Configure working variables
|
|
||||||
var action = box.getActionListeners();
|
|
||||||
int index = box.getSelectedIndex();
|
|
||||||
var item = box.getItemListeners();
|
|
||||||
|
|
||||||
// Remove event listeners
|
|
||||||
for (var lst : action) box.removeActionListener(lst);
|
|
||||||
for (var lst : item ) box.removeItemListener (lst);
|
|
||||||
|
|
||||||
// Update contents
|
|
||||||
box.setModel(new DefaultComboBoxModel<String>(values));
|
|
||||||
box.setSelectedIndex(index);
|
|
||||||
|
|
||||||
// Restore event listeners
|
|
||||||
for (var lst : action) box.addActionListener(lst);
|
|
||||||
for (var lst : item ) box.addItemListener (lst);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the control's tooltip text
|
|
||||||
if (control instanceof JComponent)
|
|
||||||
((JComponent) control).setToolTipText(
|
|
||||||
ctrl.tipKey == null ? null : evaluate(ctrl, ctrl.tipKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
package util;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Wrapper around JComboBox<String> to enforce desired behaviors
|
|
||||||
public class UComboBox extends JComboBox<String> {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private HashMap<ActionListener, ActionListener> actionListeners;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Empty item set
|
|
||||||
private static final String[] EMPTY = new String[0];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
public UComboBox() {
|
|
||||||
this(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// List constructor
|
|
||||||
public UComboBox(String[] items) {
|
|
||||||
super();
|
|
||||||
actionListeners = new HashMap<ActionListener, ActionListener>();
|
|
||||||
setItems(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a listener to receive action events
|
|
||||||
public void addActionListener(ActionListener l) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (l == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Wrap the event listener in a guard
|
|
||||||
ActionListener L = e->{
|
|
||||||
|
|
||||||
// Search the stack trace for an invocation not from Java itself
|
|
||||||
var trace = Thread.currentThread().getStackTrace();
|
|
||||||
for (int x = 2; x < trace.length; x++)
|
|
||||||
if (trace[x].getModuleName() == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Call the event handler
|
|
||||||
l.actionPerformed(e);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Manage the collections
|
|
||||||
actionListeners.put(l, L);
|
|
||||||
super.addActionListener(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a list of the current action listeners
|
|
||||||
public ActionListener[] getActionListeners() {
|
|
||||||
return actionListeners.keySet().toArray(
|
|
||||||
new ActionListener[actionListeners.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove an action listener from the collection
|
|
||||||
public void removeActionListener(ActionListener l) {
|
|
||||||
var L = actionListeners.get(l);
|
|
||||||
if (L == null)
|
|
||||||
return;
|
|
||||||
actionListeners.remove(l);
|
|
||||||
super.removeActionListener(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the items in the list
|
|
||||||
public void setItems(String[] items) {
|
|
||||||
int index = getSelectedIndex();
|
|
||||||
setModel(new DefaultComboBoxModel<String>(
|
|
||||||
items != null ? items : EMPTY));
|
|
||||||
setSelectedIndex(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
package util;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
// Wrapper around JPanel to work around a bug in GridBagLayout
|
|
||||||
public class UPanel extends JPanel {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private HashSet<PaintListener> paintListeners;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Classes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Functional interface for paint events
|
|
||||||
public interface PaintListener {
|
|
||||||
void paint(Graphics2D g, int width, int height);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
public UPanel() {
|
|
||||||
this(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Layout manager constructor
|
|
||||||
public UPanel(LayoutManager layout) {
|
|
||||||
super(layout);
|
|
||||||
paintListeners = new HashSet<PaintListener>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Add a listener to receive paint events
|
|
||||||
public void addPaintListener(PaintListener l) {
|
|
||||||
if (l != null)
|
|
||||||
paintListeners.add(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a list of the current paint listeners
|
|
||||||
public PaintListener[] getPaintListeners() {
|
|
||||||
return paintListeners.toArray(
|
|
||||||
new PaintListener[paintListeners.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the maximum size of the component
|
|
||||||
public Dimension getMaximumSize() {
|
|
||||||
var ret = super.getMaximumSize();
|
|
||||||
return ret != null ? ret : new Dimension();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the minimum size of the component
|
|
||||||
public Dimension getMinimumSize() {
|
|
||||||
var ret = super.getMinimumSize();
|
|
||||||
return ret != null ? ret : new Dimension();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the preferred size of the component
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
var ret = super.getPreferredSize();
|
|
||||||
return ret != null ? ret : new Dimension();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the component
|
|
||||||
public void paintComponent(Graphics g) {
|
|
||||||
super.paintComponent(g);
|
|
||||||
var G = (Graphics2D) g;
|
|
||||||
int width = getWidth();
|
|
||||||
int height = getHeight();
|
|
||||||
for (var lst : paintListeners)
|
|
||||||
lst.paint(G, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a paint listener from the collection
|
|
||||||
public void removePaintListener(PaintListener l) {
|
|
||||||
paintListeners.remove(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,395 +0,0 @@
|
||||||
package util;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.awt.image.*;
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.*;
|
|
||||||
import java.nio.charset.*;
|
|
||||||
import java.nio.file.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.imageio.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.border.*;
|
|
||||||
import javax.swing.event.*;
|
|
||||||
import javax.swing.plaf.basic.*;
|
|
||||||
|
|
||||||
// General utility methods
|
|
||||||
public final class Util {
|
|
||||||
|
|
||||||
// This class cannot be instantiated
|
|
||||||
private Util() { }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Classes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Event listener interfaces
|
|
||||||
public interface OnClose { void call(WindowEvent e); }
|
|
||||||
public interface OnClose2 { void call(InternalFrameEvent e); }
|
|
||||||
public interface OnFocus { void call(FocusEvent e); }
|
|
||||||
public interface OnKey { void call(KeyEvent e); }
|
|
||||||
public interface OnMouse { void call(MouseEvent e); }
|
|
||||||
public interface OnResize { void call(ComponentEvent e); }
|
|
||||||
public interface OnVisible { void call(AncestorEvent e); }
|
|
||||||
|
|
||||||
// Data class for byte-order marks
|
|
||||||
private static class BOM {
|
|
||||||
byte[] mark;
|
|
||||||
Charset set;
|
|
||||||
BOM(byte[] m, Charset s) { mark = m; set = s; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Font metrics wrapper
|
|
||||||
public static class Font extends java.awt.Font {
|
|
||||||
public final FontMetrics metrics;
|
|
||||||
public Font(java.awt.Font font) {
|
|
||||||
super(font);
|
|
||||||
metrics = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)
|
|
||||||
.getGraphics().getFontMetrics(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Directory from which the JVM was initialized
|
|
||||||
public static final File PWD = new File(System.getProperty("user.dir"));
|
|
||||||
|
|
||||||
// Text file byte-order marks
|
|
||||||
private static final BOM[] BOMS = {
|
|
||||||
new BOM(new byte[] { -17, -69, -65 }, StandardCharsets.UTF_8 ),
|
|
||||||
new BOM(new byte[] { - 2, - 1 }, StandardCharsets.UTF_16BE),
|
|
||||||
new BOM(new byte[] { - 1, - 2 }, StandardCharsets.UTF_16LE),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Available font families
|
|
||||||
private static final String[] FONTS;
|
|
||||||
|
|
||||||
// Filesystem state manager for the current .jar (if any)
|
|
||||||
private static final FileSystem JARFS;
|
|
||||||
|
|
||||||
// Static initializer
|
|
||||||
static {
|
|
||||||
|
|
||||||
// Font families
|
|
||||||
var fonts = GraphicsEnvironment
|
|
||||||
.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
|
|
||||||
Arrays.sort(fonts, String.CASE_INSENSITIVE_ORDER);
|
|
||||||
FONTS = fonts;
|
|
||||||
|
|
||||||
// .jar filesystem
|
|
||||||
FileSystem fs = null;
|
|
||||||
try {
|
|
||||||
fs = FileSystems.newFileSystem(
|
|
||||||
new URI("jar:" + Util.class.getProtectionDomain()
|
|
||||||
.getCodeSource().getLocation().toString()),
|
|
||||||
new HashMap<String, String>(),
|
|
||||||
Util.class.getClassLoader()
|
|
||||||
);
|
|
||||||
} catch (Exception e) { }
|
|
||||||
JARFS = fs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Static Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Apply an alpha value to a Color object
|
|
||||||
public static Color alpha(Color color, float alpha) {
|
|
||||||
int a = (int) Math.round(alpha * 255);
|
|
||||||
return color == null || a < 0 || a > 255 ? null :
|
|
||||||
new Color(color.getRGB() & 0x00FFFFFF | a << 24, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blend one color into another
|
|
||||||
public static Color blend(Color front, Color back, float alpha) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (front == null || back == null ||
|
|
||||||
!Float.isFinite(alpha) || alpha < 0 || alpha > 1)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Decompose components
|
|
||||||
var colors = new Color[] { front, back };
|
|
||||||
var argb = new float[3][4];
|
|
||||||
for (int x = 0; x < 2; x++) {
|
|
||||||
int bits = colors[x].getRGB();
|
|
||||||
for (int y = 3; y >= 0; y++, bits >>= 8)
|
|
||||||
argb[x][y] = (bits & 0xFF) / 255.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine the colors
|
|
||||||
argb[2][0] = argb[0][0] + argb[1][0] * (1 - argb[0][0]);
|
|
||||||
for (int x = 1; x < 4; x++)
|
|
||||||
argb[2][x] = (
|
|
||||||
argb[0][x] * argb[0][0] +
|
|
||||||
argb[1][x] * argb[1][0] * (1 - argb[0][0])
|
|
||||||
) / argb[2][0];
|
|
||||||
|
|
||||||
// Produce the resulting Color object
|
|
||||||
int bits = 0;
|
|
||||||
for (int x = 0; x < 4; x++)
|
|
||||||
bits = bits << 8 | (int) Math.round(argb[2][x] * 255);
|
|
||||||
return new Color(bits, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a file from disk
|
|
||||||
public static byte[] fileRead(File file) {
|
|
||||||
FileInputStream stream = null;
|
|
||||||
byte[] data = null;
|
|
||||||
try {
|
|
||||||
stream = new FileInputStream(file);
|
|
||||||
data = stream.readAllBytes();
|
|
||||||
} catch (Exception e) { }
|
|
||||||
try { stream.close(); } catch (Exception e) { }
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a file, first from disk, then from .jar
|
|
||||||
public static byte[] fileRead(String filename) {
|
|
||||||
InputStream stream = null;
|
|
||||||
|
|
||||||
// Open the file on disk
|
|
||||||
try { stream = new FileInputStream(filename); }
|
|
||||||
|
|
||||||
// File on disk could not be opened, so get resource from .jar
|
|
||||||
catch (Exception e) {
|
|
||||||
stream = Util.class.getResourceAsStream("/" + filename);
|
|
||||||
if (stream == null)
|
|
||||||
return null; // Resource in .jar could not be found
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the file data into memory
|
|
||||||
byte[] data = null;
|
|
||||||
try { data = stream.readAllBytes(); } catch (Exception e) { }
|
|
||||||
try { stream.close(); } catch (Exception e) { }
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select a font family from a list, if avaiable
|
|
||||||
public static String fontFamily(String[] families) {
|
|
||||||
for (String family : families)
|
|
||||||
if (Arrays.binarySearch(FONTS, family,
|
|
||||||
String.CASE_INSENSITIVE_ORDER) >= 0)
|
|
||||||
return family;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read an image file as an icon
|
|
||||||
public static Icon iconRead(String filename) {
|
|
||||||
BufferedImage img = imageRead(filename);
|
|
||||||
return img == null ? null : new ImageIcon(img);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read an image file by filename
|
|
||||||
public static BufferedImage imageRead(String filename) {
|
|
||||||
try { return
|
|
||||||
ImageIO.read(new ByteArrayInputStream(fileRead(filename)));
|
|
||||||
} catch (Exception e) { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read an image file by handle
|
|
||||||
public static BufferedImage imageRead(File file) {
|
|
||||||
try { return imageRead(file.getAbsolutePath()); }
|
|
||||||
catch (Exception e) { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a list of files contained in a directory
|
|
||||||
// If the directory is not found on disk, looks for it in the .jar
|
|
||||||
public static String[] listFiles(String path) {
|
|
||||||
|
|
||||||
// Check for the directory on disk
|
|
||||||
var file = new File(path);
|
|
||||||
if (file.exists() && file.isDirectory())
|
|
||||||
return file.list();
|
|
||||||
|
|
||||||
// Not executing out of a .jar
|
|
||||||
if (JARFS == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Check for the directory in the .jar
|
|
||||||
try {
|
|
||||||
var list = Files.list(JARFS.getPath("/" + path)).toArray();
|
|
||||||
var ret = new String[list.length];
|
|
||||||
for (int x = 0; x < list.length; x++) {
|
|
||||||
path = "/" + ((Path) list[x]).toString();
|
|
||||||
ret[x] = path.substring(path.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
} catch (Exception e) { }
|
|
||||||
|
|
||||||
// The directory was not found
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a list of available font family names
|
|
||||||
public static String[] listFonts() {
|
|
||||||
var ret = new String[FONTS.length];
|
|
||||||
System.arraycopy(FONTS, 0, ret, 0, FONTS.length);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a WindowListener with a functional interface
|
|
||||||
public static WindowListener onClose(OnClose close) {
|
|
||||||
return new WindowListener() {
|
|
||||||
public void windowActivated (WindowEvent e) { }
|
|
||||||
public void windowClosed (WindowEvent e) { }
|
|
||||||
public void windowDeactivated(WindowEvent e) { }
|
|
||||||
public void windowDeiconified(WindowEvent e) { }
|
|
||||||
public void windowIconified (WindowEvent e) { }
|
|
||||||
public void windowOpened (WindowEvent e) { }
|
|
||||||
public void windowClosing (WindowEvent e)
|
|
||||||
{ if (close != null) close.call(e); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce an InternalFrameListener with a functional interface
|
|
||||||
public static InternalFrameListener onClose2(OnClose2 close) {
|
|
||||||
return new InternalFrameListener() {
|
|
||||||
public void internalFrameActivated (InternalFrameEvent e) { }
|
|
||||||
public void internalFrameClosed (InternalFrameEvent e) { }
|
|
||||||
public void internalFrameDeactivated(InternalFrameEvent e) { }
|
|
||||||
public void internalFrameDeiconified(InternalFrameEvent e) { }
|
|
||||||
public void internalFrameIconified (InternalFrameEvent e) { }
|
|
||||||
public void internalFrameOpened (InternalFrameEvent e) { }
|
|
||||||
public void internalFrameClosing (InternalFrameEvent e)
|
|
||||||
{ if (close != null) close.call(e); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a FocusListener with functional interfaces
|
|
||||||
public static FocusListener onFocus(OnFocus focus, OnFocus blur) {
|
|
||||||
return new FocusListener() {
|
|
||||||
public void focusGained(FocusEvent e)
|
|
||||||
{ if (focus != null) focus.call(e); }
|
|
||||||
public void focusLost (FocusEvent e)
|
|
||||||
{ if (blur != null) blur .call(e); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a KeyListener with functional interfaces
|
|
||||||
public static KeyListener onKey(OnKey down, OnKey up) {
|
|
||||||
return new KeyListener() {
|
|
||||||
public void keyTyped (KeyEvent e) { }
|
|
||||||
public void keyPressed (KeyEvent e)
|
|
||||||
{ if (down != null) down.call(e); }
|
|
||||||
public void keyReleased(KeyEvent e)
|
|
||||||
{ if (up != null) up .call(e); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a MouseMotionListener with a functional interface
|
|
||||||
public static MouseMotionListener onMouseMove(OnMouse move, OnMouse drag) {
|
|
||||||
return new MouseMotionListener() {
|
|
||||||
public void mouseMoved (MouseEvent e)
|
|
||||||
{ if (move != null) move.call(e); }
|
|
||||||
public void mouseDragged(MouseEvent e)
|
|
||||||
{ if (drag != null) drag.call(e); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a MouseListener with functional interfaces
|
|
||||||
public static MouseListener onMouse(OnMouse down, OnMouse up) {
|
|
||||||
return new MouseListener() {
|
|
||||||
public void mouseClicked (MouseEvent e) { }
|
|
||||||
public void mouseEntered (MouseEvent e) { }
|
|
||||||
public void mouseExited (MouseEvent e) { }
|
|
||||||
public void mousePressed (MouseEvent e)
|
|
||||||
{ if (down != null) down.call(e); }
|
|
||||||
public void mouseReleased(MouseEvent e)
|
|
||||||
{ if (up != null) up .call(e); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a ComponentListener with a functional interface
|
|
||||||
public static ComponentListener onResize(OnResize resize) {
|
|
||||||
return new ComponentListener() {
|
|
||||||
public void componentHidden (ComponentEvent e) { }
|
|
||||||
public void componentMoved (ComponentEvent e) { }
|
|
||||||
public void componentShown (ComponentEvent e) { }
|
|
||||||
public void componentResized(ComponentEvent e)
|
|
||||||
{ if (resize != null) resize.call(e); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce an AncestorListener using functional interfaces
|
|
||||||
public static AncestorListener onVisible(OnVisible show, OnVisible hide) {
|
|
||||||
return new AncestorListener() {
|
|
||||||
public void ancestorMoved (AncestorEvent e) { }
|
|
||||||
public void ancestorAdded (AncestorEvent e)
|
|
||||||
{ if (show != null) show.call(e); }
|
|
||||||
public void ancestorRemoved(AncestorEvent e)
|
|
||||||
{ if (hide != null) hide.call(e); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the Swing look-and-feel with the system theme
|
|
||||||
public static boolean setSystemLAF() {
|
|
||||||
try {
|
|
||||||
UIManager.setLookAndFeel(
|
|
||||||
UIManager.getSystemLookAndFeelClassName());
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a JSplitPane with an un-styled divider
|
|
||||||
public static JSplitPane splitPane(int orientation) {
|
|
||||||
var split = new JSplitPane(orientation, null, null);
|
|
||||||
split.setContinuousLayout(true);
|
|
||||||
split.setDividerSize(2);
|
|
||||||
split.setUI(new BasicSplitPaneUI() {
|
|
||||||
public BasicSplitPaneDivider createDefaultDivider() {
|
|
||||||
return new BasicSplitPaneDivider(this) {
|
|
||||||
public void setBorder(Border b) { }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
split.setBorder(null);
|
|
||||||
return split;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a text file, accounting for BOMs
|
|
||||||
public static String textRead(String filename) {
|
|
||||||
|
|
||||||
// Read the file
|
|
||||||
byte[] data = fileRead(filename);
|
|
||||||
if (data == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Configure working variables
|
|
||||||
byte[] mark = null;
|
|
||||||
Charset set = StandardCharsets.ISO_8859_1; // Default charset
|
|
||||||
|
|
||||||
// Check for a byte-order mark
|
|
||||||
outer: for (BOM bom : BOMS) {
|
|
||||||
if (data.length < bom.mark.length)
|
|
||||||
continue;
|
|
||||||
for (int x = 0; x < bom.mark.length; x++)
|
|
||||||
if (data[x] != bom.mark[x])
|
|
||||||
continue outer;
|
|
||||||
mark = bom.mark;
|
|
||||||
set = bom.set;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the byte-order mark from the data
|
|
||||||
if (mark != null) {
|
|
||||||
byte[] temp = new byte[data.length - mark.length];
|
|
||||||
System.arraycopy(data, mark.length, temp, 0, temp.length);
|
|
||||||
data = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Produce a string
|
|
||||||
return new String(data, set);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
package util;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.xml.parsers.*;
|
|
||||||
import org.w3c.dom.*;
|
|
||||||
|
|
||||||
// Utility methods for managing XML documents
|
|
||||||
public class XML {
|
|
||||||
|
|
||||||
// This class cannot be instantiated
|
|
||||||
private XML() { }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Parsing instance
|
|
||||||
private static final DocumentBuilder XML_PARSER;
|
|
||||||
|
|
||||||
// Static initializer
|
|
||||||
static {
|
|
||||||
DocumentBuilder parser = null;
|
|
||||||
try { parser =
|
|
||||||
DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
|
||||||
} catch (Exception e) { }
|
|
||||||
XML_PARSER = parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Static Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Retrieve an attribute value from an XML element
|
|
||||||
public static String attribute(Element element, String attribute) {
|
|
||||||
return element.hasAttribute(attribute) ?
|
|
||||||
element.getAttribute(attribute) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the child elements of an XML node
|
|
||||||
public static Element[] children(Node node) {
|
|
||||||
var nodes = node.getChildNodes();
|
|
||||||
int count = nodes.getLength();
|
|
||||||
var ret = new ArrayList<Element>();
|
|
||||||
for (int x = 0; x < count; x++) {
|
|
||||||
node = nodes.item(x);
|
|
||||||
if (node.getNodeType() == Node.ELEMENT_NODE)
|
|
||||||
ret.add((Element) node);
|
|
||||||
}
|
|
||||||
return ret.toArray(new Element[ret.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the first node matching the given hierarchy
|
|
||||||
public static Element element(Node node, String hierarchy) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (node == null || hierarchy == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Propagate down the hierarchy
|
|
||||||
outer: for (String name : hierarchy.split("\\.")) {
|
|
||||||
var nodes = node.getChildNodes();
|
|
||||||
int count = nodes.getLength();
|
|
||||||
for (int x = 0; x < count; x++) {
|
|
||||||
node = nodes.item(x);
|
|
||||||
if (
|
|
||||||
node.getNodeType() == Node.ELEMENT_NODE &&
|
|
||||||
node.getNodeName().equals(name)
|
|
||||||
) continue outer;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Element) node;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve all nodes matching the endpoint of a given hierarchy
|
|
||||||
public static Element[] elements(Node node, String hierarchy) {
|
|
||||||
|
|
||||||
// Find the first matching node
|
|
||||||
node = element(node, hierarchy);
|
|
||||||
if (node == null)
|
|
||||||
return new Element[0];
|
|
||||||
|
|
||||||
// Working variables
|
|
||||||
var names = hierarchy.split("\\.");
|
|
||||||
String name = names[names.length - 1];
|
|
||||||
var ret = new ArrayList<Element>();
|
|
||||||
|
|
||||||
// Include all siblings with the same tag name
|
|
||||||
ret.add((Element) node);
|
|
||||||
for (;;) {
|
|
||||||
node = node.getNextSibling();
|
|
||||||
if (node == null)
|
|
||||||
break;
|
|
||||||
if (
|
|
||||||
node.getNodeType() == Node.ELEMENT_NODE &&
|
|
||||||
node.getNodeName().equals(name)
|
|
||||||
) ret.add((Element) node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret.toArray(new Element[ret.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and parse an XML file
|
|
||||||
public static Node read(String filename) {
|
|
||||||
try { return XML_PARSER.parse(
|
|
||||||
new ByteArrayInputStream(Util.fileRead(filename)));
|
|
||||||
} catch (Exception e) { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the text content of an element
|
|
||||||
public static String text(Node node) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (node == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Find the child node called #text
|
|
||||||
var nodes = node.getChildNodes();
|
|
||||||
int count = nodes.getLength();
|
|
||||||
for (int x = 0; x < count; x++) {
|
|
||||||
node = nodes.item(x);
|
|
||||||
if (node.getNodeType() != Node.TEXT_NODE)
|
|
||||||
continue;
|
|
||||||
String text = node.getNodeValue();
|
|
||||||
return text == null ? "" : text.trim();
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package vue;
|
|
||||||
|
|
||||||
// Access state
|
|
||||||
public class Access {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
public int address; // CPU bus address
|
|
||||||
public int fetch; // Index of machine code unit
|
|
||||||
public int type; // Data type
|
|
||||||
public int value; // Value read/to write
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
Access() { }
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,576 +0,0 @@
|
||||||
// This file is included through NativeVue.c and cannot be built directly. */
|
|
||||||
#ifdef NATIVEVUE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Hook flags
|
|
||||||
#define BRK_EXCEPTION 0x00000001
|
|
||||||
#define BRK_EXECUTE 0x00000002
|
|
||||||
#define BRK_FRAME 0x00000004
|
|
||||||
#define BRK_READ 0x00000008
|
|
||||||
#define BRK_WRITE 0x00000010
|
|
||||||
|
|
||||||
// Token types
|
|
||||||
#define BRK_BOOL 0 /* Value types */
|
|
||||||
#define BRK_SIGNED 1
|
|
||||||
#define BRK_UNSIGNED 2
|
|
||||||
#define BRK_FLOAT 3
|
|
||||||
#define BRK_SYMBOL 4 /* Symbol types */
|
|
||||||
#define BRK_PROREG 5
|
|
||||||
#define BRK_SYSREG 6
|
|
||||||
#define BRK_UNARY 7 /* Operator types */
|
|
||||||
#define BRK_BINARY 8
|
|
||||||
|
|
||||||
|
|
||||||
// Functional symbol IDs
|
|
||||||
#define BRK_ADDRESS 0
|
|
||||||
#define BRK_BREAK 1
|
|
||||||
#define BRK_CODE 2
|
|
||||||
#define BRK_COND 3
|
|
||||||
#define BRK_DISP 4
|
|
||||||
#define BRK_FETCH 5
|
|
||||||
#define BRK_FORMAT 6
|
|
||||||
#define BRK_ID 7
|
|
||||||
#define BRK_IMM 8
|
|
||||||
#define BRK_OPCODE 9
|
|
||||||
#define BRK_REG1 10
|
|
||||||
#define BRK_REG2 11
|
|
||||||
#define BRK_REGID 12
|
|
||||||
#define BRK_SIZE 13
|
|
||||||
#define BRK_SUBOPCODE 14
|
|
||||||
#define BRK_TYPE 15
|
|
||||||
#define BRK_VALUE 16
|
|
||||||
#define BRK_VECTOR 17
|
|
||||||
|
|
||||||
// Evaluation operator IDs
|
|
||||||
#define BRK_XS32 1 /* xs32, xword */
|
|
||||||
#define BRK_XU32 2 /* xu32, xuword */
|
|
||||||
#define BRK_XFLOAT 3 /* xfloat */
|
|
||||||
#define BRK_READ8 4 /* [] */
|
|
||||||
#define BRK_READ16 5 /* [] */
|
|
||||||
#define BRK_READ32 6 /* [] */
|
|
||||||
#define BRK_BOOL_ - 2 /* bool */
|
|
||||||
#define BRK_S32 - 3 /* s32, word */
|
|
||||||
#define BRK_U32 - 4 /* u32, uword */
|
|
||||||
#define BRK_FLOAT_ - 5 /* float */
|
|
||||||
#define BRK_ADD - 6 /* + */
|
|
||||||
#define BRK_AND_B - 7 /* & */
|
|
||||||
#define BRK_AND_L - 8 /* && */
|
|
||||||
#define BRK_CEIL - 9 /* ceil */
|
|
||||||
#define BRK_DIVIDE -10 /* / */
|
|
||||||
#define BRK_EQUAL -11 /* == */
|
|
||||||
#define BRK_FLOOR -12 /* floor */
|
|
||||||
#define BRK_GREATER -13 /* > */
|
|
||||||
#define BRK_GREQUAL -14 /* >= */
|
|
||||||
#define BRK_LEFT_L -15 /* << */
|
|
||||||
#define BRK_LEQUAL -16 /* <= */
|
|
||||||
#define BRK_LESS -17 /* < */
|
|
||||||
#define BRK_MULTIPLY -18 /* * */
|
|
||||||
#define BRK_NEQUAL -19 /* != */
|
|
||||||
#define BRK_NOT_B -20 /* ~ */
|
|
||||||
#define BRK_NOT_L -21 /* ! */
|
|
||||||
#define BRK_NEGATE -22 /* - */
|
|
||||||
#define BRK_OR_B -23 /* | */
|
|
||||||
#define BRK_OR_L -24 /* || */
|
|
||||||
#define BRK_REMAINDER -25 /* % */
|
|
||||||
#define BRK_RIGHT_A -26 /* >> */
|
|
||||||
#define BRK_RIGHT_L -27 /* >>> */
|
|
||||||
#define BRK_ROUND -28 /* round */
|
|
||||||
#define BRK_S8 -29 /* s8, byte */
|
|
||||||
#define BRK_S16 -30 /* s16, halfword */
|
|
||||||
#define BRK_SUBTRACT -31 /* - */
|
|
||||||
#define BRK_TRUNC -32 /* trunc */
|
|
||||||
#define BRK_U8 -33 /* u8, ubyte */
|
|
||||||
#define BRK_U16 -34 /* u16, uhalfword */
|
|
||||||
#define BRK_XOR_B -36 /* ^ */
|
|
||||||
#define BRK_XOR_L -37 /* ^^ */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Internal Functions //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Adjust a float value as needed
|
|
||||||
static int brkAdjust(float value) {
|
|
||||||
int32_t bits = *(int32_t *)&value;
|
|
||||||
int exp = bits & 0x7F800000;
|
|
||||||
return
|
|
||||||
(bits & 0x7FFFFFFF) == 0 || // Zero
|
|
||||||
exp == 0x7F800000 || // Indefinite
|
|
||||||
exp == 0 // Denormal
|
|
||||||
? 0 : bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate a binary operator
|
|
||||||
static int32_t brkEvalBinary(int32_t id, int32_t left, int32_t right) {
|
|
||||||
|
|
||||||
// Processing by ID
|
|
||||||
switch (id) {
|
|
||||||
|
|
||||||
// Add
|
|
||||||
case -BRK_ADD * 4 + BRK_BOOL:
|
|
||||||
case -BRK_ADD * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_ADD * 4 + BRK_UNSIGNED:
|
|
||||||
return left + right;
|
|
||||||
case -BRK_ADD * 4 + BRK_FLOAT:
|
|
||||||
return brkAdjust(*(float *)&left + *(float *)&right);
|
|
||||||
|
|
||||||
// And Bitwise
|
|
||||||
case -BRK_AND_B * 4 + BRK_BOOL:
|
|
||||||
case -BRK_AND_B * 4 + BRK_FLOAT: // Prevented by parser
|
|
||||||
case -BRK_AND_B * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_AND_B * 4 + BRK_UNSIGNED:
|
|
||||||
return left & right;
|
|
||||||
|
|
||||||
// And Logical
|
|
||||||
case -BRK_AND_L * 4 + BRK_BOOL:
|
|
||||||
case -BRK_AND_L * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_AND_L * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_AND_L * 4 + BRK_UNSIGNED:
|
|
||||||
return left == 0 ? left : right;
|
|
||||||
|
|
||||||
// Divide
|
|
||||||
case -BRK_DIVIDE * 4 + BRK_BOOL:
|
|
||||||
case -BRK_DIVIDE * 4 + BRK_SIGNED:
|
|
||||||
return right == 0 ? 0 : left / right;
|
|
||||||
case -BRK_DIVIDE * 4 + BRK_UNSIGNED:
|
|
||||||
return right == 0 ? 0 : (uint32_t) left / right;
|
|
||||||
case -BRK_DIVIDE * 4 + BRK_FLOAT:
|
|
||||||
return right == 0 ? 0 :
|
|
||||||
brkAdjust(*(float *)&left / *(float *)&right);
|
|
||||||
|
|
||||||
// Equal
|
|
||||||
case -BRK_EQUAL * 4 + BRK_BOOL:
|
|
||||||
case -BRK_EQUAL * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_EQUAL * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_EQUAL * 4 + BRK_UNSIGNED:
|
|
||||||
return left == right ? 1 : 0;
|
|
||||||
|
|
||||||
// Greater
|
|
||||||
case -BRK_GREATER * 4 + BRK_BOOL:
|
|
||||||
case -BRK_GREATER * 4 + BRK_SIGNED:
|
|
||||||
return left > right ? 1 : 0;
|
|
||||||
case -BRK_GREATER * 4 + BRK_UNSIGNED:
|
|
||||||
return (uint32_t) left > right ? 1 : 0;
|
|
||||||
case -BRK_GREATER * 4 + BRK_FLOAT:
|
|
||||||
return *(float *)&left > *(float *)&right ? 1 : 0;
|
|
||||||
|
|
||||||
// Greater or Equal
|
|
||||||
case -BRK_GREQUAL * 4 + BRK_BOOL:
|
|
||||||
case -BRK_GREQUAL * 4 + BRK_SIGNED:
|
|
||||||
return left >= right ? 1 : 0;
|
|
||||||
case -BRK_GREQUAL * 4 + BRK_UNSIGNED:
|
|
||||||
return (uint32_t) left >= right ? 1 : 0;
|
|
||||||
case -BRK_GREQUAL * 4 + BRK_FLOAT:
|
|
||||||
return *(float *)&left >= *(float *)&right ? 1 : 0;
|
|
||||||
|
|
||||||
// Shift Left
|
|
||||||
case -BRK_LEFT_L * 4 + BRK_BOOL:
|
|
||||||
case -BRK_LEFT_L * 4 + BRK_FLOAT: // Prevented by parser
|
|
||||||
case -BRK_LEFT_L * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_LEFT_L * 4 + BRK_UNSIGNED:
|
|
||||||
return left << (right & 31);
|
|
||||||
|
|
||||||
// Less or Equal
|
|
||||||
case -BRK_LEQUAL * 4 + BRK_BOOL:
|
|
||||||
case -BRK_LEQUAL * 4 + BRK_SIGNED:
|
|
||||||
return left <= right ? 1 : 0;
|
|
||||||
case -BRK_LEQUAL * 4 + BRK_UNSIGNED:
|
|
||||||
return (uint32_t) left <= right ? 1 : 0;
|
|
||||||
case -BRK_LEQUAL * 4 + BRK_FLOAT:
|
|
||||||
return *(float *)&left <= *(float *)&right ? 1 : 0;
|
|
||||||
|
|
||||||
// Less
|
|
||||||
case -BRK_LESS * 4 + BRK_BOOL:
|
|
||||||
case -BRK_LESS * 4 + BRK_SIGNED:
|
|
||||||
return left < right ? 1 : 0;
|
|
||||||
case -BRK_LESS * 4 + BRK_UNSIGNED:
|
|
||||||
return (uint32_t) left < right ? 1 : 0;
|
|
||||||
case -BRK_LESS * 4 + BRK_FLOAT:
|
|
||||||
return *(float *)&left < *(float *)&right ? 1 : 0;
|
|
||||||
|
|
||||||
// Multiply
|
|
||||||
case -BRK_MULTIPLY * 4 + BRK_BOOL:
|
|
||||||
case -BRK_MULTIPLY * 4 + BRK_SIGNED:
|
|
||||||
return left * right;
|
|
||||||
case -BRK_MULTIPLY * 4 + BRK_UNSIGNED:
|
|
||||||
return (uint32_t) left * right;
|
|
||||||
case -BRK_MULTIPLY * 4 + BRK_FLOAT:
|
|
||||||
return brkAdjust(*(float *)&left * *(float *)&right);
|
|
||||||
|
|
||||||
// Not Equal
|
|
||||||
case -BRK_NEQUAL * 4 + BRK_BOOL:
|
|
||||||
case -BRK_NEQUAL * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_NEQUAL * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_NEQUAL * 4 + BRK_UNSIGNED:
|
|
||||||
return left != right ? 1 : 0;
|
|
||||||
|
|
||||||
// Or Bitwise
|
|
||||||
case -BRK_OR_B * 4 + BRK_BOOL:
|
|
||||||
case -BRK_OR_B * 4 + BRK_FLOAT: // Prevented by parser
|
|
||||||
case -BRK_OR_B * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_OR_B * 4 + BRK_UNSIGNED:
|
|
||||||
return left | right;
|
|
||||||
|
|
||||||
// Or Logical
|
|
||||||
case -BRK_OR_L * 4 + BRK_BOOL:
|
|
||||||
case -BRK_OR_L * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_OR_L * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_OR_L * 4 + BRK_UNSIGNED:
|
|
||||||
return left != 0 ? left : right;
|
|
||||||
|
|
||||||
// Remainder
|
|
||||||
case -BRK_REMAINDER * 4 + BRK_BOOL:
|
|
||||||
case -BRK_REMAINDER * 4 + BRK_SIGNED:
|
|
||||||
return right == 0 ? 0 : left % right;
|
|
||||||
case -BRK_REMAINDER * 4 + BRK_UNSIGNED:
|
|
||||||
return right == 0 ? 0 : (uint32_t) left % right;
|
|
||||||
case -BRK_REMAINDER * 4 + BRK_FLOAT:
|
|
||||||
return right == 0 ? 0 :
|
|
||||||
brkAdjust(fmodf(*(float *)&left, *(float *)&right));
|
|
||||||
|
|
||||||
// Shift Right Arithmetic
|
|
||||||
case -BRK_RIGHT_A * 4 + BRK_BOOL:
|
|
||||||
case -BRK_RIGHT_A * 4 + BRK_FLOAT: // Prevented by parser
|
|
||||||
case -BRK_RIGHT_A * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_RIGHT_A * 4 + BRK_UNSIGNED:
|
|
||||||
return SIGN_EXTEND(left >> (right & 31), 32 - (right & 31));
|
|
||||||
|
|
||||||
// Shift Right Logical
|
|
||||||
case -BRK_RIGHT_L * 4 + BRK_BOOL:
|
|
||||||
case -BRK_RIGHT_L * 4 + BRK_FLOAT: // Prevented by parser
|
|
||||||
case -BRK_RIGHT_L * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_RIGHT_L * 4 + BRK_UNSIGNED:
|
|
||||||
return left >> (right & 31) & ((int32_t) -1 << (right & 31));
|
|
||||||
|
|
||||||
// Subtract
|
|
||||||
case -BRK_SUBTRACT * 4 + BRK_BOOL:
|
|
||||||
case -BRK_SUBTRACT * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_SUBTRACT * 4 + BRK_UNSIGNED:
|
|
||||||
return left - right;
|
|
||||||
case -BRK_SUBTRACT * 4 + BRK_FLOAT:
|
|
||||||
return brkAdjust(*(float *)&left - *(float *)&right);
|
|
||||||
|
|
||||||
// Exclusive Or Bitwise
|
|
||||||
case -BRK_XOR_B * 4 + BRK_BOOL:
|
|
||||||
case -BRK_XOR_B * 4 + BRK_FLOAT: // Prevented by parser
|
|
||||||
case -BRK_XOR_B * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_XOR_B * 4 + BRK_UNSIGNED:
|
|
||||||
return left ^ right;
|
|
||||||
|
|
||||||
// Exclusive Or Logical
|
|
||||||
case -BRK_XOR_L * 4 + BRK_BOOL:
|
|
||||||
case -BRK_XOR_L * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_XOR_L * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_XOR_L * 4 + BRK_UNSIGNED:
|
|
||||||
return left != 0 && right != 0 ? 0 : left != 0 ? left : right;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unreachable
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate a unary operator
|
|
||||||
static int32_t brkEvalUnary(Vue *vue, int32_t id, int32_t operand) {
|
|
||||||
float val; // Working variable
|
|
||||||
|
|
||||||
// Processing by ID
|
|
||||||
switch (id) {
|
|
||||||
|
|
||||||
// Cast to Boolean
|
|
||||||
case -BRK_BOOL_ * 4 + BRK_BOOL: // Removed by parser
|
|
||||||
case -BRK_BOOL_ * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_BOOL_ * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_BOOL_ * 4 + BRK_UNSIGNED:
|
|
||||||
return operand == 0 ? 0 : 1;
|
|
||||||
|
|
||||||
// Round up
|
|
||||||
case -BRK_CEIL * 4 + BRK_BOOL: // Removed by parser
|
|
||||||
case -BRK_CEIL * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_CEIL * 4 + BRK_SIGNED: // Removed by parser
|
|
||||||
case -BRK_CEIL * 4 + BRK_UNSIGNED: // Removed by parser
|
|
||||||
return brkAdjust(ceilf(*(float *)&operand));
|
|
||||||
|
|
||||||
// Cast to Float
|
|
||||||
case -BRK_FLOAT_ * 4 + BRK_BOOL:
|
|
||||||
case -BRK_FLOAT_ * 4 + BRK_FLOAT: // Removed by parser
|
|
||||||
case -BRK_FLOAT_ * 4 + BRK_SIGNED:
|
|
||||||
return brkAdjust(operand);
|
|
||||||
case -BRK_FLOAT_ * 4 + BRK_UNSIGNED:
|
|
||||||
return brkAdjust((uint32_t) operand);
|
|
||||||
|
|
||||||
// Round down
|
|
||||||
case -BRK_FLOOR * 4 + BRK_BOOL: // Removed by parser
|
|
||||||
case -BRK_FLOOR * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_FLOOR * 4 + BRK_SIGNED: // Removed by parser
|
|
||||||
case -BRK_FLOOR * 4 + BRK_UNSIGNED: // Removed by parser
|
|
||||||
return brkAdjust(floorf(*(float *)&operand));
|
|
||||||
|
|
||||||
// Bitwise Not
|
|
||||||
case -BRK_NOT_B * 4 + BRK_BOOL:
|
|
||||||
case -BRK_NOT_B * 4 + BRK_FLOAT: // Prevented by parser
|
|
||||||
case -BRK_NOT_B * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_NOT_B * 4 + BRK_UNSIGNED:
|
|
||||||
return ~operand;
|
|
||||||
|
|
||||||
// Logical Not
|
|
||||||
case -BRK_NOT_L * 4 + BRK_BOOL:
|
|
||||||
case -BRK_NOT_L * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_NOT_L * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_NOT_L * 4 + BRK_UNSIGNED:
|
|
||||||
return operand == 0 ? 1 : 0;
|
|
||||||
|
|
||||||
// Negate
|
|
||||||
case -BRK_NEGATE * 4 + BRK_BOOL:
|
|
||||||
case -BRK_NEGATE * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_NEGATE * 4 + BRK_UNSIGNED: // Removed by parser
|
|
||||||
return -operand;
|
|
||||||
case -BRK_NEGATE * 4 + BRK_FLOAT:
|
|
||||||
return brkAdjust(-*(float *)&operand);
|
|
||||||
|
|
||||||
// Read Byte
|
|
||||||
case BRK_READ8:
|
|
||||||
return vueRead(vue, operand, VUE_S8);
|
|
||||||
|
|
||||||
// Read Halfword
|
|
||||||
case BRK_READ16:
|
|
||||||
return vueRead(vue, operand, VUE_S16);
|
|
||||||
|
|
||||||
// Read Word
|
|
||||||
case BRK_READ32:
|
|
||||||
return vueRead(vue, operand, VUE_S32);
|
|
||||||
|
|
||||||
// Round to Nearest
|
|
||||||
case -BRK_ROUND * 4 + BRK_BOOL: // Removed by parser
|
|
||||||
case -BRK_ROUND * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_ROUND * 4 + BRK_SIGNED: // Removed by parser
|
|
||||||
case -BRK_ROUND * 4 + BRK_UNSIGNED: // Removed by parser
|
|
||||||
return brkAdjust(roundf(*(float *)&operand));
|
|
||||||
|
|
||||||
// Cast to Signed Byte
|
|
||||||
case -BRK_S8 * 4 + BRK_FLOAT:
|
|
||||||
operand = brkEvalUnary(vue, -BRK_S32 * 4 + BRK_FLOAT, operand);
|
|
||||||
// Fallthrough
|
|
||||||
case -BRK_S8 * 4 + BRK_BOOL:
|
|
||||||
case -BRK_S8 * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_S8 * 4 + BRK_UNSIGNED:
|
|
||||||
return SIGN_EXTEND(operand, 8);
|
|
||||||
|
|
||||||
// Cast to Signed Halfword
|
|
||||||
case -BRK_S16 * 4 + BRK_FLOAT:
|
|
||||||
operand = brkEvalUnary(vue, -BRK_S32 * 4 + BRK_FLOAT, operand);
|
|
||||||
// Fallthrough
|
|
||||||
case -BRK_S16 * 4 + BRK_BOOL:
|
|
||||||
case -BRK_S16 * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_S16 * 4 + BRK_UNSIGNED:
|
|
||||||
return SIGN_EXTEND(operand, 16);
|
|
||||||
|
|
||||||
// Cast to Signed Word
|
|
||||||
case -BRK_S32 * 4 + BRK_BOOL:
|
|
||||||
case -BRK_S32 * 4 + BRK_SIGNED: // Removed by parser
|
|
||||||
case -BRK_S32 * 4 + BRK_UNSIGNED:
|
|
||||||
return operand;
|
|
||||||
case -BRK_S32 * 4 + BRK_FLOAT:
|
|
||||||
val = *(float *)&operand;
|
|
||||||
return val >= -MAX_WORD && val < MAX_WORD ? (int32_t) val : 0;
|
|
||||||
|
|
||||||
// Truncate
|
|
||||||
case -BRK_TRUNC * 4 + BRK_BOOL: // Removed by parser
|
|
||||||
case -BRK_TRUNC * 4 + BRK_FLOAT:
|
|
||||||
case -BRK_TRUNC * 4 + BRK_SIGNED: // Removed by parser
|
|
||||||
case -BRK_TRUNC * 4 + BRK_UNSIGNED: // Removed by parser
|
|
||||||
return brkAdjust(truncf(*(float *)&operand));
|
|
||||||
|
|
||||||
// Cast to Unsigned Byte
|
|
||||||
case -BRK_U8 * 4 + BRK_FLOAT:
|
|
||||||
operand = brkEvalUnary(vue, -BRK_S32 * 4 + BRK_FLOAT, operand);
|
|
||||||
case -BRK_U8 * 4 + BRK_BOOL:
|
|
||||||
case -BRK_U8 * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_U8 * 4 + BRK_UNSIGNED:
|
|
||||||
return operand & 0xFF;
|
|
||||||
|
|
||||||
// Cast to Unsigned Halfword
|
|
||||||
case -BRK_U16 * 4 + BRK_FLOAT:
|
|
||||||
operand = brkEvalUnary(vue, -BRK_S32 * 4 + BRK_FLOAT, operand);
|
|
||||||
case -BRK_U16 * 4 + BRK_BOOL:
|
|
||||||
case -BRK_U16 * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_U16 * 4 + BRK_UNSIGNED:
|
|
||||||
return operand & 0xFFFF;
|
|
||||||
|
|
||||||
// Cast to Unsigned Word
|
|
||||||
case -BRK_U32 * 4 + BRK_BOOL:
|
|
||||||
case -BRK_U32 * 4 + BRK_SIGNED:
|
|
||||||
case -BRK_U32 * 4 + BRK_UNSIGNED: // Removed by parser
|
|
||||||
return operand;
|
|
||||||
case -BRK_U32 * 4 + BRK_FLOAT:
|
|
||||||
val = *(float *)&operand;
|
|
||||||
return val >= 0 && val < MAX_UWORD ? (uint32_t) val : 0;
|
|
||||||
|
|
||||||
// Reinterpret as Float
|
|
||||||
case BRK_XFLOAT:
|
|
||||||
return brkAdjust(*(float *)&operand);
|
|
||||||
|
|
||||||
// Reinterpret as Signed Word, Reinterpret as Unsigned Word
|
|
||||||
//case BRK_XS32: // Removed by parser
|
|
||||||
//case BRK_XU32: // Removed by parser
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unreachable
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate the condition, returning only the computed value
|
|
||||||
static int32_t brkEvaluate(Core *core, Breakpoint *brk) {
|
|
||||||
int32_t *stack = core->stack;
|
|
||||||
Vue *vue = &core->vue;
|
|
||||||
|
|
||||||
// Process all tokens
|
|
||||||
int size = 0;
|
|
||||||
Token *tok;
|
|
||||||
int32_t x, sym; // Working variables
|
|
||||||
for (tok = &brk->tokens[x=0]; x < brk->numTokens; tok = &brk->tokens[++x])
|
|
||||||
switch (tok->type) {
|
|
||||||
|
|
||||||
// Binary operator
|
|
||||||
case BRK_BINARY:
|
|
||||||
stack[size - 2] =
|
|
||||||
brkEvalBinary(tok->id, stack[size - 2], stack[size - 1]);
|
|
||||||
size--;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Literal
|
|
||||||
case BRK_BOOL:
|
|
||||||
case BRK_FLOAT:
|
|
||||||
case BRK_SIGNED:
|
|
||||||
case BRK_UNSIGNED:
|
|
||||||
stack[size++] = tok->id;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// CPU register
|
|
||||||
case BRK_PROREG:
|
|
||||||
case BRK_SYSREG:
|
|
||||||
stack[size++] = vueGetRegister(vue,tok->id,tok->type==BRK_SYSREG);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Unary operator
|
|
||||||
case BRK_UNARY:
|
|
||||||
stack[size - 1] = brkEvalUnary(vue, tok->id, stack[size - 1]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Symbol
|
|
||||||
case BRK_SYMBOL:
|
|
||||||
sym = vue->cpu.inst.imm; // IMM, REGID, VECTOR
|
|
||||||
switch (tok->id) {
|
|
||||||
case BRK_ADDRESS : sym = vue->cpu.access.address; break;
|
|
||||||
case BRK_BREAK : sym = core->breakType ; break;
|
|
||||||
case BRK_CODE : sym = vue->cpu.exception ; break;
|
|
||||||
case BRK_COND : sym = vue->cpu.inst.cond ; break;
|
|
||||||
case BRK_DISP : sym = vue->cpu.inst.disp ; break;
|
|
||||||
case BRK_FETCH : sym = vue->cpu.fetch ; break;
|
|
||||||
case BRK_FORMAT : sym = vue->cpu.inst.format ; break;
|
|
||||||
case BRK_ID : sym = vue->cpu.inst.id ; break;
|
|
||||||
case BRK_OPCODE : sym = vue->cpu.inst.opcode ; break;
|
|
||||||
case BRK_REG1 : sym = vue->cpu.inst.reg1 ; break;
|
|
||||||
case BRK_REG2 : sym = vue->cpu.inst.reg2 ; break;
|
|
||||||
case BRK_SIZE : sym = vue->cpu.inst.size ; break;
|
|
||||||
case BRK_SUBOPCODE: sym = vue->cpu.inst.subopcode; break;
|
|
||||||
case BRK_TYPE : sym = vue->cpu.access.type ; break;
|
|
||||||
case BRK_VALUE : sym = vue->cpu.access.value ; break;
|
|
||||||
}
|
|
||||||
stack[size++] = sym;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the remaining stack value
|
|
||||||
return stack[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine whether the breakpoint applies to a given address range
|
|
||||||
static vbool brkInRange(Breakpoint *brk, uint32_t start, uint32_t end) {
|
|
||||||
|
|
||||||
// Implicit inclusion
|
|
||||||
if (brk->numRanges == 0)
|
|
||||||
return VUE_TRUE;
|
|
||||||
|
|
||||||
// Check all ranges
|
|
||||||
for (int x = 0; x < brk->numRanges; x++) {
|
|
||||||
uint32_t *range = &brk->ranges[x * 2];
|
|
||||||
if (
|
|
||||||
start - range[0] <= range[1] - range[0] ||
|
|
||||||
range[0] - start <= end - start
|
|
||||||
) return VUE_TRUE;
|
|
||||||
}
|
|
||||||
return VUE_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for breakpoints
|
|
||||||
static int32_t brkOnBreakpoint(Vue *vue, int32_t breakType) {
|
|
||||||
Core *core = (Core *) vue->tag;
|
|
||||||
uint32_t end = 0;
|
|
||||||
vbool ranged = VUE_FALSE;
|
|
||||||
uint32_t start = 0;
|
|
||||||
core->breakType = breakType;
|
|
||||||
|
|
||||||
// Processing for Execute
|
|
||||||
if (breakType == BRK_EXECUTE) {
|
|
||||||
ranged = VUE_TRUE;
|
|
||||||
start = vue->cpu.pc;
|
|
||||||
end = start + vue->cpu.inst.size - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processing for Read and Write
|
|
||||||
else if (breakType == BRK_READ || breakType == BRK_WRITE) {
|
|
||||||
ranged = VUE_TRUE;
|
|
||||||
start = vue->cpu.access.address;
|
|
||||||
end = start + TYPE_SIZES[vue->cpu.access.type] - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check all breakpoints
|
|
||||||
int32_t fetch = breakType == BRK_READ && vue->cpu.fetch != -1 ? 1 : 0;
|
|
||||||
for (int x = 0; x < core->numBreakpoints; x++) {
|
|
||||||
Breakpoint *brk = &core->breakpoints[x];
|
|
||||||
if (
|
|
||||||
brk->enabled && (brk->fetch || !fetch) &&
|
|
||||||
(breakType == 0 || (breakType & brk->hooks) != 0) &&
|
|
||||||
(!ranged || brkInRange(brk, start, end)) &&
|
|
||||||
(brk->numTokens == 0 || brkEvaluate(core, brk) != 0)
|
|
||||||
) return x + 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for exception breakpoints
|
|
||||||
static int32_t brkOnException(Vue *vue, uint16_t code) {
|
|
||||||
return brkOnBreakpoint(vue, BRK_EXCEPTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for execute breakpoints
|
|
||||||
static int32_t brkOnExecute(Vue *vue, VueInstruction *inst) {
|
|
||||||
return brkOnBreakpoint(vue, BRK_EXECUTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for frame breakpoints
|
|
||||||
static int32_t brkOnFrame(Vue *vue) {
|
|
||||||
return brkOnBreakpoint(vue, BRK_FRAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for read breakpoints
|
|
||||||
static int32_t brkOnRead(Vue *vue, VueAccess *acc) {
|
|
||||||
return brkOnBreakpoint(vue, BRK_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for write breakpoints
|
|
||||||
static int32_t brkOnWrite(Vue *vue, VueAccess *acc) {
|
|
||||||
return brkOnBreakpoint(vue, BRK_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // NATIVEVUE
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,38 +0,0 @@
|
||||||
package vue;
|
|
||||||
|
|
||||||
// Simulation of the Game Pak
|
|
||||||
class GamePak {
|
|
||||||
|
|
||||||
// Package fields
|
|
||||||
byte[] ram; // Cartridge SRAM
|
|
||||||
byte[] rom; // Cartridge ROM
|
|
||||||
int wcr_exp1w; // Expansion one-wait mode
|
|
||||||
int wcr_rom1w; // ROM one-wait mode
|
|
||||||
|
|
||||||
// Private fields
|
|
||||||
private JavaVue vue; // Emulation state
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
GamePak(JavaVue vue) {
|
|
||||||
this.vue = vue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// System reset
|
|
||||||
void reset() {
|
|
||||||
wcr_exp1w = 0;
|
|
||||||
wcr_rom1w = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,228 +0,0 @@
|
||||||
package vue;
|
|
||||||
|
|
||||||
// Instruction state and decoder
|
|
||||||
public class Instruction {
|
|
||||||
|
|
||||||
// Instruction fields
|
|
||||||
public int bits; // Binary encoding
|
|
||||||
public int cond; // Condition for Bcond
|
|
||||||
public int disp; // Displacement for jumps and branches
|
|
||||||
public int format; // Binary format
|
|
||||||
public int id; // Library-specific identifier
|
|
||||||
public int imm; // Immediate operand
|
|
||||||
public int opcode; // Instruction opcode
|
|
||||||
public int reg1; // Source/right register
|
|
||||||
public int reg2; // Destination/left register
|
|
||||||
public int size; // Number of bytes in encoding
|
|
||||||
public int subopcode; // Instruction subopcode
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Intermediate instruction IDs
|
|
||||||
private static final int BITSTRING = -2;
|
|
||||||
private static final int FLOATENDO = -3;
|
|
||||||
|
|
||||||
// Opcode lookup table
|
|
||||||
private static final byte[] LOOKUP_OPCODE = {
|
|
||||||
Vue.MOV_REG, 1, Vue.ADD_REG, 1, Vue.SUB , 1, Vue.CMP_REG, 1,
|
|
||||||
Vue.SHL_REG, 1, Vue.SHR_REG, 1, Vue.JMP , 1, Vue.SAR_REG, 1,
|
|
||||||
Vue.MUL , 1, Vue.DIV , 1, Vue.MULU , 1, Vue.DIVU , 1,
|
|
||||||
Vue.OR , 1, Vue.AND , 1, Vue.XOR , 1, Vue.NOT , 1,
|
|
||||||
Vue.MOV_IMM,-2, Vue.ADD_IMM,-2, Vue.SETF , 2, Vue.CMP_IMM,-2,
|
|
||||||
Vue.SHL_IMM, 2, Vue.SHR_IMM, 2, Vue.CLI , 2, Vue.SAR_IMM, 2,
|
|
||||||
Vue.TRAP , 2, Vue.RETI , 2, Vue.HALT , 2, Vue.ILLEGAL, 0,
|
|
||||||
Vue.LDSR , 2, Vue.STSR , 2, Vue.SEI , 2, BITSTRING , 2,
|
|
||||||
Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3,
|
|
||||||
Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3,
|
|
||||||
Vue.MOVEA ,-5, Vue.ADDI ,-5, Vue.JR , 4, Vue.JAL , 4,
|
|
||||||
Vue.ORI , 5, Vue.ANDI , 5, Vue.XORI , 5, Vue.MOVHI , 5,
|
|
||||||
Vue.LD_B , 6, Vue.LD_H , 6, Vue.ILLEGAL, 0, Vue.LD_W , 6,
|
|
||||||
Vue.ST_B , 6, Vue.ST_H , 6, Vue.ILLEGAL, 0, Vue.ST_W , 6,
|
|
||||||
Vue.IN_B , 6, Vue.IN_H , 6, Vue.CAXI , 6, Vue.IN_W , 6,
|
|
||||||
Vue.OUT_B , 6, Vue.OUT_H , 6, FLOATENDO , 7, Vue.OUT_W , 6
|
|
||||||
};
|
|
||||||
|
|
||||||
// Bit string lookup table
|
|
||||||
private static final byte[] LOOKUP_BITSTRING = {
|
|
||||||
Vue.SCH0BSU, Vue.SCH0BSD, Vue.SCH1BSU, Vue.SCH1BSD,
|
|
||||||
Vue.ILLEGAL, Vue.ILLEGAL, Vue.ILLEGAL, Vue.ILLEGAL,
|
|
||||||
Vue.ORBSU , Vue.ANDBSU , Vue.XORBSU , Vue.MOVBSU ,
|
|
||||||
Vue.ORNBSU , Vue.ANDNBSU, Vue.XORNBSU, Vue.XORNBSU
|
|
||||||
};
|
|
||||||
|
|
||||||
// Floating-point and Nintendo lookup table
|
|
||||||
private static final byte[] LOOKUP_FLOATENDO = {
|
|
||||||
Vue.CMPF_S , Vue.ILLEGAL, Vue.CVT_WS , Vue.CVT_SW ,
|
|
||||||
Vue.ADDF_S , Vue.SUBF_S , Vue.MULF_S , Vue.DIVF_S ,
|
|
||||||
Vue.XB , Vue.XH , Vue.REV , Vue.TRNC_SW,
|
|
||||||
Vue.MPYHW , Vue.ILLEGAL, Vue.ILLEGAL, Vue.ILLEGAL
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Static Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Determine the size of an instruction given its opcode
|
|
||||||
public static int size(int opcode) {
|
|
||||||
return Math.abs(LOOKUP_OPCODE[opcode << 1 | 1]) < 4 ? 2 : 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
public Instruction() { }
|
|
||||||
|
|
||||||
// Decoding constructor
|
|
||||||
public Instruction(int bits) {
|
|
||||||
decode(bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cloning constructor
|
|
||||||
Instruction(Instruction o) {
|
|
||||||
this();
|
|
||||||
bits = o.bits;
|
|
||||||
cond = o.cond;
|
|
||||||
disp = o.disp;
|
|
||||||
format = o.format;
|
|
||||||
id = o.id;
|
|
||||||
imm = o.imm;
|
|
||||||
opcode = o.opcode;
|
|
||||||
reg1 = o.reg1;
|
|
||||||
reg2 = o.reg2;
|
|
||||||
size = o.size;
|
|
||||||
subopcode = o.subopcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Produce an access descriptor from the current instruction state
|
|
||||||
public Access access(Vue vue) {
|
|
||||||
boolean read = false;
|
|
||||||
var ret = new Access();
|
|
||||||
ret.address = vue.getRegister(reg1, false) + disp;
|
|
||||||
ret.fetch = vue.getFetch();
|
|
||||||
ret.type = Vue.S32;
|
|
||||||
|
|
||||||
// Configure descriptor by ID
|
|
||||||
switch (id) {
|
|
||||||
case Vue.CAXI : read = true; break;
|
|
||||||
case Vue.IN_B : ret.type = Vue.U8 ; read = true; break;
|
|
||||||
case Vue.IN_H : ret.type = Vue.U16; read = true; break;
|
|
||||||
case Vue.IN_W : read = true; break;
|
|
||||||
case Vue.LD_B : ret.type = Vue.S8 ; read = true; break;
|
|
||||||
case Vue.LD_H : ret.type = Vue.S16; read = true; break;
|
|
||||||
case Vue.LD_W : read = true; break;
|
|
||||||
case Vue.OUT_B: ret.type = Vue.U8 ; break;
|
|
||||||
case Vue.OUT_H: ret.type = Vue.U16; break;
|
|
||||||
case Vue.OUT_W: break;
|
|
||||||
case Vue.ST_B : ret.type = Vue.S8 ; break;
|
|
||||||
case Vue.ST_H : ret.type = Vue.S16; break;
|
|
||||||
case Vue.ST_W : break;
|
|
||||||
// TODO: Bit strings
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the value currently on the bus
|
|
||||||
if (read)
|
|
||||||
ret.value = vue.read(ret.address, ret.type);
|
|
||||||
|
|
||||||
// Write a register to the bus
|
|
||||||
else if (id != Vue.CAXI)
|
|
||||||
vue.getRegister(reg2, false);
|
|
||||||
|
|
||||||
// CAXI processing
|
|
||||||
else {
|
|
||||||
int value = vue.read(ret.address, Vue.S32);
|
|
||||||
int compare = vue.getRegister(reg2, false);
|
|
||||||
int exchange = vue.getRegister( 30, false);
|
|
||||||
ret.value = value == compare ? value : exchange;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode an instruction from a byte array
|
|
||||||
public Instruction decode(byte[] data, int offset) {
|
|
||||||
return decode(
|
|
||||||
(data[offset + 0] & 0xFF) |
|
|
||||||
(data[offset + 1] & 0xFF) << 8 |
|
|
||||||
(data[offset + 2] & 0xFF) << 16 |
|
|
||||||
(data[offset + 3] & 0xFF) << 24
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode an instruction from its binary encoding (swapped halfwords)
|
|
||||||
public Instruction decode(int bits) {
|
|
||||||
byte extend; // Sign-extend the immediate operand
|
|
||||||
int x; // Working variable
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
this.bits = bits = bits << 16 | bits >>> 16;
|
|
||||||
opcode = bits >> 26 & 63;
|
|
||||||
x = opcode << 1;
|
|
||||||
id = LOOKUP_OPCODE[x ];
|
|
||||||
extend = LOOKUP_OPCODE[x + 1];
|
|
||||||
format = extend < 0 ? -extend : extend;
|
|
||||||
size = format < 4 ? 2 : 4;
|
|
||||||
|
|
||||||
// Decode by format
|
|
||||||
switch (format) {
|
|
||||||
case 1:
|
|
||||||
reg2 = bits >> 21 & 31;
|
|
||||||
reg1 = bits >> 16 & 31;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
reg2 = bits >> 21 & 31;
|
|
||||||
imm = extend < 0 ? bits << 11 >> 27 : bits >> 16 & 31;
|
|
||||||
if (id == BITSTRING) {
|
|
||||||
id = imm >= 16 ? Vue.ILLEGAL : LOOKUP_BITSTRING[imm];
|
|
||||||
subopcode = imm;
|
|
||||||
}
|
|
||||||
if (id == Vue.SETF)
|
|
||||||
cond = imm & 15;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
opcode = 0x20;
|
|
||||||
cond = bits >> 25 & 15;
|
|
||||||
disp = bits << 7 >> 23;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
disp = bits << 6 >> 6;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
reg2 = bits >> 21 & 31;
|
|
||||||
reg1 = bits >> 16 & 31;
|
|
||||||
imm = extend < 0 ? bits << 16 >> 16 : bits & 0xFFFF;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
reg2 = bits >> 21 & 31;
|
|
||||||
reg1 = bits >> 16 & 31;
|
|
||||||
disp = bits << 16 >> 16;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
reg2 = bits >> 21 & 31;
|
|
||||||
reg1 = bits >> 16 & 31;
|
|
||||||
subopcode = bits >> 10 & 63;
|
|
||||||
id = subopcode >= 16 ? Vue.ILLEGAL :
|
|
||||||
LOOKUP_FLOATENDO[subopcode];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,427 +0,0 @@
|
||||||
package vue;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
// Java emulation core implementation
|
|
||||||
class JavaVue extends Vue {
|
|
||||||
|
|
||||||
// Package fields
|
|
||||||
int breakCode; // Application breakpoint code
|
|
||||||
int breakType; // Most recent breakpoint scenario
|
|
||||||
int[] stack; // Breakpoint condition evaluation stack
|
|
||||||
byte[] wram; // System WRAM
|
|
||||||
|
|
||||||
// System components
|
|
||||||
CPU cpu; // Processor
|
|
||||||
GamePak pak; // Game pak
|
|
||||||
VIP vip; // Video unit
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Memory access type sizes
|
|
||||||
static final int[] TYPE_SIZES = { 1, 1, 2, 2, 4 };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
JavaVue() {
|
|
||||||
|
|
||||||
// Configure instance fields
|
|
||||||
stack = new int[0];
|
|
||||||
wram = new byte[0x10000];
|
|
||||||
|
|
||||||
// Configure system components
|
|
||||||
cpu = new CPU (this);
|
|
||||||
pak = new GamePak(this);
|
|
||||||
vip = new VIP (this);
|
|
||||||
|
|
||||||
// Initialize state
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Release any used resources
|
|
||||||
public void dispose() { }; // No action needed
|
|
||||||
|
|
||||||
// Process the simulation
|
|
||||||
public int emulate(int maxCycles) {
|
|
||||||
|
|
||||||
// Process up to the given number of cycles
|
|
||||||
do {
|
|
||||||
|
|
||||||
// Determine the number of cycles where no breakpoint will occur
|
|
||||||
int cycles = maxCycles; // min(maxCycles, nextFrameCycles)
|
|
||||||
cycles = cpu .until(cycles);
|
|
||||||
//cycles = pad .until(cycles);
|
|
||||||
//cycles = link .until(cycles);
|
|
||||||
//cycles = timer.until(cycles);
|
|
||||||
cycles = vip .until(cycles);
|
|
||||||
|
|
||||||
// Process all system components
|
|
||||||
breakCode = 0;
|
|
||||||
cpu .emulate(cycles);
|
|
||||||
//pad .emulate(cycles);
|
|
||||||
//link .emulate(cycles);
|
|
||||||
//timer.emulate(cycles);
|
|
||||||
vip .emulate(cycles);
|
|
||||||
//vsu .emulate(cycles);
|
|
||||||
maxCycles -= cycles;
|
|
||||||
} while (breakCode == 0 && maxCycles != 0);
|
|
||||||
|
|
||||||
// A break condition has occurred
|
|
||||||
return maxCycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the most recent applicaiton break code
|
|
||||||
public int getBreakCode() {
|
|
||||||
return breakCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the most recent exception code
|
|
||||||
public int getExceptionCode() {
|
|
||||||
return cpu.exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a register value
|
|
||||||
public int getRegister(int index, boolean system) {
|
|
||||||
|
|
||||||
// Non-indexed registers
|
|
||||||
if (system) switch (index) {
|
|
||||||
case Vue.JUMP_FROM: return
|
|
||||||
cpu.jumpFrom[cpu.psw_np != 0 ? 2 : cpu.psw_ep];
|
|
||||||
case Vue.JUMP_TO : return
|
|
||||||
cpu.jumpTo [cpu.psw_np != 0 ? 2 : cpu.psw_ep];
|
|
||||||
case Vue.PC : return cpu.pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Indexed registers
|
|
||||||
return
|
|
||||||
index < 0 || index > 31 ? 0 :
|
|
||||||
system ? cpu.getSystemRegister(index) :
|
|
||||||
cpu.program[index]
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a copy of the ROM data
|
|
||||||
public byte[] getROM() {
|
|
||||||
|
|
||||||
// No ROM data
|
|
||||||
if (pak.rom == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Copy the ROM data
|
|
||||||
var ret = new byte[pak.rom.length];
|
|
||||||
System.arraycopy(pak.rom, 0, ret, 0, ret.length);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine whether the context is native-backed
|
|
||||||
public boolean isNative() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a value from the CPU bus
|
|
||||||
public int read(int address, int type) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (type < 0 || type > 4)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Perform the operation
|
|
||||||
switch (address >> 24 & 7) {
|
|
||||||
case 0: return vip.read ( address, type);
|
|
||||||
case 5: return readBuffer(wram , address, type);
|
|
||||||
case 6: return readBuffer(pak.ram, address, type);
|
|
||||||
case 7: return readBuffer(pak.rom, address, type);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read bytes from the CPU bus
|
|
||||||
public boolean readBytes(int address, byte[] dest, int offset, int length){
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (
|
|
||||||
dest == null ||
|
|
||||||
offset < 0 ||
|
|
||||||
length < 0 ||
|
|
||||||
offset + length > dest.length
|
|
||||||
) return false;
|
|
||||||
|
|
||||||
// Perform the operation
|
|
||||||
while (length > 0) {
|
|
||||||
int count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF));
|
|
||||||
switch (address >> 24 & 7) {
|
|
||||||
case 0: vip.readBytes( address,dest,offset,count); break;
|
|
||||||
case 5: readBytes(wram ,address,dest,offset,count); break;
|
|
||||||
case 6: readBytes(pak.ram,address,dest,offset,count); break;
|
|
||||||
case 7: readBytes(pak.rom,address,dest,offset,count); break;
|
|
||||||
default: Arrays.fill(dest, offset, offset + count, (byte) 0);
|
|
||||||
}
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
offset += count;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize all system components
|
|
||||||
public void reset() {
|
|
||||||
cpu.reset();
|
|
||||||
pak.reset();
|
|
||||||
Arrays.fill(wram, 0, 0x10000, (byte) 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify a register value
|
|
||||||
public int setRegister(int index, boolean system, int value) {
|
|
||||||
|
|
||||||
// PC
|
|
||||||
if (index == Vue.PC && system) {
|
|
||||||
if (cpu.stage == CPU.EXECUTE || cpu.stage == CPU.FETCH) {
|
|
||||||
cpu.fetch = -1;
|
|
||||||
cpu.stage = CPU.FETCH;
|
|
||||||
}
|
|
||||||
return cpu.pc = value & 0xFFFFFFFE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other
|
|
||||||
return
|
|
||||||
index < 0 || index > 31 ? 0 :
|
|
||||||
system ? cpu.setSystemRegister(index, value, true) :
|
|
||||||
index == 0 ? 0 : (cpu.program[index] = value)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide new ROM data
|
|
||||||
public boolean setROM(byte[] data, int offset, int length) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (
|
|
||||||
data == null ||
|
|
||||||
offset < 0 ||
|
|
||||||
length < 1024 || length > 0x01000000 ||
|
|
||||||
(length & length - 1) != 0 ||
|
|
||||||
offset + length > data.length
|
|
||||||
) return false;
|
|
||||||
|
|
||||||
// Accept the new ROM data
|
|
||||||
pak.rom = new byte[length];
|
|
||||||
System.arraycopy(data, offset, pak.rom, 0, length);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
|
||||||
public void write(int address, int type, int value) {
|
|
||||||
switch (address >> 24 & 7) {
|
|
||||||
case 0: vip.write ( address, type, value); break;
|
|
||||||
case 5: writeBuffer(wram , address, type, value); break;
|
|
||||||
case 6: writeBuffer(pak.ram, address, type, value); break;
|
|
||||||
case 7: writeBuffer(pak.rom, address, type, value); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write bytes to the CPU bus
|
|
||||||
public boolean writeBytes(int address, byte[] src, int offset, int length){
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (
|
|
||||||
src == null ||
|
|
||||||
offset < 0 ||
|
|
||||||
length < 0 ||
|
|
||||||
offset + length > src.length
|
|
||||||
) return false;
|
|
||||||
|
|
||||||
// Perform the operation
|
|
||||||
while (length > 0) {
|
|
||||||
int count = Math.min(length, 0x01000000 - (address & 0x00FFFFFF));
|
|
||||||
switch (address >> 24 & 7) {
|
|
||||||
case 0: vip.writeBytes( address,src,offset,count); break;
|
|
||||||
case 5: writeBytes(wram ,address,src,offset,count); break;
|
|
||||||
case 6: writeBytes(pak.ram,address,src,offset,count); break;
|
|
||||||
case 7: writeBytes(pak.rom,address,src,offset,count); break;
|
|
||||||
}
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
offset += count;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Retrieve the current state's breakpoint scenario
|
|
||||||
int getBreakType() {
|
|
||||||
return breakType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the current instruction fetch index
|
|
||||||
int getFetch() {
|
|
||||||
return cpu.fetch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for breakpoints
|
|
||||||
boolean onBreakpoint(int breakType) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processing for Read and Write
|
|
||||||
else if (breakType==Breakpoint.READ || breakType==Breakpoint.WRITE) {
|
|
||||||
ranged = true;
|
|
||||||
start = cpu.access.address;
|
|
||||||
end = start + TYPE_SIZES[cpu.access.type] - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check all breakpoints
|
|
||||||
int count = breakpoints.size();
|
|
||||||
boolean fetch = breakType == Breakpoint.READ && cpu.fetch != -1;
|
|
||||||
for (int x = 0; breakCode == 0 && x < count; x++) {
|
|
||||||
var brk = breakpoints.get(x);
|
|
||||||
if (
|
|
||||||
brk.appliesTo(breakType, fetch) &&
|
|
||||||
(!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
|
|
||||||
static int readBuffer(byte[] data, int address, int type) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (data == null)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Processing by data type
|
|
||||||
int size = TYPE_SIZES[type];
|
|
||||||
int value = 0;
|
|
||||||
address &= ~size + 1 & data.length - 1;
|
|
||||||
switch (type) {
|
|
||||||
case Vue.S32: value =
|
|
||||||
data[address + 3] << 24 |
|
|
||||||
(data[address + 2] & 0xFF) << 16;
|
|
||||||
// Fallthrough
|
|
||||||
case Vue.S16: // Fallthrough
|
|
||||||
case Vue.U16: value |=
|
|
||||||
(data[address + 1] & 0xFF) << 8;
|
|
||||||
// Fallthrough
|
|
||||||
case Vue.S8 : // Fallthrough
|
|
||||||
case Vue.U8 : value |=
|
|
||||||
data[address ] & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign-extend the value if appropriate
|
|
||||||
if ((type & 1) == 0) {
|
|
||||||
size = 32 - (size << 3);
|
|
||||||
value = value << size >> size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read bytes from a byte buffer
|
|
||||||
static void readBytes(byte[] data, int address, byte[] dest, int offset,
|
|
||||||
int length) {
|
|
||||||
|
|
||||||
// The source does not exist
|
|
||||||
if (data == null) {
|
|
||||||
Arrays.fill(dest, offset, offset + length, (byte) 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfer bytes from the source as a circular buffer
|
|
||||||
while (length > 0) {
|
|
||||||
address &= data.length - 1;
|
|
||||||
int count = Math.min(length, data.length - address);
|
|
||||||
System.arraycopy(data, address, dest, offset, count);
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
offset += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
static void writeBuffer(byte[] data, int address, int type, int value) {
|
|
||||||
|
|
||||||
// The destination does not exist
|
|
||||||
if (data == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Processing by data type
|
|
||||||
int size = TYPE_SIZES[type];
|
|
||||||
address &= ~size + 1 & data.length - 1;
|
|
||||||
switch (type) {
|
|
||||||
case Vue.S32:
|
|
||||||
data[address + 3] = (byte) (value >> 24);
|
|
||||||
data[address + 2] = (byte) (value >> 16);
|
|
||||||
// Fallthrough
|
|
||||||
case Vue.S16: // Fallthrough
|
|
||||||
case Vue.U16:
|
|
||||||
data[address + 1] = (byte) (value >> 8);
|
|
||||||
// Fallthrough
|
|
||||||
case Vue.S8 : // Fallthrough
|
|
||||||
case Vue.U8 : value |=
|
|
||||||
data[address ] = (byte) value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write bytes to a byte buffer
|
|
||||||
static void writeBytes(byte[] data, int address, byte[] src, int offset,
|
|
||||||
int length) {
|
|
||||||
|
|
||||||
// The destination does not exist
|
|
||||||
if (data == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Transfer bytes to the destination as a circular buffer
|
|
||||||
while (length > 0) {
|
|
||||||
address &= data.length - 1;
|
|
||||||
int count = Math.min(length, data.length - address);
|
|
||||||
System.arraycopy(src, offset, data, address, count);
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
offset += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,348 +0,0 @@
|
||||||
// Native-backed emulation core implementation
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <jni.h>
|
|
||||||
#include <vue.h>
|
|
||||||
#include "vue_NativeVue.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Memory access type sizes
|
|
||||||
static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|
||||||
|
|
||||||
// Word data type limits
|
|
||||||
#define MAX_WORD 2147483648.0f
|
|
||||||
#define MAX_UWORD 4294967296.0f
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Types //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Breakpoint condition token
|
|
||||||
typedef struct {
|
|
||||||
int32_t type; // Token category
|
|
||||||
int32_t id; // Operator or symbol ID, or literal value
|
|
||||||
} Token;
|
|
||||||
|
|
||||||
// Precompiled breakpoint
|
|
||||||
typedef struct {
|
|
||||||
int32_t enabled; // The breakpoint is enabled
|
|
||||||
int32_t fetch; // Breakpoint traps fetch reads
|
|
||||||
int32_t hooks; // Events hooked by the breakpoint
|
|
||||||
int32_t numRanges; // Number of address ranges
|
|
||||||
int32_t numTokens; // Number of condition tokens
|
|
||||||
uint32_t *ranges; // Address ranges
|
|
||||||
Token *tokens; // Condition tokens in RPN order
|
|
||||||
} Breakpoint;
|
|
||||||
|
|
||||||
// Core context state type
|
|
||||||
typedef struct {
|
|
||||||
Vue vue; // Context into the generic C library
|
|
||||||
int32_t breakType; // Most recent breakpoint scenario
|
|
||||||
int32_t numBreakpoints; // Number of breakpoints
|
|
||||||
Breakpoint *breakpoints; // Application breakpoints
|
|
||||||
int32_t *stack; // Expression stack for breakpoints
|
|
||||||
} Core;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Macros //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/* Sign-extend a value */
|
|
||||||
#define SIGN_EXTEND(bits, value) \
|
|
||||||
((value) & 1 << (bits - 1) ? (value) | (~(1 << bits) + 1) : (value))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Component Includes //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#define NATIVEVUE
|
|
||||||
#include "Breakpoint.c"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Native constructor
|
|
||||||
JNIEXPORT jlong JNICALL Java_vue_NativeVue_construct
|
|
||||||
(JNIEnv *env, jobject uve) {
|
|
||||||
Core *mem[] = { NULL, NULL };
|
|
||||||
Core *core = mem[0] = calloc(sizeof (Core), 1);
|
|
||||||
Vue *vue = &core->vue;
|
|
||||||
vueInitialize (vue);
|
|
||||||
vueOnException(vue, &brkOnException);
|
|
||||||
vueOnExecute (vue, &brkOnExecute );
|
|
||||||
vueOnFrame (vue, &brkOnFrame );
|
|
||||||
vueOnRead (vue, &brkOnRead );
|
|
||||||
vueOnWrite (vue, &brkOnWrite );
|
|
||||||
vueReset (vue);
|
|
||||||
vueSetTag (vue, core);
|
|
||||||
return *(jlong *)&core;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Produce a new breakpoint and add it to the collection
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_breakpoint
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
core->numBreakpoints++;
|
|
||||||
core->breakpoints =
|
|
||||||
realloc(core->breakpoints,core->numBreakpoints * sizeof (Breakpoint));
|
|
||||||
Breakpoint *brk = &core->breakpoints[core->numBreakpoints - 1];
|
|
||||||
memset(brk, 0 ,sizeof (Breakpoint));
|
|
||||||
brk->fetch = VUE_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release any used resources
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_dispose
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
Breakpoint *brk; // Handle to breakpoint
|
|
||||||
int x; // Iterator
|
|
||||||
|
|
||||||
// Delete breakpoints
|
|
||||||
for (x = 0; x < core->numBreakpoints; x++) {
|
|
||||||
brk = &core->breakpoints[x];
|
|
||||||
free(brk->ranges);
|
|
||||||
free(brk->tokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete core
|
|
||||||
free(core->breakpoints);
|
|
||||||
free(core->stack );
|
|
||||||
free(core->vue.pak.rom);
|
|
||||||
free(core->vue.pak.ram);
|
|
||||||
free(core);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the simulation
|
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_emulate
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint maxCycles) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
return vueEmulate(&core->vue, maxCycles);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the most recent exception code
|
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getBreakCode
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
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
|
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getRegister
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
return vueGetRegister(&core->vue, index, system);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a copy of the ROM data
|
|
||||||
JNIEXPORT jbyteArray JNICALL Java_vue_NativeVue_getROM
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
|
|
||||||
// No ROM data
|
|
||||||
if (core->vue.pak.rom == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Copy the ROM data
|
|
||||||
jbyteArray ret = (*env)->NewByteArray(env, (jint)core->vue.pak.romSize);
|
|
||||||
jbyte *elems = (*env)->GetByteArrayElements(env, ret, NULL);
|
|
||||||
memcpy(elems, core->vue.pak.rom, core->vue.pak.romSize);
|
|
||||||
(*env)->ReleaseByteArrayElements(env, ret, elems, 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a value from the CPU bus
|
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_read
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint address, jint type) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
return vueRead(&core->vue, address, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read bytes from the CPU bus
|
|
||||||
JNIEXPORT jboolean JNICALL Java_vue_NativeVue_readBytes
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint address, jbyteArray data,
|
|
||||||
jint offset, jint length) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (
|
|
||||||
data == NULL ||
|
|
||||||
offset < 0 ||
|
|
||||||
length < 0 ||
|
|
||||||
offset + length > (*env)->GetArrayLength(env, data)
|
|
||||||
) return JNI_FALSE;
|
|
||||||
|
|
||||||
// Perform the operation
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL);
|
|
||||||
vueReadBytes(&core->vue, address, &elems[offset], length);
|
|
||||||
(*env)->ReleaseByteArrayElements(env, data, elems, 0);
|
|
||||||
return JNI_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a breakpoint from the collection
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_remove
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
Breakpoint *brk = &core->breakpoints[index];
|
|
||||||
free(brk->ranges);
|
|
||||||
free(brk->tokens);
|
|
||||||
memmove(brk, &core->breakpoints[index + 1],
|
|
||||||
(core->numBreakpoints - index - 1) * sizeof (Breakpoint));
|
|
||||||
core->numBreakpoints--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize all system components
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_reset
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
vueReset(&core->vue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify a register value
|
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_setRegister
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jboolean system,
|
|
||||||
jint value) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
return vueSetRegister(&core->vue, index, system, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide new ROM data
|
|
||||||
JNIEXPORT jboolean JNICALL Java_vue_NativeVue_setROM
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jbyteArray data, jint offset,
|
|
||||||
jint length) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (
|
|
||||||
data == NULL ||
|
|
||||||
offset < 0 ||
|
|
||||||
length < 1024 || length > 0x01000000 ||
|
|
||||||
(length & length - 1) != 0 ||
|
|
||||||
offset + length > (*env)->GetArrayLength(env, data)
|
|
||||||
) return JNI_FALSE;
|
|
||||||
|
|
||||||
// Accept the new ROM data
|
|
||||||
uint8_t *rom = malloc(length);
|
|
||||||
jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL);
|
|
||||||
memcpy(rom, &elems[offset], length);
|
|
||||||
(*env)->ReleaseByteArrayElements(env, data, elems, 0);
|
|
||||||
|
|
||||||
// Transfer the ROM data to the emulation state
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
free(core->vue.pak.rom);
|
|
||||||
vueSetROM(&core->vue, rom, length);
|
|
||||||
return JNI_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_write
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint address, jint type,
|
|
||||||
jint value) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
vueWrite(&core->vue, address, type, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write bytes to the CPU bus
|
|
||||||
JNIEXPORT jboolean JNICALL Java_vue_NativeVue_writeBytes
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint address, jbyteArray data,
|
|
||||||
jint offset, jint length) {
|
|
||||||
|
|
||||||
// Error checking
|
|
||||||
if (
|
|
||||||
data == NULL ||
|
|
||||||
offset < 0 ||
|
|
||||||
length < 0 ||
|
|
||||||
offset + length > (*env)->GetArrayLength(env, data)
|
|
||||||
) return JNI_FALSE;
|
|
||||||
|
|
||||||
// Perform the operation
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
jbyte *elems = (*env)->GetByteArrayElements(env, data, NULL);
|
|
||||||
vueWriteBytes(&core->vue, address, &elems[offset], length);
|
|
||||||
(*env)->ReleaseByteArrayElements(env, data, elems, 0);
|
|
||||||
return JNI_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Retrieve the current state's breakpoint scenario
|
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getBreakType
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
return core->breakType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the current instruction fetch index
|
|
||||||
JNIEXPORT jint JNICALL Java_vue_NativeVue_getFetch
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
return core->vue.cpu.fetch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A breakpoint's address ranges have changed
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateRanges
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jintArray ranges) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
Breakpoint *brk = &core->breakpoints[index];
|
|
||||||
brk->numRanges = (*env)->GetArrayLength(env, ranges);
|
|
||||||
brk->ranges = realloc(brk->ranges, brk->numRanges * 8);
|
|
||||||
jint *elems = (*env)->GetIntArrayElements(env, ranges, NULL);
|
|
||||||
memcpy(brk->ranges, elems, brk->numRanges * 8);
|
|
||||||
(*env)->ReleaseIntArrayElements(env, ranges, elems, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A breakpoint's enabled/hook state has changed
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateState
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jboolean enabled,
|
|
||||||
jboolean fetch, jint hooks) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
Breakpoint *brk = &core->breakpoints[index];
|
|
||||||
brk->enabled = enabled;
|
|
||||||
brk->fetch = fetch;
|
|
||||||
brk->hooks = hooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A breakpoint's condition tokens have changed
|
|
||||||
JNIEXPORT void JNICALL Java_vue_NativeVue_updateTokens
|
|
||||||
(JNIEnv *env, jobject vue, jlong handle, jint index, jintArray tokens,
|
|
||||||
jint depth, jint maxDepth) {
|
|
||||||
Core *core = *(Core **)&handle;
|
|
||||||
core->stack = realloc(core->stack, maxDepth * 4);
|
|
||||||
Breakpoint *brk = &core->breakpoints[index];
|
|
||||||
brk->numTokens = (*env)->GetArrayLength(env, tokens) / 2;
|
|
||||||
brk->tokens = realloc(brk->tokens, brk->numTokens * sizeof (Token));
|
|
||||||
jint *elems = (*env)->GetIntArrayElements(env, tokens, NULL);
|
|
||||||
memcpy(brk->tokens, elems, brk->numTokens * sizeof (Token));
|
|
||||||
(*env)->ReleaseIntArrayElements(env, tokens, elems, 0);
|
|
||||||
}
|
|
|
@ -1,170 +0,0 @@
|
||||||
package vue;
|
|
||||||
|
|
||||||
// Native-backed emulation core implementation
|
|
||||||
class NativeVue extends Vue {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
private long handle; // Context address in native memory
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
private native long construct();
|
|
||||||
NativeVue() {
|
|
||||||
handle = construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Produce a new breakpoint and add it to the collection
|
|
||||||
private native void breakpoint(long handle);
|
|
||||||
public Breakpoint breakpoint() {
|
|
||||||
var brk = super.breakpoint();
|
|
||||||
breakpoint(handle);
|
|
||||||
return brk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release any used resources
|
|
||||||
private native void dispose(long handle);
|
|
||||||
public void dispose()
|
|
||||||
{ dispose(handle); }
|
|
||||||
|
|
||||||
// Process the simulation
|
|
||||||
private native int emulate(long handle, int maxCycles);
|
|
||||||
public int emulate(int maxCycles)
|
|
||||||
{ return emulate(handle, maxCycles); }
|
|
||||||
|
|
||||||
// Retrieve the most recent application break code
|
|
||||||
private native int getBreakCode(long handle);
|
|
||||||
public int getBreakCode() { return getBreakCode(handle); }
|
|
||||||
|
|
||||||
// Retrieve the most recent exception code
|
|
||||||
private native int getExceptionCode(long handle);
|
|
||||||
public int getExceptionCode() {
|
|
||||||
return getExceptionCode(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a register value
|
|
||||||
private native int getRegister(long handle, int index, boolean system);
|
|
||||||
public int getRegister(int index, boolean system)
|
|
||||||
{ return getRegister(handle, index, system); }
|
|
||||||
|
|
||||||
// Retrieve a copy of the ROM data
|
|
||||||
private native byte[] getROM(long handle);
|
|
||||||
public byte[] getROM() { return getROM(handle); }
|
|
||||||
|
|
||||||
// Determine whether the context is native-backed
|
|
||||||
public boolean isNative() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a value from the CPU bus
|
|
||||||
private native int read(long handle, int address, int type);
|
|
||||||
public int read(int address, int type)
|
|
||||||
{ return read(handle, address, type); }
|
|
||||||
|
|
||||||
// Read bytes from the CPU bus
|
|
||||||
private native boolean readBytes(long handle, int address, byte[] dest,
|
|
||||||
int offset, int length);
|
|
||||||
public boolean readBytes(int address, byte[] dest, int offset, int length)
|
|
||||||
{ return readBytes(handle, address, dest, offset, length); }
|
|
||||||
|
|
||||||
// Remove a breakpoint from the collection
|
|
||||||
private native void remove(long handle, int index);
|
|
||||||
public boolean remove(Breakpoint brk) {
|
|
||||||
int index = breakpoints.indexOf(brk);
|
|
||||||
if (!super.remove(brk))
|
|
||||||
return false;
|
|
||||||
remove(handle, index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize all system components
|
|
||||||
private native void reset(long handle);
|
|
||||||
public void reset()
|
|
||||||
{ reset(handle); }
|
|
||||||
|
|
||||||
// Specify a register value
|
|
||||||
private native int setRegister(long handle, int index, boolean system,
|
|
||||||
int value);
|
|
||||||
public int setRegister(int index, boolean system, int value)
|
|
||||||
{ return setRegister(handle, index, system, value); }
|
|
||||||
|
|
||||||
// Provide new ROM data
|
|
||||||
private native boolean setROM(long handle, byte[] data, int offset,
|
|
||||||
int length);
|
|
||||||
public boolean setROM(byte[] data, int offset, int length)
|
|
||||||
{ return setROM(handle, data, offset, length); }
|
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
|
||||||
private native void write(long handle, int address, int type, int value);
|
|
||||||
public void write(int address, int type, int value)
|
|
||||||
{ write(handle, address, type, value); }
|
|
||||||
|
|
||||||
// Write bytes to the CPU bus
|
|
||||||
private native boolean writeBytes(long handle, int address, byte[] src,
|
|
||||||
int offset, int length);
|
|
||||||
public boolean writeBytes(int address, byte[] src, int offset, int length)
|
|
||||||
{ return writeBytes(handle, address, src, offset, length); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Retrieve the current state's breakpoint scenario
|
|
||||||
private native int getBreakType(long handle);
|
|
||||||
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
|
|
||||||
private native void updateRanges(long handle, int index, int[] ranges);
|
|
||||||
void updateRanges(Breakpoint brk) {
|
|
||||||
super.updateRanges(brk);
|
|
||||||
int index = breakpoints.indexOf(brk);
|
|
||||||
if (index >= 0)
|
|
||||||
updateRanges(handle, index, brk.flattenRanges());
|
|
||||||
}
|
|
||||||
|
|
||||||
// A breakpoint's enabled/hook state has changed
|
|
||||||
private native void updateState(long handle, int index, boolean enabled,
|
|
||||||
boolean fetch, int hooks);
|
|
||||||
void updateState(Breakpoint brk) {
|
|
||||||
super.updateState(brk);
|
|
||||||
int index = breakpoints.indexOf(brk);
|
|
||||||
updateState(handle, index,
|
|
||||||
brk.isEnabled(), brk.getFetch(), brk.getHooks());
|
|
||||||
}
|
|
||||||
|
|
||||||
// A breakpoint's condition tokens have changed
|
|
||||||
private native void updateTokens(long handle, int index, int[] tokens,
|
|
||||||
int depth, int maxDepth);
|
|
||||||
void updateTokens(Breakpoint brk) {
|
|
||||||
super.updateTokens(brk);
|
|
||||||
int index = breakpoints.indexOf(brk);
|
|
||||||
if (index < 0)
|
|
||||||
return;
|
|
||||||
int maxDepth = 0;
|
|
||||||
for (var bre : breakpoints)
|
|
||||||
maxDepth = Math.max(maxDepth, bre.getDepth());
|
|
||||||
updateTokens(handle, index, brk.flattenTokens(),
|
|
||||||
brk.getDepth(), maxDepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,309 +0,0 @@
|
||||||
package vue;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
// VIP state
|
|
||||||
class VIP {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
byte[] vram; // Video memory
|
|
||||||
|
|
||||||
// Private fields
|
|
||||||
private JavaVue vue; // Emulation state
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
VIP(JavaVue vue) {
|
|
||||||
vram = new byte[0x40000];
|
|
||||||
this.vue = vue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Package Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Process the simulation
|
|
||||||
void emulate(int cycles) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a value from the CPU bus
|
|
||||||
int read(int address, int type) {
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
// VRAM
|
|
||||||
if (address < 0x00040000)
|
|
||||||
return JavaVue.readBuffer(vram, address, type);
|
|
||||||
|
|
||||||
// Mirrors of character memory
|
|
||||||
if (address >= 0x00078000)
|
|
||||||
return JavaVue.readBuffer(vram,
|
|
||||||
address - 0x00078000 >> 13 << 15 | 0x00006000 |
|
|
||||||
address & 0x00001FFF,
|
|
||||||
type);
|
|
||||||
|
|
||||||
// I/O register or unmapped
|
|
||||||
int value = readRegister(address);
|
|
||||||
if (type < 2 && (address & 1) == 1)
|
|
||||||
value >>= 8;
|
|
||||||
switch (type) {
|
|
||||||
case Vue.S8 : return value << 24 >> 24;
|
|
||||||
case Vue.U8 : return value & 0x000000FF;
|
|
||||||
case Vue.S16: return value << 16 >> 16;
|
|
||||||
case Vue.S32: return value | readRegister(address + 2) << 16;
|
|
||||||
}
|
|
||||||
return value; // U16
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read bytes from the CPU bus
|
|
||||||
void readBytes(int address, byte[] dest, int offset, int length) {
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
// Perform the operation
|
|
||||||
while (length > 0) {
|
|
||||||
int count;
|
|
||||||
|
|
||||||
// VRAM
|
|
||||||
if (address < 0x00040000) {
|
|
||||||
count = Math.min(length, 0x00040000 - address);
|
|
||||||
JavaVue.readBytes(vram, address, dest, offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mirrors of character memory
|
|
||||||
else if (address >= 0x00078000) {
|
|
||||||
count = Math.min(length, 0x2000 - (address & 0x1FFF));
|
|
||||||
JavaVue.readBytes(vram,
|
|
||||||
address - 0x00078000 >> 13 << 15 | 0x00006000 |
|
|
||||||
address & 0x00001FFF,
|
|
||||||
dest, offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// I/O register or unmapped
|
|
||||||
else {
|
|
||||||
count = Math.min(length, 0x00078000 - address);
|
|
||||||
|
|
||||||
// Read all registers in the range
|
|
||||||
while (count > 0) {
|
|
||||||
int value = readRegister(address);
|
|
||||||
|
|
||||||
// Odd address
|
|
||||||
if ((address & 1) == 1) {
|
|
||||||
dest[offset] = (byte) (value >> 8);
|
|
||||||
address++;
|
|
||||||
count --;
|
|
||||||
length --;
|
|
||||||
offset ++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Even address
|
|
||||||
int size = count == 1 ? 1 : 2;
|
|
||||||
dest[offset] = (byte) value;
|
|
||||||
if (size == 2)
|
|
||||||
dest[offset + 1] = (byte) (value >> 8);
|
|
||||||
address += size;
|
|
||||||
count -= size;
|
|
||||||
length -= size;
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance to the next region
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
offset += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// System reset
|
|
||||||
void reset() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the number of CPU cycles until a breakpoint could trigger
|
|
||||||
int until(int cycles) {
|
|
||||||
return cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
|
||||||
void write(int address, int type, int value) {
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
// VRAM
|
|
||||||
if (address < 0x00040000) {
|
|
||||||
JavaVue.writeBuffer(vram, address, type, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mirrors of character memory
|
|
||||||
if (address >= 0x00078000) {
|
|
||||||
JavaVue.writeBuffer(vram,
|
|
||||||
address - 0x00078000 >> 13 << 15 | 0x00006000 |
|
|
||||||
address & 0x00001FFF,
|
|
||||||
type, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// I/O register or unmapped
|
|
||||||
if (type < 2 && (address & 1) == 1)
|
|
||||||
value <<= 8;
|
|
||||||
writeRegister(address, value);
|
|
||||||
if (type == Vue.S32)
|
|
||||||
writeRegister(address + 2, value >> 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write bytes to the CPU bus
|
|
||||||
void writeBytes(int address, byte[] src, int offset, int length) {
|
|
||||||
address &= 0x0007FFFF;
|
|
||||||
|
|
||||||
// Perform the operation
|
|
||||||
while (length > 0) {
|
|
||||||
int count;
|
|
||||||
|
|
||||||
// VRAM
|
|
||||||
if (address < 0x00040000) {
|
|
||||||
count = Math.min(length, 0x00040000 - address);
|
|
||||||
JavaVue.writeBytes(vram, address, src, offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mirrors of character memory
|
|
||||||
else if (address >= 0x00078000) {
|
|
||||||
count = Math.min(length, 0x2000 - (address & 0x1FFF));
|
|
||||||
JavaVue.writeBytes(vram,
|
|
||||||
address - 0x00078000 >> 13 << 15 | 0x00006000 |
|
|
||||||
address & 0x00001FFF,
|
|
||||||
src, offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// I/O register or unmapped
|
|
||||||
else {
|
|
||||||
count = Math.min(length, 0x00078000 - address);
|
|
||||||
|
|
||||||
// Write all registers in the range
|
|
||||||
while (count > 0) {
|
|
||||||
int value = src[offset] & 0xFF;
|
|
||||||
|
|
||||||
// Odd address
|
|
||||||
if ((address & 1) == 1) {
|
|
||||||
writeRegister(address, value << 8);
|
|
||||||
address++;
|
|
||||||
count --;
|
|
||||||
length --;
|
|
||||||
offset ++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Even address
|
|
||||||
int size = count == 1 ? 1 : 2;
|
|
||||||
if (size == 2)
|
|
||||||
value |= src[offset + 1] << 8;
|
|
||||||
writeRegister(address, value);
|
|
||||||
address += size;
|
|
||||||
count -= size;
|
|
||||||
length -= size;
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance to the next region
|
|
||||||
address += count;
|
|
||||||
length -= count;
|
|
||||||
offset += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Read an I/O register
|
|
||||||
private int readRegister(int address) {
|
|
||||||
|
|
||||||
// Process by register
|
|
||||||
switch (address & ~1) {
|
|
||||||
case 0x0005F800: break; // INTPND
|
|
||||||
case 0x0005F802: break; // INTENB
|
|
||||||
case 0x0005F804: break; // INTCLR
|
|
||||||
case 0x0005F820: break; // DPSTTS
|
|
||||||
case 0x0005F822: break; // DPCTRL
|
|
||||||
case 0x0005F824: break; // BRTA
|
|
||||||
case 0x0005F826: break; // BRTB
|
|
||||||
case 0x0005F828: break; // BRTC
|
|
||||||
case 0x0005F82A: break; // REST
|
|
||||||
case 0x0005F82E: break; // FRMCYC
|
|
||||||
case 0x0005F830: break; // CTA
|
|
||||||
case 0x0005F840: break; // XPSTTS
|
|
||||||
case 0x0005F842: break; // XPCTRL
|
|
||||||
case 0x0005F844: break; // VER
|
|
||||||
case 0x0005F848: break; // SPT0
|
|
||||||
case 0x0005F84A: break; // SPT1
|
|
||||||
case 0x0005F84C: break; // SPT2
|
|
||||||
case 0x0005F84E: break; // SPT3
|
|
||||||
case 0x0005F860: break; // GPLT0
|
|
||||||
case 0x0005F862: break; // GPLT1
|
|
||||||
case 0x0005F864: break; // GPLT2
|
|
||||||
case 0x0005F866: break; // GPLT3
|
|
||||||
case 0x0005F868: break; // JPLT0
|
|
||||||
case 0x0005F86A: break; // JPLT1
|
|
||||||
case 0x0005F86C: break; // JPLT2
|
|
||||||
case 0x0005F86E: break; // JPLT3
|
|
||||||
case 0x0005F870: break; // BKCOL
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmapped
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write an I/O register
|
|
||||||
private void writeRegister(int address, int value) {
|
|
||||||
|
|
||||||
// Process by register
|
|
||||||
switch (address & ~1) {
|
|
||||||
case 0x0005F800: break; // INTPND
|
|
||||||
case 0x0005F802: break; // INTENB
|
|
||||||
case 0x0005F804: break; // INTCLR
|
|
||||||
case 0x0005F820: break; // DPSTTS
|
|
||||||
case 0x0005F822: break; // DPCTRL
|
|
||||||
case 0x0005F824: break; // BRTA
|
|
||||||
case 0x0005F826: break; // BRTB
|
|
||||||
case 0x0005F828: break; // BRTC
|
|
||||||
case 0x0005F82A: break; // REST
|
|
||||||
case 0x0005F82E: break; // FRMCYC
|
|
||||||
case 0x0005F830: break; // CTA
|
|
||||||
case 0x0005F840: break; // XPSTTS
|
|
||||||
case 0x0005F842: break; // XPCTRL
|
|
||||||
case 0x0005F844: break; // VER
|
|
||||||
case 0x0005F848: break; // SPT0
|
|
||||||
case 0x0005F84A: break; // SPT1
|
|
||||||
case 0x0005F84C: break; // SPT2
|
|
||||||
case 0x0005F84E: break; // SPT3
|
|
||||||
case 0x0005F860: break; // GPLT0
|
|
||||||
case 0x0005F862: break; // GPLT1
|
|
||||||
case 0x0005F864: break; // GPLT2
|
|
||||||
case 0x0005F866: break; // GPLT3
|
|
||||||
case 0x0005F868: break; // JPLT0
|
|
||||||
case 0x0005F86A: break; // JPLT1
|
|
||||||
case 0x0005F86C: break; // JPLT2
|
|
||||||
case 0x0005F86E: break; // JPLT3
|
|
||||||
case 0x0005F870: break; // BKCOL
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,266 +0,0 @@
|
||||||
package vue;
|
|
||||||
|
|
||||||
// Java imports
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
// Template for emulation core implementations
|
|
||||||
public abstract class Vue {
|
|
||||||
|
|
||||||
// Instance fields
|
|
||||||
ArrayList<Breakpoint> breakpoints; // Current breakpoints
|
|
||||||
|
|
||||||
// Static fields
|
|
||||||
private static String nativeID = null; // ID of loaded native library
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constants //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Memory access types
|
|
||||||
public static final int S8 = 0;
|
|
||||||
public static final int U8 = 1;
|
|
||||||
public static final int S16 = 2;
|
|
||||||
public static final int U16 = 3;
|
|
||||||
public static final int S32 = 4;
|
|
||||||
public static final int CANCEL = 5;
|
|
||||||
|
|
||||||
// System register indexes
|
|
||||||
public static final int ADTRE = 25;
|
|
||||||
public static final int CHCW = 24;
|
|
||||||
public static final int ECR = 4;
|
|
||||||
public static final int EIPC = 0;
|
|
||||||
public static final int EIPSW = 1;
|
|
||||||
public static final int FEPC = 2;
|
|
||||||
public static final int FEPSW = 3;
|
|
||||||
public static final int PIR = 6;
|
|
||||||
public static final int PSW = 5;
|
|
||||||
public static final int TKCW = 7;
|
|
||||||
|
|
||||||
// Non-standard register indexes
|
|
||||||
public static final int PC = -1;
|
|
||||||
public static final int JUMP_FROM = -2;
|
|
||||||
public static final int JUMP_TO = -3;
|
|
||||||
|
|
||||||
// Program register indexes
|
|
||||||
public static final int GP = 4;
|
|
||||||
public static final int HP = 2;
|
|
||||||
public static final int LP = 31;
|
|
||||||
public static final int SP = 3;
|
|
||||||
public static final int TP = 5;
|
|
||||||
|
|
||||||
// Instruction IDs
|
|
||||||
public static final int ILLEGAL = -1;
|
|
||||||
public static final int ADD_IMM = 0;
|
|
||||||
public static final int ADD_REG = 1;
|
|
||||||
public static final int ADDF_S = 2;
|
|
||||||
public static final int ADDI = 3;
|
|
||||||
public static final int AND = 4;
|
|
||||||
public static final int ANDBSU = 5;
|
|
||||||
public static final int ANDI = 6;
|
|
||||||
public static final int ANDNBSU = 7;
|
|
||||||
public static final int BCOND = 8;
|
|
||||||
public static final int CAXI = 9;
|
|
||||||
public static final int CLI = 10;
|
|
||||||
public static final int CMP_IMM = 11;
|
|
||||||
public static final int CMP_REG = 12;
|
|
||||||
public static final int CMPF_S = 13;
|
|
||||||
public static final int CVT_SW = 14;
|
|
||||||
public static final int CVT_WS = 15;
|
|
||||||
public static final int DIV = 16;
|
|
||||||
public static final int DIVF_S = 17;
|
|
||||||
public static final int DIVU = 18;
|
|
||||||
public static final int HALT = 19;
|
|
||||||
public static final int IN_B = 20;
|
|
||||||
public static final int IN_H = 21;
|
|
||||||
public static final int IN_W = 22;
|
|
||||||
public static final int JAL = 23;
|
|
||||||
public static final int JMP = 24;
|
|
||||||
public static final int JR = 25;
|
|
||||||
public static final int LD_B = 26;
|
|
||||||
public static final int LD_H = 27;
|
|
||||||
public static final int LD_W = 28;
|
|
||||||
public static final int LDSR = 29;
|
|
||||||
public static final int MOV_IMM = 30;
|
|
||||||
public static final int MOV_REG = 31;
|
|
||||||
public static final int MOVBSU = 32;
|
|
||||||
public static final int MOVEA = 33;
|
|
||||||
public static final int MOVHI = 34;
|
|
||||||
public static final int MPYHW = 35;
|
|
||||||
public static final int MUL = 36;
|
|
||||||
public static final int MULF_S = 37;
|
|
||||||
public static final int MULU = 38;
|
|
||||||
public static final int NOT = 39;
|
|
||||||
public static final int NOTBSU = 40;
|
|
||||||
public static final int OR = 41;
|
|
||||||
public static final int ORBSU = 42;
|
|
||||||
public static final int ORI = 43;
|
|
||||||
public static final int ORNBSU = 44;
|
|
||||||
public static final int OUT_B = 45;
|
|
||||||
public static final int OUT_H = 46;
|
|
||||||
public static final int OUT_W = 47;
|
|
||||||
public static final int RETI = 48;
|
|
||||||
public static final int REV = 49;
|
|
||||||
public static final int SAR_IMM = 50;
|
|
||||||
public static final int SAR_REG = 51;
|
|
||||||
public static final int SCH0BSD = 52;
|
|
||||||
public static final int SCH0BSU = 53;
|
|
||||||
public static final int SCH1BSD = 54;
|
|
||||||
public static final int SCH1BSU = 55;
|
|
||||||
public static final int SEI = 56;
|
|
||||||
public static final int SETF = 57;
|
|
||||||
public static final int SHL_IMM = 58;
|
|
||||||
public static final int SHL_REG = 59;
|
|
||||||
public static final int SHR_IMM = 60;
|
|
||||||
public static final int SHR_REG = 61;
|
|
||||||
public static final int ST_B = 62;
|
|
||||||
public static final int ST_H = 63;
|
|
||||||
public static final int ST_W = 64;
|
|
||||||
public static final int STSR = 65;
|
|
||||||
public static final int SUB = 66;
|
|
||||||
public static final int SUBF_S = 67;
|
|
||||||
public static final int TRAP = 68;
|
|
||||||
public static final int TRNC_SW = 69;
|
|
||||||
public static final int XB = 70;
|
|
||||||
public static final int XH = 71;
|
|
||||||
public static final int XOR = 72;
|
|
||||||
public static final int XORBSU = 73;
|
|
||||||
public static final int XORI = 74;
|
|
||||||
public static final int XORNBSU = 75;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Static Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Produce an emulation core context
|
|
||||||
public static Vue create(boolean useNative) {
|
|
||||||
return !useNative ? new JavaVue() :
|
|
||||||
nativeID != null ? new NativeVue() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the ID of the loaded native library, if any
|
|
||||||
public static String getNativeID() {
|
|
||||||
return nativeID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the ID of the loaded native library
|
|
||||||
public static void setNativeID(String nativeID) {
|
|
||||||
Vue.nativeID = nativeID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default constructor
|
|
||||||
Vue() {
|
|
||||||
breakpoints = new ArrayList<Breakpoint>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Public Methods //
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Produce a new breakpoint and add it to the collection
|
|
||||||
public Breakpoint breakpoint() {
|
|
||||||
var brk = new Breakpoint(this);
|
|
||||||
breakpoints.add(brk);
|
|
||||||
return brk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release any used resources
|
|
||||||
public abstract void dispose();
|
|
||||||
|
|
||||||
// Process the simulation
|
|
||||||
public abstract int emulate(int maxCycles);
|
|
||||||
|
|
||||||
// Evaluate an expression
|
|
||||||
public Object evaluate(String expression) {
|
|
||||||
var inst = new Instruction(read(getRegister(PC, true), S32));
|
|
||||||
var brk = new Breakpoint(this);
|
|
||||||
brk.setCondition(expression);
|
|
||||||
brk.setEnabled (true);
|
|
||||||
return brk.evaluateTyped(
|
|
||||||
new int[brk.getDepth()], 0, inst, inst.access(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the most recent applicaiton break code
|
|
||||||
public abstract int getBreakCode();
|
|
||||||
|
|
||||||
// Retrieve the most recent exception code
|
|
||||||
public abstract int getExceptionCode();
|
|
||||||
|
|
||||||
// Retrieve a register value
|
|
||||||
public abstract int getRegister(int index, boolean system);
|
|
||||||
|
|
||||||
// Retrieve a copy of the ROM data
|
|
||||||
public abstract byte[] getROM();
|
|
||||||
|
|
||||||
// Determine whether the context is native-backed
|
|
||||||
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
|
|
||||||
public abstract int read(int address, int type);
|
|
||||||
|
|
||||||
// Read bytes from the CPU bus
|
|
||||||
public abstract boolean readBytes(int address, byte[] dest, int offset,
|
|
||||||
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
|
|
||||||
public abstract void reset();
|
|
||||||
|
|
||||||
// Specify a register value
|
|
||||||
public abstract int setRegister(int index, boolean system, int value);
|
|
||||||
|
|
||||||
// Provide new ROM data
|
|
||||||
public abstract boolean setROM(byte[] data, int offset, int length);
|
|
||||||
|
|
||||||
// Write a value to the CPU bus
|
|
||||||
public abstract void write(int address, int type, int value);
|
|
||||||
|
|
||||||
// Write bytes to the CPU bus
|
|
||||||
public abstract boolean writeBytes(int address, byte[] src, int offset,
|
|
||||||
int length);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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
|
|
||||||
void updateRanges(Breakpoint brk) { }
|
|
||||||
|
|
||||||
// A breakpoint's enabled/hook state has changed
|
|
||||||
void updateState(Breakpoint brk) { }
|
|
||||||
|
|
||||||
// A breakpoint's condition tokens have changed
|
|
||||||
void updateTokens(Breakpoint brk) { }
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue