Merge remote-tracking branch 'upstream/master'
Conflicts: src/main/java/com/loomcom/symon/machines/MulticompMachine.java
This commit is contained in:
commit
e9f662cc17
17 files changed
+9298
-84
No files matched your search
@@ -364,6 +364,9 @@ public class Simulator {
|
||||
|
||||
if (videoWindow != null && stepsSinceLastCrtcRefresh++ > stepsBetweenCrtcRefreshes) {
|
||||
stepsSinceLastCrtcRefresh = 0;
|
||||
if (videoWindow.isVisible()) {
|
||||
videoWindow.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
// This is a very expensive update, and we're doing it without
|
||||
|
||||
@@ -65,6 +65,11 @@ public class Crtc extends Device {
|
||||
|
||||
private int currentRegister = 0;
|
||||
|
||||
// Status bits
|
||||
private boolean rowColumnAddressing = false;
|
||||
private boolean displayEnableSkew = false;
|
||||
private boolean cursorSkew = false;
|
||||
|
||||
private Memory memory;
|
||||
|
||||
public Crtc(int deviceAddress, Memory memory) throws MemoryRangeException, IOException {
|
||||
@@ -118,8 +123,9 @@ public class Crtc extends Device {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[] getDmaAccess() {
|
||||
return memory.getDmaAccess();
|
||||
public int getCharAtAddress(int address) throws MemoryAccessException {
|
||||
// TODO: Row/Column addressing
|
||||
return memory.read(address);
|
||||
}
|
||||
|
||||
public int getHorizontalDisplayed() {
|
||||
@@ -162,6 +168,18 @@ public class Crtc extends Device {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public boolean getRowColumnAddressing() {
|
||||
return rowColumnAddressing;
|
||||
}
|
||||
|
||||
public boolean getDisplayEnableSkew() {
|
||||
return displayEnableSkew;
|
||||
}
|
||||
|
||||
public boolean getCursorSkew() {
|
||||
return cursorSkew;
|
||||
}
|
||||
|
||||
private void setCurrentRegister(int registerNumber) {
|
||||
this.currentRegister = registerNumber;
|
||||
}
|
||||
@@ -180,7 +198,9 @@ public class Crtc extends Device {
|
||||
pageSize = horizontalDisplayed * verticalDisplayed;
|
||||
break;
|
||||
case MODE_CONTROL:
|
||||
// TODO: Implement multiple addressing modes and cursor skew.
|
||||
rowColumnAddressing = (data & 0x04) != 0;
|
||||
displayEnableSkew = (data & 0x10) != 0;
|
||||
cursorSkew = (data & 0x20) != 0;
|
||||
break;
|
||||
case SCAN_LINE:
|
||||
scanLinesPerRow = data;
|
||||
|
||||
+6
-32
@@ -23,45 +23,19 @@
|
||||
|
||||
package com.loomcom.symon.devices;
|
||||
|
||||
import com.loomcom.symon.exceptions.MemoryAccessException;
|
||||
import com.loomcom.symon.exceptions.MemoryRangeException;
|
||||
|
||||
public class Via extends Device {
|
||||
public static final int VIA_SIZE = 16;
|
||||
public abstract class Pia extends Device {
|
||||
|
||||
private static final int ORB = 0;
|
||||
private static final int ORA = 1;
|
||||
private static final int DDRB = 2;
|
||||
private static final int DDRA = 3;
|
||||
private static final int T1C_L = 4;
|
||||
private static final int T1C_H = 5;
|
||||
private static final int T1L_L = 6;
|
||||
private static final int T1L_H = 7;
|
||||
private static final int T2C_L = 8;
|
||||
private static final int T2C_H = 9;
|
||||
private static final int SR = 10;
|
||||
private static final int ACR = 11;
|
||||
private static final int PCR = 12;
|
||||
private static final int IFR = 13;
|
||||
private static final int IER = 14;
|
||||
private static final int ORA_H = 15;
|
||||
private final String name;
|
||||
|
||||
public Via(int address) throws MemoryRangeException {
|
||||
super(address, address + VIA_SIZE - 1, "VIA");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int address, int data) throws MemoryAccessException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(int address) throws MemoryAccessException {
|
||||
return 0;
|
||||
public Pia(int startAddress, int endAddress, String name) throws MemoryRangeException {
|
||||
super(startAddress, endAddress, name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return null;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.loomcom.symon.devices;
|
||||
|
||||
import com.loomcom.symon.exceptions.MemoryAccessException;
|
||||
import com.loomcom.symon.exceptions.MemoryRangeException;
|
||||
|
||||
/**
|
||||
* Very basic implementation of a MOS 6522 VIA.
|
||||
*
|
||||
* TODO: Implement timers as threads.
|
||||
*/
|
||||
public class Via6522 extends Pia {
|
||||
public static final int VIA_SIZE = 16;
|
||||
|
||||
enum Register {
|
||||
ORB, ORA, DDRB, DDRA, T1C_L, T1C_H, T1L_L, T1L_H,
|
||||
T2C_L, T2C_H, SR, ACR, PCR, IFR, IER, ORA_H
|
||||
}
|
||||
|
||||
// Ports A and B
|
||||
private char[] portData = {0, 0};
|
||||
private char[] portDirections = {0, 0};
|
||||
|
||||
public Via6522(int address) throws MemoryRangeException {
|
||||
super(address, address + VIA_SIZE - 1, "MOS 6522 VIA");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int address, int data) throws MemoryAccessException {
|
||||
Register[] registers = Register.values();
|
||||
|
||||
if (address >= registers.length) {
|
||||
throw new MemoryAccessException("Unknown register: " + address);
|
||||
}
|
||||
|
||||
Register r = registers[address];
|
||||
|
||||
switch (r) {
|
||||
case ORA:
|
||||
case ORB:
|
||||
case DDRA:
|
||||
case DDRB:
|
||||
case T1C_L:
|
||||
case T1C_H:
|
||||
case T1L_L:
|
||||
case T1L_H:
|
||||
case T2C_L:
|
||||
case T2C_H:
|
||||
case SR:
|
||||
case ACR:
|
||||
case PCR:
|
||||
case IFR:
|
||||
case IER:
|
||||
case ORA_H:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(int address) throws MemoryAccessException {
|
||||
Register[] registers = Register.values();
|
||||
|
||||
if (address >= registers.length) {
|
||||
throw new MemoryAccessException("Unknown register: " + address);
|
||||
}
|
||||
|
||||
Register r = registers[address];
|
||||
|
||||
switch (r) {
|
||||
case ORA:
|
||||
case ORB:
|
||||
case DDRA:
|
||||
case DDRB:
|
||||
case T1C_L:
|
||||
case T1C_H:
|
||||
case T1L_L:
|
||||
case T1L_H:
|
||||
case T2C_L:
|
||||
case T2C_H:
|
||||
case SR:
|
||||
case ACR:
|
||||
case PCR:
|
||||
case IFR:
|
||||
case IER:
|
||||
case ORA_H:
|
||||
default:
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import com.loomcom.symon.Cpu;
|
||||
import com.loomcom.symon.devices.Acia;
|
||||
import com.loomcom.symon.devices.Crtc;
|
||||
import com.loomcom.symon.devices.Memory;
|
||||
import com.loomcom.symon.devices.Via;
|
||||
import com.loomcom.symon.devices.Pia;
|
||||
import com.loomcom.symon.exceptions.MemoryRangeException;
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public interface Machine {
|
||||
|
||||
public Acia getAcia();
|
||||
|
||||
public Via getVia();
|
||||
public Pia getPia();
|
||||
|
||||
public Crtc getCrtc();
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ import com.loomcom.symon.devices.Acia;
|
||||
import com.loomcom.symon.devices.Acia6850;
|
||||
import com.loomcom.symon.devices.Crtc;
|
||||
import com.loomcom.symon.devices.Memory;
|
||||
import com.loomcom.symon.devices.Pia;
|
||||
import com.loomcom.symon.devices.SdController;
|
||||
import com.loomcom.symon.devices.Via;
|
||||
import com.loomcom.symon.exceptions.MemoryRangeException;
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
@@ -118,7 +118,7 @@ public class MulticompMachine implements Machine {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Via getVia() {
|
||||
public Pia getPia() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.loomcom.symon.Cpu;
|
||||
import com.loomcom.symon.devices.Acia;
|
||||
import com.loomcom.symon.devices.Crtc;
|
||||
import com.loomcom.symon.devices.Memory;
|
||||
import com.loomcom.symon.devices.Via;
|
||||
import com.loomcom.symon.devices.Pia;
|
||||
import com.loomcom.symon.exceptions.MemoryRangeException;
|
||||
|
||||
/**
|
||||
@@ -52,7 +52,7 @@ public class SimpleMachine implements Machine {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Via getVia() {
|
||||
public Pia getPia() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,7 @@ package com.loomcom.symon.machines;
|
||||
|
||||
import com.loomcom.symon.Bus;
|
||||
import com.loomcom.symon.Cpu;
|
||||
import com.loomcom.symon.devices.Acia;
|
||||
import com.loomcom.symon.devices.Acia6551;
|
||||
import com.loomcom.symon.devices.Crtc;
|
||||
import com.loomcom.symon.devices.Memory;
|
||||
import com.loomcom.symon.devices.Via;
|
||||
import com.loomcom.symon.devices.*;
|
||||
import com.loomcom.symon.exceptions.MemoryRangeException;
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
@@ -48,16 +44,15 @@ public class SymonMachine implements Machine {
|
||||
private static final int MEMORY_BASE = 0x0000;
|
||||
private static final int MEMORY_SIZE = 0x8000;
|
||||
|
||||
// VIA at $8000-$800F
|
||||
// PIA at $8000-$800F
|
||||
|
||||
private static final int VIA_BASE = 0x8000;
|
||||
private static final int PIA_BASE = 0x8000;
|
||||
|
||||
// ACIA at $8800-$8803
|
||||
private static final int ACIA_BASE = 0x8800;
|
||||
|
||||
// CRTC at $9000-$9001
|
||||
private static final int CRTC_BASE = 0x9000;
|
||||
private static final int VIDEO_RAM_BASE = 0x7000;
|
||||
|
||||
// 16KB ROM at $C000-$FFFF
|
||||
private static final int ROM_BASE = 0xC000;
|
||||
@@ -68,7 +63,7 @@ public class SymonMachine implements Machine {
|
||||
private final Bus bus;
|
||||
private final Cpu cpu;
|
||||
private final Acia acia;
|
||||
private final Via via;
|
||||
private final Pia pia;
|
||||
private final Crtc crtc;
|
||||
private final Memory ram;
|
||||
private Memory rom;
|
||||
@@ -78,13 +73,13 @@ public class SymonMachine implements Machine {
|
||||
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.via = new Via(VIA_BASE);
|
||||
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(via);
|
||||
bus.addDevice(pia);
|
||||
bus.addDevice(acia);
|
||||
bus.addDevice(crtc);
|
||||
|
||||
@@ -124,8 +119,8 @@ public class SymonMachine implements Machine {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Via getVia() {
|
||||
return via;
|
||||
public Pia getPia() {
|
||||
return pia;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,6 +25,7 @@ package com.loomcom.symon.ui;
|
||||
|
||||
import com.loomcom.symon.devices.Crtc;
|
||||
import com.loomcom.symon.devices.DeviceChangeListener;
|
||||
import com.loomcom.symon.exceptions.MemoryAccessException;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -36,8 +37,11 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.lang.System.*;
|
||||
|
||||
/**
|
||||
* VideoWindow represents a graphics framebuffer backed by a 6545 CRTC.
|
||||
* Each time the window's VideoPanel is repainted, the video memory is
|
||||
@@ -65,7 +69,6 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
||||
|
||||
private BufferedImage image;
|
||||
private int[] charRom;
|
||||
private int[] videoRam;
|
||||
|
||||
private int horizontalDisplayed;
|
||||
private int verticalDisplayed;
|
||||
@@ -85,17 +88,21 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
||||
private class VideoPanel extends JPanel {
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
for (int i = 0; i < crtc.getPageSize(); i++) {
|
||||
int address = crtc.getStartAddress() + i;
|
||||
int originX = (i % horizontalDisplayed) * CHAR_WIDTH;
|
||||
int originY = (i / horizontalDisplayed) * scanLinesPerRow;
|
||||
image.getRaster().setPixels(originX, originY, CHAR_WIDTH, scanLinesPerRow, getGlyph(address));
|
||||
try {
|
||||
for (int i = 0; i < crtc.getPageSize(); i++) {
|
||||
int address = crtc.getStartAddress() + i;
|
||||
int originX = (i % horizontalDisplayed) * CHAR_WIDTH;
|
||||
int originY = (i / horizontalDisplayed) * scanLinesPerRow;
|
||||
image.getRaster().setPixels(originX, originY, CHAR_WIDTH, scanLinesPerRow, getGlyph(address));
|
||||
}
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
if (shouldScale) {
|
||||
g2d.scale(scaleX, scaleY);
|
||||
}
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
} catch (MemoryAccessException ex) {
|
||||
logger.log(Level.SEVERE, "Memory Access Exception, can't paint video window! " + ex.getMessage());
|
||||
}
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
if (shouldScale) {
|
||||
g2d.scale(scaleX, scaleY);
|
||||
}
|
||||
g2d.drawImage(image, 0, 0, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,8 +138,7 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
||||
|
||||
this.scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
this.crtc = crtc;
|
||||
this.charRom = loadCharRom("/pet.rom");
|
||||
this.videoRam = crtc.getDmaAccess();
|
||||
this.charRom = loadCharRom("/cga8.rom");
|
||||
this.scaleX = scaleX;
|
||||
this.scaleY = scaleY;
|
||||
this.shouldScale = (scaleX > 1 || scaleY > 1);
|
||||
@@ -158,13 +164,6 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
||||
|
||||
}
|
||||
|
||||
public void refreshDisplay() {
|
||||
// TODO: Verify whether this is necessary. Does `repaint()' do anything if the window is not visible?
|
||||
if (isVisible()) {
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the CRTC on state change.
|
||||
*/
|
||||
@@ -239,15 +238,13 @@ public class VideoWindow extends JFrame implements DeviceChangeListener {
|
||||
* @param address The address of the character being requested.
|
||||
* @return An array of integers representing the pixel data.
|
||||
*/
|
||||
private int[] getGlyph(int address) {
|
||||
int chr = videoRam[address];
|
||||
private int[] getGlyph(int address) throws MemoryAccessException {
|
||||
int chr = crtc.getCharAtAddress(address);
|
||||
int romOffset = (chr & 0xff) * (CHAR_HEIGHT * CHAR_WIDTH);
|
||||
int[] glyph = new int[CHAR_WIDTH * scanLinesPerRow];
|
||||
|
||||
// Populate the character
|
||||
for (int i = 0; i < (CHAR_WIDTH * Math.min(CHAR_HEIGHT, scanLinesPerRow)); i++) {
|
||||
glyph[i] = charRom[romOffset + i];
|
||||
}
|
||||
arraycopy(charRom, romOffset, glyph, 0, CHAR_WIDTH * Math.min(CHAR_HEIGHT, scanLinesPerRow));
|
||||
|
||||
// Overlay the cursor
|
||||
if (!hideCursor && crtc.isCursorEnabled() && crtc.getCursorPosition() == address) {
|
||||
|
||||
Reference in new issue
Block a user