twoapple-reboot/src/iomem.d

312 lines
7.8 KiB
D

/+
+ iomem.d
+
+ Copyright: 2007 Gerald Stocker
+
+ This file is part of twoapple-reboot.
+
+ twoapple-reboot is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ twoapple-reboot 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with twoapple-reboot; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+/
import memory;
import timer;
import system.peripheral;
import peripheral.base;
import device.base;
import std.conv;
class IOMem
{
// NOTE: It is implied that a peripheral slot with
// an I/O STROBE ROM' always responds to I/O STROBE'.
class IOSelectMem : Rom
{
int slotNum;
this(int slotNum_, ubyte[] rom)
{
super(
cast(ushort)(0xC000 + (slotNum_ * 0x100)),
cast(uint)0x0100, rom);
slotNum = slotNum_;
}
ubyte read(ushort addr)
{
activateStrobeMem(slotNum);
return data[addr - baseAddress];
}
void write(ushort addr, ubyte val)
{
activateStrobeMem(slotNum);
}
}
// NOTE: It is implied that all peripherals obey the
// $CFFF I/O STROBE' protocol.
class IOStrobeMem : Rom
{
int slotNum; // XXX not just num, but a reference to the
// rom object for that slot (for debug
// display).
this(int slotNum_, ubyte[] rom)
{
super(0xC800, 0x0800, rom);
slotNum = slotNum_;
}
ubyte read(ushort addr)
{
if (addr == 0xCFFF) deactivateStrobeMem();
return data[addr - 0xC800];
}
void write(ushort addr)
{
if (addr == 0xCFFF) deactivateStrobeMem();
}
}
int strobeSlotNum;
IOSelectMem[8] selectMem;
IOStrobeMem[8] strobeMem;
AddressDecoder decoder;
void initialize(AddressDecoder decoder_, SoftSwitchPage switches,
Timer timer, Peripherals peripherals)
{
decoder = decoder_;
Peripheral card;
for (int slot = 0; slot <=7; ++slot)
{
card = peripherals.cards[slot];
if (slot > 0)
{
if ((card is null) || (card.ioSelectROM is null))
{
installEmptySelect(slot);
}
else
{
selectMem[slot] = new IOSelectMem(slot, card.ioSelectROM);
selectMem[slot].debugName =
"Slot " ~ to!string(slot) ~ " ROM";
decoder.install(selectMem[slot]);
if (card.ioStrobeROM !is null)
{
strobeMem[slot] = new IOStrobeMem(slot,
card.ioStrobeROM);
strobeMem[slot].debugName = selectMem[slot].debugName;
}
}
}
if (card !is null) card.plugIn(slot, switches, timer);
}
}
void reboot()
{
deactivateStrobeMem();
}
void installEmptySelect(int slotNum)
{
// NOTE: using these read/write delegates implies that
// a slot without an I/O SELECT' ROM _cannot_ have an
// I/O STROBE' ROM.
decoder.installNull(0xC000 + (slotNum * 0x100), 0x100);
}
void activateStrobeMem(int slotNum)
{
// Do nothing if the I/O STROBE' memory for
// the given slotNum is already active.
if (strobeSlotNum == slotNum) return;
if (strobeMem[slotNum] is null)
{
deactivateStrobeMem();
}
else
{
decoder.install(strobeMem[slotNum]);
strobeSlotNum = slotNum;
}
}
void deactivateStrobeMem()
{
decoder.installNull(0xC800, 0x0800);
strobeSlotNum = 0;
}
}
class IOMem_IIe : IOMem
{
class IntC3ROM : Rom
{
this(ubyte[] rom)
{
super(0xC300, 0x0100, rom);
}
ubyte read(ushort addr)
{
activateIntStrobeMem();
return data[addr - 0xC300];
}
void write(ushort addr, ubyte val)
{
activateIntStrobeMem();
}
}
bool intC8ROM, slotC3ROM, intCXROM;
IOStrobeMem intStrobeMem;
IntC3ROM intC3ROM;
Rom c100c2ff, c400c7ff;
ubyte delegate() kbdLatch;
void reboot()
{
super.reboot();
resetIntCXROM();
resetSlotC3ROM();
}
void reset()
{
deactivateStrobeMem();
resetIntCXROM();
resetSlotC3ROM();
}
void setSlotC3ROM()
{
if (slotC3ROM) return;
slotC3ROM = true;
// $C3XX cannot be configured for slot response if
// INTCXROM is set.
if (intCXROM) return;
if (selectMem[3] !is null)
{
decoder.install(selectMem[3]);
}
else
{
installEmptySelect(3);
}
}
void resetSlotC3ROM()
{
slotC3ROM = false;
decoder.install(intC3ROM);
}
void setIntCXROM()
{
if (intCXROM) return;
intCXROM = true;
decoder.install(c100c2ff);
decoder.install(intC3ROM);
decoder.install(c400c7ff);
decoder.install(intStrobeMem);
}
void resetIntCXROM()
{
intCXROM = false;
for (int s = 1; s <= 7; ++s)
{
if (selectMem[s] !is null)
{
if ((s != 3) || (slotC3ROM)) decoder.install(selectMem[s]);
}
else
{
if ((s != 3) || (slotC3ROM)) installEmptySelect(s);
}
}
if (!intC8ROM) deactivateStrobeMem();
}
void activateIntStrobeMem()
{
if (intC8ROM) return;
decoder.install(intStrobeMem);
strobeSlotNum = -1; // XXX hack (-1 represents internal?)
intC8ROM = true;
}
void activateStrobeMem(int slotNum)
{
if (intC8ROM) return;
super.activateStrobeMem(slotNum);
}
void deactivateStrobeMem()
{
intC8ROM = false;
super.deactivateStrobeMem();
}
ubyte readIntCXROM()
{
return kbdLatch() | (intCXROM ? 0x80 : 0x00);
}
ubyte readSlotC3ROM()
{
return kbdLatch() | (slotC3ROM ? 0x80 : 0x00);
}
mixin(InitSwitches("", [
mixin(MakeSwitch([0xC006], "W", "resetIntCXROM")),
mixin(MakeSwitch([0xC007], "W", "setIntCXROM")),
mixin(MakeSwitch([0xC00A], "W", "resetSlotC3ROM")),
mixin(MakeSwitch([0xC00B], "W", "setSlotC3ROM")),
mixin(MakeSwitch([0xC015], "R", "readIntCXROM")),
mixin(MakeSwitch([0xC017], "R", "readSlotC3ROM"))
]));
void setRom(ubyte[] romDump)
{
int c100 = cast(int)(romDump.length - 16128);
c100c2ff = new Rom(0xC100, 0x0200, romDump[c100 .. (c100 + 0x0200)]);
intC3ROM = new IntC3ROM(romDump[(c100 + 0x0200) .. (c100 + 0x0300)]);
c400c7ff = new Rom(0xC400, 0x0400,
romDump[(c100 + 0x0300) .. (c100 + 0x0700)]);
// XXX not slot, but ref to intc3rom
intStrobeMem = new IOStrobeMem(3,
romDump[(c100 + 0x0700) .. (c100 + 0x0F00)]);
c100c2ff.debugName = intC3ROM.debugName = c400c7ff.debugName =
intStrobeMem.debugName = "Internal ROM";
}
}