mirror of https://github.com/badvision/jace.git
286 lines
11 KiB
Java
286 lines
11 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.apple2e;
|
|
|
|
import jace.core.Card;
|
|
import jace.core.Computer;
|
|
import jace.core.PagedMemory;
|
|
import jace.core.RAM;
|
|
import jace.state.Stateful;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
|
|
/**
|
|
* Implementation of a 128k memory space and the MMU found in an Apple //e. The
|
|
* MMU behavior is mimicked by configureActiveMemory.
|
|
*
|
|
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
|
*/
|
|
@Stateful
|
|
abstract public class RAM128k extends RAM {
|
|
@Stateful
|
|
public PagedMemory mainMemory;
|
|
@Stateful
|
|
public PagedMemory languageCard;
|
|
@Stateful
|
|
public PagedMemory languageCard2;
|
|
public PagedMemory cPageRom;
|
|
public PagedMemory rom;
|
|
public PagedMemory blank;
|
|
|
|
public RAM128k() {
|
|
super();
|
|
mainMemory = new PagedMemory(0xc000, PagedMemory.Type.ram);
|
|
rom = new PagedMemory(0x3000, PagedMemory.Type.firmwareMain);
|
|
cPageRom = new PagedMemory(0x1000, PagedMemory.Type.slotRom);
|
|
languageCard = new PagedMemory(0x3000, PagedMemory.Type.languageCard);
|
|
languageCard2 = new PagedMemory(0x1000, PagedMemory.Type.languageCard);
|
|
activeRead = new PagedMemory(0x10000, PagedMemory.Type.ram);
|
|
activeWrite = new PagedMemory(0x10000, PagedMemory.Type.ram);
|
|
blank = new PagedMemory(0x100, PagedMemory.Type.ram);
|
|
|
|
// Format memory with FF FF 00 00 pattern
|
|
for (int i = 0; i < 0x0100; i++) {
|
|
blank.get(0)[i] = (byte) 0x0FF;
|
|
}
|
|
initMemoryPattern(mainMemory);
|
|
}
|
|
|
|
public final void initMemoryPattern(PagedMemory mem) {
|
|
// Format memory with FF FF 00 00 pattern
|
|
for (int i = 0; i < 0x0100; i++) {
|
|
for (int j = 0; j < 0x0c0; j++) {
|
|
byte use = (byte) ((i % 4) > 1 ? 0x0FF : 0x00);
|
|
mem.get(j)[i] = use;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
@Override
|
|
public void configureActiveMemory() {
|
|
log("MMU Switches");
|
|
synchronized (this) {
|
|
// First off, set up read/write for main memory (might get changed later on)
|
|
activeRead.fillBanks(SoftSwitches.RAMRD.getState() ? getAuxMemory() : mainMemory);
|
|
activeWrite.fillBanks(SoftSwitches.RAMWRT.getState() ? getAuxMemory() : mainMemory);
|
|
|
|
// Handle language card softswitches
|
|
activeRead.fillBanks(rom);
|
|
//activeRead.fillBanks(cPageRom);
|
|
for (int i = 0x0c0; i < 0x0d0; i++) {
|
|
activeWrite.set(i, null);
|
|
}
|
|
if (SoftSwitches.LCRAM.getState()) {
|
|
if (!SoftSwitches.AUXZP.getState()) {
|
|
activeRead.fillBanks(languageCard);
|
|
if (!SoftSwitches.LCBANK1.getState()) {
|
|
activeRead.fillBanks(languageCard2);
|
|
}
|
|
} else {
|
|
activeRead.fillBanks(getAuxLanguageCard());
|
|
if (!SoftSwitches.LCBANK1.getState()) {
|
|
activeRead.fillBanks(getAuxLanguageCard2());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SoftSwitches.LCWRITE.getState()) {
|
|
if (!SoftSwitches.AUXZP.getState()) {
|
|
activeWrite.fillBanks(languageCard);
|
|
if (!SoftSwitches.LCBANK1.getState()) {
|
|
activeWrite.fillBanks(languageCard2);
|
|
}
|
|
} else {
|
|
activeWrite.fillBanks(getAuxLanguageCard());
|
|
if (!SoftSwitches.LCBANK1.getState()) {
|
|
activeWrite.fillBanks(getAuxLanguageCard2());
|
|
}
|
|
}
|
|
} else {
|
|
// Make 0xd000 - 0xffff non-writable!
|
|
for (int i = 0x0d0; i < 0x0100; i++) {
|
|
activeWrite.set(i, null);
|
|
}
|
|
}
|
|
|
|
// Handle 80STORE logic for bankswitching video ram
|
|
if (SoftSwitches._80STORE.isOn()) {
|
|
activeRead.setBanks(0x04, 0x04, 0x04,
|
|
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
|
activeWrite.setBanks(0x04, 0x04, 0x04,
|
|
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
|
if (SoftSwitches.HIRES.isOn()) {
|
|
activeRead.setBanks(0x020, 0x020, 0x020,
|
|
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
|
activeWrite.setBanks(0x020, 0x020, 0x020,
|
|
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
|
}
|
|
}
|
|
|
|
// Handle zero-page bankswitching
|
|
if (SoftSwitches.AUXZP.getState()) {
|
|
// Aux pages 0 and 1
|
|
activeRead.setBanks(0, 2, 0, getAuxMemory());
|
|
activeWrite.setBanks(0, 2, 0, getAuxMemory());
|
|
} else {
|
|
// Main pages 0 and 1
|
|
activeRead.setBanks(0, 2, 0, mainMemory);
|
|
activeWrite.setBanks(0, 2, 0, mainMemory);
|
|
}
|
|
|
|
/*
|
|
INTCXROM SLOTC3ROM C1,C2,C4-CF C3
|
|
0 0 slot rom
|
|
0 1 slot slot
|
|
1 - rom rom
|
|
*/
|
|
if (SoftSwitches.CXROM.getState()) {
|
|
// Enable C1-CF to point to rom
|
|
activeRead.setBanks(0, 0x0F, 0x0C1, cPageRom);
|
|
} else {
|
|
// Enable C1-CF to point to slots
|
|
for (int slot = 1; slot <= 7; slot++) {
|
|
Card c = getCard(slot);
|
|
if (c != null) {
|
|
// Enable card slot ROM
|
|
activeRead.setBanks(0, 1, 0x0C0 + slot, c.getCxRom());
|
|
if (getActiveSlot() == slot) {
|
|
activeRead.setBanks(0, 8, 0x0C8, c.getC8Rom());
|
|
}
|
|
} else {
|
|
// Disable card slot ROM (TODO: floating bus)
|
|
activeRead.set(0x0C0 + slot, blank.get(0));
|
|
}
|
|
}
|
|
if (getActiveSlot() == 0) {
|
|
for (int i = 0x0C8; i < 0x0D0; i++) {
|
|
activeRead.set(i, blank.get(0));
|
|
}
|
|
}
|
|
if (SoftSwitches.SLOTC3ROM.isOff()) {
|
|
// Enable C3 to point to internal ROM
|
|
activeRead.setBanks(2, 1, 0x0C3, cPageRom);
|
|
}
|
|
if (SoftSwitches.INTC8ROM.getState()) {
|
|
// Enable C8-CF to point to internal ROM
|
|
activeRead.setBanks(7, 8, 0x0C8, cPageRom);
|
|
}
|
|
}
|
|
}
|
|
// All ROM reads not intecepted will return 0xFF! (TODO: floating bus)
|
|
activeRead.set(0x0c0, blank.get(0));
|
|
}
|
|
|
|
public void log(String message) {
|
|
if (Computer.getComputer().cpu != null && Computer.getComputer().cpu.isLogEnabled()) {
|
|
String stack = "";
|
|
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
|
|
stack += e.getClassName() + "." + e.getMethodName() + "(" + e.getLineNumber() + ");";
|
|
}
|
|
Computer.getComputer().cpu.log(stack);
|
|
Computer.getComputer().cpu.log(message + ";" + SoftSwitches.RAMRD + ";" + SoftSwitches.RAMWRT + ";" + SoftSwitches.AUXZP + ";" + SoftSwitches._80STORE + ";" + SoftSwitches.HIRES + ";" + SoftSwitches.PAGE2 + ";" + SoftSwitches.LCBANK1 + ";" + SoftSwitches.LCRAM + ";" + SoftSwitches.LCWRITE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param path
|
|
* @throws java.io.IOException
|
|
*/
|
|
@Override
|
|
protected void loadRom(String path) throws IOException {
|
|
// Remap writable ram to reflect rom file structure
|
|
byte[] ignore = new byte[256];
|
|
activeWrite.set(0, ignore); // Ignore first bank of data
|
|
for (int i = 1; i < 17; i++) {
|
|
activeWrite.set(i, ignore);
|
|
}
|
|
activeWrite.setBanks(0, cPageRom.getMemory().length, 0x011, cPageRom);
|
|
activeWrite.setBanks(0, rom.getMemory().length, 0x020, rom);
|
|
//----------------------
|
|
InputStream inputRom = getClass().getClassLoader().getResourceAsStream(path);
|
|
int read = 0;
|
|
int addr = 0;
|
|
byte[] in = new byte[1024];
|
|
while (addr < 0x00FFFF && (read = inputRom.read(in)) > 0) {
|
|
for (int i = 0; i < read; i++) {
|
|
write(addr++, in[i], false, false);
|
|
}
|
|
}
|
|
// System.out.println("Finished reading rom with " + inputRom.available() + " bytes left unread!");
|
|
//dump();
|
|
configureActiveMemory();
|
|
}
|
|
|
|
/**
|
|
* @return the mainMemory
|
|
*/
|
|
public PagedMemory getMainMemory() {
|
|
return mainMemory;
|
|
}
|
|
|
|
abstract public PagedMemory getAuxVideoMemory();
|
|
abstract public PagedMemory getAuxMemory();
|
|
abstract public PagedMemory getAuxLanguageCard();
|
|
abstract public PagedMemory getAuxLanguageCard2();
|
|
|
|
/**
|
|
* @return the languageCard
|
|
*/
|
|
public PagedMemory getLanguageCard() {
|
|
return languageCard;
|
|
}
|
|
|
|
/**
|
|
* @return the languageCard2
|
|
*/
|
|
public PagedMemory getLanguageCard2() {
|
|
return languageCard2;
|
|
}
|
|
|
|
/**
|
|
* @return the cPageRom
|
|
*/
|
|
public PagedMemory getcPageRom() {
|
|
return cPageRom;
|
|
}
|
|
|
|
/**
|
|
* @return the rom
|
|
*/
|
|
public PagedMemory getRom() {
|
|
return rom;
|
|
}
|
|
|
|
void copyFrom(RAM128k currentMemory) {
|
|
// This is really quick and dirty but should be sufficient to avoid most crashes...
|
|
blank = currentMemory.blank;
|
|
cPageRom = currentMemory.cPageRom;
|
|
rom = currentMemory.rom;
|
|
listeners = currentMemory.listeners;
|
|
mainMemory = currentMemory.mainMemory;
|
|
languageCard = currentMemory.languageCard;
|
|
languageCard2 = currentMemory.languageCard2;
|
|
cards = currentMemory.cards;
|
|
activeSlot = currentMemory.activeSlot;
|
|
}
|
|
} |