Simulator is just about ready for real-world testing now. Added a simulated
MOS6551 ACIA at address $C000 which does buffered input and output via the console. Updated the README with a bit more documentation, and bumped the version number to 0.1 because I'm impatient.
This commit is contained in:
1 parent
596d05e398
commit
00ab8cd9ff
10 files changed
+749
-124
No files matched your search
@@ -0,0 +1,124 @@
|
||||
package com.loomcom.symon.devices;
|
||||
|
||||
import com.loomcom.symon.exceptions.*;
|
||||
import com.loomcom.symon.util.*;
|
||||
|
||||
/**
|
||||
* This is a simulation of the MOS 6551 ACIA, with limited
|
||||
* functionality. Interrupts are not supported.
|
||||
*
|
||||
* Unlike a 16550 UART, the 6551 ACIA has only one-byte transmit and
|
||||
* receive buffers. It is the programmer's responsibility to check the
|
||||
* status (full or empty) for transmit and receive buffers before
|
||||
* writing / reading. However, in the simulation we maintain two
|
||||
* small buffers of 256 characters, since we only wake up to check for
|
||||
* keyboard input and do output every 500 instructions.
|
||||
*/
|
||||
public class Acia extends Device {
|
||||
|
||||
public static final int ACIA_SIZE = 4;
|
||||
public static final int BUF_LEN = 256;
|
||||
|
||||
static final int DATA_REG = 0;
|
||||
static final int STAT_REG = 1;
|
||||
static final int CMND_REG = 2;
|
||||
static final int CTRL_REG = 3;
|
||||
|
||||
/** Register addresses */
|
||||
private int baseAddress;
|
||||
|
||||
/** Registers. These are ignored in the current implementation. */
|
||||
private int commandRegister;
|
||||
private int controlRegister;
|
||||
|
||||
/** Read/Write buffers */
|
||||
private FifoRingBuffer rxBuffer = new FifoRingBuffer(BUF_LEN);
|
||||
private FifoRingBuffer txBuffer = new FifoRingBuffer(BUF_LEN);
|
||||
|
||||
public Acia(int address) throws MemoryRangeException {
|
||||
super(address, ACIA_SIZE, "ACIA");
|
||||
this.baseAddress = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(int address) throws MemoryAccessException {
|
||||
switch (address) {
|
||||
case DATA_REG:
|
||||
try {
|
||||
return rxRead();
|
||||
} catch (FifoUnderrunException ex) {
|
||||
throw new MemoryAccessException("Buffer underrun");
|
||||
}
|
||||
case STAT_REG:
|
||||
return ((rxBuffer.isEmpty() ? 0x00 : 0x08) |
|
||||
(txBuffer.isEmpty() ? 0x10 : 0x00));
|
||||
case CMND_REG:
|
||||
return commandRegister;
|
||||
case CTRL_REG:
|
||||
return controlRegister;
|
||||
default:
|
||||
throw new MemoryAccessException("No register.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int address, int data) throws MemoryAccessException {
|
||||
switch (address) {
|
||||
case 0:
|
||||
txWrite(data);
|
||||
break;
|
||||
case 1:
|
||||
reset();
|
||||
break;
|
||||
case 2:
|
||||
commandRegister = data;
|
||||
break;
|
||||
case 3:
|
||||
controlRegister = data;
|
||||
break;
|
||||
default:
|
||||
throw new MemoryAccessException("No register.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ACIA@" + String.format("%04X", baseAddress);
|
||||
}
|
||||
|
||||
public int rxRead() throws FifoUnderrunException {
|
||||
return rxBuffer.pop();
|
||||
}
|
||||
|
||||
public void rxWrite(int data) {
|
||||
rxBuffer.push(data);
|
||||
}
|
||||
|
||||
public int txRead() throws FifoUnderrunException {
|
||||
return txBuffer.pop();
|
||||
}
|
||||
|
||||
public void txWrite(int data) {
|
||||
txBuffer.push(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there is character data in the TX register.
|
||||
*/
|
||||
public boolean hasTxChar() {
|
||||
return !txBuffer.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there is character data in the RX register.
|
||||
*/
|
||||
public boolean hasRxChar() {
|
||||
return !rxBuffer.isEmpty();
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
txBuffer.reset();
|
||||
rxBuffer.reset();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user