158 lines
4.3 KiB
Java
158 lines
4.3 KiB
Java
package com.loomcom.symon;
|
|
|
|
import java.util.logging.*;
|
|
|
|
import com.loomcom.symon.devices.*;
|
|
import com.loomcom.symon.exceptions.*;
|
|
import com.loomcom.symon.ui.UiUpdater;
|
|
|
|
import javax.swing.*;
|
|
|
|
/**
|
|
* Main entry point and control for the Symon Simulator.
|
|
* This class is responsible for creating the UI and starting
|
|
* the IO threads that pass data to and from the simulated
|
|
* Bus and Cpu.
|
|
*/
|
|
public class Simulator implements Runnable {
|
|
|
|
private final static Logger logger = Logger.getLogger(Simulator.class.getName());
|
|
|
|
private Bus bus;
|
|
private Cpu cpu;
|
|
private Acia acia;
|
|
private Memory ram;
|
|
private Memory rom;
|
|
private boolean isRunning = false;
|
|
|
|
private int updatesRequested = 0;
|
|
|
|
private UiUpdater uiUpdater;
|
|
|
|
private static final int BUS_BOTTOM = 0x0000;
|
|
private static final int BUS_TOP = 0xffff;
|
|
|
|
private static final int MEMORY_BASE = 0x0000;
|
|
private static final int MEMORY_SIZE = 0xc000; // 48 KB
|
|
|
|
private static final int ROM_BASE = 0xe000;
|
|
private static final int ROM_SIZE = 0x2000; // 8 KB
|
|
|
|
public static final int ACIA_BASE = 0xc000;
|
|
|
|
private static final int MAX_REQUESTS_BETWEEN_UPDATES = 25000;
|
|
|
|
public Simulator() throws MemoryRangeException {
|
|
this.acia = new Acia(ACIA_BASE);
|
|
this.bus = new Bus(BUS_BOTTOM, BUS_TOP);
|
|
this.cpu = new Cpu();
|
|
this.ram = new Memory(MEMORY_BASE, MEMORY_SIZE, false);
|
|
// TODO: Load this ROM from a file, naturally!
|
|
this.rom = new Memory(ROM_BASE, ROM_SIZE, false);
|
|
bus.addCpu(cpu);
|
|
bus.addDevice(acia);
|
|
bus.addDevice(ram);
|
|
bus.addDevice(rom);
|
|
}
|
|
|
|
public void loadProgram(byte[] program, int startAddress) throws MemoryAccessException {
|
|
cpu.setResetVector(startAddress);
|
|
|
|
int addr = startAddress, i;
|
|
for (i = 0; i < program.length; i++) {
|
|
bus.write(addr++, program[i] & 0xff);
|
|
}
|
|
|
|
logger.log(Level.INFO, "Loaded " + i + " bytes at address 0x" +
|
|
Integer.toString(startAddress, 16));
|
|
}
|
|
|
|
public void setUiUpdater(UiUpdater uiUpdater) {
|
|
this.uiUpdater = uiUpdater;
|
|
}
|
|
|
|
public boolean isRunning() {
|
|
return isRunning;
|
|
}
|
|
|
|
public void requestStop() {
|
|
isRunning = false;
|
|
}
|
|
|
|
public void reset() throws MemoryAccessException {
|
|
cpu.reset();
|
|
}
|
|
|
|
public void clearMemory() {
|
|
ram.fill(0x00);
|
|
}
|
|
|
|
public int getProcessorStatus() {
|
|
return cpu.getProcessorStatus();
|
|
}
|
|
|
|
public Cpu getCpu() {
|
|
return this.cpu;
|
|
}
|
|
|
|
public long memorySize() {
|
|
return MEMORY_SIZE;
|
|
}
|
|
|
|
public void run() {
|
|
logger.log(Level.INFO, "Entering 'run' on main Simulator thread");
|
|
isRunning = true;
|
|
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
public void run() {
|
|
uiUpdater.simulatorDidStart();
|
|
}
|
|
});
|
|
|
|
try {
|
|
while (isRunning && !cpu.getBreakFlag()) {
|
|
step();
|
|
}
|
|
} catch (SymonException ex) {
|
|
logger.log(Level.SEVERE, "Exception in main simulator run thread. Exiting run.");
|
|
ex.printStackTrace();
|
|
}
|
|
|
|
logger.log(Level.INFO, "Exiting 'run'. BREAK=" + cpu.getBreakBit() + "; RUN_FLAG=" + isRunning);
|
|
isRunning = false;
|
|
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
public void run() {
|
|
uiUpdater.simulatorDidStop();
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
|
|
public void step() throws MemoryAccessException, FifoUnderrunException {
|
|
|
|
cpu.step();
|
|
|
|
// TODO: ACIA interrupt handling. For now, poll ACIA on each step.
|
|
|
|
// Read from the ACIA and add to the UiUpdater buffer
|
|
while (acia.hasTxChar()) {
|
|
uiUpdater.consoleWrite(acia.txRead());
|
|
}
|
|
|
|
// This is a very expensive update, and we're doing it without
|
|
// a delay, so we don't want to overwhelm the Swing event processing thread
|
|
// with requests. Limit the number of ui updates that can be performed.
|
|
if (updatesRequested++ > MAX_REQUESTS_BETWEEN_UPDATES) {
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
public void run() {
|
|
uiUpdater.updateUi();
|
|
}
|
|
});
|
|
updatesRequested = 0;
|
|
}
|
|
}
|
|
}
|
|
|