twoapple-reboot/src/ioummu.d

407 lines
9.8 KiB
D

/+
+ ioummu.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 device.base;
import system.io; // XXX XXX too many dependencies?
import video.base;
import peripheral.langcard;
import iomem;
struct MemMap
{
Memory X0000_01FF;
Memory X0200_03FF;
Memory X0400_07FF;
Memory X0800_1FFF;
Memory X2000_3FFF;
Memory X4000_BFFF;
void reboot()
{
X0000_01FF.reboot();
X0200_03FF.reboot();
X0400_07FF.reboot();
X0800_1FFF.reboot();
X2000_3FFF.reboot();
X4000_BFFF.reboot();
}
}
class IOU
{
IO io_;
SignalBase signal;
bool dHGR;
this(IO ioDevices, SignalBase sig)
{
io_ = ioDevices;
signal = sig;
}
void resetAn0()
{
io_.annun.ann_0_Off();
}
void resetAn1()
{
io_.annun.ann_1_Off();
}
void resetAn2()
{
io_.annun.ann_2_Off();
}
void resetAn3()
{
io_.annun.ann_3_Off();
dHGR = true;
signal.dHGRChange(true);
}
void setAn0()
{
io_.annun.ann_0_On();
}
void setAn1()
{
io_.annun.ann_1_On();
}
void setAn2()
{
io_.annun.ann_2_On();
}
void setAn3()
{
io_.annun.ann_3_On();
dHGR = false;
signal.dHGRChange(false);
}
ubyte readDHGR()
{
io_.paddles.trigger();
return (dHGR ? 0x80 : 0x00);
}
void triggerTimers()
{
io_.paddles.trigger();
}
mixin(InitSwitches("", [
mixin(MakeSwitch([0xC058], "R0W", "resetAn0")),
mixin(MakeSwitch([0xC059], "R0W", "setAn0")),
mixin(MakeSwitch([0xC05A], "R0W", "resetAn1")),
mixin(MakeSwitch([0xC05B], "R0W", "setAn1")),
mixin(MakeSwitch([0xC05C], "R0W", "resetAn2")),
mixin(MakeSwitch([0xC05D], "R0W", "setAn2")),
mixin(MakeSwitch([0xC05E], "R0W", "resetAn3")),
mixin(MakeSwitch([0xC05F], "R0W", "setAn3")),
// XXX next two only for enhanced:
mixin(MakeSwitch([0xC07F], "R7", "readDHGR")),
mixin(MakeSwitch([0xC07F], "W", "triggerTimers"))
]));
}
class MMU
{
LanguageCard_IIe himemManager;
AddressDecoder decoder;
AuxiliaryCard auxCard;
IOMem_IIe ioMem;
ScannerBase scanner;
ubyte delegate() kbdLatch;
MemMap[2] mem;
this()
{
himemManager = new LanguageCard_IIe();
}
void reboot()
{
himemManager.reboot();
mem[0].reboot();
}
void reset()
{
himemManager.reset();
ioMem.reset();
}
void init(SoftSwitchPage switches, AuxiliaryCard auxCard_,
AddressDecoder addrDecode, DataMem mainRam, DataMem mainRom)
{
auxCard = auxCard_;
decoder = addrDecode;
himemManager.auxslot = auxCard.himem;
himemManager.initSwitches(switches);
himemManager.init(decoder, &mainRom.read,
&mainRom.write);
initMem(mainRam);
initSwitches(switches);
ioMem.initSwitches(switches);
}
void initMem(DataMem mainRam)
{
mem[0].X0000_01FF = new SliceMem(0x0000, 0x0200, mainRam);
mem[0].X0200_03FF = new SliceMem(0x0200, 0x0200, mainRam);
mem[0].X0400_07FF = new SliceMem(0x0400, 0x0400, mainRam);
mem[0].X0800_1FFF = new SliceMem(0x0800, 0x1800, mainRam);
mem[0].X2000_3FFF = new SliceMem(0x2000, 0x2000, mainRam);
mem[0].X4000_BFFF = new SliceMem(0x4000, 0x8000, mainRam);
mem[1] = auxCard.mem;
}
void initIO(ScannerBase scn, ubyte delegate() peekLatch)
{
kbdLatch = peekLatch;
scanner = scn;
ioMem.kbdLatch = kbdLatch;
himemManager.kbdLatch = kbdLatch;
}
bool switchPage2, switchHires, switch80Store;
bool ramRd, ramWrt, altZP;
void mapVidMem(bool rd, bool wrt)
{
decoder.installRead(mem[cast(int)rd].X0400_07FF);
decoder.installWrite(mem[cast(int)wrt].X0400_07FF);
if (switchHires)
{
mapHiresVidMem(rd, wrt);
}
}
void mapHiresVidMem(bool rd, bool wrt)
{
decoder.installRead(mem[cast(int)rd].X2000_3FFF);
decoder.installWrite(mem[cast(int)wrt].X2000_3FFF);
}
void resetRamRd()
{
ramRd = false;
changeRamSwitch(ramRd, true, false);
}
void setRamRd()
{
ramRd = true;
changeRamSwitch(ramRd, true, false);
}
void resetRamWrt()
{
ramWrt = false;
changeRamSwitch(ramWrt, false, true);
}
void setRamWrt()
{
ramWrt = true;
changeRamSwitch(ramWrt, false, true);
}
void changeRamSwitch(bool sw, bool rd, bool wrt)
{
int bank = cast(int)sw;
decoder.install(mem[bank].X0200_03FF, rd, wrt);
if (!switch80Store)
decoder.install(mem[bank].X0400_07FF, rd, wrt);
decoder.install(mem[bank].X0800_1FFF, rd, wrt);
if ((!switch80Store) || (!switchHires))
decoder.install(mem[bank].X2000_3FFF, rd, wrt);
decoder.install(mem[bank].X4000_BFFF, rd, wrt);
}
void resetAltZP()
{
altZP = false;
himemManager.enableAuxSlot(false);
decoder.install(mem[0].X0000_01FF);
}
void setAltZP()
{
altZP = true;
himemManager.enableAuxSlot(true);
decoder.install(mem[1].X0000_01FF);
}
void reset80Store()
{
if (switchPage2)
scanner.page2SwitchOn();
else
scanner.page2SwitchOff();
switch80Store = false;
mapVidMem(ramRd, ramWrt);
}
void set80Store()
{
scanner.page2SwitchOff();
switch80Store = true;
mapVidMem(switchPage2, switchPage2);
}
void resetPage2()
{
if (!switch80Store) scanner.page2SwitchOff();
switchPage2 = false;
if (switch80Store) mapVidMem(switchPage2, switchPage2);
}
void setPage2()
{
if (!switch80Store) scanner.page2SwitchOn();
switchPage2 = true;
if (switch80Store) mapVidMem(switchPage2, switchPage2);
}
void resetHires()
{
scanner.hiresSwitchOff();
switchHires = false;
if (switch80Store) mapHiresVidMem(ramRd, ramWrt);
}
void setHires()
{
scanner.hiresSwitchOn();
switchHires = true;
if (switch80Store) mapHiresVidMem(switchPage2, switchPage2);
}
ubyte readKbdSwitch(bool sw)
{
return kbdLatch() | (sw ? 0x80 : 0x00);
}
ubyte readRamRd()
{
return readKbdSwitch(ramRd);
}
ubyte readRamWrt()
{
return readKbdSwitch(ramWrt);
}
ubyte readAltZP()
{
return readKbdSwitch(altZP);
}
ubyte read80Store()
{
return readKbdSwitch(switch80Store);
}
ubyte readPage2()
{
return readKbdSwitch(switchPage2);
}
ubyte readHires()
{
return readKbdSwitch(switchHires);
}
mixin(InitSwitches("", [
mixin(MakeSwitch([0xC000], "W", "reset80Store")),
mixin(MakeSwitch([0xC001], "W", "set80Store")),
mixin(MakeSwitch([0xC002], "W", "resetRamRd")),
mixin(MakeSwitch([0xC003], "W", "setRamRd")),
mixin(MakeSwitch([0xC004], "W", "resetRamWrt")),
mixin(MakeSwitch([0xC005], "W", "setRamWrt")),
mixin(MakeSwitch([0xC008], "W", "resetAltZP")),
mixin(MakeSwitch([0xC009], "W", "setAltZP")),
mixin(MakeSwitch([0xC013], "R", "readRamRd")),
mixin(MakeSwitch([0xC014], "R", "readRamWrt")),
mixin(MakeSwitch([0xC016], "R", "readAltZP")),
mixin(MakeSwitch([0xC018], "R", "read80Store")),
mixin(MakeSwitch([0xC01C], "R", "readPage2")),
mixin(MakeSwitch([0xC01D], "R", "readHires")),
mixin(MakeSwitch([0xC054], "R0W", "resetPage2")),
mixin(MakeSwitch([0xC055], "R0W", "setPage2")),
mixin(MakeSwitch([0xC056], "R0W", "resetHires")),
mixin(MakeSwitch([0xC057], "R0W", "setHires"))
]));
}
class AuxiliaryCard
{
HighRam_IIe himem;
MemMap mem;
VideoPages vidPages;
abstract void reboot();
abstract void reset();
}
class Extended80ColumnCard : AuxiliaryCard
{
PrimaryMem auxRam;
this()
{
auxRam = new PrimaryMem(0x0000, 0xC000);
auxRam.debugName = "Aux RAM";
himem = new HighRam_IIe(false, 1);
himem.setDebugName("Aux high RAM");
vidPages.lores1 = new SliceMem(0x0400, 0x0400, auxRam);
vidPages.lores2 = new SliceMem(0x0800, 0x0400, auxRam);
vidPages.hires1 = new SliceMem(0x2000, 0x2000, auxRam);
vidPages.hires2 = new SliceMem(0x4000, 0x2000, auxRam);
mem.X0000_01FF = new SliceMem(0x0000, 0x0200, auxRam);
mem.X0200_03FF = new SliceMem(0x0200, 0x0200, auxRam);
mem.X0400_07FF = new SliceMem(0x0400, 0x0400, auxRam);
mem.X0800_1FFF = new SliceMem(0x0800, 0x1800, auxRam);
mem.X2000_3FFF = new SliceMem(0x2000, 0x2000, auxRam);
mem.X4000_BFFF = new SliceMem(0x4000, 0x8000, auxRam);
}
void reboot()
{
auxRam.reboot();
vidPages.reboot();
mem.reboot();
}
void reset() {}
}