mirror of
https://github.com/sethm/symon.git
synced 2024-06-15 08:29:27 +00:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ecd4bbbd9a | ||
|
a537328852 | ||
|
4975fca506 | ||
|
199d96c025 | ||
|
0c026e38dd | ||
|
5e56627f32 | ||
|
67f5e17f78 | ||
|
5a25750f46 | ||
|
4a8a803472 | ||
|
4423623816 | ||
|
5df775bbb0 | ||
|
d076046f57 | ||
|
b725fb5fdd | ||
|
9351d785ae | ||
|
66a92f4196 | ||
|
cda9a218af | ||
|
b5a470d3ba | ||
|
e210a40639 | ||
|
0bad9912ce | ||
|
b36b442b14 |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
*~
|
||||
*.jar
|
||||
*#
|
||||
target
|
||||
.DS_Store
|
||||
|
|
88
README.md
88
README.md
|
@ -1,9 +1,9 @@
|
|||
SYMON - A 6502 System Simulator
|
||||
===============================
|
||||
|
||||
**Version:** 1.3.2
|
||||
**Version:** 1.4.0
|
||||
|
||||
**Last Updated:** 08 March, 2021
|
||||
**Last Updated:** 11 November, 2023
|
||||
|
||||
See the file COPYING for license.
|
||||
|
||||
|
@ -25,8 +25,8 @@ Klaus Dormann's 6502 Functional Test Suite as of version 0.8.2
|
|||
(See [this thread on the 6502.org Forums](http://forum.6502.org/viewtopic.php?f=2&t=2241)
|
||||
for more information about this functional test suite).
|
||||
|
||||
Symon is under constant, active development. Feedback and patches
|
||||
are always welcome.
|
||||
Symon is under active maintenance. Feedback and patches are always
|
||||
welcome.
|
||||
|
||||
## 2.0 Requirements
|
||||
|
||||
|
@ -36,9 +36,9 @@ are always welcome.
|
|||
|
||||
## 3.0 Features
|
||||
|
||||
Symon can simulate multiple 6502 based architectures. At present, three
|
||||
machines are implemented: Symon (the default), MULTICOMP, and a "Simple"
|
||||
machine useful for debugging.
|
||||
Symon can simulate multiple 6502 based architectures. At present, four
|
||||
machines are implemented: Symon (the default), MULTICOMP, BenEater, and
|
||||
a "Simple" machine useful for debugging.
|
||||
|
||||
### 3.1 Memory Maps
|
||||
|
||||
|
@ -64,19 +64,41 @@ memory.
|
|||
|
||||
- `$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
|
||||
|
||||
![Serial Console](https://github.com/sethm/symon/raw/master/screenshots/console.png)
|
||||
|
||||
The main window of the simulator acts as the primary Input/Output
|
||||
system through a virtual serial terminal. The terminal is attached to
|
||||
a simulated ACIA, including a programmable baud rate generator that
|
||||
tries to approximate the correct "feel" of the programmed baud rate.
|
||||
(The sample Enhanced BASIC ROM image is programmed for 9600 baud)
|
||||
system through a virtual serial terminal. It also provides CPU status.
|
||||
Contents of the accumulator, index registers, processor status flags,
|
||||
disassembly of the instruction register, and stack pointer are all displayed.
|
||||
|
||||
It also provides CPU status. Contents of the accumulator, index
|
||||
registers, processor status flags, disassembly of the instruction
|
||||
register, and stack pointer are all displayed.
|
||||
The terminal is attached to a simulated MOS 6551 ACIA. It behaves very much
|
||||
as described in the datasheet, with some exceptions:
|
||||
|
||||
- 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)
|
||||
|
||||
![Font Selection](https://github.com/sethm/symon/raw/master/screenshots/font_selection.png)
|
||||
|
||||
|
@ -198,12 +220,14 @@ interface.
|
|||
Two command line options may be passed to the JAR file on startup,
|
||||
to specify machine type and CPU type. The options are:
|
||||
|
||||
- `-cpu 6502`: Use the NMOS 6502 CPU type by default.
|
||||
- `-cpu 65c02`: Use the CMOS 65C02 CPU type by default.
|
||||
- `-machine symon`: Use the **Symon** machine type by default.
|
||||
- `-machine multicomp`: Use the **Multicomp** machine type by default.
|
||||
- `-machine simple`: Use the **Simple** machine type by default.
|
||||
- `-rom <file>`: Use the specified file as the ROM image.
|
||||
- `-c`,`-cpu 6502`: Use the NMOS 6502 CPU type by default.
|
||||
- `-c`,`-cpu 65c02`: Use the CMOS 65C02 CPU type by default.
|
||||
- `-c`,`-machine symon`: Use the **Symon** machine type by default.
|
||||
- `-c`,`-machine multicomp`: Use the **Multicomp** machine type by default.
|
||||
- `-m`,`-machine simple`: Use the **Simple** machine type by default.
|
||||
- `-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
|
||||
|
||||
|
@ -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
|
||||
address space.
|
||||
|
||||
By default, any file named `rom.bin` that exists in the same directory
|
||||
where Symon is launched will be loaded as a ROM image. ROM images can
|
||||
also be swapped out at run-time with the "Load ROM Image..." in the
|
||||
File menu.
|
||||
ROM images can be loaded with the `-rom` argument when running
|
||||
Symon from the command line. ROM images can also be swapped out at
|
||||
run-time with the "Load ROM..." item in the File menu.
|
||||
|
||||
The "samples" directory contains a ROM image for the Symon
|
||||
architecture named 'ehbasic.rom', containing Lee Davison's Enhanced
|
||||
|
@ -247,6 +270,16 @@ running.
|
|||
|
||||
## 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
|
||||
option `-cpu <type>` to specify one of `6502` or `65c02` on startup,
|
||||
and new option `-rom <file>` to specify a ROM file to load.
|
||||
|
@ -346,7 +379,12 @@ running.
|
|||
|
||||
**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.
|
||||
|
||||
|
|
12
pom.xml
12
pom.xml
|
@ -4,7 +4,7 @@
|
|||
<groupId>com.loomcom.symon</groupId>
|
||||
<artifactId>symon</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.0</version>
|
||||
<name>symon</name>
|
||||
<url>http://www.loomcom.com/symon</url>
|
||||
<properties>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
<version>1.4.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
@ -30,13 +30,13 @@
|
|||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.12.4</version>
|
||||
<version>4.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.4</version>
|
||||
<version>1.5.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -79,8 +79,8 @@
|
|||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ Sample Programs
|
|||
When loaded at address $0300, this program will echo back to the console
|
||||
anything typed.
|
||||
|
||||
|
||||
Both hello.prg and echo_poll.prg were assembled with the Ophis assembler:
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
This is Lee Davison's Enhanced 6502 BASIC.
|
||||
|
||||
To use this ROM image, just copy the file 'ehbasic.rom' into the directory
|
||||
where you run Symon. Rename the file to 'rom.bin'. When you start Symon,
|
||||
the ROM file will be automatically loaded at address $d000.
|
||||
The EhBASIC ROM can be loaded either through the "File -> Load ROM..."
|
||||
menu in Symon, or by specifying the path to "ehbasic.rom" with
|
||||
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.
|
||||
|
||||
Type 'C' to do a cold start.
|
||||
|
||||
Then, type $C000 when prompted for the memory size.
|
||||
|
||||
NOTE: EhBASIC only wants upper-case input. This confused me at first!
|
||||
Then, type '49152' (without the quotes) when prompted for the memory size.
|
||||
|
||||
More information can be found in the 'ehbasic' directory, and by visiting
|
||||
the EhBASIC web page:
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* 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
|
||||
* NON-INFRINGEMENT. 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.
|
||||
|
@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory;
|
|||
/**
|
||||
* 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,
|
||||
* 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 {
|
||||
|
||||
|
@ -126,7 +126,7 @@ public class Cpu implements InstructionTable {
|
|||
// Clear status register bits.
|
||||
state.carryFlag = false;
|
||||
state.zeroFlag = false;
|
||||
state.irqDisableFlag = false;
|
||||
state.irqDisableFlag = true;
|
||||
state.decimalModeFlag = false;
|
||||
state.breakFlag = false;
|
||||
state.overflowFlag = false;
|
||||
|
@ -283,7 +283,7 @@ public class Cpu implements InstructionTable {
|
|||
// Execute
|
||||
switch (state.ir) {
|
||||
|
||||
/** Single Byte Instructions; Implied and Relative **/
|
||||
// Single Byte Instructions; Implied and Relative
|
||||
case 0x00: // BRK - Force Interrupt - Implied
|
||||
handleBrk(state.pc + 1);
|
||||
break;
|
||||
|
@ -457,7 +457,7 @@ public class Cpu implements InstructionTable {
|
|||
setArithmeticFlags(state.x);
|
||||
break;
|
||||
|
||||
/** JMP *****************************************************************/
|
||||
// JMP
|
||||
case 0x4c: // JMP - Absolute
|
||||
state.pc = Utils.address(state.args[0], state.args[1]);
|
||||
break;
|
||||
|
@ -495,7 +495,7 @@ public class Cpu implements InstructionTable {
|
|||
state.pc = Utils.address(bus.read(lo, true), bus.read(hi, true));
|
||||
break;
|
||||
|
||||
/** ORA - Logical Inclusive Or ******************************************/
|
||||
// ORA - Logical Inclusive Or
|
||||
case 0x09: // #Immediate
|
||||
state.a |= state.args[0];
|
||||
setArithmeticFlags(state.a);
|
||||
|
@ -517,7 +517,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** ASL - Arithmetic Shift Left *****************************************/
|
||||
// ASL - Arithmetic Shift Left
|
||||
case 0x0a: // Accumulator
|
||||
state.a = asl(state.a);
|
||||
setArithmeticFlags(state.a);
|
||||
|
@ -532,7 +532,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** BIT - Bit Test ******************************************************/
|
||||
// BIT - Bit Test
|
||||
case 0x89: // 65C02 #Immediate
|
||||
setZeroFlag((state.a & state.args[0]) == 0);
|
||||
break;
|
||||
|
@ -551,7 +551,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** AND - Logical AND ***************************************************/
|
||||
// AND - Logical AND
|
||||
case 0x29: // #Immediate
|
||||
state.a &= state.args[0];
|
||||
setArithmeticFlags(state.a);
|
||||
|
@ -573,7 +573,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** ROL - Rotate Left ***************************************************/
|
||||
// ROL - Rotate Left
|
||||
case 0x2a: // Accumulator
|
||||
state.a = rol(state.a);
|
||||
setArithmeticFlags(state.a);
|
||||
|
@ -588,7 +588,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** EOR - Exclusive OR **************************************************/
|
||||
// EOR - Exclusive OR
|
||||
case 0x49: // #Immediate
|
||||
state.a ^= state.args[0];
|
||||
setArithmeticFlags(state.a);
|
||||
|
@ -610,7 +610,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** LSR - Logical Shift Right *******************************************/
|
||||
// LSR - Logical Shift Right
|
||||
case 0x4a: // Accumulator
|
||||
state.a = lsr(state.a);
|
||||
setArithmeticFlags(state.a);
|
||||
|
@ -625,7 +625,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** ADC - Add with Carry ************************************************/
|
||||
// ADC - Add with Carry
|
||||
case 0x69: // #Immediate
|
||||
if (state.decimalModeFlag) {
|
||||
state.a = adcDecimal(state.a, state.args[0]);
|
||||
|
@ -653,7 +653,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** ROR - Rotate Right **************************************************/
|
||||
// ROR - Rotate Right
|
||||
case 0x6a: // Accumulator
|
||||
state.a = ror(state.a);
|
||||
setArithmeticFlags(state.a);
|
||||
|
@ -668,7 +668,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** STA - Store Accumulator *********************************************/
|
||||
// STA - Store Accumulator
|
||||
case 0x92: // 65C02 STA (ZP)
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
|
@ -685,7 +685,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** STY - Store Y Register **********************************************/
|
||||
// STY - Store Y Register
|
||||
case 0x84: // Zero Page
|
||||
case 0x8c: // Absolute
|
||||
case 0x94: // Zero Page,X
|
||||
|
@ -693,14 +693,14 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** STX - Store X Register **********************************************/
|
||||
// STX - Store X Register
|
||||
case 0x86: // Zero Page
|
||||
case 0x8e: // Absolute
|
||||
case 0x96: // Zero Page,Y
|
||||
bus.write(effectiveAddress, state.x);
|
||||
break;
|
||||
|
||||
/** STZ - 65C02 Store Zero ****************************************************/
|
||||
// STZ - 65C02 Store Zero
|
||||
case 0x64: // Zero Page
|
||||
case 0x74: // Zero Page,X
|
||||
case 0x9c: // Absolute
|
||||
|
@ -712,7 +712,7 @@ public class Cpu implements InstructionTable {
|
|||
bus.write(effectiveAddress, 0);
|
||||
break;
|
||||
|
||||
/** LDY - Load Y Register ***********************************************/
|
||||
// LDY - Load Y Register
|
||||
case 0xa0: // #Immediate
|
||||
state.y = state.args[0];
|
||||
setArithmeticFlags(state.y);
|
||||
|
@ -726,7 +726,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** LDX - Load X Register ***********************************************/
|
||||
// LDX - Load X Register
|
||||
case 0xa2: // #Immediate
|
||||
state.x = state.args[0];
|
||||
setArithmeticFlags(state.x);
|
||||
|
@ -740,7 +740,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** LDA - Load Accumulator **********************************************/
|
||||
// LDA - Load Accumulator
|
||||
case 0xa9: // #Immediate
|
||||
state.a = state.args[0];
|
||||
setArithmeticFlags(state.a);
|
||||
|
@ -762,7 +762,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** CPY - Compare Y Register ********************************************/
|
||||
// CPY - Compare Y Register
|
||||
case 0xc0: // #Immediate
|
||||
cmp(state.y, state.args[0]);
|
||||
break;
|
||||
|
@ -772,7 +772,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** CMP - Compare Accumulator *******************************************/
|
||||
// CMP - Compare Accumulator
|
||||
case 0xc9: // #Immediate
|
||||
cmp(state.a, state.args[0]);
|
||||
break;
|
||||
|
@ -792,7 +792,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** DEC - Decrement Memory **********************************************/
|
||||
// DEC - Decrement Memory
|
||||
case 0x3a: // 65C02 Immediate
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
|
@ -811,7 +811,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** CPX - Compare X Register ********************************************/
|
||||
// CPX - Compare X Register
|
||||
case 0xe0: // #Immediate
|
||||
cmp(state.x, state.args[0]);
|
||||
break;
|
||||
|
@ -821,7 +821,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** SBC - Subtract with Carry (Borrow) **********************************/
|
||||
// SBC - Subtract with Carry (Borrow)
|
||||
case 0xe9: // #Immediate
|
||||
if (state.decimalModeFlag) {
|
||||
state.a = sbcDecimal(state.a, state.args[0]);
|
||||
|
@ -849,7 +849,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** INC - Increment Memory **********************************************/
|
||||
// INC - Increment Memory
|
||||
case 0x1a: // 65C02 Increment Immediate
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
|
@ -868,14 +868,14 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** 65C02 RMB - Reset Memory Bit **************************************/
|
||||
// 65C02 RMB - Reset Memory Bit
|
||||
case 0x07: // 65C02 RMB0 - Zero Page
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true) & 0xff;
|
||||
tmp &= ~(1 << 0);
|
||||
tmp &= ~1;
|
||||
bus.write(effectiveAddress, tmp);
|
||||
break;
|
||||
case 0x17: // 65C02 RMB1 - Zero Page
|
||||
|
@ -943,14 +943,14 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
|
||||
|
||||
/** 65C02 SMB - Set Memory Bit **************************************/
|
||||
// 65C02 SMB - Set Memory Bit
|
||||
case 0x87: // 65C02 SMB0 - Zero Page
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true) & 0xff;
|
||||
tmp |= (1);
|
||||
tmp |= 1;
|
||||
bus.write(effectiveAddress, tmp);
|
||||
break;
|
||||
case 0x97: // 65C02 SMB1 - Zero Page
|
||||
|
@ -1017,7 +1017,7 @@ public class Cpu implements InstructionTable {
|
|||
bus.write(effectiveAddress, tmp);
|
||||
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 0x1c: // 65C02 TRB - Test and Reset bit - Absolute
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
|
@ -1026,8 +1026,9 @@ public class Cpu implements InstructionTable {
|
|||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
setZeroFlag((state.a & tmp) == 0);
|
||||
tmp = (tmp &= ~(state.a)) & 0xff;
|
||||
bus.write(effectiveAddress,tmp);
|
||||
tmp &= ~(state.a);
|
||||
tmp &= 0xff;
|
||||
bus.write(effectiveAddress, tmp);
|
||||
break;
|
||||
|
||||
case 0x04: // 65C02 TSB - Test and Set bit - Zero Page
|
||||
|
@ -1038,18 +1039,19 @@ public class Cpu implements InstructionTable {
|
|||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
setZeroFlag((state.a & tmp) == 0);
|
||||
tmp = (tmp |= (state.a)) & 0xff;
|
||||
tmp |= state.a;
|
||||
tmp = tmp & 0xff;
|
||||
bus.write(effectiveAddress,tmp);
|
||||
break;
|
||||
|
||||
/** 65C02 BBR - Branch if Bit Reset *************************************/
|
||||
// 65C02 BBR - Branch if Bit Reset
|
||||
case 0x0f: // 65C02 BBR - Branch if bit 0 reset - Zero Page
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 0) == 0) {
|
||||
if ((tmp & 1) == 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1060,7 +1062,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 1) == 0) {
|
||||
if ((tmp & (1 << 1)) == 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1071,7 +1073,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 2) == 0) {
|
||||
if ((tmp & (1 << 2)) == 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1082,7 +1084,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 3) == 0) {
|
||||
if ((tmp & (1 << 3)) == 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1093,7 +1095,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 4) == 0) {
|
||||
if ((tmp & (1 << 4)) == 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1105,7 +1107,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 5) == 0) {
|
||||
if ((tmp & (1 << 5)) == 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1116,7 +1118,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 6) == 0) {
|
||||
if ((tmp & (1 << 6)) == 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1127,20 +1129,20 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 7) == 0) {
|
||||
if ((tmp & (1 << 7)) == 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/** 65C02 BBS - Branch if Bit Set ************************************/
|
||||
// 65C02 BBS - Branch if Bit Set
|
||||
case 0x8f: // 65C02 BBS - Branch if bit 0 set - Zero Page
|
||||
if (behavior == CpuBehavior.NMOS_6502 ||
|
||||
behavior == CpuBehavior.NMOS_WITH_ROR_BUG) {
|
||||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 0) > 0) {
|
||||
if ((tmp & 1) != 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1151,7 +1153,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 1) > 0) {
|
||||
if ((tmp & (1 << 1)) != 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1162,7 +1164,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 2) > 0) {
|
||||
if ((tmp & (1 << 2)) > 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1173,7 +1175,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 3) > 0) {
|
||||
if ((tmp & (1 << 3)) > 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1185,7 +1187,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 4) > 0) {
|
||||
if ((tmp & (1 << 4)) > 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1197,7 +1199,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 5) > 0) {
|
||||
if ((tmp & (1 << 5)) > 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1208,7 +1210,7 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 6) > 0) {
|
||||
if ((tmp & (1 << 6)) > 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
@ -1219,13 +1221,13 @@ public class Cpu implements InstructionTable {
|
|||
break;
|
||||
}
|
||||
tmp = bus.read(effectiveAddress, true);
|
||||
if ((tmp & 1 << 7) > 0) {
|
||||
if ((tmp & (1 << 7)) > 0) {
|
||||
state.pc = relAddress(state.args[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/** Unimplemented Instructions ****************************************/
|
||||
// Unimplemented Instructions
|
||||
// TODO: Create a flag to enable highly-accurate emulation of unimplemented instructions.
|
||||
default:
|
||||
setOpTrap();
|
||||
|
@ -1234,7 +1236,7 @@ public class Cpu implements InstructionTable {
|
|||
|
||||
delayLoop(state.ir);
|
||||
|
||||
// Peek ahead to the next insturction and arguments
|
||||
// Peek ahead to the next instruction and arguments
|
||||
peekAhead();
|
||||
}
|
||||
|
||||
|
@ -1265,7 +1267,7 @@ public class Cpu implements InstructionTable {
|
|||
/**
|
||||
* 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 {
|
||||
|
||||
|
@ -1674,7 +1676,7 @@ public class Cpu implements InstructionTable {
|
|||
public void setProgramCounter(int 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.
|
||||
try {
|
||||
peekAhead();
|
||||
|
@ -1971,7 +1973,7 @@ public class Cpu implements InstructionTable {
|
|||
*/
|
||||
public String disassembleOpAtAddress(int address) throws MemoryAccessException {
|
||||
int opCode = bus.read(address, true);
|
||||
int args[] = new int[2];
|
||||
int[] args = new int[2];
|
||||
int size = Cpu.instructionSizes[opCode];
|
||||
for (int i = 1; i < size; i++) {
|
||||
int nextRead = (address + i) % bus.endAddress();
|
||||
|
|
|
@ -12,7 +12,7 @@ public class CpuState {
|
|||
public int a;
|
||||
|
||||
/**
|
||||
* X index regsiter
|
||||
* X index register
|
||||
*/
|
||||
public int x;
|
||||
|
||||
|
@ -61,13 +61,12 @@ public class CpuState {
|
|||
public 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)
|
||||
* 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)
|
||||
*
|
||||
* @param s The CpuState to copy.
|
||||
*/
|
||||
@SuppressWarnings("CopyConstructorMissesField")
|
||||
public CpuState(CpuState s) {
|
||||
this.a = s.a;
|
||||
this.x = s.x;
|
||||
|
@ -83,6 +82,7 @@ public class CpuState {
|
|||
this.nextArgs[1] = s.nextArgs[1];
|
||||
this.instSize = s.instSize;
|
||||
this.opTrap = s.opTrap;
|
||||
this.nmiAsserted = s.nmiAsserted;
|
||||
this.irqAsserted = s.irqAsserted;
|
||||
this.carryFlag = s.carryFlag;
|
||||
this.negativeFlag = s.negativeFlag;
|
||||
|
|
|
@ -28,6 +28,7 @@ package com.loomcom.symon;
|
|||
import com.loomcom.symon.machines.MulticompMachine;
|
||||
import com.loomcom.symon.machines.SimpleMachine;
|
||||
import com.loomcom.symon.machines.SymonMachine;
|
||||
import com.loomcom.symon.machines.BenEaterMachine;
|
||||
import org.apache.commons.cli.*;
|
||||
|
||||
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("c", "cpu", true, "Specify CPU type."));
|
||||
options.addOption(new Option("r", "rom", true, "Specify ROM file."));
|
||||
options.addOption(new Option("b", "brk", false, "Halt on BRK"));
|
||||
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
|
||||
|
@ -59,6 +61,7 @@ public class Main {
|
|||
CommandLine line = parser.parse(options, args);
|
||||
InstructionTable.CpuBehavior cpuBehavior = null;
|
||||
String romFile = null;
|
||||
boolean haltOnBreak = false;
|
||||
|
||||
if (line.hasOption("machine")) {
|
||||
String machine = line.getOptionValue("machine").toLowerCase(Locale.ENGLISH);
|
||||
|
@ -72,6 +75,9 @@ public class Main {
|
|||
case "symon":
|
||||
machineClass = SymonMachine.class;
|
||||
break;
|
||||
case "beneater":
|
||||
machineClass = BenEaterMachine.class;
|
||||
break;
|
||||
default:
|
||||
System.err.println("Could not start Symon. Unknown machine type " + machine);
|
||||
return;
|
||||
|
@ -100,9 +106,13 @@ public class Main {
|
|||
romFile = line.getOptionValue("rom");
|
||||
}
|
||||
|
||||
if (line.hasOption("brk")) {
|
||||
haltOnBreak = true;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (machineClass == null) {
|
||||
Object[] possibilities = {"Symon", "Multicomp", "Simple"};
|
||||
Object[] possibilities = {"Symon", "Multicomp", "Simple", "BenEater"};
|
||||
String s = (String)JOptionPane.showInputDialog(
|
||||
null,
|
||||
"Please choose the machine type to be emulated:",
|
||||
|
@ -117,6 +127,8 @@ public class Main {
|
|||
machineClass = MulticompMachine.class;
|
||||
} else if (s != null && s.equals("Simple")) {
|
||||
machineClass = SimpleMachine.class;
|
||||
} else if (s != null && s.equals("BenEater")) {
|
||||
machineClass = BenEaterMachine.class;
|
||||
} else {
|
||||
machineClass = SymonMachine.class;
|
||||
}
|
||||
|
@ -126,7 +138,7 @@ public class Main {
|
|||
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() {
|
||||
@Override
|
||||
|
|
|
@ -29,8 +29,6 @@ public interface Preferences {
|
|||
|
||||
int DEFAULT_PROGRAM_LOAD_ADDRESS = 0x0300;
|
||||
|
||||
boolean DEFAULT_HALT_ON_BREAK = true;
|
||||
|
||||
JDialog getDialog();
|
||||
|
||||
int getProgramStartAddress();
|
||||
|
|
|
@ -126,6 +126,8 @@ public class Simulator {
|
|||
|
||||
private MainCommand command = MainCommand.NONE;
|
||||
|
||||
private boolean haltOnBreak;
|
||||
|
||||
public enum MainCommand {
|
||||
NONE,
|
||||
SELECTMACHINE
|
||||
|
@ -137,16 +139,17 @@ public class Simulator {
|
|||
private static final String[] STEPS = {"1", "5", "10", "20", "50", "100"};
|
||||
|
||||
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.machine = (Machine) machineClass.getConstructors()[0].newInstance(romFile);
|
||||
this.machine.getCpu().setBehavior(cpuType);
|
||||
|
||||
|
||||
// Initialize final fields in the constructor.
|
||||
this.traceLog = new TraceLog();
|
||||
this.memoryWindow = new MemoryWindow(machine.getBus());
|
||||
|
@ -176,7 +179,7 @@ public class Simulator {
|
|||
|
||||
// File Chooser
|
||||
fileChooser = new JFileChooser(System.getProperty("user.dir"));
|
||||
preferences = new PreferencesDialog(mainWindow, true);
|
||||
preferences = new PreferencesDialog(mainWindow, true, haltOnBreak);
|
||||
|
||||
// Panel for Console and Buttons
|
||||
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
|
||||
* functionality. Interrupts are not supported.
|
||||
* functionality.
|
||||
* <p/>
|
||||
* Unlike a 16550 UART, the 6551 ACIA has only one-byte transmit and
|
||||
* 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 {
|
||||
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
|
||||
|
@ -74,16 +82,16 @@ public class Acia6551 extends Acia {
|
|||
@Override
|
||||
public void write(int address, int data) throws MemoryAccessException {
|
||||
switch (address) {
|
||||
case 0:
|
||||
case DATA_REG:
|
||||
txWrite(data);
|
||||
break;
|
||||
case 1:
|
||||
case STAT_REG:
|
||||
reset();
|
||||
break;
|
||||
case 2:
|
||||
case CMND_REG:
|
||||
setCommandRegister(data);
|
||||
break;
|
||||
case 3:
|
||||
case CTRL_REG:
|
||||
setControlRegister(data);
|
||||
break;
|
||||
default:
|
||||
|
@ -110,67 +118,60 @@ public class Acia6551 extends Acia {
|
|||
controlRegister = data;
|
||||
int rate = 0;
|
||||
|
||||
// If the value of the data is 0, this is a request to reset,
|
||||
// otherwise it's a control update.
|
||||
|
||||
if (data == 0) {
|
||||
reset();
|
||||
} else {
|
||||
// Mask the lower three bits to get the baud rate.
|
||||
int baudSelector = data & 0x0f;
|
||||
switch (baudSelector) {
|
||||
case 0:
|
||||
rate = 0;
|
||||
break;
|
||||
case 1:
|
||||
rate = 50;
|
||||
break;
|
||||
case 2:
|
||||
rate = 75;
|
||||
break;
|
||||
case 3:
|
||||
rate = 110; // Real rate is actually 109.92
|
||||
break;
|
||||
case 4:
|
||||
rate = 135; // Real rate is actually 134.58
|
||||
break;
|
||||
case 5:
|
||||
rate = 150;
|
||||
break;
|
||||
case 6:
|
||||
rate = 300;
|
||||
break;
|
||||
case 7:
|
||||
rate = 600;
|
||||
break;
|
||||
case 8:
|
||||
rate = 1200;
|
||||
break;
|
||||
case 9:
|
||||
rate = 1800;
|
||||
break;
|
||||
case 10:
|
||||
rate = 2400;
|
||||
break;
|
||||
case 11:
|
||||
rate = 3600;
|
||||
break;
|
||||
case 12:
|
||||
rate = 4800;
|
||||
break;
|
||||
case 13:
|
||||
rate = 7200;
|
||||
break;
|
||||
case 14:
|
||||
rate = 9600;
|
||||
break;
|
||||
case 15:
|
||||
rate = 19200;
|
||||
break;
|
||||
}
|
||||
|
||||
setBaudRate(rate);
|
||||
// Mask the lower four bits to get the baud rate.
|
||||
int baudSelector = data & 0x0f;
|
||||
switch (baudSelector) {
|
||||
case 0:
|
||||
rate = 0;
|
||||
break;
|
||||
case 1:
|
||||
rate = 50;
|
||||
break;
|
||||
case 2:
|
||||
rate = 75;
|
||||
break;
|
||||
case 3:
|
||||
rate = 110; // Real rate is actually 109.92
|
||||
break;
|
||||
case 4:
|
||||
rate = 135; // Real rate is actually 134.58
|
||||
break;
|
||||
case 5:
|
||||
rate = 150;
|
||||
break;
|
||||
case 6:
|
||||
rate = 300;
|
||||
break;
|
||||
case 7:
|
||||
rate = 600;
|
||||
break;
|
||||
case 8:
|
||||
rate = 1200;
|
||||
break;
|
||||
case 9:
|
||||
rate = 1800;
|
||||
break;
|
||||
case 10:
|
||||
rate = 2400;
|
||||
break;
|
||||
case 11:
|
||||
rate = 3600;
|
||||
break;
|
||||
case 12:
|
||||
rate = 4800;
|
||||
break;
|
||||
case 13:
|
||||
rate = 7200;
|
||||
break;
|
||||
case 14:
|
||||
rate = 9600;
|
||||
break;
|
||||
case 15:
|
||||
rate = 19200;
|
||||
break;
|
||||
}
|
||||
|
||||
setBaudRate(rate);
|
||||
}
|
||||
|
||||
|
||||
|
@ -203,13 +204,16 @@ public class Acia6551 extends Acia {
|
|||
|
||||
|
||||
private synchronized void reset() {
|
||||
txChar = 0;
|
||||
txEmpty = true;
|
||||
rxChar = 0;
|
||||
rxFull = false;
|
||||
receiveIrqEnabled = false;
|
||||
transmitIrqEnabled = false;
|
||||
interrupt = false;
|
||||
}
|
||||
// Figure 6 in the 6551 ACIA data sheet says the "program reset"
|
||||
// event does not modify the control register.
|
||||
|
||||
// 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':
|
||||
while ((++cursorColumn % TAB_WIDTH) != 0);
|
||||
continue;
|
||||
case 127:
|
||||
case 8: // ASCII Backspace
|
||||
case 127: // ASCII Delete
|
||||
if (cursorColumn > 0) {
|
||||
cells[cursorRow][--cursorColumn] = null;
|
||||
}
|
||||
|
|
169
src/main/java/com/loomcom/symon/machines/BenEaterMachine.java
Normal file
169
src/main/java/com/loomcom/symon/machines/BenEaterMachine.java
Normal file
|
@ -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 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.haltOnBreak = haltOnBreak;
|
||||
createUi();
|
||||
updateUi();
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
|||
|
||||
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_HEIGHT = 8;
|
||||
|
||||
|
@ -127,6 +128,18 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
|||
public void run() {
|
||||
if (cursorBlinkRate > 0) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -152,6 +165,11 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
|||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
scheduler.scheduleAtFixedRate(new WindowPainter(),
|
||||
WINDOW_REPAINT_INTERVAL,
|
||||
WINDOW_REPAINT_INTERVAL,
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
// Capture some state from the CRTC that will define the
|
||||
// window size. When these values change, the window will
|
||||
// need to re-pack and redraw.
|
||||
|
|
|
@ -254,4 +254,76 @@ public class AciaTest {
|
|||
|
||||
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(0x200, cpu.getProgramCounter());
|
||||
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));
|
||||
|
||||
// No flags should have changed.
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
/* BIT - Bit Test - $2c */
|
||||
|
@ -362,7 +362,7 @@ public class CpuAbsoluteModeTest extends TestCase {
|
|||
cpu.step();
|
||||
assertEquals(0x3400, cpu.getProgramCounter());
|
||||
// No change to status flags.
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
/* EOR - Exclusive OR - $4d */
|
||||
|
|
|
@ -29,7 +29,7 @@ public class CpuAbsoluteXModeTest extends TestCase {
|
|||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x200, cpu.getProgramCounter());
|
||||
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(0x200, cpu.getProgramCounter());
|
||||
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(0x200, cpu.getProgramCounter());
|
||||
assertEquals(0xff, cpu.getStackPointer());
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -306,4 +306,4 @@ public class CpuAccumulatorModeTest extends TestCase {
|
|||
assertFalse(cpu.getCarryFlag());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class CpuImmediateModeTest extends TestCase {
|
|||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x200, cpu.getProgramCounter());
|
||||
assertEquals(0xff, cpu.getStackPointer());
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -33,7 +33,7 @@ public class CpuImpliedModeTest {
|
|||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x200, cpu.getProgramCounter());
|
||||
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 {
|
||||
cpu.setCarryFlag();
|
||||
cpu.setOverflowFlag();
|
||||
cpu.clearIrqDisableFlag();
|
||||
assertEquals(0x20 | Cpu.P_CARRY | Cpu.P_OVERFLOW,
|
||||
cpu.getProcessorStatus());
|
||||
assertEquals(0x00, cpu.stackPeek());
|
||||
|
@ -343,7 +344,7 @@ public class CpuImpliedModeTest {
|
|||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x201, cpu.getProgramCounter());
|
||||
assertEquals(0xff, cpu.getStackPointer());
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
/* PHA - Push Accumulator - $48 */
|
||||
|
@ -432,7 +433,7 @@ public class CpuImpliedModeTest {
|
|||
cpu.step();
|
||||
|
||||
assertEquals(0x0f12, cpu.getProgramCounter());
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
/* SEC - Set Carry Flag - $38 */
|
||||
|
@ -641,4 +642,4 @@ public class CpuImpliedModeTest {
|
|||
assertFalse(cpu.getZeroFlag());
|
||||
assertTrue(cpu.getNegativeFlag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class CpuIndexedIndirectModeTest {
|
|||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x200, cpu.getProgramCounter());
|
||||
assertEquals(0xff, cpu.getStackPointer());
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -105,4 +105,4 @@ public class CpuIndexedIndirectModeTest {
|
|||
assertEquals(0x11, cpu.getAccumulator());
|
||||
assertEquals(0x31, bus.read(0xc51f, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class CpuIndirectIndexedModeTest {
|
|||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x200, cpu.getProgramCounter());
|
||||
assertEquals(0xff, cpu.getStackPointer());
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -81,4 +81,4 @@ public class CpuIndirectIndexedModeTest {
|
|||
assertEquals(0xe3, bus.read(0xd828, true));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x200, cpu.getProgramCounter());
|
||||
assertEquals(0xff, cpu.getStackPointer());
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -48,7 +48,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
cpu.step();
|
||||
assertEquals(0x5400, cpu.getProgramCounter());
|
||||
// No change to status flags.
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
public void test_JMP_with_ROR_Bug() throws MemoryAccessException {
|
||||
|
@ -60,7 +60,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
cpu.step();
|
||||
assertEquals(0x2200, cpu.getProgramCounter());
|
||||
// No change to status flags.
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
public void test_JMP_withIndirectBug() throws MemoryAccessException {
|
||||
|
@ -72,7 +72,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
cpu.step();
|
||||
assertEquals(0x2200, cpu.getProgramCounter());
|
||||
// No change to status flags.
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
public void test_JMP_withOutIndirectBug() throws MemoryAccessException {
|
||||
|
@ -84,7 +84,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
cpu.step();
|
||||
assertEquals(0x5400, cpu.getProgramCounter());
|
||||
// No change to status flags.
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
public void test_JMP_cmos() throws MemoryAccessException {
|
||||
|
@ -96,7 +96,7 @@ public class CpuIndirectModeTest extends TestCase {
|
|||
cpu.step();
|
||||
assertEquals(0x5400, cpu.getProgramCounter());
|
||||
// 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(0x200, cpu.getProgramCounter());
|
||||
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(0x200, cpu.getProgramCounter());
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class CpuTest extends TestCase {
|
|||
assertEquals(0x0200, cpu.getProgramCounter());
|
||||
assertFalse(cpu.getCarryFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertFalse(cpu.getIrqDisableFlag());
|
||||
assertTrue(cpu.getIrqDisableFlag());
|
||||
assertFalse(cpu.getDecimalModeFlag());
|
||||
assertFalse(cpu.getBreakFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
|
@ -205,14 +205,12 @@ public class CpuTest extends TestCase {
|
|||
}
|
||||
|
||||
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'.
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
cpu.setCarryFlag();
|
||||
assertEquals(0x21, cpu.getProcessorStatus());
|
||||
assertEquals(0x25, cpu.getProcessorStatus());
|
||||
cpu.setZeroFlag();
|
||||
assertEquals(0x23, cpu.getProcessorStatus());
|
||||
cpu.setIrqDisableFlag();
|
||||
assertEquals(0x27, cpu.getProcessorStatus());
|
||||
cpu.setDecimalModeFlag();
|
||||
assertEquals(0x2f, cpu.getProcessorStatus());
|
||||
|
@ -237,13 +235,16 @@ public class CpuTest extends TestCase {
|
|||
assertEquals(0xa0, cpu.getProcessorStatus());
|
||||
cpu.clearNegativeFlag();
|
||||
assertEquals(0x20, cpu.getProcessorStatus());
|
||||
|
||||
cpu.setIrqDisableFlag();
|
||||
assertEquals(0x24, cpu.getProcessorStatus());
|
||||
}
|
||||
|
||||
public void testSetProcessorStatus() {
|
||||
// Default
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertFalse(cpu.getZeroFlag());
|
||||
assertFalse(cpu.getIrqDisableFlag());
|
||||
assertTrue(cpu.getIrqDisableFlag());
|
||||
assertFalse(cpu.getDecimalModeFlag());
|
||||
assertFalse(cpu.getBreakFlag());
|
||||
assertFalse(cpu.getOverflowFlag());
|
||||
|
@ -669,4 +670,4 @@ public class CpuTest extends TestCase {
|
|||
cpu.step();
|
||||
assertEquals(0x3E, cpu.getAccumulator());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class CpuZeroPageModeTest extends TestCase {
|
|||
assertEquals(0, cpu.getYRegister());
|
||||
assertEquals(0x200, cpu.getProgramCounter());
|
||||
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(0x200, cpu.getProgramCounter());
|
||||
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(0x200, cpu.getProgramCounter());
|
||||
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.runner.RunWith;
|
||||
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.assertFalse;
|
||||
|
|
Loading…
Reference in New Issue
Block a user