forked from Apple-2-Tools/jace
234 lines
7.4 KiB
Java
234 lines
7.4 KiB
Java
/*
|
|
* Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301 USA
|
|
*/
|
|
package jace.hardware;
|
|
|
|
import jace.Emulator;
|
|
import jace.config.ConfigurableField;
|
|
import jace.config.Name;
|
|
import jace.core.Card;
|
|
import jace.core.Motherboard;
|
|
import jace.core.RAMEvent;
|
|
import jace.core.RAMEvent.TYPE;
|
|
import jace.state.Stateful;
|
|
import jace.core.Utility;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.Arrays;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import javax.swing.ImageIcon;
|
|
|
|
/**
|
|
* This card strives to be a clone of the Applied Engineering RamFactor card
|
|
* http://www.downloads.reactivemicro.com/Public/Apple%20II%20Items/Hardware/RAMFactor/RAMFactor%20v1.5.pdf
|
|
*
|
|
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
|
*/
|
|
@Stateful
|
|
@Name("RamFactor")
|
|
public class CardRamFactor extends Card {
|
|
int ADDR1 = 0;
|
|
int ADDR2 = 1;
|
|
int ADDR3 = 2;
|
|
int DATA = 3;
|
|
int BANK_SELECT = 0x0f;
|
|
@ConfigurableField(category = "memory", name = "Ram size", description = "Size of card ram in KB", shortName = "size", defaultValue = "8192")
|
|
public int RAM_SIZE = 8192;
|
|
int actualSize = RAM_SIZE * 1024;
|
|
// Important: pointer of current ram read/write for slinky access
|
|
@Stateful
|
|
int addressPointer = 0x0ffffff;
|
|
@Stateful
|
|
int firmwareBank = 0;
|
|
@ConfigurableField(category = "performance", name = "Speed Boost", description = "Boost emulator speed when RAM in use", shortName = "boostSpeed", defaultValue = "false")
|
|
public boolean speedBoost = false;
|
|
|
|
@Override
|
|
public String getDeviceName() {
|
|
return "RamFactor";
|
|
}
|
|
ImageIcon indicator;
|
|
public CardRamFactor() {
|
|
indicator=Utility.loadIcon("ram.png");
|
|
try {
|
|
loadRom("jace/data/RAMFactor14.rom");
|
|
} catch (IOException ex) {
|
|
Logger.getLogger(CardRamFactor.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
allocateMemory(actualSize);
|
|
updateFirmwareMemory();
|
|
}
|
|
|
|
@Override
|
|
public void reset() {
|
|
firmwareBank = 0;
|
|
updateFirmwareMemory();
|
|
}
|
|
|
|
@Override
|
|
public void reconfigure() {
|
|
actualSize = RAM_SIZE * 1024;
|
|
allocateMemory(actualSize);
|
|
updateFirmwareMemory();
|
|
}
|
|
|
|
@Override
|
|
protected void handleIOAccess(int register, TYPE type, int value, RAMEvent e) {
|
|
Emulator.getFrame().addIndicator(this, indicator);
|
|
value &= 0x0ff;
|
|
switch (register) {
|
|
case 0:
|
|
case 4:
|
|
// Lo-byte of pointer
|
|
if (type.isRead()) {
|
|
e.setNewValue(addressPointer & 0x0ff);
|
|
} else {
|
|
addressPointer = (addressPointer & 0x0ffff00) | value;
|
|
if (RAM_SIZE <= 1024) {
|
|
addressPointer |= 0x0f00000;
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
case 5:
|
|
// Mid-byte of pointer
|
|
if (type.isRead()) {
|
|
e.setNewValue((addressPointer >> 8) & 0x0ff);
|
|
} else {
|
|
addressPointer = (addressPointer & 0x0ff00ff) | (value << 8);
|
|
if (RAM_SIZE <= 1024) {
|
|
addressPointer |= 0x0f00000;
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
case 6:
|
|
// Hi-byte of pointer
|
|
if (type.isRead()) {
|
|
if (RAM_SIZE <= 1024) {
|
|
e.setNewValue(0x0f0 | ((addressPointer >> 16) & 0x0ff));
|
|
} else {
|
|
e.setNewValue((addressPointer >> 16) & 0x0ff);
|
|
}
|
|
} else {
|
|
addressPointer = (addressPointer & 0x00ffff) | (value << 16);
|
|
if (RAM_SIZE <= 1024) {
|
|
addressPointer |= 0x0f00000;
|
|
}
|
|
}
|
|
break;
|
|
case 3:
|
|
case 7:
|
|
if (type.isRead()) {
|
|
e.setNewValue(readMemory(addressPointer));
|
|
} else {
|
|
writeMemory(addressPointer, (byte) value);
|
|
}
|
|
addressPointer++;
|
|
// Keep the pointer in range
|
|
addressPointer &= 0x0ffffff;
|
|
break;
|
|
case 15: {
|
|
// Firmware bank select
|
|
if (type == TYPE.WRITE) {
|
|
firmwareBank = value;
|
|
updateFirmwareMemory();
|
|
}
|
|
}
|
|
default:
|
|
if (type.isRead()) {
|
|
e.setNewValue(0x0ff);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void handleFirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
|
|
if (speedBoost) {
|
|
Motherboard.requestSpeed(this);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
protected void handleC8FirmwareAccess(int register, TYPE type, int value, RAMEvent e) {
|
|
if (speedBoost) {
|
|
Motherboard.requestSpeed(this);
|
|
}
|
|
}
|
|
|
|
@Stateful
|
|
public byte[] cardRam;
|
|
int ADDRESS_MASK = 0x07FFFFF;
|
|
private byte readMemory(int i) {
|
|
while (i >= cardRam.length) {
|
|
i -= cardRam.length;
|
|
}
|
|
return cardRam[i];
|
|
}
|
|
|
|
private void writeMemory(int i, byte newValue) {
|
|
while (i >= cardRam.length) {
|
|
i -= cardRam.length;
|
|
}
|
|
cardRam[i] = newValue;
|
|
}
|
|
|
|
private void allocateMemory(int size) {
|
|
if (cardRam != null && cardRam.length == size) return;
|
|
cardRam = new byte[size];
|
|
Arrays.fill(cardRam, (byte) 0);
|
|
}
|
|
|
|
@Override
|
|
public void setSlot(int slot) {
|
|
super.setSlot(slot);
|
|
indicator.setDescription("Slot "+getSlot());
|
|
// Rom has different images for each slot
|
|
updateFirmwareMemory();
|
|
}
|
|
|
|
final int cxRomLength = 0x02000;
|
|
byte[] romData = new byte[cxRomLength];
|
|
public void loadRom(String path) throws IOException {
|
|
InputStream romFile = CardRamFactor.class.getClassLoader().getResourceAsStream(path);
|
|
try {
|
|
if (romFile.read(romData) != cxRomLength) {
|
|
throw new IOException("Bad RamFactor rom size");
|
|
}
|
|
updateFirmwareMemory();
|
|
} catch (IOException ex) {
|
|
throw ex;
|
|
}
|
|
}
|
|
|
|
private void updateFirmwareMemory() {
|
|
int romOffset = 0;
|
|
if ((firmwareBank&1) == 1) {
|
|
romOffset = 0x01000;
|
|
}
|
|
getCxRom().loadData(romData, romOffset + getSlot()*0x0100, 256);
|
|
getC8Rom().loadData(romData, romOffset + 0x0800, 0x0800);
|
|
}
|
|
} |