mirror of
https://codeberg.org/sethm/symon.git
synced 2026-11-07 19:12:23 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
199d96c025 | ||
|
|
0c026e38dd | ||
|
|
5e56627f32 | ||
|
|
67f5e17f78 | ||
|
|
5a25750f46 | ||
|
|
4a8a803472 | ||
|
|
4423623816 | ||
|
|
5df775bbb0 | ||
|
|
d076046f57 | ||
|
|
b725fb5fdd | ||
|
|
9351d785ae | ||
|
|
66a92f4196 | ||
|
|
cda9a218af | ||
|
|
b5a470d3ba | ||
|
|
e210a40639 | ||
|
|
0bad9912ce | ||
|
|
b36b442b14 | ||
|
|
5f8f743f7d | ||
|
|
4ce8bc86de | ||
|
|
4644fe9b55 | ||
|
|
655bbb3ab0 | ||
|
|
e2d31fd39c | ||
|
|
087ba28b82 | ||
|
|
8edca5d595 |
No files matched your search
@@ -1,6 +1,8 @@
|
|||||||
*~
|
*~
|
||||||
|
*.jar
|
||||||
*#
|
*#
|
||||||
target
|
target
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.idea
|
.idea
|
||||||
symon.iml
|
symon.iml
|
||||||
|
/dependency-reduced-pom.xml
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
SYMON - A 6502 System Simulator
|
SYMON - A 6502 System Simulator
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
**Version:** 1.3.1
|
**Version:** 1.3.2
|
||||||
|
|
||||||
**Last Updated:** 12 October, 2019
|
**Last Updated:** 08 March, 2021
|
||||||
|
|
||||||
See the file COPYING for license.
|
See the file COPYING for license.
|
||||||
|
|
||||||
@@ -36,8 +36,8 @@ are always welcome.
|
|||||||
|
|
||||||
## 3.0 Features
|
## 3.0 Features
|
||||||
|
|
||||||
Symon can simulate multiple 6502 based architectures. At present, three
|
Symon can simulate multiple 6502 based architectures. At present, four
|
||||||
machines are implemented: Symon (the default), MULTICOMP, and a "Simple"
|
machines are implemented: Symon (the default), MULTICOMP, BenEater, and a "Simple"
|
||||||
machine useful for debugging.
|
machine useful for debugging.
|
||||||
|
|
||||||
### 3.1 Memory Maps
|
### 3.1 Memory Maps
|
||||||
@@ -64,19 +64,41 @@ memory.
|
|||||||
|
|
||||||
- `$0000`--`$FFFF`: 64KB RAM
|
- `$0000`--`$FFFF`: 64KB RAM
|
||||||
|
|
||||||
|
#### 3.1.4 BenEater Memory Map
|
||||||
|
|
||||||
|
- `$0000`--`$3FFF`: 16KB RAM
|
||||||
|
- `$5000`--`$5003`: MOS 6551 ACIA (Serial Console)
|
||||||
|
- `$6000`--`$600F`: 6522 VIA
|
||||||
|
- `$8000`--`$FFFF`: 16KB ROM
|
||||||
|
|
||||||
### 3.2 Serial Console and CPU Status
|
### 3.2 Serial Console and CPU Status
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The main window of the simulator acts as the primary Input/Output
|
The main window of the simulator acts as the primary Input/Output
|
||||||
system through a virtual serial terminal. The terminal is attached to
|
system through a virtual serial terminal. It also provides CPU status.
|
||||||
a simulated ACIA, including a programmable baud rate generator that
|
Contents of the accumulator, index registers, processor status flags,
|
||||||
tries to approximate the correct "feel" of the programmed baud rate.
|
disassembly of the instruction register, and stack pointer are all displayed.
|
||||||
(The sample Enhanced BASIC ROM image is programmed for 9600 baud)
|
|
||||||
|
|
||||||
It also provides CPU status. Contents of the accumulator, index
|
The terminal is attached to a simulated MOS 6551 ACIA. It behaves very much
|
||||||
registers, processor status flags, disassembly of the instruction
|
as described in the datasheet, with some exceptions:
|
||||||
register, and stack pointer are all displayed.
|
|
||||||
|
- The simulated ACIA is permanently connected to the virtual terminal,
|
||||||
|
the Data Carrier Detect and Data Set Ready status bits always indicate
|
||||||
|
a connection is ready.
|
||||||
|
- The parity, stop-bits and bits-per-character settings are ignored. The
|
||||||
|
ACIA always sends and receives 8-bit characters, and parity errors
|
||||||
|
do not occur.
|
||||||
|
- The ACIA tries to honour the configured baud rate, but as a special case
|
||||||
|
the default "16x External Clock" rate is interpreted to mean "as fast as
|
||||||
|
possible" (The sample Enhanced BASIC ROM image is programmed for 9600 baud).
|
||||||
|
- The ACIA ignores the configured state of the Data Terminal Ready pin;
|
||||||
|
it is always ready to receive and transmit.
|
||||||
|
|
||||||
|
For more information on the MOS 6551 ACIA and its programming model,
|
||||||
|
see the official datasheet:
|
||||||
|
|
||||||
|
- [MOS 6551 ACIA](http://archive.6502.org/datasheets/mos_6551_acia.pdf)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -198,12 +220,14 @@ interface.
|
|||||||
Two command line options may be passed to the JAR file on startup,
|
Two command line options may be passed to the JAR file on startup,
|
||||||
to specify machine type and CPU type. The options are:
|
to specify machine type and CPU type. The options are:
|
||||||
|
|
||||||
- `-cpu 6502`: Use the NMOS 6502 CPU type by default.
|
- `-c`,`-cpu 6502`: Use the NMOS 6502 CPU type by default.
|
||||||
- `-cpu 65c02`: Use the CMOS 65C02 CPU type by default.
|
- `-c`,`-cpu 65c02`: Use the CMOS 65C02 CPU type by default.
|
||||||
- `-machine symon`: Use the **Symon** machine type by default.
|
- `-c`,`-machine symon`: Use the **Symon** machine type by default.
|
||||||
- `-machine multicomp`: Use the **Multicomp** machine type by default.
|
- `-c`,`-machine multicomp`: Use the **Multicomp** machine type by default.
|
||||||
- `-machine simple`: Use the **Simple** machine type by default.
|
- `-m`,`-machine simple`: Use the **Simple** machine type by default.
|
||||||
- `-rom <file>`: Use the specified file as the ROM image.
|
- `-m`,`-machine beneater`: Use the **BenEater** machine type by default.
|
||||||
|
- `-r`,`-rom <file>`: Use the specified file as the ROM image.
|
||||||
|
- `-b`,`-brk`: Halt the simulator on a BRK instruction (default is to continue)
|
||||||
|
|
||||||
### 4.2 ROM images
|
### 4.2 ROM images
|
||||||
|
|
||||||
@@ -212,10 +236,9 @@ properly. Without a ROM in memory, the simulator will not be able to
|
|||||||
reset, since the reset vector for the 6502 is located in the ROM
|
reset, since the reset vector for the 6502 is located in the ROM
|
||||||
address space.
|
address space.
|
||||||
|
|
||||||
By default, any file named `rom.bin` that exists in the same directory
|
ROM images can be loaded with the `-rom` argument when running
|
||||||
where Symon is launched will be loaded as a ROM image. ROM images can
|
Symon from the command line. ROM images can also be swapped out at
|
||||||
also be swapped out at run-time with the "Load ROM Image..." in the
|
run-time with the "Load ROM..." item in the File menu.
|
||||||
File menu.
|
|
||||||
|
|
||||||
The "samples" directory contains a ROM image for the Symon
|
The "samples" directory contains a ROM image for the Symon
|
||||||
architecture named 'ehbasic.rom', containing Lee Davison's Enhanced
|
architecture named 'ehbasic.rom', containing Lee Davison's Enhanced
|
||||||
@@ -247,6 +270,16 @@ running.
|
|||||||
|
|
||||||
## 5.0 Revision History
|
## 5.0 Revision History
|
||||||
|
|
||||||
|
- **1.4.0:** 11 November 2023 - Adds a new machine, the Ben Eater
|
||||||
|
machine. Correct handling of 6551 interrupts, and several 6551
|
||||||
|
bug fixes. Fixes power-on status of 6502 status register. Fixes a
|
||||||
|
bug with ASCII backspace character not moving the cursor
|
||||||
|
backwards. Finally, "halt on BRK" is no longer enabled by default,
|
||||||
|
but can be set at runtime or by a command line flag. Thank you to
|
||||||
|
Tim Allen and Chelsea Wilkinson for contributions!
|
||||||
|
|
||||||
|
- **1.3.2:** 8 March 2022 - Minor bug fixes.
|
||||||
|
|
||||||
- **1.3.1:** 12 October, 2019 - Add support for new command line
|
- **1.3.1:** 12 October, 2019 - Add support for new command line
|
||||||
option `-cpu <type>` to specify one of `6502` or `65c02` on startup,
|
option `-cpu <type>` to specify one of `6502` or `65c02` on startup,
|
||||||
and new option `-rom <file>` to specify a ROM file to load.
|
and new option `-rom <file>` to specify a ROM file to load.
|
||||||
@@ -347,6 +380,8 @@ running.
|
|||||||
**Copyright (c) 2014 Seth J. Morabito <web@loomcom.com>**
|
**Copyright (c) 2014 Seth J. Morabito <web@loomcom.com>**
|
||||||
|
|
||||||
Portions Copyright (c) 2014 Maik Merten <maikmerten@googlemail.com>
|
Portions Copyright (c) 2014 Maik Merten <maikmerten@googlemail.com>
|
||||||
|
Portions Copyright (c) 2022 Tim Allen <thristian@gmail.com>
|
||||||
|
Portions Copyright (c) 2023 Chelsea Wilkinson <mail@chelseawilkinson.me>
|
||||||
|
|
||||||
Additional components used in this project are copyright their respective owners.
|
Additional components used in this project are copyright their respective owners.
|
||||||
|
|
||||||
@@ -356,7 +391,7 @@ Additional components used in this project are copyright their respective owners
|
|||||||
|
|
||||||
This project would not have been possible without the following resources:
|
This project would not have been possible without the following resources:
|
||||||
|
|
||||||
- [Andrew Jacobs' 6502 Pages](http://www.obelisk.demon.co.uk/6502/), for
|
- [Andrew Jacobs' 6502 Pages](http://obelisk.me.uk/6502/), for
|
||||||
wonderfully detailed information about the 6502
|
wonderfully detailed information about the 6502
|
||||||
|
|
||||||
- [Neil Parker's "The 6502/65C02/65C816 Instruction Set Decoded"](http://www.llx.com/~nparker/a2/opcodes.html),
|
- [Neil Parker's "The 6502/65C02/65C816 Instruction Set Decoded"](http://www.llx.com/~nparker/a2/opcodes.html),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<groupId>com.loomcom.symon</groupId>
|
<groupId>com.loomcom.symon</groupId>
|
||||||
<artifactId>symon</artifactId>
|
<artifactId>symon</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<version>1.3.1</version>
|
<version>1.4.0</version>
|
||||||
<name>symon</name>
|
<name>symon</name>
|
||||||
<url>http://www.loomcom.com/symon</url>
|
<url>http://www.loomcom.com/symon</url>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -19,24 +19,24 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.4.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.12</version>
|
<version>4.13.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.mockito</groupId>
|
||||||
<artifactId>mockito-all</artifactId>
|
<artifactId>mockito-core</artifactId>
|
||||||
<version>1.10.19</version>
|
<version>4.8.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-cli</groupId>
|
<groupId>commons-cli</groupId>
|
||||||
<artifactId>commons-cli</artifactId>
|
<artifactId>commons-cli</artifactId>
|
||||||
<version>1.4</version>
|
<version>1.5.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
@@ -44,24 +44,31 @@
|
|||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.6</version>
|
<version>3.2.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<descriptorRefs>
|
<transformers>
|
||||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
</descriptorRefs>
|
|
||||||
<appendAssemblyId>false</appendAssemblyId>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<mainClass>com.loomcom.symon.Main</mainClass>
|
<mainClass>com.loomcom.symon.Main</mainClass>
|
||||||
</manifest>
|
</transformer>
|
||||||
</archive>
|
</transformers>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>single</goal>
|
<goal>shade</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
@@ -72,8 +79,8 @@
|
|||||||
<version>3.7.0</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||||
<source>1.7</source>
|
<source>11</source>
|
||||||
<target>1.7</target>
|
<target>11</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
@@ -81,7 +88,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>2.6</version>
|
<version>3.2.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
|
|||||||
+9
-8
@@ -11,7 +11,6 @@ Sample Programs
|
|||||||
When loaded at address $0300, this program will echo back to the console
|
When loaded at address $0300, this program will echo back to the console
|
||||||
anything typed.
|
anything typed.
|
||||||
|
|
||||||
|
|
||||||
Both hello.prg and echo_poll.prg were assembled with the Ophis assembler:
|
Both hello.prg and echo_poll.prg were assembled with the Ophis assembler:
|
||||||
|
|
||||||
https://hkn.eecs.berkeley.edu/~mcmartin/ophis/
|
https://hkn.eecs.berkeley.edu/~mcmartin/ophis/
|
||||||
@@ -19,23 +18,25 @@ Both hello.prg and echo_poll.prg were assembled with the Ophis assembler:
|
|||||||
3. echo_irq.rom
|
3. echo_irq.rom
|
||||||
|
|
||||||
This is another echo program, and behaves identically to echo_poll.prg,
|
This is another echo program, and behaves identically to echo_poll.prg,
|
||||||
except it is interrupt-driven.
|
except it is interrupt-driven. This ROM can be loaded either through the
|
||||||
|
"File->Load ROM..." menu in Symon, or by specifying the path to
|
||||||
|
"echo_irq.rom" with the "-jar" command line option when running Symon,
|
||||||
|
for example: `java -jar symon-1.3.2.jar -rom samples/echo_irq.rom`
|
||||||
|
|
||||||
4. ehbasic.rom
|
4. ehbasic.rom
|
||||||
|
|
||||||
This is Lee Davison's Enhanced 6502 BASIC.
|
This is Lee Davison's Enhanced 6502 BASIC.
|
||||||
|
|
||||||
To use this ROM image, just copy the file 'ehbasic.rom' into the directory
|
The EhBASIC ROM can be loaded either through the "File -> Load ROM..."
|
||||||
where you run Symon. Rename the file to 'rom.bin'. When you start Symon,
|
menu in Symon, or by specifying the path to "ehbasic.rom" with
|
||||||
the ROM file will be automatically loaded at address $d000.
|
the "-jar" command line option when running Symon, for example:
|
||||||
|
`java -jar symon-1.3.2.jar -rom samples/ehbasic.rom`
|
||||||
|
|
||||||
Click the "Run" button and EhBASIC should automatically start running.
|
Click the "Run" button and EhBASIC should automatically start running.
|
||||||
|
|
||||||
Type 'C' to do a cold start.
|
Type 'C' to do a cold start.
|
||||||
|
|
||||||
Then, type $C000 when prompted for the memory size.
|
Then, type '49152' (without the quotes) when prompted for the memory size.
|
||||||
|
|
||||||
NOTE: EhBASIC only wants upper-case input. This confused me at first!
|
|
||||||
|
|
||||||
More information can be found in the 'ehbasic' directory, and by visiting
|
More information can be found in the 'ehbasic' directory, and by visiting
|
||||||
the EhBASIC web page:
|
the EhBASIC web page:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
* NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
/**
|
/**
|
||||||
* This class provides a simulation of the MOS 6502 CPU's state machine.
|
* This class provides a simulation of the MOS 6502 CPU's state machine.
|
||||||
* A simple interface allows this 6502 to read and write to a simulated bus,
|
* A simple interface allows this 6502 to read and write to a simulated bus,
|
||||||
* and exposes some of the internal state for inspection and debugging.
|
* and exposes some internal state for inspection and debugging.
|
||||||
*/
|
*/
|
||||||
public class Cpu implements InstructionTable {
|
public class Cpu implements InstructionTable {
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ public class Cpu implements InstructionTable {
|
|||||||
// Clear status register bits.
|
// Clear status register bits.
|
||||||
state.carryFlag = false;
|
state.carryFlag = false;
|
||||||
state.zeroFlag = false;
|
state.zeroFlag = false;
|
||||||
state.irqDisableFlag = false;
|
state.irqDisableFlag = true;
|
||||||
state.decimalModeFlag = false;
|
state.decimalModeFlag = false;
|
||||||
state.breakFlag = false;
|
state.breakFlag = false;
|
||||||
state.overflowFlag = false;
|
state.overflowFlag = false;
|
||||||
@@ -283,7 +283,7 @@ public class Cpu implements InstructionTable {
|
|||||||
// Execute
|
// Execute
|
||||||
switch (state.ir) {
|
switch (state.ir) {
|
||||||
|
|
||||||
/** Single Byte Instructions; Implied and Relative **/
|
// Single Byte Instructions; Implied and Relative
|
||||||
case 0x00: // BRK - Force Interrupt - Implied
|
case 0x00: // BRK - Force Interrupt - Implied
|
||||||
handleBrk(state.pc + 1);
|
handleBrk(state.pc + 1);
|
||||||
break;
|
break;
|
||||||
@@ -457,7 +457,7 @@ public class Cpu implements InstructionTable {
|
|||||||
setArithmeticFlags(state.x);
|
setArithmeticFlags(state.x);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/** JMP *****************************************************************/
|
// JMP
|
||||||
case 0x4c: // JMP - Absolute
|
case 0x4c: // JMP - Absolute
|
||||||
state.pc = Utils.address(state.args[0], state.args[1]);
|
state.pc = Utils.address(state.args[0], state.args[1]);
|
||||||
break;
|
break;
|
||||||
@@ -495,7 +495,7 @@ public class Cpu implements InstructionTable {
|
|||||||
state.pc = Utils.address(bus.read(lo, true), bus.read(hi, true));
|
state.pc = Utils.address(bus.read(lo, true), bus.read(hi, true));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/** ORA - Logical Inclusive Or ******************************************/
|
// ORA - Logical Inclusive Or
|
||||||
case 0x09: // #Immediate
|
case 0x09: // #Immediate
|
||||||
state.a |= state.args[0];
|
state.a |= state.args[0];
|
||||||
setArithmeticFlags(state.a);
|
setArithmeticFlags(state.a);
|
||||||
@@ -517,7 +517,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** ASL - Arithmetic Shift Left *****************************************/
|
// ASL - Arithmetic Shift Left
|
||||||
case 0x0a: // Accumulator
|
case 0x0a: // Accumulator
|
||||||
state.a = asl(state.a);
|
state.a = asl(state.a);
|
||||||
setArithmeticFlags(state.a);
|
setArithmeticFlags(state.a);
|
||||||
@@ -532,7 +532,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** BIT - Bit Test ******************************************************/
|
// BIT - Bit Test
|
||||||
case 0x89: // 65C02 #Immediate
|
case 0x89: // 65C02 #Immediate
|
||||||
setZeroFlag((state.a & state.args[0]) == 0);
|
setZeroFlag((state.a & state.args[0]) == 0);
|
||||||
break;
|
break;
|
||||||
@@ -551,7 +551,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** AND - Logical AND ***************************************************/
|
// AND - Logical AND
|
||||||
case 0x29: // #Immediate
|
case 0x29: // #Immediate
|
||||||
state.a &= state.args[0];
|
state.a &= state.args[0];
|
||||||
setArithmeticFlags(state.a);
|
setArithmeticFlags(state.a);
|
||||||
@@ -573,7 +573,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** ROL - Rotate Left ***************************************************/
|
// ROL - Rotate Left
|
||||||
case 0x2a: // Accumulator
|
case 0x2a: // Accumulator
|
||||||
state.a = rol(state.a);
|
state.a = rol(state.a);
|
||||||
setArithmeticFlags(state.a);
|
setArithmeticFlags(state.a);
|
||||||
@@ -588,7 +588,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** EOR - Exclusive OR **************************************************/
|
// EOR - Exclusive OR
|
||||||
case 0x49: // #Immediate
|
case 0x49: // #Immediate
|
||||||
state.a ^= state.args[0];
|
state.a ^= state.args[0];
|
||||||
setArithmeticFlags(state.a);
|
setArithmeticFlags(state.a);
|
||||||
@@ -610,7 +610,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** LSR - Logical Shift Right *******************************************/
|
// LSR - Logical Shift Right
|
||||||
case 0x4a: // Accumulator
|
case 0x4a: // Accumulator
|
||||||
state.a = lsr(state.a);
|
state.a = lsr(state.a);
|
||||||
setArithmeticFlags(state.a);
|
setArithmeticFlags(state.a);
|
||||||
@@ -625,7 +625,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** ADC - Add with Carry ************************************************/
|
// ADC - Add with Carry
|
||||||
case 0x69: // #Immediate
|
case 0x69: // #Immediate
|
||||||
if (state.decimalModeFlag) {
|
if (state.decimalModeFlag) {
|
||||||
state.a = adcDecimal(state.a, state.args[0]);
|
state.a = adcDecimal(state.a, state.args[0]);
|
||||||
@@ -653,7 +653,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** ROR - Rotate Right **************************************************/
|
// ROR - Rotate Right
|
||||||
case 0x6a: // Accumulator
|
case 0x6a: // Accumulator
|
||||||
state.a = ror(state.a);
|
state.a = ror(state.a);
|
||||||
setArithmeticFlags(state.a);
|
setArithmeticFlags(state.a);
|
||||||
@@ -668,7 +668,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** STA - Store Accumulator *********************************************/
|
// STA - Store Accumulator
|
||||||
case 0x92: // 65C02 STA (ZP)
|
case 0x92: // 65C02 STA (ZP)
|
||||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||||
@@ -685,7 +685,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** STY - Store Y Register **********************************************/
|
// STY - Store Y Register
|
||||||
case 0x84: // Zero Page
|
case 0x84: // Zero Page
|
||||||
case 0x8c: // Absolute
|
case 0x8c: // Absolute
|
||||||
case 0x94: // Zero Page,X
|
case 0x94: // Zero Page,X
|
||||||
@@ -693,14 +693,14 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** STX - Store X Register **********************************************/
|
// STX - Store X Register
|
||||||
case 0x86: // Zero Page
|
case 0x86: // Zero Page
|
||||||
case 0x8e: // Absolute
|
case 0x8e: // Absolute
|
||||||
case 0x96: // Zero Page,Y
|
case 0x96: // Zero Page,Y
|
||||||
bus.write(effectiveAddress, state.x);
|
bus.write(effectiveAddress, state.x);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/** STZ - 65C02 Store Zero ****************************************************/
|
// STZ - 65C02 Store Zero
|
||||||
case 0x64: // Zero Page
|
case 0x64: // Zero Page
|
||||||
case 0x74: // Zero Page,X
|
case 0x74: // Zero Page,X
|
||||||
case 0x9c: // Absolute
|
case 0x9c: // Absolute
|
||||||
@@ -712,7 +712,7 @@ public class Cpu implements InstructionTable {
|
|||||||
bus.write(effectiveAddress, 0);
|
bus.write(effectiveAddress, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/** LDY - Load Y Register ***********************************************/
|
// LDY - Load Y Register
|
||||||
case 0xa0: // #Immediate
|
case 0xa0: // #Immediate
|
||||||
state.y = state.args[0];
|
state.y = state.args[0];
|
||||||
setArithmeticFlags(state.y);
|
setArithmeticFlags(state.y);
|
||||||
@@ -726,7 +726,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** LDX - Load X Register ***********************************************/
|
// LDX - Load X Register
|
||||||
case 0xa2: // #Immediate
|
case 0xa2: // #Immediate
|
||||||
state.x = state.args[0];
|
state.x = state.args[0];
|
||||||
setArithmeticFlags(state.x);
|
setArithmeticFlags(state.x);
|
||||||
@@ -740,7 +740,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** LDA - Load Accumulator **********************************************/
|
// LDA - Load Accumulator
|
||||||
case 0xa9: // #Immediate
|
case 0xa9: // #Immediate
|
||||||
state.a = state.args[0];
|
state.a = state.args[0];
|
||||||
setArithmeticFlags(state.a);
|
setArithmeticFlags(state.a);
|
||||||
@@ -762,7 +762,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** CPY - Compare Y Register ********************************************/
|
// CPY - Compare Y Register
|
||||||
case 0xc0: // #Immediate
|
case 0xc0: // #Immediate
|
||||||
cmp(state.y, state.args[0]);
|
cmp(state.y, state.args[0]);
|
||||||
break;
|
break;
|
||||||
@@ -772,7 +772,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** CMP - Compare Accumulator *******************************************/
|
// CMP - Compare Accumulator
|
||||||
case 0xc9: // #Immediate
|
case 0xc9: // #Immediate
|
||||||
cmp(state.a, state.args[0]);
|
cmp(state.a, state.args[0]);
|
||||||
break;
|
break;
|
||||||
@@ -792,7 +792,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** DEC - Decrement Memory **********************************************/
|
// DEC - Decrement Memory
|
||||||
case 0x3a: // 65C02 Immediate
|
case 0x3a: // 65C02 Immediate
|
||||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||||
@@ -811,7 +811,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** CPX - Compare X Register ********************************************/
|
// CPX - Compare X Register
|
||||||
case 0xe0: // #Immediate
|
case 0xe0: // #Immediate
|
||||||
cmp(state.x, state.args[0]);
|
cmp(state.x, state.args[0]);
|
||||||
break;
|
break;
|
||||||
@@ -821,7 +821,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** SBC - Subtract with Carry (Borrow) **********************************/
|
// SBC - Subtract with Carry (Borrow)
|
||||||
case 0xe9: // #Immediate
|
case 0xe9: // #Immediate
|
||||||
if (state.decimalModeFlag) {
|
if (state.decimalModeFlag) {
|
||||||
state.a = sbcDecimal(state.a, state.args[0]);
|
state.a = sbcDecimal(state.a, state.args[0]);
|
||||||
@@ -849,7 +849,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** INC - Increment Memory **********************************************/
|
// INC - Increment Memory
|
||||||
case 0x1a: // 65C02 Increment Immediate
|
case 0x1a: // 65C02 Increment Immediate
|
||||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||||
@@ -868,14 +868,14 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** 65C02 RMB - Reset Memory Bit **************************************/
|
// 65C02 RMB - Reset Memory Bit
|
||||||
case 0x07: // 65C02 RMB0 - Zero Page
|
case 0x07: // 65C02 RMB0 - Zero Page
|
||||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true) & 0xff;
|
tmp = bus.read(effectiveAddress, true) & 0xff;
|
||||||
tmp &= ~(1 << 0);
|
tmp &= ~1;
|
||||||
bus.write(effectiveAddress, tmp);
|
bus.write(effectiveAddress, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x17: // 65C02 RMB1 - Zero Page
|
case 0x17: // 65C02 RMB1 - Zero Page
|
||||||
@@ -943,14 +943,14 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** 65C02 SMB - Set Memory Bit **************************************/
|
// 65C02 SMB - Set Memory Bit
|
||||||
case 0x87: // 65C02 SMB0 - Zero Page
|
case 0x87: // 65C02 SMB0 - Zero Page
|
||||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true) & 0xff;
|
tmp = bus.read(effectiveAddress, true) & 0xff;
|
||||||
tmp |= (1);
|
tmp |= 1;
|
||||||
bus.write(effectiveAddress, tmp);
|
bus.write(effectiveAddress, tmp);
|
||||||
break;
|
break;
|
||||||
case 0x97: // 65C02 SMB1 - Zero Page
|
case 0x97: // 65C02 SMB1 - Zero Page
|
||||||
@@ -1017,7 +1017,7 @@ public class Cpu implements InstructionTable {
|
|||||||
bus.write(effectiveAddress, tmp);
|
bus.write(effectiveAddress, tmp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/** 65C02 TRB/TSB - Test and Reset Bit/Test and Set Bit ***************/
|
// 65C02 TRB/TSB - Test and Reset Bit/Test and Set Bit
|
||||||
case 0x14: // 65C02 TRB - Test and Reset bit - Zero Page
|
case 0x14: // 65C02 TRB - Test and Reset bit - Zero Page
|
||||||
case 0x1c: // 65C02 TRB - Test and Reset bit - Absolute
|
case 0x1c: // 65C02 TRB - Test and Reset bit - Absolute
|
||||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||||
@@ -1026,8 +1026,9 @@ public class Cpu implements InstructionTable {
|
|||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
setZeroFlag((state.a & tmp) == 0);
|
setZeroFlag((state.a & tmp) == 0);
|
||||||
tmp = (tmp &= ~(state.a)) & 0xff;
|
tmp &= ~(state.a);
|
||||||
bus.write(effectiveAddress,tmp);
|
tmp &= 0xff;
|
||||||
|
bus.write(effectiveAddress, tmp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x04: // 65C02 TSB - Test and Set bit - Zero Page
|
case 0x04: // 65C02 TSB - Test and Set bit - Zero Page
|
||||||
@@ -1038,18 +1039,19 @@ public class Cpu implements InstructionTable {
|
|||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
setZeroFlag((state.a & tmp) == 0);
|
setZeroFlag((state.a & tmp) == 0);
|
||||||
tmp = (tmp |= (state.a)) & 0xff;
|
tmp |= state.a;
|
||||||
|
tmp = tmp & 0xff;
|
||||||
bus.write(effectiveAddress,tmp);
|
bus.write(effectiveAddress,tmp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/** 65C02 BBR - Branch if Bit Reset *************************************/
|
// 65C02 BBR - Branch if Bit Reset
|
||||||
case 0x0f: // 65C02 BBR - Branch if bit 0 reset - Zero Page
|
case 0x0f: // 65C02 BBR - Branch if bit 0 reset - Zero Page
|
||||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 0) == 0) {
|
if ((tmp & 1) == 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1060,7 +1062,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 1) == 0) {
|
if ((tmp & (1 << 1)) == 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1071,7 +1073,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 2) == 0) {
|
if ((tmp & (1 << 2)) == 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1082,7 +1084,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 3) == 0) {
|
if ((tmp & (1 << 3)) == 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1093,7 +1095,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 4) == 0) {
|
if ((tmp & (1 << 4)) == 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1105,7 +1107,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 5) == 0) {
|
if ((tmp & (1 << 5)) == 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1116,7 +1118,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 6) == 0) {
|
if ((tmp & (1 << 6)) == 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1127,20 +1129,20 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 7) == 0) {
|
if ((tmp & (1 << 7)) == 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** 65C02 BBS - Branch if Bit Set ************************************/
|
// 65C02 BBS - Branch if Bit Set
|
||||||
case 0x8f: // 65C02 BBS - Branch if bit 0 set - Zero Page
|
case 0x8f: // 65C02 BBS - Branch if bit 0 set - Zero Page
|
||||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 0) > 0) {
|
if ((tmp & 1) != 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1151,7 +1153,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 1) > 0) {
|
if ((tmp & (1 << 1)) != 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1162,7 +1164,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 2) > 0) {
|
if ((tmp & (1 << 2)) > 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1173,7 +1175,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 3) > 0) {
|
if ((tmp & (1 << 3)) > 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1185,7 +1187,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 4) > 0) {
|
if ((tmp & (1 << 4)) > 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1197,7 +1199,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 5) > 0) {
|
if ((tmp & (1 << 5)) > 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1208,7 +1210,7 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 6) > 0) {
|
if ((tmp & (1 << 6)) > 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1219,13 +1221,13 @@ public class Cpu implements InstructionTable {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = bus.read(effectiveAddress, true);
|
tmp = bus.read(effectiveAddress, true);
|
||||||
if ((tmp & 1 << 7) > 0) {
|
if ((tmp & (1 << 7)) > 0) {
|
||||||
state.pc = relAddress(state.args[1]);
|
state.pc = relAddress(state.args[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
/** Unimplemented Instructions ****************************************/
|
// Unimplemented Instructions
|
||||||
// TODO: Create a flag to enable highly-accurate emulation of unimplemented instructions.
|
// TODO: Create a flag to enable highly-accurate emulation of unimplemented instructions.
|
||||||
default:
|
default:
|
||||||
setOpTrap();
|
setOpTrap();
|
||||||
@@ -1234,7 +1236,7 @@ public class Cpu implements InstructionTable {
|
|||||||
|
|
||||||
delayLoop(state.ir);
|
delayLoop(state.ir);
|
||||||
|
|
||||||
// Peek ahead to the next insturction and arguments
|
// Peek ahead to the next instruction and arguments
|
||||||
peekAhead();
|
peekAhead();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1265,7 +1267,7 @@ public class Cpu implements InstructionTable {
|
|||||||
/**
|
/**
|
||||||
* Handle the common behavior of BRK, /IRQ, and /NMI
|
* Handle the common behavior of BRK, /IRQ, and /NMI
|
||||||
*
|
*
|
||||||
* @throws MemoryAccessException
|
* @throws MemoryAccessException on memory access failure
|
||||||
*/
|
*/
|
||||||
private void handleInterrupt(int returnPc, int vectorLow, int vectorHigh, boolean isBreak) throws MemoryAccessException {
|
private void handleInterrupt(int returnPc, int vectorLow, int vectorHigh, boolean isBreak) throws MemoryAccessException {
|
||||||
|
|
||||||
@@ -1674,7 +1676,7 @@ public class Cpu implements InstructionTable {
|
|||||||
public void setProgramCounter(int addr) {
|
public void setProgramCounter(int addr) {
|
||||||
state.pc = addr;
|
state.pc = addr;
|
||||||
|
|
||||||
// As a side-effect of setting the program counter,
|
// As a side effect of setting the program counter,
|
||||||
// we want to peek ahead at the next state.
|
// we want to peek ahead at the next state.
|
||||||
try {
|
try {
|
||||||
peekAhead();
|
peekAhead();
|
||||||
@@ -1971,7 +1973,7 @@ public class Cpu implements InstructionTable {
|
|||||||
*/
|
*/
|
||||||
public String disassembleOpAtAddress(int address) throws MemoryAccessException {
|
public String disassembleOpAtAddress(int address) throws MemoryAccessException {
|
||||||
int opCode = bus.read(address, true);
|
int opCode = bus.read(address, true);
|
||||||
int args[] = new int[2];
|
int[] args = new int[2];
|
||||||
int size = Cpu.instructionSizes[opCode];
|
int size = Cpu.instructionSizes[opCode];
|
||||||
for (int i = 1; i < size; i++) {
|
for (int i = 1; i < size; i++) {
|
||||||
int nextRead = (address + i) % bus.endAddress();
|
int nextRead = (address + i) % bus.endAddress();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class CpuState {
|
|||||||
public int a;
|
public int a;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* X index regsiter
|
* X index register
|
||||||
*/
|
*/
|
||||||
public int x;
|
public int x;
|
||||||
|
|
||||||
@@ -61,13 +61,12 @@ public class CpuState {
|
|||||||
public CpuState() {}
|
public CpuState() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Snapshot a copy of the CpuState.
|
* Snapshot a copy of the CpuState. (This is a copy constructor rather than an
|
||||||
*
|
* implementation of <code>Cloneable</code> based on Josh Bloch's recommendation)
|
||||||
* (This is a copy constructor rather than an implementation of <code>Cloneable</code>
|
|
||||||
* based on Josh Bloch's recommendation)
|
|
||||||
*
|
*
|
||||||
* @param s The CpuState to copy.
|
* @param s The CpuState to copy.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("CopyConstructorMissesField")
|
||||||
public CpuState(CpuState s) {
|
public CpuState(CpuState s) {
|
||||||
this.a = s.a;
|
this.a = s.a;
|
||||||
this.x = s.x;
|
this.x = s.x;
|
||||||
@@ -83,6 +82,7 @@ public class CpuState {
|
|||||||
this.nextArgs[1] = s.nextArgs[1];
|
this.nextArgs[1] = s.nextArgs[1];
|
||||||
this.instSize = s.instSize;
|
this.instSize = s.instSize;
|
||||||
this.opTrap = s.opTrap;
|
this.opTrap = s.opTrap;
|
||||||
|
this.nmiAsserted = s.nmiAsserted;
|
||||||
this.irqAsserted = s.irqAsserted;
|
this.irqAsserted = s.irqAsserted;
|
||||||
this.carryFlag = s.carryFlag;
|
this.carryFlag = s.carryFlag;
|
||||||
this.negativeFlag = s.negativeFlag;
|
this.negativeFlag = s.negativeFlag;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ package com.loomcom.symon;
|
|||||||
import com.loomcom.symon.machines.MulticompMachine;
|
import com.loomcom.symon.machines.MulticompMachine;
|
||||||
import com.loomcom.symon.machines.SimpleMachine;
|
import com.loomcom.symon.machines.SimpleMachine;
|
||||||
import com.loomcom.symon.machines.SymonMachine;
|
import com.loomcom.symon.machines.SymonMachine;
|
||||||
|
import com.loomcom.symon.machines.BenEaterMachine;
|
||||||
import org.apache.commons.cli.*;
|
import org.apache.commons.cli.*;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -52,6 +53,7 @@ public class Main {
|
|||||||
options.addOption(new Option("m", "machine", true, "Specify machine type."));
|
options.addOption(new Option("m", "machine", true, "Specify machine type."));
|
||||||
options.addOption(new Option("c", "cpu", true, "Specify CPU type."));
|
options.addOption(new Option("c", "cpu", true, "Specify CPU type."));
|
||||||
options.addOption(new Option("r", "rom", true, "Specify ROM file."));
|
options.addOption(new Option("r", "rom", true, "Specify ROM file."));
|
||||||
|
options.addOption(new Option("b", "brk", false, "Halt on BRK"));
|
||||||
|
|
||||||
CommandLineParser parser = new DefaultParser();
|
CommandLineParser parser = new DefaultParser();
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ public class Main {
|
|||||||
CommandLine line = parser.parse(options, args);
|
CommandLine line = parser.parse(options, args);
|
||||||
InstructionTable.CpuBehavior cpuBehavior = null;
|
InstructionTable.CpuBehavior cpuBehavior = null;
|
||||||
String romFile = null;
|
String romFile = null;
|
||||||
|
boolean haltOnBreak = false;
|
||||||
|
|
||||||
if (line.hasOption("machine")) {
|
if (line.hasOption("machine")) {
|
||||||
String machine = line.getOptionValue("machine").toLowerCase(Locale.ENGLISH);
|
String machine = line.getOptionValue("machine").toLowerCase(Locale.ENGLISH);
|
||||||
@@ -72,6 +75,9 @@ public class Main {
|
|||||||
case "symon":
|
case "symon":
|
||||||
machineClass = SymonMachine.class;
|
machineClass = SymonMachine.class;
|
||||||
break;
|
break;
|
||||||
|
case "beneater":
|
||||||
|
machineClass = BenEaterMachine.class;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
System.err.println("Could not start Symon. Unknown machine type " + machine);
|
System.err.println("Could not start Symon. Unknown machine type " + machine);
|
||||||
return;
|
return;
|
||||||
@@ -100,9 +106,13 @@ public class Main {
|
|||||||
romFile = line.getOptionValue("rom");
|
romFile = line.getOptionValue("rom");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line.hasOption("brk")) {
|
||||||
|
haltOnBreak = true;
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (machineClass == null) {
|
if (machineClass == null) {
|
||||||
Object[] possibilities = {"Symon", "Multicomp", "Simple"};
|
Object[] possibilities = {"Symon", "Multicomp", "Simple", "BenEater"};
|
||||||
String s = (String)JOptionPane.showInputDialog(
|
String s = (String)JOptionPane.showInputDialog(
|
||||||
null,
|
null,
|
||||||
"Please choose the machine type to be emulated:",
|
"Please choose the machine type to be emulated:",
|
||||||
@@ -117,6 +127,8 @@ public class Main {
|
|||||||
machineClass = MulticompMachine.class;
|
machineClass = MulticompMachine.class;
|
||||||
} else if (s != null && s.equals("Simple")) {
|
} else if (s != null && s.equals("Simple")) {
|
||||||
machineClass = SimpleMachine.class;
|
machineClass = SimpleMachine.class;
|
||||||
|
} else if (s != null && s.equals("BenEater")) {
|
||||||
|
machineClass = BenEaterMachine.class;
|
||||||
} else {
|
} else {
|
||||||
machineClass = SymonMachine.class;
|
machineClass = SymonMachine.class;
|
||||||
}
|
}
|
||||||
@@ -126,7 +138,7 @@ public class Main {
|
|||||||
cpuBehavior = InstructionTable.CpuBehavior.NMOS_6502;
|
cpuBehavior = InstructionTable.CpuBehavior.NMOS_6502;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Simulator simulator = new Simulator(machineClass, cpuBehavior, romFile);
|
final Simulator simulator = new Simulator(machineClass, cpuBehavior, romFile, haltOnBreak);
|
||||||
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ public interface Preferences {
|
|||||||
|
|
||||||
int DEFAULT_PROGRAM_LOAD_ADDRESS = 0x0300;
|
int DEFAULT_PROGRAM_LOAD_ADDRESS = 0x0300;
|
||||||
|
|
||||||
boolean DEFAULT_HALT_ON_BREAK = true;
|
|
||||||
|
|
||||||
JDialog getDialog();
|
JDialog getDialog();
|
||||||
|
|
||||||
int getProgramStartAddress();
|
int getProgramStartAddress();
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ public class Simulator {
|
|||||||
|
|
||||||
private MainCommand command = MainCommand.NONE;
|
private MainCommand command = MainCommand.NONE;
|
||||||
|
|
||||||
|
private boolean haltOnBreak;
|
||||||
|
|
||||||
public enum MainCommand {
|
public enum MainCommand {
|
||||||
NONE,
|
NONE,
|
||||||
SELECTMACHINE
|
SELECTMACHINE
|
||||||
@@ -137,16 +139,17 @@ public class Simulator {
|
|||||||
private static final String[] STEPS = {"1", "5", "10", "20", "50", "100"};
|
private static final String[] STEPS = {"1", "5", "10", "20", "50", "100"};
|
||||||
|
|
||||||
public Simulator(Class machineClass) throws Exception {
|
public Simulator(Class machineClass) throws Exception {
|
||||||
this(machineClass, InstructionTable.CpuBehavior.NMOS_6502, null);
|
this(machineClass, InstructionTable.CpuBehavior.NMOS_6502, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Simulator(Class machineClass, InstructionTable.CpuBehavior cpuType, String romFile) throws Exception {
|
public Simulator(Class machineClass, InstructionTable.CpuBehavior cpuType,
|
||||||
|
String romFile, boolean haltOnBreak) throws Exception {
|
||||||
|
this.haltOnBreak = haltOnBreak;
|
||||||
this.breakpoints = new Breakpoints(this);
|
this.breakpoints = new Breakpoints(this);
|
||||||
|
|
||||||
this.machine = (Machine) machineClass.getConstructors()[0].newInstance(romFile);
|
this.machine = (Machine) machineClass.getConstructors()[0].newInstance(romFile);
|
||||||
this.machine.getCpu().setBehavior(cpuType);
|
this.machine.getCpu().setBehavior(cpuType);
|
||||||
|
|
||||||
|
|
||||||
// Initialize final fields in the constructor.
|
// Initialize final fields in the constructor.
|
||||||
this.traceLog = new TraceLog();
|
this.traceLog = new TraceLog();
|
||||||
this.memoryWindow = new MemoryWindow(machine.getBus());
|
this.memoryWindow = new MemoryWindow(machine.getBus());
|
||||||
@@ -176,7 +179,7 @@ public class Simulator {
|
|||||||
|
|
||||||
// File Chooser
|
// File Chooser
|
||||||
fileChooser = new JFileChooser(System.getProperty("user.dir"));
|
fileChooser = new JFileChooser(System.getProperty("user.dir"));
|
||||||
preferences = new PreferencesDialog(mainWindow, true);
|
preferences = new PreferencesDialog(mainWindow, true, haltOnBreak);
|
||||||
|
|
||||||
// Panel for Console and Buttons
|
// Panel for Console and Buttons
|
||||||
JPanel consoleContainer = new JPanel();
|
JPanel consoleContainer = new JPanel();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import com.loomcom.symon.exceptions.MemoryRangeException;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a simulation of the MOS 6551 ACIA, with limited
|
* This is a simulation of the MOS 6551 ACIA, with limited
|
||||||
* functionality. Interrupts are not supported.
|
* functionality.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Unlike a 16550 UART, the 6551 ACIA has only one-byte transmit and
|
* Unlike a 16550 UART, the 6551 ACIA has only one-byte transmit and
|
||||||
* receive buffers. It is the programmer's responsibility to check the
|
* receive buffers. It is the programmer's responsibility to check the
|
||||||
@@ -53,6 +53,14 @@ public class Acia6551 extends Acia {
|
|||||||
|
|
||||||
public Acia6551(int address) throws MemoryRangeException {
|
public Acia6551(int address) throws MemoryRangeException {
|
||||||
super(address, ACIA_SIZE, "ACIA");
|
super(address, ACIA_SIZE, "ACIA");
|
||||||
|
|
||||||
|
// Figure 6 in the 6551 ACIA data sheet says the "hardware reset"
|
||||||
|
// state of the Control Register is all zeros.
|
||||||
|
setControlRegister(0b00000000);
|
||||||
|
// Figure 7 of the 6551 ACIA data sheet says the "hardware reset"
|
||||||
|
// state of the Command Register is zeros, but Transmitter Control
|
||||||
|
// is set to "interrupt disabled, ready to send".
|
||||||
|
setCommandRegister(0b00000010);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -74,16 +82,16 @@ public class Acia6551 extends Acia {
|
|||||||
@Override
|
@Override
|
||||||
public void write(int address, int data) throws MemoryAccessException {
|
public void write(int address, int data) throws MemoryAccessException {
|
||||||
switch (address) {
|
switch (address) {
|
||||||
case 0:
|
case DATA_REG:
|
||||||
txWrite(data);
|
txWrite(data);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case STAT_REG:
|
||||||
reset();
|
reset();
|
||||||
break;
|
break;
|
||||||
case 2:
|
case CMND_REG:
|
||||||
setCommandRegister(data);
|
setCommandRegister(data);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case CTRL_REG:
|
||||||
setControlRegister(data);
|
setControlRegister(data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -110,67 +118,60 @@ public class Acia6551 extends Acia {
|
|||||||
controlRegister = data;
|
controlRegister = data;
|
||||||
int rate = 0;
|
int rate = 0;
|
||||||
|
|
||||||
// If the value of the data is 0, this is a request to reset,
|
// Mask the lower four bits to get the baud rate.
|
||||||
// otherwise it's a control update.
|
int baudSelector = data & 0x0f;
|
||||||
|
switch (baudSelector) {
|
||||||
if (data == 0) {
|
case 0:
|
||||||
reset();
|
rate = 0;
|
||||||
} else {
|
break;
|
||||||
// Mask the lower three bits to get the baud rate.
|
case 1:
|
||||||
int baudSelector = data & 0x0f;
|
rate = 50;
|
||||||
switch (baudSelector) {
|
break;
|
||||||
case 0:
|
case 2:
|
||||||
rate = 0;
|
rate = 75;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 3:
|
||||||
rate = 50;
|
rate = 110; // Real rate is actually 109.92
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 4:
|
||||||
rate = 75;
|
rate = 135; // Real rate is actually 134.58
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 5:
|
||||||
rate = 110; // Real rate is actually 109.92
|
rate = 150;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 6:
|
||||||
rate = 135; // Real rate is actually 134.58
|
rate = 300;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 7:
|
||||||
rate = 150;
|
rate = 600;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 8:
|
||||||
rate = 300;
|
rate = 1200;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 9:
|
||||||
rate = 600;
|
rate = 1800;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 10:
|
||||||
rate = 1200;
|
rate = 2400;
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 11:
|
||||||
rate = 1800;
|
rate = 3600;
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 12:
|
||||||
rate = 2400;
|
rate = 4800;
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 13:
|
||||||
rate = 3600;
|
rate = 7200;
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 14:
|
||||||
rate = 4800;
|
rate = 9600;
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 15:
|
||||||
rate = 7200;
|
rate = 19200;
|
||||||
break;
|
break;
|
||||||
case 14:
|
|
||||||
rate = 9600;
|
|
||||||
break;
|
|
||||||
case 15:
|
|
||||||
rate = 19200;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
setBaudRate(rate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBaudRate(rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -203,13 +204,16 @@ public class Acia6551 extends Acia {
|
|||||||
|
|
||||||
|
|
||||||
private synchronized void reset() {
|
private synchronized void reset() {
|
||||||
txChar = 0;
|
// Figure 6 in the 6551 ACIA data sheet says the "program reset"
|
||||||
txEmpty = true;
|
// event does not modify the control register.
|
||||||
rxChar = 0;
|
|
||||||
rxFull = false;
|
|
||||||
receiveIrqEnabled = false;
|
|
||||||
transmitIrqEnabled = false;
|
|
||||||
interrupt = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Figure 7 in the 6551 ACIA data sheet says the "program reset"
|
||||||
|
// event keeps the "parity check" configuration in the command
|
||||||
|
// register, but resets the other bits to defaults.
|
||||||
|
setCommandRegister((commandRegister & 0xe0) | 0x02);
|
||||||
|
|
||||||
|
// Figure 8 in the 6551 ACIA data sheet says the "program reset"
|
||||||
|
// event clears the "overrun" flag but otherwise has no effect.
|
||||||
|
overrun = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +215,8 @@ public class Vt100TerminalModel extends AbstractTerminalModel {
|
|||||||
case '\t':
|
case '\t':
|
||||||
while ((++cursorColumn % TAB_WIDTH) != 0);
|
while ((++cursorColumn % TAB_WIDTH) != 0);
|
||||||
continue;
|
continue;
|
||||||
case 127:
|
case 8: // ASCII Backspace
|
||||||
|
case 127: // ASCII Delete
|
||||||
if (cursorColumn > 0) {
|
if (cursorColumn > 0) {
|
||||||
cells[cursorRow][--cursorColumn] = null;
|
cells[cursorRow][--cursorColumn] = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com>
|
||||||
|
* Maik Merten <maikmerten@googlemail.com>
|
||||||
|
* Chelsea Wilkinson <mail@chelseawilkinson.me>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.machines;
|
||||||
|
|
||||||
|
import com.loomcom.symon.Bus;
|
||||||
|
import com.loomcom.symon.Cpu;
|
||||||
|
import com.loomcom.symon.devices.*;
|
||||||
|
import com.loomcom.symon.exceptions.MemoryRangeException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class BenEaterMachine implements Machine {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(BenEaterMachine.class.getName());
|
||||||
|
|
||||||
|
// Constants used by the simulated system. These define the memory map.
|
||||||
|
private static final int BUS_BOTTOM = 0x0000;
|
||||||
|
private static final int BUS_TOP = 0xffff;
|
||||||
|
|
||||||
|
// 16K of RAM from $0000 - $3FFF
|
||||||
|
private static final int MEMORY_BASE = 0x0000;
|
||||||
|
private static final int MEMORY_SIZE = 0x4000;
|
||||||
|
|
||||||
|
// VIA at $6000-$600F
|
||||||
|
private static final int PIA_BASE = 0x6000;
|
||||||
|
|
||||||
|
// ACIA at $5000-$5003
|
||||||
|
private static final int ACIA_BASE = 0x5000;
|
||||||
|
|
||||||
|
// CRTC at $4000-$4001
|
||||||
|
private static final int CRTC_BASE = 0x4000;
|
||||||
|
|
||||||
|
// 32KB ROM at $8000-$FFFF
|
||||||
|
private static final int ROM_BASE = 0x8000;
|
||||||
|
private static final int ROM_SIZE = 0x8000;
|
||||||
|
|
||||||
|
|
||||||
|
// The simulated peripherals
|
||||||
|
private final Bus bus;
|
||||||
|
private final Cpu cpu;
|
||||||
|
private final Acia acia;
|
||||||
|
private final Pia pia;
|
||||||
|
private final Crtc crtc;
|
||||||
|
private final Memory ram;
|
||||||
|
private Memory rom;
|
||||||
|
|
||||||
|
|
||||||
|
public BenEaterMachine(String romFile) throws Exception {
|
||||||
|
this.bus = new Bus(BUS_BOTTOM, BUS_TOP);
|
||||||
|
this.cpu = new Cpu();
|
||||||
|
this.ram = new Memory(MEMORY_BASE, MEMORY_BASE + MEMORY_SIZE - 1, false);
|
||||||
|
this.pia = new Via6522(PIA_BASE);
|
||||||
|
this.acia = new Acia6551(ACIA_BASE);
|
||||||
|
this.crtc = new Crtc(CRTC_BASE, ram);
|
||||||
|
|
||||||
|
bus.addCpu(cpu);
|
||||||
|
bus.addDevice(ram);
|
||||||
|
bus.addDevice(pia);
|
||||||
|
bus.addDevice(acia);
|
||||||
|
bus.addDevice(crtc);
|
||||||
|
|
||||||
|
if (romFile != null) {
|
||||||
|
File romImage = new File(romFile);
|
||||||
|
if (romImage.canRead()) {
|
||||||
|
logger.info("Loading ROM image from file {}", romImage);
|
||||||
|
this.rom = Memory.makeROM(ROM_BASE, ROM_BASE + ROM_SIZE - 1, romImage);
|
||||||
|
} else {
|
||||||
|
logger.info("Default ROM file {} not found, loading empty R/W memory image.", romImage);
|
||||||
|
this.rom = Memory.makeRAM(ROM_BASE, ROM_BASE + ROM_SIZE - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info("No ROM file specified, loading empty R/W memory image.");
|
||||||
|
this.rom = Memory.makeRAM(ROM_BASE, ROM_BASE + ROM_SIZE - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.addDevice(rom);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bus getBus() {
|
||||||
|
return bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cpu getCpu() {
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Memory getRam() {
|
||||||
|
return ram;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Acia getAcia() {
|
||||||
|
return acia;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pia getPia() {
|
||||||
|
return pia;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Crtc getCrtc() {
|
||||||
|
return crtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Memory getRom() {
|
||||||
|
return rom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRom(Memory rom) throws MemoryRangeException {
|
||||||
|
if(this.rom != null) {
|
||||||
|
bus.removeDevice(this.rom);
|
||||||
|
}
|
||||||
|
this.rom = rom;
|
||||||
|
bus.addDevice(this.rom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRomBase() {
|
||||||
|
return ROM_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRomSize() {
|
||||||
|
return ROM_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMemorySize() {
|
||||||
|
return MEMORY_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "benEater";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -42,11 +42,11 @@ public class PreferencesDialog extends Observable implements Preferences {
|
|||||||
private JTextField programLoadAddressField;
|
private JTextField programLoadAddressField;
|
||||||
|
|
||||||
private int programLoadAddress = DEFAULT_PROGRAM_LOAD_ADDRESS;
|
private int programLoadAddress = DEFAULT_PROGRAM_LOAD_ADDRESS;
|
||||||
private boolean haltOnBreak = DEFAULT_HALT_ON_BREAK;
|
private boolean haltOnBreak;
|
||||||
|
|
||||||
public PreferencesDialog(Frame parent, boolean modal) {
|
public PreferencesDialog(Frame parent, boolean modal, boolean haltOnBreak) {
|
||||||
this.dialog = new JDialog(parent, modal);
|
this.dialog = new JDialog(parent, modal);
|
||||||
|
this.haltOnBreak = haltOnBreak;
|
||||||
createUi();
|
createUi();
|
||||||
updateUi();
|
updateUi();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import com.loomcom.symon.machines.Machine;
|
|||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
import javax.swing.border.EtchedBorder;
|
import javax.swing.border.EtchedBorder;
|
||||||
|
import javax.swing.plaf.metal.MetalTextFieldUI;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
@@ -69,7 +70,7 @@ public class StatusPanel extends JPanel {
|
|||||||
private JTextField xField;
|
private JTextField xField;
|
||||||
private JTextField yField;
|
private JTextField yField;
|
||||||
|
|
||||||
private Machine machine;
|
private final Machine machine;
|
||||||
|
|
||||||
private static final int EMPTY_BORDER = 10;
|
private static final int EMPTY_BORDER = 10;
|
||||||
private static final Border LABEL_BORDER = BorderFactory.createEmptyBorder(0, 5, 0, 0);
|
private static final Border LABEL_BORDER = BorderFactory.createEmptyBorder(0, 5, 0, 0);
|
||||||
@@ -392,6 +393,13 @@ public class StatusPanel extends JPanel {
|
|||||||
textField.setMaximumSize(size);
|
textField.setMaximumSize(size);
|
||||||
textField.setPreferredSize(size);
|
textField.setPreferredSize(size);
|
||||||
textField.setBackground(Color.WHITE);
|
textField.setBackground(Color.WHITE);
|
||||||
|
// Although we usually defer to the system look-and-feel, for
|
||||||
|
// these small text fields in particular, we use a Metal
|
||||||
|
// look-and-feel because native look-and-feel breaks very small
|
||||||
|
// text fields under GTK+ (they are drawn with an inner margin
|
||||||
|
// even if the margin is set to 0)
|
||||||
|
textField.setUI(new MetalTextFieldUI());
|
||||||
|
|
||||||
return textField;
|
return textField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
|||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(VideoWindow.class.getName());
|
private static final Logger logger = Logger.getLogger(VideoWindow.class.getName());
|
||||||
|
|
||||||
|
private static final long WINDOW_REPAINT_INTERVAL = 66; // 30fps rate
|
||||||
private static final int CHAR_WIDTH = 8;
|
private static final int CHAR_WIDTH = 8;
|
||||||
private static final int CHAR_HEIGHT = 8;
|
private static final int CHAR_HEIGHT = 8;
|
||||||
|
|
||||||
@@ -127,6 +128,18 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
|||||||
public void run() {
|
public void run() {
|
||||||
if (cursorBlinkRate > 0) {
|
if (cursorBlinkRate > 0) {
|
||||||
hideCursor = !hideCursor;
|
hideCursor = !hideCursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WindowPainter implements Runnable {
|
||||||
|
public void run() {
|
||||||
|
SwingUtilities.invokeLater(new Runnable () {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (VideoWindow.this.isVisible()) {
|
||||||
VideoWindow.this.repaint();
|
VideoWindow.this.repaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,6 +165,11 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
|||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scheduler.scheduleAtFixedRate(new WindowPainter(),
|
||||||
|
WINDOW_REPAINT_INTERVAL,
|
||||||
|
WINDOW_REPAINT_INTERVAL,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
// Capture some state from the CRTC that will define the
|
// Capture some state from the CRTC that will define the
|
||||||
// window size. When these values change, the window will
|
// window size. When these values change, the window will
|
||||||
// need to re-pack and redraw.
|
// need to re-pack and redraw.
|
||||||
|
|||||||
@@ -254,4 +254,76 @@ public class AciaTest {
|
|||||||
|
|
||||||
assertEquals(0x08, acia.read(0x0001, true));
|
assertEquals(0x08, acia.read(0x0001, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void statusRegisterInitializedAtHardwareReset() throws Exception {
|
||||||
|
Acia6551 acia = new Acia6551(0x0000);
|
||||||
|
|
||||||
|
assertEquals(0x10, acia.read(0x0001, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void commandRegisterInitializedAtHardwareReset() throws Exception {
|
||||||
|
Acia6551 acia = new Acia6551(0x0000);
|
||||||
|
|
||||||
|
assertEquals(0x02, acia.read(0x0002, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void controlRegisterInitializedAtHardwareReset() throws Exception {
|
||||||
|
Acia6551 acia = new Acia6551(0x0000);
|
||||||
|
|
||||||
|
assertEquals(0x00, acia.read(0x0003, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void programResetClearsOverrunStatus() throws Exception {
|
||||||
|
Acia6551 acia = new Acia6551(0x0000);
|
||||||
|
Bus bus = new Bus(acia.ACIA_SIZE);
|
||||||
|
acia.setBus(bus);
|
||||||
|
|
||||||
|
// Change as many status bits as we can.
|
||||||
|
acia.write(0x0002, 0x00); // enable receive interrupt
|
||||||
|
acia.rxWrite('a');
|
||||||
|
acia.rxWrite('b'); // overrun, receive full, interrupt signalled
|
||||||
|
acia.write(0x0000, 'c'); // Transmitter Data Register not empty
|
||||||
|
|
||||||
|
// Check that all the bits we expected to be set actually are
|
||||||
|
assertEquals(0x8C, acia.read(0x0001, false));
|
||||||
|
|
||||||
|
// Do a "program reset". The value is ignored.
|
||||||
|
acia.write(0x0001, 0xFF);
|
||||||
|
|
||||||
|
// Check that only bit 2 was cleared.
|
||||||
|
assertEquals(0x88, acia.read(0x0001, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void programResetKeepsParitySettings() throws Exception {
|
||||||
|
Acia6551 acia = new Acia6551(0x0000);
|
||||||
|
|
||||||
|
// Set all the command register bits
|
||||||
|
acia.write(0x0002, 0xFF);
|
||||||
|
|
||||||
|
// Do a "program reset". The value is ignored.
|
||||||
|
acia.write(0x0001, 0xFF);
|
||||||
|
|
||||||
|
// The top 3 bits should be kept as-is,
|
||||||
|
// the bottom 5 bits should be reset to defaults.
|
||||||
|
assertEquals(0xE2, acia.read(0x0002, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void programResetLeavesControlRegisterUnchanged() throws Exception {
|
||||||
|
Acia6551 acia = new Acia6551(0x0000);
|
||||||
|
|
||||||
|
// Set all the control register bits
|
||||||
|
acia.write(0x0003, 0xFF);
|
||||||
|
|
||||||
|
// Do a "program reset". The value is ignored.
|
||||||
|
acia.write(0x0001, 0xFF);
|
||||||
|
|
||||||
|
// No bits should have changed.
|
||||||
|
assertEquals(0xFF, acia.read(0x0003, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ public class CpuAbsoluteModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -169,7 +169,7 @@ public class CpuAbsoluteModeTest extends TestCase {
|
|||||||
assertEquals(0x04, bus.read(0x1fe, true));
|
assertEquals(0x04, bus.read(0x1fe, true));
|
||||||
|
|
||||||
// No flags should have changed.
|
// No flags should have changed.
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BIT - Bit Test - $2c */
|
/* BIT - Bit Test - $2c */
|
||||||
@@ -362,7 +362,7 @@ public class CpuAbsoluteModeTest extends TestCase {
|
|||||||
cpu.step();
|
cpu.step();
|
||||||
assertEquals(0x3400, cpu.getProgramCounter());
|
assertEquals(0x3400, cpu.getProgramCounter());
|
||||||
// No change to status flags.
|
// No change to status flags.
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EOR - Exclusive OR - $4d */
|
/* EOR - Exclusive OR - $4d */
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class CpuAbsoluteXModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class CpuAbsoluteYModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class CpuAccumulatorModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -306,4 +306,4 @@ public class CpuAccumulatorModeTest extends TestCase {
|
|||||||
assertFalse(cpu.getCarryFlag());
|
assertFalse(cpu.getCarryFlag());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ public class CpuImmediateModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class CpuImpliedModeTest {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -76,6 +76,7 @@ public class CpuImpliedModeTest {
|
|||||||
public void test_BRK() throws MemoryAccessException {
|
public void test_BRK() throws MemoryAccessException {
|
||||||
cpu.setCarryFlag();
|
cpu.setCarryFlag();
|
||||||
cpu.setOverflowFlag();
|
cpu.setOverflowFlag();
|
||||||
|
cpu.clearIrqDisableFlag();
|
||||||
assertEquals(0x20 | Cpu.P_CARRY | Cpu.P_OVERFLOW,
|
assertEquals(0x20 | Cpu.P_CARRY | Cpu.P_OVERFLOW,
|
||||||
cpu.getProcessorStatus());
|
cpu.getProcessorStatus());
|
||||||
assertEquals(0x00, cpu.stackPeek());
|
assertEquals(0x00, cpu.stackPeek());
|
||||||
@@ -343,7 +344,7 @@ public class CpuImpliedModeTest {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x201, cpu.getProgramCounter());
|
assertEquals(0x201, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PHA - Push Accumulator - $48 */
|
/* PHA - Push Accumulator - $48 */
|
||||||
@@ -432,7 +433,7 @@ public class CpuImpliedModeTest {
|
|||||||
cpu.step();
|
cpu.step();
|
||||||
|
|
||||||
assertEquals(0x0f12, cpu.getProgramCounter());
|
assertEquals(0x0f12, cpu.getProgramCounter());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SEC - Set Carry Flag - $38 */
|
/* SEC - Set Carry Flag - $38 */
|
||||||
@@ -641,4 +642,4 @@ public class CpuImpliedModeTest {
|
|||||||
assertFalse(cpu.getZeroFlag());
|
assertFalse(cpu.getZeroFlag());
|
||||||
assertTrue(cpu.getNegativeFlag());
|
assertTrue(cpu.getNegativeFlag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ public class CpuIndexedIndirectModeTest {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -105,4 +105,4 @@ public class CpuIndexedIndirectModeTest {
|
|||||||
assertEquals(0x11, cpu.getAccumulator());
|
assertEquals(0x11, cpu.getAccumulator());
|
||||||
assertEquals(0x31, bus.read(0xc51f, true));
|
assertEquals(0x31, bus.read(0xc51f, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ public class CpuIndirectIndexedModeTest {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -81,4 +81,4 @@ public class CpuIndirectIndexedModeTest {
|
|||||||
assertEquals(0xe3, bus.read(0xd828, true));
|
assertEquals(0xe3, bus.read(0xd828, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -48,7 +48,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||||||
cpu.step();
|
cpu.step();
|
||||||
assertEquals(0x5400, cpu.getProgramCounter());
|
assertEquals(0x5400, cpu.getProgramCounter());
|
||||||
// No change to status flags.
|
// No change to status flags.
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void test_JMP_with_ROR_Bug() throws MemoryAccessException {
|
public void test_JMP_with_ROR_Bug() throws MemoryAccessException {
|
||||||
@@ -60,7 +60,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||||||
cpu.step();
|
cpu.step();
|
||||||
assertEquals(0x2200, cpu.getProgramCounter());
|
assertEquals(0x2200, cpu.getProgramCounter());
|
||||||
// No change to status flags.
|
// No change to status flags.
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void test_JMP_withIndirectBug() throws MemoryAccessException {
|
public void test_JMP_withIndirectBug() throws MemoryAccessException {
|
||||||
@@ -72,7 +72,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||||||
cpu.step();
|
cpu.step();
|
||||||
assertEquals(0x2200, cpu.getProgramCounter());
|
assertEquals(0x2200, cpu.getProgramCounter());
|
||||||
// No change to status flags.
|
// No change to status flags.
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void test_JMP_withOutIndirectBug() throws MemoryAccessException {
|
public void test_JMP_withOutIndirectBug() throws MemoryAccessException {
|
||||||
@@ -84,7 +84,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||||||
cpu.step();
|
cpu.step();
|
||||||
assertEquals(0x5400, cpu.getProgramCounter());
|
assertEquals(0x5400, cpu.getProgramCounter());
|
||||||
// No change to status flags.
|
// No change to status flags.
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void test_JMP_cmos() throws MemoryAccessException {
|
public void test_JMP_cmos() throws MemoryAccessException {
|
||||||
@@ -96,7 +96,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||||||
cpu.step();
|
cpu.step();
|
||||||
assertEquals(0x5400, cpu.getProgramCounter());
|
assertEquals(0x5400, cpu.getProgramCounter());
|
||||||
// No change to status flags.
|
// No change to status flags.
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ public class CpuIndirectXModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class CpuRelativeModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -278,4 +278,4 @@ public class CpuRelativeModeTest extends TestCase {
|
|||||||
assertEquals(0x202, cpu.getProgramCounter());
|
assertEquals(0x202, cpu.getProgramCounter());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ public class CpuTest extends TestCase {
|
|||||||
assertEquals(0x0200, cpu.getProgramCounter());
|
assertEquals(0x0200, cpu.getProgramCounter());
|
||||||
assertFalse(cpu.getCarryFlag());
|
assertFalse(cpu.getCarryFlag());
|
||||||
assertFalse(cpu.getZeroFlag());
|
assertFalse(cpu.getZeroFlag());
|
||||||
assertFalse(cpu.getIrqDisableFlag());
|
assertTrue(cpu.getIrqDisableFlag());
|
||||||
assertFalse(cpu.getDecimalModeFlag());
|
assertFalse(cpu.getDecimalModeFlag());
|
||||||
assertFalse(cpu.getBreakFlag());
|
assertFalse(cpu.getBreakFlag());
|
||||||
assertFalse(cpu.getOverflowFlag());
|
assertFalse(cpu.getOverflowFlag());
|
||||||
@@ -205,14 +205,12 @@ public class CpuTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testGetProcessorStatus() {
|
public void testGetProcessorStatus() {
|
||||||
// By default, no flags are set. Remember, bit 5
|
// By default, only "interrupt disable" is set. Remember, bit 5
|
||||||
// is always '1'.
|
// is always '1'.
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
cpu.setCarryFlag();
|
cpu.setCarryFlag();
|
||||||
assertEquals(0x21, cpu.getProcessorStatus());
|
assertEquals(0x25, cpu.getProcessorStatus());
|
||||||
cpu.setZeroFlag();
|
cpu.setZeroFlag();
|
||||||
assertEquals(0x23, cpu.getProcessorStatus());
|
|
||||||
cpu.setIrqDisableFlag();
|
|
||||||
assertEquals(0x27, cpu.getProcessorStatus());
|
assertEquals(0x27, cpu.getProcessorStatus());
|
||||||
cpu.setDecimalModeFlag();
|
cpu.setDecimalModeFlag();
|
||||||
assertEquals(0x2f, cpu.getProcessorStatus());
|
assertEquals(0x2f, cpu.getProcessorStatus());
|
||||||
@@ -237,13 +235,16 @@ public class CpuTest extends TestCase {
|
|||||||
assertEquals(0xa0, cpu.getProcessorStatus());
|
assertEquals(0xa0, cpu.getProcessorStatus());
|
||||||
cpu.clearNegativeFlag();
|
cpu.clearNegativeFlag();
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x20, cpu.getProcessorStatus());
|
||||||
|
|
||||||
|
cpu.setIrqDisableFlag();
|
||||||
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSetProcessorStatus() {
|
public void testSetProcessorStatus() {
|
||||||
// Default
|
// Default
|
||||||
assertFalse(cpu.getZeroFlag());
|
assertFalse(cpu.getZeroFlag());
|
||||||
assertFalse(cpu.getZeroFlag());
|
assertFalse(cpu.getZeroFlag());
|
||||||
assertFalse(cpu.getIrqDisableFlag());
|
assertTrue(cpu.getIrqDisableFlag());
|
||||||
assertFalse(cpu.getDecimalModeFlag());
|
assertFalse(cpu.getDecimalModeFlag());
|
||||||
assertFalse(cpu.getBreakFlag());
|
assertFalse(cpu.getBreakFlag());
|
||||||
assertFalse(cpu.getOverflowFlag());
|
assertFalse(cpu.getOverflowFlag());
|
||||||
@@ -669,4 +670,4 @@ public class CpuTest extends TestCase {
|
|||||||
cpu.step();
|
cpu.step();
|
||||||
assertEquals(0x3E, cpu.getAccumulator());
|
assertEquals(0x3E, cpu.getAccumulator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ public class CpuZeroPageModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class CpuZeroPageXModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class CpuZeroPageYModeTest extends TestCase {
|
|||||||
assertEquals(0, cpu.getYRegister());
|
assertEquals(0, cpu.getYRegister());
|
||||||
assertEquals(0x200, cpu.getProgramCounter());
|
assertEquals(0x200, cpu.getProgramCounter());
|
||||||
assertEquals(0xff, cpu.getStackPointer());
|
assertEquals(0xff, cpu.getStackPointer());
|
||||||
assertEquals(0x20, cpu.getProcessorStatus());
|
assertEquals(0x24, cpu.getProcessorStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|||||||
Reference in new issue
Block a user