Catakig/Source/LibAppleII/A2Computer/CPU-RW.h

429 lines
10 KiB
C

/* CPU-RW.h
Helper file that's included, twice, from "CPU.m": once for the read
phase, and once for the write phase. This code implements reads and
writes in the Apple II's $C0xx memory area.
*/
#if READ_PHASE
#define DONE goto Epilog
#define DONE_F goto R_Floater8
#define LABEL(NAME) R_##NAME
#else // write phase
#define DONE goto NewOpcode
#define DONE_F goto NewOpcode
#define LABEL(NAME) W_##NAME
#endif
#define CASE(N) case 0x##N + 1
#define VF_CASES(N, FLAGS) \
CASE(N ): mFlags &= ~((FLAGS) & mMutableFlags); DONE_F; \
CASE(N+1): mFlags |= ((FLAGS) & mMutableFlags); DONE_F;
// for possibly changing video flags; and memory map not affected
#define MF_CASES(N, FLAGS) \
CASE(N): \
d = mFlags & ~((FLAGS) & mMutableFlags); goto LABEL(Remap); \
CASE(N+1): \
d = mFlags | ((FLAGS) & mMutableFlags); goto LABEL(Remap);
// for possibly changing memory flags; memory map affected
//---------------------------------------------------------------------------
switch ((ea ^ 0xC800) - 0x7FF)
{
enum
{
kfIOU = kfXYMASK | kfVBLMASK | kfX0EDGE | kfY0EDGE,
kmLCEven = ~(kfLCBANK2 | kfLCRD | kfLCWRThi | kfLCWRTlo),
kmHotSlot = ~(7UL << ksHotSlot),
};
//-------------------------------------------------- $C00x, $C01x
#if READ_PHASE
CASE(00): CASE(01): CASE(02): CASE(03):
CASE(04): CASE(05): CASE(06): CASE(07):
CASE(08): CASE(09): CASE(0A): CASE(0B):
CASE(0C): CASE(0D): CASE(0E): CASE(0F):
if (mKeyQ.tail == mKeyQ.head) // then char queue is empty
d = 0; // should be last char queued??
else // queue has one or more characters
d = 0x80 | mKeyQ.buf[mKeyQ.head];
DONE;
CASE(10):
if (mKeyQ.tail != mKeyQ.head)
mKeyQ.head += 1;
d = A2G.buttons << 3 & 0x80; // or'd with previous char!!
DONE;
CASE(11): d = ksLCBANK2; goto R_Flag;
CASE(12): d = ksLCRD; goto R_Flag;
CASE(13): d = ksRAMRD; goto R_Flag;
CASE(14): d = ksRAMWRT; goto R_Flag;
CASE(15): d = ksCXROM; goto R_MuFlag;
CASE(16): d = ksALTZP; goto R_Flag;
CASE(17): d = ksC3ROM; goto R_MuFlag;
CASE(18): d = ks80STOREv; goto R_Flag;
CASE(19): d = (scanLine >> 6) - 3; goto R_Floater7;
CASE(1A): d = ksTEXT; goto R_Flag;
CASE(1B): d = ksMIXED; goto R_Flag;
CASE(1C): d = ksPAGE2v; goto R_Flag;
CASE(1D): d = ksHIRESv; goto R_Flag;
CASE(1E): d = ksALTCHAR; goto R_Flag;
CASE(1F): d = ks80COL; goto R_Flag;
#else // write phase
MF_CASES(00, kf80STOREm | kf80STOREv)
MF_CASES(02, kfRAMRD)
MF_CASES(04, kfRAMWRT)
MF_CASES(06, kfCXROM)
MF_CASES(08, kfALTZP)
MF_CASES(0A, kfC3ROM)
VF_CASES(0C, kf80COL)
VF_CASES(0E, kfALTCHAR)
CASE(10): CASE(11): CASE(12): CASE(13):
CASE(14): CASE(15): CASE(16): CASE(17):
CASE(18): CASE(19): CASE(1A): CASE(1B):
CASE(1C): CASE(1D): CASE(1E): CASE(1F):
if (mKeyQ.tail != mKeyQ.head)
mKeyQ.head += 1;
DONE;
#endif
//-------------------------------------------------- $C02x, $C03x
CASE(20): CASE(21): CASE(22): CASE(23):
CASE(24): CASE(25): CASE(26): CASE(27):
CASE(28): CASE(29): CASE(2A): CASE(2B):
CASE(2C): CASE(2D): CASE(2E): CASE(2F):
if (mModel >= kA2ModelIIc)
{
d = mFlags ^ kfCXROM;
goto LABEL(Remap);
}
if (not A2G.hearC02x)
DONE_F;
// else fall into C03x handler
CASE(30): CASE(31): CASE(32): CASE(33):
CASE(34): CASE(35): CASE(36): CASE(37):
CASE(38): CASE(39): CASE(3A): CASE(3B):
CASE(3C): CASE(3D): CASE(3E): CASE(3F):
{
uint32_t *out, *delta;
d = ((t + 65*scanLine) * (kA2SamplesPerStep << 7)) / 17030;
out = gSpkrOut + (d >> 7);
delta = A2T.audio.delta + (d & 127);
out[0] = ~out[0] + delta[kFilterRes * 4];
out[1] = ~out[1] + delta[kFilterRes * 3];
out[2] = ~out[2] + delta[kFilterRes * 2];
out[3] = ~out[3] + delta[kFilterRes];
out[4] = (~out[4] + delta[0]) ^ 0xFF;
} DONE_F;
//-------------------------------------------------- $C04x, $C06x
#if READ_PHASE
CASE(40): d = ksXYMASK; goto R_Flag;
CASE(41): d = ksVBLMASK; goto R_Flag;
CASE(42): d = ksX0EDGE; goto R_Flag;
CASE(43): d = ksY0EDGE; goto R_Flag;
CASE(60): CASE(68):
d = 0; // cassette-in ??
goto R_Floater7;
CASE(61): CASE(69):
CASE(62): CASE(6A):
CASE(63): CASE(6B):
d = A2G.buttons << (-ea & 7);
goto R_Floater7;
CASE(64): CASE(6C):
CASE(65): CASE(6D):
CASE(66): CASE(6E):
CASE(67): CASE(6F):
d = (CYCLES - mWhenC07x - A2G.paddle[ea&3]) >> 24;
goto R_Floater7;
#else // write phase
CASE(40): CASE(41): CASE(42): CASE(43):
CASE(60): CASE(61): CASE(62): CASE(63):
CASE(64): CASE(65): CASE(66): CASE(67):
CASE(68): CASE(69): CASE(6A): CASE(6B):
CASE(6C): CASE(6D): CASE(6E): CASE(6F):
// fall into DONE
#endif
CASE(44): CASE(45): CASE(46): CASE(47):
CASE(48): CASE(49): CASE(4A): CASE(4B):
CASE(4C): CASE(4D): CASE(4E): CASE(4F):
DONE;
//-------------------------------------------------- $C05x
CASE(50): mFlags &= ~kfTEXT; DONE_F;
CASE(51): mFlags |= kfTEXT; DONE_F;
CASE(52): mFlags &= ~kfMIXED; DONE_F;
CASE(53): mFlags |= kfMIXED; DONE_F;
CASE(54): d = mFlags & ~(kfPAGE2m | kfPAGE2v); goto LABEL(Remap);
CASE(55): d = mFlags | (kfPAGE2m | kfPAGE2v); goto LABEL(Remap);
CASE(56): d = mFlags & ~(kfHIRESm | kfHIRESv); goto LABEL(Remap);
CASE(57): d = mFlags | (kfHIRESm | kfHIRESv); goto LABEL(Remap);
VF_CASES(58, kfSINGRES | kfXYMASK)
VF_CASES(5A, kfSINGRES | kfVBLMASK)
VF_CASES(5C, kfSINGRES | kfX0EDGE)
VF_CASES(5E, kfSINGRES | kfY0EDGE)
//-------------------------------------------------- $C07x
#if READ_PHASE
CASE(77): d = 0; // whether in graphics scanline!!
goto R_Floater7;
CASE(7E): d = (mMutableFlags >> ksSINGRES) << 7;
goto R_Floater7;
CASE(7F): d = ksSINGRES;
goto R_Flag;
#else // write phase
CASE(7E): if (mModel >= kA2ModelIIc)
mMutableFlags = mMutableFlags & ~kfIOU | kfSINGRES;
goto LABEL(HitC07x);
CASE(7F): if (mModel >= kA2ModelIIc)
mMutableFlags = mMutableFlags & ~kfSINGRES | kfIOU;
goto LABEL(HitC07x);
CASE(77):
// fall thru
#endif
CASE(70): CASE(71): CASE(72): CASE(73):
CASE(74): CASE(75): CASE(76):
CASE(78): CASE(79): CASE(7A): CASE(7B):
CASE(7C): CASE(7D):
LABEL(HitC07x):
mWhenC07x = CYCLES;
DONE_F;
//-------------------------------------------------- $C08x (lang card)
CASE(80):
CASE(84): d = mFlags & kmLCEven | (kfLCBANK2 | kfLCRD);
goto LABEL(Remap);
CASE(82):
CASE(86): d = mFlags & kmLCEven | kfLCBANK2;
goto LABEL(Remap);
CASE(88):
CASE(8C): d = mFlags & kmLCEven | kfLCRD;
goto LABEL(Remap);
CASE(8A):
CASE(8E): d = mFlags & kmLCEven;
goto LABEL(Remap);
CASE(81):
CASE(85): d = kfLCBANK2;
goto LABEL(HitC08xOdd);
CASE(83):
CASE(87): d = kfLCBANK2 | kfLCRD;
goto LABEL(HitC08xOdd);
CASE(89):
CASE(8D): d = 0;
goto LABEL(HitC08xOdd);
CASE(8B):
CASE(8F): d = kfLCRD;
goto LABEL(HitC08xOdd);
LABEL(HitC08xOdd):
d |= mFlags & ~(kfLCBANK2 | kfLCRD);
d += ~d >> 1 & kfLCWRTlo;
goto LABEL(Remap);
//-------------------------------------------------- $C09x (printer)
#if READ_PHASE
CASE(90): CASE(91): CASE(92): CASE(93):
CASE(94): CASE(95): CASE(96): CASE(97):
CASE(98): CASE(99): CASE(9A): CASE(9B):
CASE(9C): CASE(9D): CASE(9E): CASE(9F):
d = mPrinter.reg[ea & 15];
DONE;
#else // write phase
CASE(98): mPrinter.lights = kLightSustain | 1;
putc(d & 0x7F, mPrinter.session);
DONE;
CASE(9A):
CASE(9B): mPrinter.reg[ea & 15] = d;
DONE;
CASE(90): CASE(91): CASE(92): CASE(93):
CASE(94): CASE(95): CASE(96): CASE(97): CASE(99):
CASE(9C): CASE(9D): CASE(9E): CASE(9F):
DONE;
#endif
//-------------------------------------------------- $C0Ax, $C0Bx
CASE(A0): CASE(A1): CASE(A2): CASE(A3):
CASE(A4): CASE(A5): CASE(A6): CASE(A7):
CASE(A8): CASE(A9): CASE(AA): CASE(AB):
CASE(AC): CASE(AD): CASE(AE): CASE(AF):
CASE(B0): CASE(B1): CASE(B2): CASE(B3):
CASE(B4): CASE(B5): CASE(B6): CASE(B7):
CASE(B8): CASE(B9): CASE(BA): CASE(BB):
CASE(BC): CASE(BD): CASE(BE):
DONE;
CASE(BF):
#if READ_PHASE
d = A2T.curTime[mClock.index-- & 31];
#else // write phase
mClock.index = d;
#endif
DONE;
//-------------------------------------------------- $C0Cx (Slinky RAM)
#if READ_PHASE
CASE(C0): d = mSlinky.pos; DONE;
CASE(C1): d = mSlinky.pos >> 8; DONE;
CASE(C2): d = mSlinky.pos >> 16 | 0xF0; DONE;
CASE(C3): d = mSlinky.base[mSlinky.pos++ & mSlinky.mask]; DONE;
CASE(CE): d = (mSlinky.mask + 1) >> 9; DONE;
CASE(CF): d = (mSlinky.mask + 1) >> (9+8); DONE;
#else // write phase
CASE(C0): mSlinky.pos = mSlinky.pos & 0xFFFF00 | d; DONE;
CASE(C1): mSlinky.pos = mSlinky.pos & 0xFF00FF | d<< 8; DONE;
CASE(C2): mSlinky.pos = mSlinky.pos & 0x00FFFF | d<<16; DONE;
CASE(C3): mSlinky.base[mSlinky.pos++ & mSlinky.mask] = d; DONE;
CASE(CE):
CASE(CF): // fall thru
#endif
CASE(C4): CASE(C5): CASE(C6): CASE(C7):
CASE(C8): CASE(C9): CASE(CA): CASE(CB):
CASE(CC): CASE(CD):
DONE_F;
//-------------------------------------------------- $C0D0-EF (IWMs)
CASE(D0): CASE(D1): CASE(D2): CASE(D3):
CASE(D4): CASE(D5): CASE(D6): CASE(D7):
CASE(D8): CASE(D9): CASE(DA): CASE(DB):
CASE(DC): CASE(DD): CASE(DE): CASE(DF):
CASE(E0): CASE(E1): CASE(E2): CASE(E3):
CASE(E4): CASE(E5): CASE(E6): CASE(E7):
CASE(E8): CASE(E9): CASE(EA): CASE(EB):
CASE(EC): CASE(ED): CASE(EE): CASE(EF):
#if READ_PHASE
d = A2HitIWM(mIWM + (ea>>4 & 1), ea&31, 0);
#else // write phase
A2HitIWM(mIWM + (ea>>4 & 1), ea|32, d);
#endif
DONE;
//-------------------------------------------------- $CFFF
#if 0
CASE(FF): //temp!!
#if READ_PHASE
d = mFlags >> ksHotSlot & 7;
#else
mFlags = d = (mFlags & kmHotSlot) | ((d&7) << ksHotSlot);
REMAP_(d);
#endif
DONE;
#endif
case 0:
#if 0
if (mModel < kA2ModelIIc and (d = (pc>>8) ^ 0xC7) < 7)
{
mFlags = d = (mFlags & kmHotSlot) | ((d^7) << ksHotSlot);
REMAP_(d);
}
#endif
d = READ(ea);
DONE;
//-------------------------------------------------- Misc epilogs
// Arrive at R_Remap or W_Remap with 'd' equal to the new value for
// 'mFlags'. Arrive at R_Flag with 'd' equal to one of the 'ks'
// flag constants. Arrive at R_Floater7 with 'd' having a significant
// bit 7.
#if READ_PHASE
R_Remap: if (mFlags != d) {
mFlags = d; REMAP_(d);
}
R_Floater8: d = FLOATER;
DONE;
R_MuFlag: d = ((mFlags & mMutableFlags) >> d) << 7;
goto R_Floater7;
R_Flag: d = (mFlags >> d) << 7;
R_Floater7: d = (d & 0x80) | (FLOATER & 0x7F);
DONE;
#else // write phase
W_Remap: if (mFlags != d) {
mFlags = d; REMAP_(d);
}
DONE;
#endif
} // end of big switch on 'ea'
//---------------------------------------------------------------------------
#undef DONE
#undef DONE_F
#undef LABEL
#undef CASE
#undef VF_CASES
#undef MF_CASES