13 Commits
Author SHA1 Message Date
Seth Morabito 5f8f743f7d Update for 1.3.2 2022-03-08 14:36:59 -08:00
Seth Morabito 4ce8bc86de Update pom.xml
- Switched from maven-assembly-plugin to maven-shade-plugin
  for final packaging
- Updated maven-jar-plugin to 3.2.0
2021-09-25 10:46:36 -07:00
Seth Morabito 4644fe9b55 Update junit and mockito
- JUnit has been bumped to 4.13.2.
- Mockito has gone from 1.10.19 to 3.12.4, and now compiles correctly
  on OpenJDK 16 using Maven 3.8.
2021-09-24 09:39:00 -07:00
Seth Morabito 655bbb3ab0 Merge pull request #26 from sethm/dependabot/maven/junit-junit-4.13.1
Bump junit from 4.12 to 4.13.1
2020-10-13 14:45:47 -07:00
dependabot[bot] e2d31fd39c Bump junit from 4.12 to 4.13.1
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-13 09:09:28 +00:00
Seth Morabito 087ba28b82 Force metal look-and-feel
* On Linux GTK+, the small text fields in the Status Panel displayed a
  large inner margin, cutting off text. This change forces Java to use the
  Metal look-and-feel for these fields, which forces no default inner
  margin.
2020-09-01 10:48:17 -07:00
Seth Morabito 8edca5d595 Update link in README 2020-05-21 15:01:34 -07:00
Seth Morabito 105a09067f Fix README for 1.3.1 2019-10-12 14:58:16 -07:00
Seth Morabito 08efd81be3 Merge branch 'master' into 1.3.branch 2019-10-12 14:55:43 -07:00
Seth Morabito 0aeb97bb56 Add new options -cpu and -rom 2019-10-12 14:54:05 -07:00
Seth Morabito d466a21b3e Fix README screenshots (again) 2018-07-09 14:00:32 -07:00
Seth Morabito 31d1f7c5e1 Update screenshots 2018-03-01 19:21:56 -08:00
Seth Morabito 247f2ba2fc Update screenshots 2018-03-01 19:21:21 -08:00
9 changed files with 200 additions and 102 deletions

No files matched your search

+1
View File
@@ -4,3 +4,4 @@ target
.DS_Store
.idea
symon.iml
/dependency-reduced-pom.xml
+31 -15
View File
@@ -1,13 +1,13 @@
SYMON - A 6502 System Simulator
===============================
**Version:** 1.3.0
**Version:** 1.3.2
**Last Updated:** 25 February, 2018
**Last Updated:** 08 March, 2021
See the file COPYING for license.
![Symon Simulator in Action](http://www.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](http://www.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](http://www.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](http://www.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](http://www.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](http://www.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](http://www.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](http://www.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](http://www.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.
@@ -340,7 +356,7 @@ Additional components used in this project are copyright their respective owners
This project would not have been possible without the following resources:
- [Andrew Jacobs' 6502 Pages](http://www.obelisk.demon.co.uk/6502/), for
- [Andrew Jacobs' 6502 Pages](http://obelisk.me.uk/6502/), for
wonderfully detailed information about the 6502
- [Neil Parker's "The 6502/65C02/65C816 Instruction Set Decoded"](http://www.llx.com/~nparker/a2/opcodes.html),
+28 -16
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.2</version>
<name>symon</name>
<url>http://www.loomcom.com/symon</url>
<properties>
@@ -24,39 +24,51 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<artifactId>mockito-core</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.loomcom.symon.Main</mainClass>
</manifest>
</archive>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
<goal>shade</goal>
</goals>
</execution>
</executions>
@@ -76,7 +88,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
+94 -48
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());
}
}
}
+11 -3
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");
@@ -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);
}
@@ -30,6 +30,7 @@ import com.loomcom.symon.machines.Machine;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
import javax.swing.plaf.metal.MetalTextFieldUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -69,7 +70,7 @@ public class StatusPanel extends JPanel {
private JTextField xField;
private JTextField yField;
private Machine machine;
private final Machine machine;
private static final int EMPTY_BORDER = 10;
private static final Border LABEL_BORDER = BorderFactory.createEmptyBorder(0, 5, 0, 0);
@@ -392,6 +393,13 @@ public class StatusPanel extends JPanel {
textField.setMaximumSize(size);
textField.setPreferredSize(size);
textField.setBackground(Color.WHITE);
// Although we usually defer to the system look-and-feel, for
// these small text fields in particular, we use a Metal
// look-and-feel because native look-and-feel breaks very small
// text fields under GTK+ (they are drawn with an inner margin
// even if the margin is set to 0)
textField.setUI(new MetalTextFieldUI());
return textField;
}