mirror of
https://github.com/sethm/symon.git
synced 2025-05-12 20:39:14 +00:00
Merge branch 'master' into 1.3.branch
This commit is contained in:
commit
08efd81be3
40
README.md
40
README.md
@ -7,7 +7,7 @@ SYMON - A 6502 System Simulator
|
||||
|
||||
See the file COPYING for license.
|
||||
|
||||

|
||||

|
||||
|
||||
## 1.0 About
|
||||
|
||||
@ -66,7 +66,7 @@ memory.
|
||||
|
||||
### 3.2 Serial Console and CPU Status
|
||||
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||

|
||||
|
||||
The console supports font sizes from 10 to 20 points.
|
||||
|
||||
### 3.3 ROM Loading
|
||||
|
||||

|
||||

|
||||
|
||||
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 contents can be viewed (and edited) one page at a time through the Memory Window.
|
||||
|
||||
### 3.5 Trace Log
|
||||
|
||||

|
||||

|
||||
|
||||
The last 20,000 execution steps are disassembled and logged to the Trace Log
|
||||
Window.
|
||||
|
||||
### 3.6 Simulator Speeds
|
||||
|
||||

|
||||

|
||||
|
||||
Simulated speeds may be set from 1MHz to 8MHz.
|
||||
|
||||
### 3.7 Breakpoints
|
||||
|
||||

|
||||

|
||||
|
||||
Breakpoints can be set and removed through the Breakpoints window.
|
||||
|
||||
### 3.8 Experimental 6545 CRTC Video
|
||||
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
7
pom.xml
7
pom.xml
@ -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>
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user