Merge branch 'master' into 1.3.branch

This commit is contained in:
Seth Morabito 2019-10-12 14:55:43 -07:00
commit 08efd81be3
7 changed files with 165 additions and 83 deletions

View File

@ -7,7 +7,7 @@ SYMON - A 6502 System Simulator
See the file COPYING for license.
![Symon Simulator in Action](https://static.loomcom.com/symon/screenshots/full.jpg)
![Symon Simulator in Action](https://github.com/sethm/symon/raw/master/screenshots/full.jpg)
## 1.0 About
@ -66,7 +66,7 @@ memory.
### 3.2 Serial Console and CPU Status
![Serial Console](https://static.loomcom.com/symon/screenshots/console.png)
![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
@ -78,13 +78,13 @@ 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.
![Font Selection](https://static.loomcom.com/symon/screenshots/font_selection.png)
![Font Selection](https://github.com/sethm/symon/raw/master/screenshots/font_selection.png)
The console supports font sizes from 10 to 20 points.
### 3.3 ROM Loading
![ROM Loading](https://static.loomcom.com/symon/screenshots/load_rom.png)
![ROM Loading](https://github.com/sethm/symon/raw/master/screenshots/load_rom.png)
Symon can load any appropriately sized ROM image. The Symon
architecture expects as 16KB (16384 byte) ROM image, while the
@ -95,32 +95,32 @@ address.
### 3.4 Memory Window
![Memory Window](https://static.loomcom.com/symon/screenshots/memory_window.png)
![Memory Window](https://github.com/sethm/symon/raw/master/screenshots/memory_window.png)
Memory contents can be viewed (and edited) one page at a time through the Memory Window.
### 3.5 Trace Log
![Trace Log](https://static.loomcom.com/symon/screenshots/trace_log.png)
![Trace Log](https://github.com/sethm/symon/raw/master/screenshots/trace_log.png)
The last 20,000 execution steps are disassembled and logged to the Trace Log
Window.
### 3.6 Simulator Speeds
![Speeds](https://static.loomcom.com/symon/screenshots/simulator_menu.png)
![Speeds](https://github.com/sethm/symon/raw/master/screenshots/simulator_menu.png)
Simulated speeds may be set from 1MHz to 8MHz.
### 3.7 Breakpoints
![Breakpoints](https://static.loomcom.com/symon/screenshots/breakpoints.png)
![Breakpoints](https://github.com/sethm/symon/raw/master/screenshots/breakpoints.png)
Breakpoints can be set and removed through the Breakpoints window.
### 3.8 Experimental 6545 CRTC Video
![Composite Video](https://static.loomcom.com/symon/screenshots/video_window.png)
![Composite Video](https://github.com/sethm/symon/raw/master/screenshots/video_window.png)
This feature is highly experimental. It's possible to open a video window
from the "View" menu. This window simulates the output of a MOS 6545 CRT
@ -154,7 +154,7 @@ between the simulated 6545 and a real 6545:
of 6545 programming tricks that were achieved by updating the
frame address during vertical and horizontal sync times are not
achievable. There is no way (for example) to change the Display Start
Address (R12 and R13) while a frame is being drawn.
Address (R12 and R13) while a frame is being drawn.
For more information on the 6545 CRTC and its programming model, please see the following resources
@ -193,6 +193,18 @@ Java 1.8 or greater, just type:
When Symon is running, you should be presented with a simple graphical
interface.
#### 4.1.1 Command Line Options
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.
### 4.2 ROM images
The simulator requires a ROM image loaded into memory to work
@ -235,6 +247,10 @@ running.
## 5.0 Revision History
- **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.
- **1.3.0:** 24 February, 2018 - Adds support for 65C02 opcodes.
- **1.2.1:** 8 January, 2016 - Remove dependency on Java 8. Now
@ -242,11 +258,11 @@ running.
- **1.2.0:** 3 January, 2016 - Add symbolic disassembly to breakpoints
window.
- **1.1.1:** 2 January, 2016 - Minor enhancement: Allows breakpoints
to be added with the Enter key.
- **1.1.0:** 31 December, 2015 - Fixed delay loop to better
- **1.1.0:** 31 December, 2015 - Fixed delay loop to better
simulate various clock speeds. Added ability to select clock
speed at runtime. Status display now shows the next instruction
to be executed, instead of the last instruction executed.

View File

@ -4,7 +4,7 @@
<groupId>com.loomcom.symon</groupId>
<artifactId>symon</artifactId>
<packaging>jar</packaging>
<version>1.3.0</version>
<version>1.3.1</version>
<name>symon</name>
<url>http://www.loomcom.com/symon</url>
<properties>
@ -33,6 +33,11 @@
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>

View File

@ -28,6 +28,8 @@ package com.loomcom.symon;
import com.loomcom.symon.machines.MulticompMachine;
import com.loomcom.symon.machines.SimpleMachine;
import com.loomcom.symon.machines.SymonMachine;
import org.apache.commons.cli.*;
import java.util.Locale;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
@ -41,71 +43,115 @@ public class Main {
*
* @param args Program arguments
*/
public static void main(String args[]) throws Exception {
public static void main(String[] args) throws Exception {
Class machineClass = SymonMachine.class;
for(int i = 0; i < args.length; ++i) {
String arg = args[i].toLowerCase(Locale.ENGLISH);
if(arg.equals("-machine") && (i+1) < args.length) {
String machine = args[i+1].trim().toLowerCase(Locale.ENGLISH);
Options options = new Options();
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."));
CommandLineParser parser = new DefaultParser();
try {
CommandLine line = parser.parse(options, args);
InstructionTable.CpuBehavior cpuBehavior = null;
String romFile = null;
if (line.hasOption("machine")) {
String machine = line.getOptionValue("machine").toLowerCase(Locale.ENGLISH);
switch (machine) {
case "symon":
machineClass = SymonMachine.class;
break;
case "multicomp":
machineClass = MulticompMachine.class;
break;
case "simple":
machineClass = SimpleMachine.class;
break;
case "symon":
machineClass = SymonMachine.class;
break;
default:
System.err.println("Could not start Symon. Unknown machine type " + machine);
return;
}
}
}
while (true) {
if (machineClass == null) {
Object[] possibilities = {"Symon", "Multicomp", "Simple"};
String s = (String)JOptionPane.showInputDialog(
null,
"Please choose the machine type to be emulated:",
"Machine selection",
JOptionPane.PLAIN_MESSAGE,
null,
possibilities,
"Symon");
if (s != null && s.equals("Multicomp")) {
machineClass = MulticompMachine.class;
} else if (s != null && s.equals("Simple")) {
machineClass = SimpleMachine.class;
} else {
machineClass = SymonMachine.class;
if (line.hasOption("cpu")) {
String cpu = line.getOptionValue("cpu").toLowerCase(Locale.ENGLISH);
switch (cpu) {
case "6502":
cpuBehavior = InstructionTable.CpuBehavior.NMOS_6502;
break;
case "65c02":
cpuBehavior = InstructionTable.CpuBehavior.CMOS_6502;
break;
case "65c816":
cpuBehavior = InstructionTable.CpuBehavior.CMOS_65816;
break;
default:
System.err.println("Could not start Symon. Unknown cpu type " + cpu);
return;
}
}
final Simulator simulator = new Simulator(machineClass);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// Create the main UI window
simulator.createAndShowUi();
} catch (Exception e) {
e.printStackTrace();
if (line.hasOption("rom")) {
romFile = line.getOptionValue("rom");
}
while (true) {
if (machineClass == null) {
Object[] possibilities = {"Symon", "Multicomp", "Simple"};
String s = (String)JOptionPane.showInputDialog(
null,
"Please choose the machine type to be emulated:",
"Machine selection",
JOptionPane.PLAIN_MESSAGE,
null,
possibilities,
"Symon");
if (s != null && s.equals("Multicomp")) {
machineClass = MulticompMachine.class;
} else if (s != null && s.equals("Simple")) {
machineClass = SimpleMachine.class;
} else {
machineClass = SymonMachine.class;
}
}
});
Simulator.MainCommand cmd = simulator.waitForCommand();
if (cmd.equals(Simulator.MainCommand.SELECTMACHINE)) {
machineClass = null;
} else {
break;
if (cpuBehavior == null) {
cpuBehavior = InstructionTable.CpuBehavior.NMOS_6502;
}
final Simulator simulator = new Simulator(machineClass, cpuBehavior, romFile);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// Create the main UI window
simulator.createAndShowUi();
} catch (Exception e) {
e.printStackTrace();
}
}
});
Simulator.MainCommand cmd = simulator.waitForCommand();
if (cmd.equals(Simulator.MainCommand.SELECTMACHINE)) {
machineClass = null;
} else {
break;
}
}
} catch (ParseException ex) {
System.err.println("Could not start Symon. Reason: " + ex.getMessage());
}
}
}

View File

@ -31,6 +31,7 @@ import com.loomcom.symon.ui.Console;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.monitor.CounterMonitor;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
@ -136,9 +137,15 @@ 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);
}
public Simulator(Class machineClass, InstructionTable.CpuBehavior cpuType, String romFile) throws Exception {
this.breakpoints = new Breakpoints(this);
this.machine = (Machine) machineClass.getConstructors()[0].newInstance();
this.machine = (Machine) machineClass.getConstructors()[0].newInstance(romFile);
this.machine.getCpu().setBehavior(cpuType);
// Initialize final fields in the constructor.
this.traceLog = new TraceLog();
@ -887,8 +894,9 @@ public class Simulator {
JMenu cpuTypeMenu = new JMenu("CPU");
ButtonGroup cpuGroup = new ButtonGroup();
makeCpuMenuItem("NMOS 6502", Cpu.CpuBehavior.NMOS_6502, cpuTypeMenu, cpuGroup);
makeCpuMenuItem("CMOS 65C02", Cpu.CpuBehavior.CMOS_6502, cpuTypeMenu, cpuGroup);
makeCpuMenuItem("6502", Cpu.CpuBehavior.NMOS_6502, cpuTypeMenu, cpuGroup);
makeCpuMenuItem("65C02", Cpu.CpuBehavior.CMOS_6502, cpuTypeMenu, cpuGroup);
makeCpuMenuItem("65C816", Cpu.CpuBehavior.CMOS_65816, cpuTypeMenu, cpuGroup);
// "Clock Speed" sub-menu
JMenu speedSubMenu = new JMenu("Clock Speed");

View File

@ -68,7 +68,7 @@ public class MulticompMachine implements Machine {
private Memory rom;
public MulticompMachine() throws Exception {
public MulticompMachine(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);
@ -79,20 +79,23 @@ public class MulticompMachine implements Machine {
bus.addDevice(ram);
bus.addDevice(acia, 1);
bus.addDevice(new SdController(SD_BASE), 1);
// TODO: Make this configurable, of course.
File romImage = new File("rom.bin");
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 " + romImage +
if (romFile != null) {
File romImage = new File("rom.bin");
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 " + romImage +
" not found, loading empty R/W memory image.");
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

View File

@ -46,7 +46,7 @@ public class SimpleMachine implements Machine {
private final Memory ram;
private final Cpu cpu;
public SimpleMachine() throws MemoryRangeException {
public SimpleMachine(String romFile) throws MemoryRangeException {
this.bus = new Bus(BUS_BOTTOM, BUS_TOP);
this.ram = new Memory(BUS_BOTTOM, BUS_TOP, false);
this.cpu = new Cpu();

View File

@ -70,7 +70,7 @@ public class SymonMachine implements Machine {
private Memory rom;
public SymonMachine() throws Exception {
public SymonMachine(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);
@ -83,14 +83,18 @@ public class SymonMachine implements Machine {
bus.addDevice(pia);
bus.addDevice(acia);
bus.addDevice(crtc);
// TODO: Make this configurable, of course.
File romImage = new File("rom.bin");
if (romImage.canRead()) {
logger.info("Loading ROM image from file {}", romImage);
this.rom = Memory.makeROM(ROM_BASE, ROM_BASE + ROM_SIZE - 1, romImage);
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("Default ROM file {} not found, loading empty R/W memory image.", romImage);
logger.info("No ROM file specified, loading empty R/W memory image.");
this.rom = Memory.makeRAM(ROM_BASE, ROM_BASE + ROM_SIZE - 1);
}