diff --git a/src/main/java/jace/hardware/CardMockingboard.java b/src/main/java/jace/hardware/CardMockingboard.java index 3b190ce..b12e2b1 100644 --- a/src/main/java/jace/hardware/CardMockingboard.java +++ b/src/main/java/jace/hardware/CardMockingboard.java @@ -159,14 +159,17 @@ public class CardMockingboard extends Card implements Runnable { if (e.getType().isRead()) { int val = controller.readRegister(register & 0x0f); e.setNewValue(val); +// System.out.println("Read "+Integer.toHexString(register)+" == "+val); } else { controller.writeRegister(register & 0x0f, e.getNewValue()); +// System.out.println("Write "+Integer.toHexString(register)+" == "+e.getNewValue()); } } @Override protected void handleIOAccess(int register, TYPE type, int value, RAMEvent e) { // Oddly, all IO is done at the firmware address bank. It's a strange card. +// System.out.println("MB I/O Access "+type.name()+" "+register+":"+value); e.setNewValue(computer.getVideo().getFloatingBus()); } long ticksSinceLastPlayback = 0; @@ -319,6 +322,9 @@ public class CardMockingboard extends Card implements Runnable { int zeroSamples = 0; setRun(true); while (isRunning()) { + while (!computer.isRunning()) { + Thread.sleep(500); + } computer.getMotherboard().requestSpeed(this); playSound(leftBuffer, rightBuffer); int p = 0; @@ -381,6 +387,8 @@ public class CardMockingboard extends Card implements Runnable { } catch (LineUnavailableException ex) { Logger.getLogger(CardMockingboard.class .getName()).log(Level.SEVERE, null, ex); + } catch (InterruptedException ex) { + Logger.getLogger(CardMockingboard.class.getName()).log(Level.SEVERE, null, ex); } finally { computer.getMotherboard().cancelSpeedRequest(this); System.out.println("Mockingboard playback stopped"); diff --git a/src/main/java/jace/hardware/mockingboard/R6522.java b/src/main/java/jace/hardware/mockingboard/R6522.java index 32b8e1c..72e9dea 100644 --- a/src/main/java/jace/hardware/mockingboard/R6522.java +++ b/src/main/java/jace/hardware/mockingboard/R6522.java @@ -23,17 +23,22 @@ import jace.core.Device; /** * Implementation of 6522 VIA chip - * @author Brendan Robert (BLuRry) brendan.robert@gmail.com + * + * @author Brendan Robert (BLuRry) brendan.robert@gmail.com */ public abstract class R6522 extends Device { - + public R6522(Computer computer) { super(computer); + timer1freerun = true; + timer1running = true; + timer1latch = 0x1fff; + timer1interruptEnabled = false; + setRun(true); } - + // 6522 VIA // http://www.applevault.com/twiki/Main/Mockingboard/6522.pdf - // I/O registers public static enum Register { ORB(0), // Output Register B @@ -54,13 +59,16 @@ public abstract class R6522 extends Device { ORAH(15);// Output Register A (no handshake) int val; + Register(int v) { val = v; } static public Register fromInt(int i) { for (Register r : Register.values()) { - if (r.val == i) return r; + if (r.val == i) { + return r; + } } return null; } @@ -130,14 +138,16 @@ public abstract class R6522 extends Device { protected String getDeviceName() { return "6522 VIA Chip"; } - + @Override public void tick() { if (timer1running) { - timer1counter --; + timer1counter--; if (timer1counter < 0) { timer1counter = timer1latch; - if (!timer1freerun) timer1running = false; + if (!timer1freerun) { + timer1running = false; + } if (timer1interruptEnabled) { // System.out.println("Timer 1 generated interrupt"); timer1IRQ = true; @@ -146,7 +156,7 @@ public abstract class R6522 extends Device { } } if (timer2running) { - timer2counter --; + timer2counter--; if (timer2counter < 0) { timer2running = false; timer2counter = timer2latch; @@ -156,39 +166,42 @@ public abstract class R6522 extends Device { } } } - if (!timer1running && !timer2running) + if (!timer1running && !timer2running) { setRun(false); + } } - + @Override public void attach() { // Start chip } - + @Override public void reconfigure() { // Reset } - public void writeRegister(int reg, int value) { - value &= 0x0ff; + public void writeRegister(int reg, int val) { + int value = val & 0x0ff; Register r = Register.fromInt(reg); // System.out.println("Writing "+(value&0x0ff)+" to register "+r.toString()); switch (r) { case ORB: - if (dataDirectionB == 0) break; - value = value & dataDirectionB; - sendOutputB(value); + if (dataDirectionB == 0) { + break; + } + sendOutputB(value & dataDirectionB); break; case ORA: // case ORAH: - if (dataDirectionA == 0) break; - value = value & dataDirectionA; - sendOutputA(value); + if (dataDirectionA == 0) { + break; + } + sendOutputA(value & dataDirectionA); break; case DDRB: dataDirectionB = value; - break; + break; case DDRA: dataDirectionA = value; break; @@ -223,39 +236,55 @@ public abstract class R6522 extends Device { case ACR: // SHIFT REGISTER NOT IMPLEMENTED timer1freerun = (value & 64) != 0; - if (timer1freerun) timer1running = true; + if (timer1freerun) { + timer1running = true; + setRun(true); + } break; case PCR: // TODO: Implement if Votrax (SSI) is to be supported break; case IFR: - if ((value & 64) != 0) timer1IRQ = false; - if ((value & 32) != 0) timer2IRQ = false; + if ((value & 64) != 0) { + timer1IRQ = false; + } + if ((value & 32) != 0) { + timer2IRQ = false; + } break; case IER: boolean enable = (value & 128) != 0; - if ((value & 64) != 0) timer1interruptEnabled = enable; - if ((value & 32) != 0) timer2interruptEnabled = enable; + if ((value & 64) != 0) { + timer1interruptEnabled = enable; + } + if ((value & 32) != 0) { + timer2interruptEnabled = enable; + } break; default: } } - + // Whatever uses 6522 will want to know when it is outputting values // So to hook that in, these abstract methods will be defined as appropriate public abstract void sendOutputA(int value); - public abstract void sendOutputB(int value); + public abstract void sendOutputB(int value); + public int readRegister(int reg) { Register r = Register.fromInt(reg); // System.out.println("Reading register "+r.toString()); switch (r) { case ORB: - if (dataDirectionB == 0x0ff) break; + if (dataDirectionB == 0x0ff) { + break; + } return receiveOutputB() & (dataDirectionB ^ 0x0ff); case ORA: case ORAH: - if (dataDirectionA == 0x0ff) break; + if (dataDirectionA == 0x0ff) { + break; + } return receiveOutputA() & (dataDirectionA ^ 0x0ff); case DDRB: return dataDirectionB; @@ -263,14 +292,8 @@ public abstract class R6522 extends Device { return dataDirectionA; case T1CL: timer1IRQ = false; -// int out = timer1counter & 0x0ff; - // Behavior to get SkyFox to detect mockingboard -- thanks to tom@snsys.com! - timer1counter -= 8; -// return out; - return timer1counter & 0x0ff; + return timer1counter & 0x0ff; case T1CH: - // Behavior to get SkyFox to detect mockingboard -- thanks to tom@snsys.com! - timer1counter -= 8; return (timer1counter & 0x0ff00) >> 8; case T1LL: return timer1latch & 0x0ff; @@ -286,24 +309,38 @@ public abstract class R6522 extends Device { return 0; case ACR: // SHIFT REGISTER NOT IMPLEMENTED - if (timer1freerun) return 64; + if (timer1freerun) { + return 64; + } return 0; case PCR: break; case IFR: int val = 0; - if (timer1IRQ) val |= 64; - if (timer2IRQ) val |= 32; - if (val != 0) val |= 128; + if (timer1IRQ) { + val |= 64; + } + if (timer2IRQ) { + val |= 32; + } + if (val != 0) { + val |= 128; + } return val; case IER: val = 128; - if (timer1interruptEnabled) val |= 64; - if (timer2interruptEnabled) val |= 32; + if (timer1interruptEnabled) { + val |= 64; + } + if (timer2interruptEnabled) { + val |= 32; + } return val; } return 0; } + public abstract int receiveOutputA(); + public abstract int receiveOutputB(); -} \ No newline at end of file +} diff --git a/src/main/java/jace/hardware/mockingboard/TimedGenerator.java b/src/main/java/jace/hardware/mockingboard/TimedGenerator.java index 86bea7e..1e0fe9c 100644 --- a/src/main/java/jace/hardware/mockingboard/TimedGenerator.java +++ b/src/main/java/jace/hardware/mockingboard/TimedGenerator.java @@ -50,7 +50,7 @@ public class TimedGenerator { } public void setRate(int clock, int sample_rate) { - sampleRate = sample_rate; + sampleRate = sample_rate == 0 ? 44100 : sample_rate; this.clock = clock; cyclesPerSample = clock / sampleRate; }