1
0
mirror of https://github.com/sethm/symon.git synced 2024-06-03 07:29:30 +00:00

Merge pull request #10 from maikmerten/master

Multicomp: SD card controller emulation
This commit is contained in:
Seth Morabito 2014-08-15 13:51:26 -07:00
commit af12039686
4 changed files with 232 additions and 6 deletions

View File

@ -58,6 +58,7 @@ memory.
- `$0000`--`$DFFF`: 56KB RAM
- `$E000`--`$FFFF`: 8KB ROM
- `$FFD0`--`$FFD1`: Motorola 6850 ACIA
- `$FFD8`--`$FFDF`: Controller for SD cards
### 3.1.3 Simple Memory Map

View File

@ -0,0 +1,212 @@
/*
* Copyright (c) 2008-2013 Seth J. Morabito <web@loomcom.com>
* Maik Merten <maikmerten@googlemail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.loomcom.symon.devices;
import com.loomcom.symon.exceptions.MemoryAccessException;
import com.loomcom.symon.exceptions.MemoryRangeException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Emulation for the SD-card controller of the MULTICOMP system.
* Neiter comlete nor correct.
*
*/
public class SdController extends Device {
private enum Status {
IDLE,
READ,
WRITE
}
public static final int CONTROLLER_SIZE = 8;
private final int SECTOR_SIZE = 512;
private final static Logger logger = Logger.getLogger(SdController.class.getName());
private File sdImageFile;
private int lba0,lba1,lba2;
private int command;
private int position;
private Status status = Status.IDLE;
private final byte[] readBuffer = new byte[SECTOR_SIZE];
private final byte[] writeBuffer = new byte[SECTOR_SIZE];
private int readPosition = 0;
private int writePosition = 0;
public SdController(int address) throws MemoryRangeException {
super(address, address + CONTROLLER_SIZE - 1, "SDCONTROLLER");
sdImageFile = new File("sd.img");
if(!sdImageFile.exists()) {
sdImageFile = null;
logger.log(Level.INFO, "Could not find SD card image 'sd.img'");
}
}
@Override
public void write(int address, int data) throws MemoryAccessException {
switch(address) {
case 0 :
writeData(data);
return;
case 1 :
writeCommand(data);
return;
case 2 :
this.lba0 = data;
return;
case 3 :
this.lba1 = data;
return;
case 4 :
this.lba2 = data;
}
}
@Override
public int read(int address) throws MemoryAccessException {
switch(address) {
case 0:
return readData();
case 1:
return readStatus();
default:
return 0;
}
}
private void computePosition() {
this.position = lba0 + (lba1 << 8) + (lba2 << 16);
// each sector is 512 bytes, so multiply accordingly
this.position <<= 9;
}
private void prepareRead() {
this.status = Status.READ;
this.readPosition = 0;
computePosition();
if(sdImageFile != null) {
try {
FileInputStream fis = new FileInputStream(sdImageFile);
fis.skip(this.position);
int read = fis.read(readBuffer);
if(read < SECTOR_SIZE) {
logger.log(Level.WARNING, "not enough data to fill read buffer from SD image file");
}
fis.close();
} catch (IOException ex) {
logger.log(Level.WARNING, "could not fill read buffer from SD image file", ex);
}
}
}
private void prepareWrite() {
this.status = Status.WRITE;
this.writePosition = 0;
computePosition();
}
private int readData() {
if(status != Status.READ) {
return 0;
}
int data = readBuffer[readPosition++];
if(readPosition >= SECTOR_SIZE) {
this.status = Status.IDLE;
}
return data;
}
private void writeData(int data) {
if(status != Status.WRITE) {
return;
}
writeBuffer[writePosition++] = (byte) data;
if(writePosition >= SECTOR_SIZE) {
if(sdImageFile != null) {
try {
RandomAccessFile raf = new RandomAccessFile(sdImageFile, "rw");
raf.skipBytes(this.position);
raf.write(writeBuffer, 0, writeBuffer.length);
raf.close();
} catch (IOException ex) {
logger.log(Level.WARNING, "could not write data back to SD image file!", ex);
}
}
this.status = Status.IDLE;
}
}
private int readStatus() {
switch(this.status) {
case IDLE:
return 128;
case READ:
return 224;
case WRITE:
return 160;
default:
return 0;
}
}
private void writeCommand(int data) {
this.command = data;
switch(this.command) {
case 0 :
prepareRead();
return;
case 1 :
prepareWrite();
return;
default:
this.status = Status.IDLE;
}
}
@Override
public String toString() {
return getName() + "@" + String.format("%04X", this.getMemoryRange().startAddress);
}
}

View File

@ -31,6 +31,7 @@ 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.exceptions.MemoryRangeException;
import java.io.File;
import java.util.logging.Logger;
@ -51,6 +52,8 @@ public class MulticompMachine implements Machine {
// ACIA at $FFD0-$FFD1
private static final int ACIA_BASE = 0xFFD0;
// SD controller at $FFD8-$FFDF
private static final int SD_BASE = 0xFFD8;
// 8KB ROM at $E000-$FFFF
private static final int ROM_BASE = 0xE000;
@ -62,6 +65,7 @@ public class MulticompMachine implements Machine {
private final Cpu cpu;
private final Acia acia;
private final Memory ram;
private final SdController sdController;
private Memory rom;
@ -70,10 +74,13 @@ public class MulticompMachine implements Machine {
this.cpu = new Cpu();
this.ram = new Memory(MEMORY_BASE, MEMORY_BASE + MEMORY_SIZE - 1, false);
this.acia = new Acia6850(ACIA_BASE);
this.acia.setBaudRate(0);
this.sdController = new SdController(SD_BASE);
bus.addCpu(cpu);
bus.addDevice(ram);
bus.addDevice(acia, 1);
bus.addDevice(sdController, 1);
// TODO: Make this configurable, of course.
File romImage = new File("rom.bin");

View File

@ -35,8 +35,8 @@ import java.awt.*;
*/
public class TraceLog extends JFrame {
private FifoRingBuffer<Cpu.CpuState> traceLog;
private JTextArea traceLogTextArea;
private final FifoRingBuffer<Cpu.CpuState> traceLog;
private final JTextArea traceLogTextArea;
private static final Dimension MIN_SIZE = new Dimension(320, 200);
private static final Dimension PREFERRED_SIZE = new Dimension(640, 480);
@ -67,11 +67,15 @@ public class TraceLog extends JFrame {
* call.
*/
public void refresh() {
synchronized (this) {
StringBuilder logString = new StringBuilder();
StringBuilder logString = new StringBuilder();
synchronized(traceLog) {
for (Cpu.CpuState state : traceLog) {
logString.append(state.toTraceEvent());
}
}
synchronized(traceLogTextArea) {
traceLogTextArea.setText(logString.toString());
}
}
@ -80,8 +84,10 @@ public class TraceLog extends JFrame {
* Reset the log area.
*/
public void reset() {
synchronized (this) {
synchronized(traceLog) {
traceLog.reset();
}
synchronized(traceLogTextArea) {
traceLogTextArea.setText("");
traceLogTextArea.setEnabled(true);
}
@ -93,7 +99,7 @@ public class TraceLog extends JFrame {
* @param state The CPU State to append.
*/
public void append(Cpu.CpuState state) {
synchronized(this) {
synchronized(traceLog) {
traceLog.push(new Cpu.CpuState(state));
}
}