#include <EDK.h>
#include "General.h"
#include "CVIC656x.h"

#define Class CVIC656x
extern Class MSVC4Bug;

#pragma optimize("g", off)
#pragma warning(disable: 4414)

extern "C" pfnv gapfnDisplaySC[256];
extern "C" pfnv gapfnDisplayMC[256];

extern void fn(Sprites54)();


#define Next(Name) /* 9 */ \
  } extern void fn(Name)(); __asm { \
  __asm mov EAX,[ThisReg]Clock.TimerRoot.iClocks \
  __asm mov EDX,offset fnia(Name) \
  __asm inc EAX \
  __asm mov [ThisReg]Chip.pfnOnClock,EDX \
  __asm mov [ThisReg]Clock.TimerRoot.iClocks,EAX \
  __asm mov ThisReg,[ThisReg]Chip.pNextChip \
  __asm je ExecEvent \
  __asm jmp [ThisReg]Chip.pfnOnClock


#define Next2(Name, Label) Next(Name)


#undef NextReg
#define NextReg(Register) \
  __asm mov [ThisReg]Chip.pfnOnClock,Register \
  __asm mov EAX,[ThisReg]Clock.TimerRoot.iClocks \
  __asm mov EBP,[ThisReg]Chip.pNextChip \
  __asm inc EAX \
  __asm mov [ThisReg]Clock.TimerRoot.iClocks,EAX \
  __asm mov ThisReg,EBP \
  __asm je ExecEvent \
  __asm jmp [ThisReg]Chip.pfnOnClock


#define Frame(x) \
  __asm mov EBX,mvar(pbLine) \
  __asm mov EAX,mvar(i4Frame) \
  __asm mov [EBX+x*8+0],EAX \
  __asm mov [EBX+x*8+4],EAX


#define FrameAndNext(x, Name) \
  } \
  extern void fn(Name)(); \
  __asm { \
  __asm mov EDX,offset fnia(Name) \
  __asm mov EBX,mvar(pbLine) \
  __asm mov [ThisReg]Chip.pfnOnClock,EDX \
  __asm mov EDX,[ThisReg]Clock.TimerRoot.iClocks \
  __asm mov EAX,mvar(i4Frame) \
  __asm inc EDX \
  __asm mov [EBX+x*8+0],EAX \
  __asm mov [EBX+x*8+4],EAX \
  __asm mov [ThisReg]Clock.TimerRoot.iClocks,EDX \
  __asm mov ThisReg,[ThisReg]Chip.pNextChip \
  __asm je ExecEvent \
  __asm jmp [ThisReg]Chip.pfnOnClock


#define SetHighAndJump(x, y) \
  SetHigh(x, 1) \
  __asm jmp y

#define SetLowAndJump(x, y) \
  SetLow(x, 1) \
  __asm jmp y


proc(Frame1) index(1)
/*
  } static int giCount = 312 * 63; __asm { 
  dec giCount
  jne Nothing
  mov giCount,312 * 63
  } static CDisplay* pDisplay; __asm { 
  mov EAX,mvar(pDisplay)
  mov pDisplay,EAX
  } pDisplay->Refresh(); __asm {
Nothing:
  mov ThisReg,[ThisReg]Chip.pNextChip
  inc EDI
  je Event
  jmp [ThisReg]Chip.pfnOnClock
Event:
  jmp ExecEvent
*/
  mov AL,mvar(bSprites)
  and AL,00011100b
  cmp AL,00000100b
  je DMAOff
DMACont:
  cmp mvar(abSpriteCnt[3]),63
  jne Fetch
Cont:
  Next(Frame2)
DMAOff:
  SetHighAndJump(mvar(BA), DMACont)
Fetch:
  mov EBX,mvar(pbVideoBase)
  xor EAX,EAX
  mov AL,[EBX+0x03F8+3]
  shl EAX,6
  add AL,mvar(abSpriteCnt[3])
  add EAX,mvar(pbVideoRAM)
  mov EAX,[EAX]
  mov mvar(aiSpriteData[3*4]),EAX
  jmp Cont
endp
proc(Frame2) index(2)
  mov AL,mvar(bSprites)
  and AL,00111000b
  cmp AL,00100000b
  je DMAOn
DMACont:
  Next(Frame3)
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
endp
proc(Frame3) index(3)
  mov AL,mvar(bSprites)
  and AL,00111000b
  cmp AL,00001000b
  je DMAOff
DMACont:
  cmp mvar(abSpriteCnt[4]),63
  jne Fetch
Cont:
  Next(Frame4)
DMAOff:
  SetHighAndJump(mvar(BA), DMACont)
Fetch:
  mov EBX,mvar(pbVideoBase)
  xor EAX,EAX
  mov AL,[EBX+0x03F8+4]
  shl EAX,6
  add AL,mvar(abSpriteCnt[4])
  add EAX,mvar(pbVideoRAM)
  mov EAX,[EAX]
  mov mvar(aiSpriteData[4*4]),EAX
  jmp Cont
endp
proc(Frame4) index(4)
  mov AL,mvar(bSprites)
  and AL,01110000b
  cmp AL,01000000b
  je DMAOn
DMACont:
  Next(Frame5)
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
endp
proc(Frame5) index(5)
  mov AL,mvar(bSprites)
  and AL,01110000b
  cmp AL,00010000b
  je DMAOff
DMACont:
  cmp mvar(abSpriteCnt[5]),63
  jne Fetch
Cont:
  Next(Frame6)
DMAOff:
  SetHighAndJump(mvar(BA), DMACont)
Fetch:
  mov EBX,mvar(pbVideoBase)
  xor EAX,EAX
  mov AL,[EBX+0x03F8+5]
  shl EAX,6
  add AL,mvar(abSpriteCnt[5])
  add EAX,mvar(pbVideoRAM)
  mov EAX,[EAX]
  mov mvar(aiSpriteData[5*4]),EAX
  jmp Cont
endp
proc(Frame6) index(6)
  mov AL,mvar(bSprites)
  and AL,11100000b
  cmp AL,10000000b
  je DMAOn
DMACont:
  Next(Frame7)
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
endp
proc(Frame7) index(7)
  mov AL,mvar(bSprites)
  and AL,11100000b
  cmp AL,00100000b
  je DMAOff
DMACont:
  cmp mvar(abSpriteCnt[6]),63
  jne Fetch
Cont:
  Next(Frame8)
DMAOff:
  SetHighAndJump(mvar(BA), DMACont)
Fetch:
  mov EBX,mvar(pbVideoBase)
  xor EAX,EAX
  mov AL,[EBX+0x03F8+6]
  shl EAX,6
  add AL,mvar(abSpriteCnt[6])
  add EAX,mvar(pbVideoRAM)
  mov EAX,[EAX]
  mov mvar(aiSpriteData[6*4]),EAX
  jmp Cont
endp
proc(Frame8) index(8)
  Next(Frame9)
endp
proc(Frame9) index(9)
  mov AL,mvar(bSprites)
  and AL,11000000b
  cmp AL,01000000b
  je DMAOff
DMACont:
  cmp mvar(abSpriteCnt[7]),63
  jne Fetch
Cont:
  Next(Frame10)
DMAOff:
  SetHighAndJump(mvar(BA), DMACont)
Fetch:
  mov EBX,mvar(pbVideoBase)
  xor EAX,EAX
  mov AL,[EBX+0x03F8+7]
  shl EAX,6
  add AL,mvar(abSpriteCnt[7])
  add EAX,mvar(pbVideoRAM)
  mov EAX,[EAX]
  mov mvar(aiSpriteData[7*4]),EAX
  jmp Cont
endp
proc(Frame10) index(10)
  Next(Frame11)
endp
proc(Frame11) index(11)
  test mvar(bSprites),10000000b
  jne DMAOff
DMACont:
  Next(Frame12)
DMAOff:
  SetHighAndJump(mvar(BA), DMACont)
endp
proc(Frame12) index(12)
  test mvar(iMode),fDMA
  jne DMAOn
DMACont:
  Frame(12)
  Next(Frame13)
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
endp
proc(Frame13) index(13)
  Frame(13)
  Next(Frame14)
endp
extern pfnv* gappfnMode[8 * 8];
proc(Frame14) index(14)
  Frame(14)
  mov EAX,mvar(iMode)
  mov EAX,gappfnMode[EAX*4]
  mov EAX,[EAX]
  NextReg(EAX)
endp
#define Special15 \
  __asm mov EBX,mvar(iVideoLatch) \
  __asm mov EAX,mvar(pbVideoBase) \
  __asm add EAX,EBX \
  __asm mov mvar(pbVideoCounter),EAX \
  __asm mov EAX,mvar(pbColorBase) \
  __asm add EAX,EBX \
  __asm mov mvar(pbColorCounter),EAX \
  __asm shl EBX,3 \
  __asm add EBX,mvar(pbGraphBase) \
  __asm mov mvar(pbGraphCounter),EBX
#define SpecialDMA15 \
  __asm mov mvar(iRowCounter),0
proc(Frame15) index(15)
  Special15
  FrameAndNext(15, Frame16)
endp
proc(Frame16) index(16)
  FrameAndNext(16, Frame17)
endp
proc(Frame17) index(17)
  FrameAndNext(17, Frame18)
endp
proc(Frame18) index(18)
  FrameAndNext(18, Frame19)
endp
proc(Frame19) index(19)
  FrameAndNext(19, Frame20)
endp
proc(Frame20) index(20)
  FrameAndNext(20, Frame21)
endp
proc(Frame21) index(21)
  FrameAndNext(21, Frame22)
endp
proc(Frame22) index(22)
  FrameAndNext(22, Frame23)
endp
proc(Frame23) index(23)
  FrameAndNext(23, Frame24)
endp
proc(Frame24) index(24)
  FrameAndNext(24, Frame25)
endp
proc(Frame25) index(25)
  FrameAndNext(25, Frame26)
endp
proc(Frame26) index(26)
  FrameAndNext(26, Frame27)
endp
proc(Frame27) index(27)
  FrameAndNext(27, Frame28)
endp
proc(Frame28) index(28)
  FrameAndNext(28, Frame29)
endp
proc(Frame29) index(29)
  FrameAndNext(29, Frame30)
endp
proc(Frame30) index(30)
  FrameAndNext(30, Frame31)
endp
proc(Frame31) index(31)
  FrameAndNext(31, Frame32)
endp
proc(Frame32) index(32)
  FrameAndNext(32, Frame33)
endp
proc(Frame33) index(33)
  FrameAndNext(33, Frame34)
endp
proc(Frame34) index(34)
  FrameAndNext(34, Frame35)
endp
proc(Frame35) index(35)
  FrameAndNext(35, Frame36)
endp
proc(Frame36) index(36)
  FrameAndNext(36, Frame37)
endp
proc(Frame37) index(37)
  FrameAndNext(37, Frame38)
endp
proc(Frame38) index(38)
  FrameAndNext(38, Frame39)
endp
proc(Frame39) index(39)
  FrameAndNext(39, Frame40)
endp
proc(Frame40) index(40)
  FrameAndNext(40, Frame41)
endp
proc(Frame41) index(41)
  FrameAndNext(41, Frame42)
endp
proc(Frame42) index(42)
  FrameAndNext(42, Frame43)
endp
proc(Frame43) index(43)
  FrameAndNext(43, Frame44)
endp
proc(Frame44) index(44)
  FrameAndNext(44, Frame45)
endp
proc(Frame45) index(45)
  FrameAndNext(45, Frame46)
endp
proc(Frame46) index(46)
  FrameAndNext(46, Frame47)
endp
proc(Frame47) index(47)
  FrameAndNext(47, Frame48)
endp
proc(Frame48) index(48)
  FrameAndNext(48, Frame49)
endp
proc(Frame49) index(49)
  FrameAndNext(49, Frame50)
endp
proc(Frame50) index(50)
  FrameAndNext(50, Frame51)
endp
proc(Frame51) index(51)
  FrameAndNext(51, Frame52)
endp
proc(Frame52) index(52)
  FrameAndNext(52, Frame53)
endp
proc(Frame53) index(53)
  FrameAndNext(53, Frame54)
endp
proc(Frame54) index(54)
  call fn(Sprites54)
  FrameAndNext(54, Frame55)
endp
proc(Frame55) index(55)
  Frame(55)
  test mvar(bSprites),00000001b
  jne DMAOn
DMACont:
  Next(Frame56)
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
endp
proc(Frame56) index(56)
  FrameAndNext(56, Frame57)
endp
proc(Frame57) index(57)
  Frame(57)
  mov AL,mvar(bSprites)
  and AL,00000011b
  cmp AL,00000010b
  je DMAOn
DMACont:
  Next(Frame58)
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
endp

/*
  Bad scan line, at least the sprites 3--7 active on the current scan
  line and the sprites 0--2 on the following scan line:

           1         2         3         4         5         6
  123456789012345678901234567890123456789012345678901234567890123
           [      {                                      }   ]
  3s4s5s6s7srrrrrgggggggggggggggggggggggggggggggggggggggg--0s1s2s Phi-1 6569R3
  ssssssssss    cccccccccccccccccccccccccccccccccccccccc   ssssss Phi-2 6569R3
  ==========xXXX========================================***====== Phi-2 6510
                                                        00000
                                                          11111
                                                            22222
  33                                                          333
  4444                                                          4
   55555
     66666
       77777
*/                                                           

proc(Frame58) index(58)
  Frame(58)
  cmp mvar(abSpriteCnt[0]),63
  jne Fetch
Cont:
  Next(Frame59)
Fetch:
  mov EBX,mvar(pbVideoBase)
  xor EAX,EAX
  mov AL,[EBX+0x03F8+0]
  shl EAX,6
  add AL,mvar(abSpriteCnt[0])
  add EAX,mvar(pbVideoRAM)
  mov EAX,[EAX]
  mov mvar(aiSpriteData[0*4]),EAX
  jmp Cont
endp
proc(Frame59) index(59)
  Frame(59)
  mov AL,mvar(bSprites)
  and AL,00000111b
  cmp AL,00000100b
  je DMAOn
DMACont:
  Next(Frame60)
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
endp
/*
  case 60:
    if (bRC == 7) {
      iVCBase = iVCCount;
      fDisplay = OFF;
	} else {
      bRC++;
	}
    break;
*/
proc(Frame60) index(60)
  mov AL,mvar(bSprites)
  and AL,00000111b
  cmp AL,00000001b
  je DMAOff
DMACont:
  cmp mvar(abSpriteCnt[1]),63
  jne Fetch
Cont:
  mov AL,byte ptr mvar(iRowCounter)
  cmp AL,7
  jne DisplayOn
  test mvar(iMode),fDISPLAY
  je NoAdd
  mov EBX,mvar(iVideoLatch)
  add EBX,40
  and EBX,0x03FF
  mov mvar(iVideoLatch),EBX
  mov EAX,mvar(pbVideoBase)
  add EAX,EBX
  mov mvar(pbVideoCounter),EAX
  mov EAX,mvar(pbColorBase)
  add EAX,EBX
  mov mvar(pbColorCounter),EAX
  and mvar(iMode),~fDISPLAY
  jmp NoAdd
DMAOff:
  SetHighAndJump(mvar(BA), DMACont)
Fetch:
  mov EBX,mvar(pbVideoBase)
  xor EAX,EAX
  mov AL,[EBX+0x03F8+1]
  shl EAX,6
  add AL,mvar(abSpriteCnt[1])
  add EAX,mvar(pbVideoRAM)
  mov EAX,[EAX]
  mov mvar(aiSpriteData[1*4]),EAX
  jmp Cont
DisplayOn:
  inc EAX
  mov byte ptr mvar(iRowCounter),AL
NoAdd:
  Next(Frame61)
endp
proc(Frame61) index(61)
  mov AL,mvar(bSprites)
  and AL,00001110b
  cmp AL,00001000b
  je DMAOn
DMACont:
  Next(Frame62)
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
endp
proc(Frame62) index(62)
  Frame(59)
  mov AL,mvar(bSprites)
  and AL,00001110b
  cmp AL,00000010b
  je DMAOff
DMACont:
  cmp mvar(abSpriteCnt[2]),63
  jne Fetch
Cont:
  Next(Frame63)
DMAOff:
  SetHighAndJump(mvar(BA), DMACont)
Fetch:
  mov EBX,mvar(pbVideoBase)
  xor EAX,EAX
  mov AL,[EBX+0x03F8+2]
  shl EAX,6
  add AL,mvar(abSpriteCnt[2])
  add EAX,mvar(pbVideoRAM)
  mov EAX,[EAX]
  mov mvar(aiSpriteData[2*4]),EAX
  jmp Cont
endp
proc(SetBadLine)
  cmp mvar(bDisplay),0
  je NoBad
  mov EAX,mvar(iLine)
  cmp EAX,0x30
  jb NoBad
  cmp EAX,0xF8
  jae NoBad
  xor AL,mvar(bYScroll)
  test AL,0x07
  jne NoBad
  or mvar(iMode),fDMA | fDISPLAY
  ret
NoBad:
  and mvar(iMode),~fDMA
  ret
endp
/*
  iLine++;
  if (iLine == 312) {
    iLine = 0;
    iVCBase = 0;
    Refresh();
  }
*/
extern void fn(Sprites63)();
flag gfMoreSpeedButLessCompatibility;
extern void fn(Idle1)();
proc(Frame63) index(63)
  mov AL,mvar(bSprites)
  and AL,00011100b
  cmp AL,00010000b
  je DMAOn
DMACont:
  call fn(Sprites63)
  mov EAX,mvar(iLine)
  cmp EAX,311
  je NextFrame
  inc EAX
  mov mvar(iLine),EAX
  add mvar(pbLine),512
  add mvar(pbLineShift),512
  cmp EAX,47 // why not 48?
  je Line48
Cont48:
  cmp EAX,mvar(iScreenOn)
  je ScreenOn
  cmp EAX,mvar(iScreenOff)
  je ScreenOff
Continue:
  mov EAX,mvar(iLine)
  cmp EAX,mvar(iIntLine)
  jne NoIRQ
  or mvar(bIRR),1
  test mvar(bIMR),1
  je NoIRQ
  SetLow(mvar(Int), 1)
NoIRQ:
  call fn(SetBadLine)
  Next(Frame1)
Line48:
  mov AL,mvar(bControl1)
  and AL,16
  mov mvar(bDisplay),AL
  jmp Cont48
DMAOn:
  SetLowAndJump(mvar(BA), DMACont)
ScreenOn:
  test mvar(bControl1),16
  je Continue
  and mvar(iMode),~fFRAME
FuckMS:
  jmp Continue
ScreenOff:
  or mvar(iMode),fFRAME
  jmp FuckMS
NextFrame:
  mov mvar(iLine),0
  mov mvar(iVideoLatch),0
  mov EAX,mvar(pbBitmap)
  mov mvar(pbLine),EAX
  add EAX,mvar(iXScroll)
  mov mvar(pbLineShift),EAX
  mov mvar(bLPTriggered),0
  } static CDisplay* pDisplay; __asm { 
  mov EAX,mvar(pDisplay)
  mov pDisplay,EAX
  } pDisplay->Refresh(); __asm {
  cmp gfMoreSpeedButLessCompatibility,0
  je Continue
  and EAX,EAX
  jne Continue
  SetHigh(mvar(BA), 1)
  Next(Idle1)
endp

#define Back(x) \
  __asm mov EBX,mvar(pbLine) \
  __asm mov EAX,mvar(i4Back) \
  __asm mov [EBX+x*8+0],EAX \
  __asm mov [EBX+x*8+4],EAX

#define NextSC(Name) \
  } \
  extern void fn(Name)(); \
  __asm { \
  __asm mov [ThisReg]Chip.pfnOnClock,offset fnia(Name) \
  __asm jmp gapfnDisplaySC[EAX*4]

#define NextMC(Name) \
  } \
  extern void fn(Name)(); \
  __asm { \
  __asm mov [ThisReg]Chip.pfnOnClock,offset fnia(Name) \
  __asm jmp gapfnDisplayMC[EAX*4]

#define NextSCMC(Name) \
  } \
  extern void fn(Name)(); \
  __asm { \
  __asm mov [ThisReg]Chip.pfnOnClock,offset fnia(Name) \
  __asm jmp gapfnDisplaySC[EAX*4]

#define Implement15to34(Name) \
  proc(Name##15) index(15) \
    Special15 \
    Frame(15) \
    Next(Name##16) \
  endp \
  proc(Name##16) index(16) \
    Back(16) \
    Name(16) \
    Name##Next(Name##17) \
  endp \
  proc(Name##17) index(17) \
    __asm test mvar(bControl2),08h \
    __asm jne Wide \
    Frame(16) \
    __asm Wide: \
    Name(17) \
    Name##Next(Name##18) \
  endp \
  proc(Name##18) index(18) \
    Name(18) \
    Name##Next(Name##19) \
  endp \
  proc(Name##19) index(19) \
    Name(19) \
    Name##Next(Name##20) \
  endp \
  proc(Name##20) index(20) \
    Name(20) \
    Name##Next(Name##21) \
  endp \
  proc(Name##21) index(21) \
    Name(21) \
    Name##Next(Name##22) \
  endp \
  proc(Name##22) index(22) \
    Name(22) \
    Name##Next(Name##23) \
  endp \
  proc(Name##23) index(23) \
    Name(23) \
    Name##Next(Name##24) \
  endp \
  proc(Name##24) index(24) \
    Name(24) \
    Name##Next(Name##25) \
  endp \
  proc(Name##25) index(25) \
    Name(25) \
    Name##Next(Name##26) \
  endp \
  proc(Name##26) index(26) \
    Name(26) \
    Name##Next(Name##27) \
  endp \
  proc(Name##27) index(27) \
    Name(27) \
    Name##Next(Name##28) \
  endp \
  proc(Name##28) index(28) \
    Name(28) \
    Name##Next(Name##29) \
  endp \
  proc(Name##29) index(29) \
    Name(29) \
    Name##Next(Name##30) \
  endp \
  proc(Name##30) index(30) \
    Name(30) \
    Name##Next(Name##31) \
  endp \
  proc(Name##31) index(31) \
    Name(31) \
    Name##Next(Name##32) \
  endp \
  proc(Name##32) index(32) \
    Name(32) \
    Name##Next(Name##33) \
  endp \
  proc(Name##33) index(33) \
    Name(33) \
    Name##Next(Name##34) \
  endp \
  proc(Name##34) index(34) \
    Name(34) \
    Name##Next(Name##35) \
  endp
#define Implement35to55(Name) \
  proc(Name##35) index(35) \
    Name(35) \
    Name##Next(Name##36) \
  endp \
  proc(Name##36) index(36) \
    Name(36) \
    Name##Next(Name##37) \
  endp \
  proc(Name##37) index(37) \
    Name(37) \
    Name##Next(Name##38) \
  endp \
  proc(Name##38) index(38) \
    Name(38) \
    Name##Next(Name##39) \
  endp \
  proc(Name##39) index(39) \
    Name(39) \
    Name##Next(Name##40) \
  endp \
  proc(Name##40) index(40) \
    Name(40) \
    Name##Next(Name##41) \
  endp \
  proc(Name##41) index(41) \
    Name(41) \
    Name##Next(Name##42) \
  endp \
  proc(Name##42) index(42) \
    Name(42) \
    Name##Next(Name##43) \
  endp \
  proc(Name##43) index(43) \
    Name(43) \
    Name##Next(Name##44) \
  endp \
  proc(Name##44) index(44) \
    Name(44) \
    Name##Next(Name##45) \
  endp \
  proc(Name##45) index(45) \
    Name(45) \
    Name##Next(Name##46) \
  endp \
  proc(Name##46) index(46) \
    Name(46) \
    Name##Next(Name##47) \
  endp \
  proc(Name##47) index(47) \
    Name(47) \
    Name##Next(Name##48) \
  endp \
  proc(Name##48) index(48) \
    Name(48) \
    Name##Next(Name##49) \
  endp \
  proc(Name##49) index(49) \
    Name(49) \
    Name##Next(Name##50) \
  endp \
  proc(Name##50) index(50) \
    Name(50) \
    Name##Next(Name##51) \
  endp \
  proc(Name##51) index(51) \
    Name(51) \
    Name##Next(Name##52) \
  endp \
  proc(Name##52) index(52) \
    Name(52) \
    Name##Next(Name##53) \
  endp \
  proc(Name##53) index(53) \
    Name(53) \
    Name##Next(Name##54) \
  endp \
  proc(Name##54) index(54) \
    __asm call fn(Sprites54) \
    Name(54) \
    Name##Next(Name##55) \
  endp \
  proc(Name##55) index(55) \
    __asm test mvar(bSprites),00000001b \
    __asm jne DMAOn \
    __asm DMACont: \
    __asm test mvar(bControl2),08h \
    __asm je near Narrow \
    Name(55) \
    Name##Next(Frame56) \
    __asm Narrow: \
    Frame(55) \
    Next2(Frame56, 2) \
    __asm DMAOn: \
    __asm lea EAX,mvar(BA) \
    __asm call MySetLow \
    __asm jmp DMACont \
  endp

#define ImplementDMA15to34(Name) \
  proc(Name##DMA15) index(15) \
    Special15 \
    SpecialDMA15 \
    Name##DMA(15) \
    Frame(15) \
    Next(Name##DMA16) \
  endp \
  proc(Name##DMA16) index(16) \
    Name##DMA(16) \
    Back(16) \
    Name(16) \
    Name##Next(Name##DMA17) \
  endp \
  proc(Name##DMA17) index(17) \
    Name##DMA(17) \
    __asm test mvar(bControl2),08h \
    __asm jne Wide \
    Frame(16) \
    __asm Wide: \
    Name(17) \
    Name##Next(Name##DMA18) \
  endp \
  proc(Name##DMA18) index(18) \
    Name##DMA(18) \
    Name(18) \
    Name##Next(Name##DMA19) \
  endp \
  proc(Name##DMA19) index(19) \
    Name##DMA(19) \
    Name(19) \
    Name##Next(Name##DMA20) \
  endp \
  proc(Name##DMA20) index(20) \
    Name##DMA(20) \
    Name(20) \
    Name##Next(Name##DMA21) \
  endp \
  proc(Name##DMA21) index(21) \
    Name##DMA(21) \
    Name(21) \
    Name##Next(Name##DMA22) \
  endp \
  proc(Name##DMA22) index(22) \
    Name##DMA(22) \
    Name(22) \
    Name##Next(Name##DMA23) \
  endp \
  proc(Name##DMA23) index(23) \
    Name##DMA(23) \
    Name(23) \
    Name##Next(Name##DMA24) \
  endp \
  proc(Name##DMA24) index(24) \
    Name##DMA(24) \
    Name(24) \
    Name##Next(Name##DMA25) \
  endp \
  proc(Name##DMA25) index(25) \
    Name##DMA(25) \
    Name(25) \
    Name##Next(Name##DMA26) \
  endp \
  proc(Name##DMA26) index(26) \
    Name##DMA(26) \
    Name(26) \
    Name##Next(Name##DMA27) \
  endp \
  proc(Name##DMA27) index(27) \
    Name##DMA(27) \
    Name(27) \
    Name##Next(Name##DMA28) \
  endp \
  proc(Name##DMA28) index(28) \
    Name##DMA(28) \
    Name(28) \
    Name##Next(Name##DMA29) \
  endp \
  proc(Name##DMA29) index(29) \
    Name##DMA(29) \
    Name(29) \
    Name##Next(Name##DMA30) \
  endp \
  proc(Name##DMA30) index(30) \
    Name##DMA(30) \
    Name(30) \
    Name##Next(Name##DMA31) \
  endp \
  proc(Name##DMA31) index(31) \
    Name##DMA(31) \
    Name(31) \
    Name##Next(Name##DMA32) \
  endp \
  proc(Name##DMA32) index(32) \
    Name##DMA(32) \
    Name(32) \
    Name##Next(Name##DMA33) \
  endp \
  proc(Name##DMA33) index(33) \
    Name##DMA(33) \
    Name(33) \
    Name##Next(Name##DMA34) \
  endp \
  proc(Name##DMA34) index(34) \
    Name##DMA(34) \
    Name(34) \
    Name##Next(Name##DMA35) \
  endp
#define ImplementDMA35to55(Name) \
  proc(Name##DMA35) index(35) \
    Name##DMA(35) \
    Name(35) \
    Name##Next(Name##DMA36) \
  endp \
  proc(Name##DMA36) index(36) \
    Name##DMA(36) \
    Name(36) \
    Name##Next(Name##DMA37) \
  endp \
  proc(Name##DMA37) index(37) \
    Name##DMA(37) \
    Name(37) \
    Name##Next(Name##DMA38) \
  endp \
  proc(Name##DMA38) index(38) \
    Name##DMA(38) \
    Name(38) \
    Name##Next(Name##DMA39) \
  endp \
  proc(Name##DMA39) index(39) \
    Name##DMA(39) \
    Name(39) \
    Name##Next(Name##DMA40) \
  endp \
  proc(Name##DMA40) index(40) \
    Name##DMA(40) \
    Name(40) \
    Name##Next(Name##DMA41) \
  endp \
  proc(Name##DMA41) index(41) \
    Name##DMA(41) \
    Name(41) \
    Name##Next(Name##DMA42) \
  endp \
  proc(Name##DMA42) index(42) \
    Name##DMA(42) \
    Name(42) \
    Name##Next(Name##DMA43) \
  endp \
  proc(Name##DMA43) index(43) \
    Name##DMA(43) \
    Name(43) \
    Name##Next(Name##DMA44) \
  endp \
  proc(Name##DMA44) index(44) \
    Name##DMA(44) \
    Name(44) \
    Name##Next(Name##DMA45) \
  endp \
  proc(Name##DMA45) index(45) \
    Name##DMA(45) \
    Name(45) \
    Name##Next(Name##DMA46) \
  endp \
  proc(Name##DMA46) index(46) \
    Name##DMA(46) \
    Name(46) \
    Name##Next(Name##DMA47) \
  endp \
  proc(Name##DMA47) index(47) \
    Name##DMA(47) \
    Name(47) \
    Name##Next(Name##DMA48) \
  endp \
  proc(Name##DMA48) index(48) \
    Name##DMA(48) \
    Name(48) \
    Name##Next(Name##DMA49) \
  endp \
  proc(Name##DMA49) index(49) \
    Name##DMA(49) \
    Name(49) \
    Name##Next(Name##DMA50) \
  endp \
  proc(Name##DMA50) index(50) \
    Name##DMA(50) \
    Name(50) \
    Name##Next(Name##DMA51) \
  endp \
  proc(Name##DMA51) index(51) \
    Name##DMA(51) \
    Name(51) \
    Name##Next(Name##DMA52) \
  endp \
  proc(Name##DMA52) index(52) \
    Name##DMA(52) \
    Name(52) \
    Name##Next(Name##DMA53) \
  endp \
  proc(Name##DMA53) index(53) \
    Name##DMA(53) \
    Name(53) \
    Name##Next(Name##DMA54) \
  endp \
  proc(Name##DMA54) index(54) \
    __asm call fn(Sprites54) \
    Name##DMA(54) \
    Name(54) \
    Name##Next(Name##DMA55) \
  endp \
  proc(Name##DMA55) index(55) \
    __asm test mvar(bSprites),00000001b \
    __asm je DMAOff \
    __asm DMACont: \
    __asm test mvar(bControl2),08h \
    __asm je Narrow \
    Name(55) \
    Name##Next(Frame56) \
    __asm Narrow: \
    Frame(55) \
    Next2(Frame56, 2) \
    __asm DMAOff: \
    __asm lea EAX,mvar(BA) \
    __asm call MySetHigh \
    __asm jmp DMACont \
  endp

#define ImplementFrameDMA15to34(Name) \
  proc(Frame##Name##DMA15) index(15) \
    Special15 \
    SpecialDMA15 \
    Name##DMA(15) \
    Frame(15) \
    Next(Frame##Name##DMA16) \
  endp \
  proc(Frame##Name##DMA16) index(16) \
    Name##DMA(16) \
    Frame(16) \
    Next(Frame##Name##DMA17) \
  endp \
  proc(Frame##Name##DMA17) index(17) \
    Name##DMA(17) \
    Frame(17) \
    Next(Frame##Name##DMA18) \
  endp \
  proc(Frame##Name##DMA18) index(18) \
    Name##DMA(18) \
    Frame(18) \
    Next(Frame##Name##DMA19) \
  endp \
  proc(Frame##Name##DMA19) index(19) \
    Name##DMA(19) \
    Frame(19) \
    Next(Frame##Name##DMA20) \
  endp \
  proc(Frame##Name##DMA20) index(20) \
    Name##DMA(20) \
    Frame(20) \
    Next(Frame##Name##DMA21) \
  endp \
  proc(Frame##Name##DMA21) index(21) \
    Name##DMA(21) \
    Frame(21) \
    Next(Frame##Name##DMA22) \
  endp \
  proc(Frame##Name##DMA22) index(22) \
    Name##DMA(22) \
    Frame(22) \
    Next(Frame##Name##DMA23) \
  endp \
  proc(Frame##Name##DMA23) index(23) \
    Name##DMA(23) \
    Frame(23) \
    Next(Frame##Name##DMA24) \
  endp \
  proc(Frame##Name##DMA24) index(24) \
    Name##DMA(24) \
    Frame(24) \
    Next(Frame##Name##DMA25) \
  endp \
  proc(Frame##Name##DMA25) index(25) \
    Name##DMA(25) \
    Frame(25) \
    Next(Frame##Name##DMA26) \
  endp \
  proc(Frame##Name##DMA26) index(26) \
    Name##DMA(26) \
    Frame(26) \
    Next(Frame##Name##DMA27) \
  endp \
  proc(Frame##Name##DMA27) index(27) \
    Name##DMA(27) \
    Frame(27) \
    Next(Frame##Name##DMA28) \
  endp \
  proc(Frame##Name##DMA28) index(28) \
    Name##DMA(28) \
    Frame(28) \
    Next(Frame##Name##DMA29) \
  endp \
  proc(Frame##Name##DMA29) index(29) \
    Name##DMA(29) \
    Frame(29) \
    Next(Frame##Name##DMA30) \
  endp \
  proc(Frame##Name##DMA30) index(30) \
    Name##DMA(30) \
    Frame(30) \
    Next(Frame##Name##DMA31) \
  endp \
  proc(Frame##Name##DMA31) index(31) \
    Name##DMA(31) \
    Frame(31) \
    Next(Frame##Name##DMA32) \
  endp \
  proc(Frame##Name##DMA32) index(32) \
    Name##DMA(32) \
    Frame(32) \
    Next(Frame##Name##DMA33) \
  endp \
  proc(Frame##Name##DMA33) index(33) \
    Name##DMA(33) \
    Frame(33) \
    Next(Frame##Name##DMA34) \
  endp \
  proc(Frame##Name##DMA34) index(34) \
    Name##DMA(34) \
    Frame(34) \
    Next(Frame##Name##DMA35) \
  endp
#define ImplementFrameDMA35to55(Name) \
  proc(Frame##Name##DMA35) index(35) \
    Name##DMA(35) \
    Frame(35) \
    Next(Frame##Name##DMA36) \
  endp \
  proc(Frame##Name##DMA36) index(36) \
    Name##DMA(36) \
    Frame(36) \
    Next(Frame##Name##DMA37) \
  endp \
  proc(Frame##Name##DMA37) index(37) \
    Name##DMA(37) \
    Frame(37) \
    Next(Frame##Name##DMA38) \
  endp \
  proc(Frame##Name##DMA38) index(38) \
    Name##DMA(38) \
    Frame(38) \
    Next(Frame##Name##DMA39) \
  endp \
  proc(Frame##Name##DMA39) index(39) \
    Name##DMA(39) \
    Frame(39) \
    Next(Frame##Name##DMA40) \
  endp \
  proc(Frame##Name##DMA40) index(40) \
    Name##DMA(40) \
    Frame(40) \
    Next(Frame##Name##DMA41) \
  endp \
  proc(Frame##Name##DMA41) index(41) \
    Name##DMA(41) \
    Frame(41) \
    Next(Frame##Name##DMA42) \
  endp \
  proc(Frame##Name##DMA42) index(42) \
    Name##DMA(42) \
    Frame(42) \
    Next(Frame##Name##DMA43) \
  endp \
  proc(Frame##Name##DMA43) index(43) \
    Name##DMA(43) \
    Frame(43) \
    Next(Frame##Name##DMA44) \
  endp \
  proc(Frame##Name##DMA44) index(44) \
    Name##DMA(44) \
    Frame(44) \
    Next(Frame##Name##DMA45) \
  endp \
  proc(Frame##Name##DMA45) index(45) \
    Name##DMA(45) \
    Frame(45) \
    Next(Frame##Name##DMA46) \
  endp \
  proc(Frame##Name##DMA46) index(46) \
    Name##DMA(46) \
    Frame(46) \
    Next(Frame##Name##DMA47) \
  endp \
  proc(Frame##Name##DMA47) index(47) \
    Name##DMA(47) \
    Frame(47) \
    Next(Frame##Name##DMA48) \
  endp \
  proc(Frame##Name##DMA48) index(48) \
    Name##DMA(48) \
    Frame(48) \
    Next(Frame##Name##DMA49) \
  endp \
  proc(Frame##Name##DMA49) index(49) \
    Name##DMA(49) \
    Frame(49) \
    Next(Frame##Name##DMA50) \
  endp \
  proc(Frame##Name##DMA50) index(50) \
    Name##DMA(50) \
    Frame(50) \
    Next(Frame##Name##DMA51) \
  endp \
  proc(Frame##Name##DMA51) index(51) \
    Name##DMA(51) \
    Frame(51) \
    Next(Frame##Name##DMA52) \
  endp \
  proc(Frame##Name##DMA52) index(52) \
    Name##DMA(52) \
    Frame(52) \
    Next(Frame##Name##DMA53) \
  endp \
  proc(Frame##Name##DMA53) index(53) \
    Name##DMA(53) \
    Frame(53) \
    Next(Frame##Name##DMA54) \
  endp \
  proc(Frame##Name##DMA54) index(54) \
    __asm call fn(Sprites54) \
    Name##DMA(54) \
    Frame(54) \
    Next(Frame##Name##DMA55) \
  endp \
  proc(Frame##Name##DMA55) index(55) \
    __asm test mvar(bSprites),00000001b \
    __asm je DMAOff \
    __asm DMACont: \
    Frame(55) \
    Next(Frame56) \
    __asm DMAOff: \
    SetHighAndJump(mvar(BA), DMACont) \
  endp

/* 
ghost byte

  bData = *pbGhostByte;
  bColor0 = iBack;
  bColor1 = 0;
*/

#define Ghost(x) \
  \
  __asm mov EDX,mvar(pbGhostByte) \
  __asm xor EAX,EAX \
  \
  __asm mov ECX,mvar(iBack) \
  __asm mov EBX,mvar(pbLineShift) \
  \
  __asm mov AL,[EDX] \
  __asm add EBX,x*8

#define GhostNext(x) \
  NextSC(x)

Implement15to34(Ghost)
Implement35to55(Ghost)

/* 
single color text

  bData = pbGraphBase[abVideoPtr[i] * 8 + iRowCounter];
  bColor0 = iBack;
  bColor1 = abColorPtr[i]; 
*/

#define TextSCDMA(x) \
  __asm mov EBX,mvar(pbVideoCounter) \
  __asm xor EAX,EAX \
  __asm mov AL,[EBX+x-15] \
  __asm mov mvar(abVideoPtr[x-15]),AL \
  __asm shl EAX,3 \
  __asm add EAX,mvar(pbCharBase) \
  __asm mov EBX,mvar(pbColorCounter) \
  __asm mov mvar(aiVideoCache[(x-15)*4]),EAX \
  __asm mov AL,[EBX+x-15] \
  __asm mov mvar(abColorPtr[x-15]),AL

#define TextSC(x) \
  __asm mov EDX,mvar(aiVideoCache[(x-16)*4]) \
  __asm mov EAX,mvar(iRowCounter) \
  \
  __asm add EDX,EAX \
  __asm mov ECX,mvar(iBack) \
  \
  __asm xor EAX,EAX \
  __asm mov EBX,mvar(pbLineShift) \
  \
  __asm mov AL,[EDX] \
  __asm mov CH,mvar(abColorPtr[x-16]) \
  \
  __asm add EBX,x*8

#define TextSCNext(x) \
  NextSC(x)

Implement15to34(TextSC)
Implement35to55(TextSC)
ImplementDMA15to34(TextSC)
ImplementDMA35to55(TextSC)
ImplementFrameDMA15to34(TextSC)
ImplementFrameDMA35to55(TextSC)

/* 
multicolor text

  bData = pbGraphBase[abVideoPtr[i] * 8 + iRowCounter];
  bColor0 = iBack;
  bColor1 = bBack1;
  bColor2 = bBack2;
  bColor3 = abColorPtr[i];
*/

const byte gabMCColor[16] = {
  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
};

const byte gabMCShift[16] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
};

#define TextMCDMA(x) \
  __asm mov EBX,mvar(pbVideoCounter) \
  __asm xor EAX,EAX \
  __asm mov AL,[EBX+x-15] \
  __asm mov mvar(abVideoPtr[x-15]),AL \
  __asm shl EAX,3 \
  __asm add EAX,mvar(pbCharBase) \
  __asm mov EBX,mvar(pbColorCounter) \
  __asm mov mvar(aiVideoCache[(x-15)*4]),EAX \
  __asm mov AL,[EBX+x-15] \
  __asm mov mvar(abColorPtr[x-15]),AL

#define TextMC(x) \
  __asm mov EBX,mvar(aiVideoCache[(x-16)*4]) \
  __asm mov EAX,mvar(iRowCounter) \
  \
  __asm add EBX,EAX \
  __asm xor EAX,EAX \
  \
  __asm mov ECX,mvar(iBack) \
  __asm mov AL,mvar(abColorPtr[x-16]) \
  \
  __asm mov CH,gabMCColor[EAX-0x10] \
  __asm mov AH,gabMCShift[EAX-0x10] \
  \
  __asm mov AL,[EBX] \
  __asm mov EBX,mvar(pbLineShift) \
  \
  __asm mov EDX,mvar(iBack2and1) \
  __asm add EBX,x*8

#define TextMCNext(x) \
  NextSCMC(x)

Implement15to34(TextMC) 
Implement35to55(TextMC) 
ImplementDMA15to34(TextMC)
ImplementDMA35to55(TextMC)
ImplementFrameDMA15to34(TextMC)
ImplementFrameDMA35to55(TextMC)

/* 
extended color text

  bData = pbGraphBase[abVideoPtr[i] * 8 + iRowCounter];
  bColor0 = iBack;
  bColor1 = bBack1;
  bColor2 = bBack2;
  bColor3 = abColorPtr[i];
*/

#define TextECDMA(x) \
  __asm mov EBX,mvar(pbVideoCounter) \
  __asm mov ECX,mvar(pbCharBase) \
  __asm mov AL,[EBX+x-15] \
  __asm mov mvar(abVideoPtr[x-15]),AL \
  __asm and EAX,00111111b \
  __asm mov EBX,mvar(pbColorCounter) \
  __asm lea EAX,[ECX+EAX*8] \
  __asm mov mvar(aiVideoCache[(x-15)*4]),EAX \
  __asm mov AL,[EBX+x-15] \
  __asm mov mvar(abColorPtr[x-15]),AL

#define TextEC(x) \
  __asm mov EBX,mvar(aiVideoCache[(x-16)*4]) \
  __asm add EBX,mvar(iRowCounter) \
  __asm xor EAX,EAX \
  __asm mov AL,mvar(abVideoPtr[x-16]) \
  __asm shr AL,6 \
  __asm mov CH,mvar(abColorPtr[x-16]) \
  __asm mov CL,mvar(abBackECM[EAX]) \
  __asm mov AL,[EBX] \
  __asm mov EBX,mvar(pbLineShift) \
  __asm add EBX,x*8

#define TextECNext(x) \
  NextSC(x)

Implement15to34(TextEC)
Implement35to55(TextEC)
ImplementDMA15to34(TextEC)
ImplementDMA35to55(TextEC)
ImplementFrameDMA15to34(TextEC)
ImplementFrameDMA35to55(TextEC)

/*
single color graphics

  bData = pbGraphBase[iVideoCounter * 8 + iRowCounter];
  bColor0 = abVideoPtr[i] & 15;
  bColor1 = abVideoPtr[i] * 16;
*/

int gaiGraphColors[256] = {
  0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 
  0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
  0x1100, 0x1101, 0x1102, 0x1103, 0x1104, 0x1105, 0x1106, 0x1107, 
  0x1108, 0x1109, 0x110A, 0x110B, 0x110C, 0x110D, 0x110E, 0x110F,
  0x1200, 0x1201, 0x1202, 0x1203, 0x1204, 0x1205, 0x1206, 0x1207, 
  0x1208, 0x1209, 0x120A, 0x120B, 0x120C, 0x120D, 0x120E, 0x120F,
  0x1300, 0x1301, 0x1302, 0x1303, 0x1304, 0x1305, 0x1306, 0x1307, 
  0x1308, 0x1309, 0x130A, 0x130B, 0x130C, 0x130D, 0x130E, 0x130F,
  0x1400, 0x1401, 0x1402, 0x1403, 0x1404, 0x1405, 0x1406, 0x1407, 
  0x1408, 0x1409, 0x140A, 0x140B, 0x140C, 0x140D, 0x140E, 0x140F,
  0x1500, 0x1501, 0x1502, 0x1503, 0x1504, 0x1505, 0x1506, 0x1507, 
  0x1508, 0x1509, 0x150A, 0x150B, 0x150C, 0x150D, 0x150E, 0x150F,
  0x1600, 0x1601, 0x1602, 0x1603, 0x1604, 0x1605, 0x1606, 0x1607, 
  0x1608, 0x1609, 0x160A, 0x160B, 0x160C, 0x160D, 0x160E, 0x160F,
  0x1700, 0x1701, 0x1702, 0x1703, 0x1704, 0x1705, 0x1706, 0x1707, 
  0x1708, 0x1709, 0x170A, 0x170B, 0x170C, 0x170D, 0x170E, 0x170F,
  0x1800, 0x1801, 0x1802, 0x1803, 0x1804, 0x1805, 0x1806, 0x1807, 
  0x1808, 0x1809, 0x180A, 0x180B, 0x180C, 0x180D, 0x180E, 0x180F,
  0x1900, 0x1901, 0x1902, 0x1903, 0x1904, 0x1905, 0x1906, 0x1907, 
  0x1908, 0x1909, 0x190A, 0x190B, 0x190C, 0x190D, 0x190E, 0x190F,
  0x1A00, 0x1A01, 0x1A02, 0x1A03, 0x1A04, 0x1A05, 0x1A06, 0x1A07, 
  0x1A08, 0x1A09, 0x1A0A, 0x1A0B, 0x1A0C, 0x1A0D, 0x1A0E, 0x1A0F,
  0x1B00, 0x1B01, 0x1B02, 0x1B03, 0x1B04, 0x1B05, 0x1B06, 0x1B07, 
  0x1B08, 0x1B09, 0x1B0A, 0x1B0B, 0x1B0C, 0x1B0D, 0x1B0E, 0x1B0F,
  0x1C00, 0x1C01, 0x1C02, 0x1C03, 0x1C04, 0x1C05, 0x1C06, 0x1C07, 
  0x1C08, 0x1C09, 0x1C0A, 0x1C0B, 0x1C0C, 0x1C0D, 0x1C0E, 0x1C0F,
  0x1D00, 0x1D01, 0x1D02, 0x1D03, 0x1D04, 0x1D05, 0x1D06, 0x1D07, 
  0x1D08, 0x1D09, 0x1D0A, 0x1D0B, 0x1D0C, 0x1D0D, 0x1D0E, 0x1D0F,
  0x1E00, 0x1E01, 0x1E02, 0x1E03, 0x1E04, 0x1E05, 0x1E06, 0x1E07, 
  0x1E08, 0x1E09, 0x1E0A, 0x1E0B, 0x1E0C, 0x1E0D, 0x1E0E, 0x1E0F,
  0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07, 
  0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F
};

#define GraphSCDMA(x) \
  __asm mov EBX,mvar(pbVideoCounter) \
  __asm xor EAX,EAX \
  __asm mov AL,[EBX+(x-15)] \
  __asm mov mvar(abVideoPtr[x-15]),AL \
  __asm mov EAX,gaiGraphColors[EAX*4] \
  __asm mov EBX,mvar(pbColorCounter) \
  __asm mov mvar(aiVideoCache[(x-15)*4]),EAX \
  __asm mov AL,[EBX+(x-15)] \
  __asm mov mvar(abColorPtr[x-15]),AL

#define GraphSC(x) \
  __asm mov EBX,mvar(pbGraphCounter) \
  __asm add EBX,mvar(iRowCounter) \
  __asm xor EAX,EAX \
  __asm mov AL,[EBX+(x-16)*8] \
  __asm mov ECX,mvar(aiVideoCache[(x-16)*4]) \
  __asm mov EBX,mvar(pbLineShift) \
  __asm add EBX,x*8

#define GraphSCNext(x) \
  NextSC(x)

Implement15to34(GraphSC)
Implement35to55(GraphSC)
ImplementDMA15to34(GraphSC)
ImplementDMA35to55(GraphSC)
ImplementFrameDMA15to34(GraphSC)
ImplementFrameDMA35to55(GraphSC)

/*
multicolor graphics

  bData = pbGraphBase[iVideoCounter * 8 + iRowCounter];
  bColor0 = iBack;
  bColor1 = abVideoPtr[i] * 16;
  bColor2 = abVideoPtr[i] & 15;
  bColor3 = abColorPtr[i];
*/

#define GraphMCDMA(x) \
  __asm mov EBX,mvar(pbVideoCounter) \
  __asm xor EAX,EAX \
  __asm mov AL,[EBX+(x-15)] \
  __asm mov mvar(abVideoPtr[x-15]),AL \
  __asm mov EAX,gaiGraphColors[EAX*4] \
  __asm mov EBX,mvar(pbColorCounter) \
  __asm mov mvar(aiVideoCache[(x-15)*4]),EAX \
  __asm mov AL,[EBX+(x-15)] \
  __asm mov mvar(abColorPtr[x-15]),AL

#define GraphMC(x) \
  __asm mov EBX,mvar(pbGraphCounter) \
  __asm add EBX,mvar(iRowCounter) \
  __asm xor EAX,EAX \
  __asm mov AL,[EBX+(x-16)*8] \
  __asm mov CL,byte ptr mvar(iBack) \
  __asm mov CH,mvar(abColorPtr[x-16]) \
  __asm mov EDX,mvar(aiVideoCache[(x-16)*4]) \
  __asm mov EBX,mvar(pbLineShift) \
  __asm add EBX,x*8

#define GraphMCNext(x) \
  NextMC(x)

Implement15to34(GraphMC)
Implement35to55(GraphMC)
ImplementDMA15to34(GraphMC)
ImplementDMA35to55(GraphMC)
ImplementFrameDMA15to34(GraphMC)
ImplementFrameDMA35to55(GraphMC)

// black screen

#define BlackDMA(x) \
  __asm mov EBX,mvar(pbVideoCounter) \
  __asm xor EAX,EAX \
  __asm mov AL,[EBX+x-15] \
  __asm mov EBX,mvar(pbColorCounter) \
  __asm mov mvar(abVideoPtr[x-15]),AL \
  __asm mov AL,[EBX+x-15] \
  __asm mov mvar(abColorPtr[x-15]),AL

#define Black(x) \
  __asm mov EBX,mvar(pbLineShift) \
  __asm mov EAX,0x00000000 \
  __asm mov [EBX+0],EAX \
  __asm mov [EBX+4],EAX

#define BlackNext(x) \
  Next(x)

Implement15to34(Black)
Implement35to55(Black)
ImplementDMA15to34(Black)
ImplementDMA35to55(Black)
ImplementFrameDMA15to34(Black)
ImplementFrameDMA35to55(Black)

// tables of proc addresses for index to proc conversion

#define Table(Name) \
  static pfnv gapfn##Name[41] = { \
    fn(Name##15), \
    fn(Name##16), \
    fn(Name##17), \
    fn(Name##18), \
    fn(Name##19), \
    fn(Name##20), \
    fn(Name##21), \
    fn(Name##22), \
    fn(Name##23), \
    fn(Name##24), \
    fn(Name##25), \
    fn(Name##26), \
    fn(Name##27), \
    fn(Name##28), \
    fn(Name##29), \
    fn(Name##30), \
    fn(Name##31), \
    fn(Name##32), \
    fn(Name##33), \
    fn(Name##34), \
    fn(Name##35), \
    fn(Name##36), \
    fn(Name##37), \
    fn(Name##38), \
    fn(Name##39), \
    fn(Name##40), \
    fn(Name##41), \
    fn(Name##42), \
    fn(Name##43), \
    fn(Name##44), \
    fn(Name##45), \
    fn(Name##46), \
    fn(Name##47), \
    fn(Name##48), \
    fn(Name##49), \
    fn(Name##50), \
    fn(Name##51), \
    fn(Name##52), \
    fn(Name##53), \
    fn(Name##54), \
    fn(Name##55) \
  };

Table(Frame)
  
Table(Ghost)

Table(TextSC)
Table(TextSCDMA)
Table(FrameTextSCDMA)

Table(TextMC)
Table(TextMCDMA)
Table(FrameTextMCDMA)
  
Table(TextEC)
Table(TextECDMA)
Table(FrameTextECDMA)
  
Table(GraphSC)
Table(GraphSCDMA)
Table(FrameGraphSCDMA)
  
Table(GraphMC)
Table(GraphMCDMA)
Table(FrameGraphMCDMA)
  
Table(Black)
Table(BlackDMA)
Table(FrameBlackDMA)

// bug in MSVC 2.0: macro ip(Name) = ((pfnv)((int)Name + 4)) in release mode
// does not work within constant definitions

static class CorrectAddressTables {
public:
  CorrectAddressTables() {
    for (int i = 0; i < 41; i++) {
      gapfnFrame[i] = ip(gapfnFrame[i]);
      gapfnGhost[i] = ip(gapfnGhost[i]);
      gapfnTextSC[i] = ip(gapfnTextSC[i]);
      gapfnTextSCDMA[i] = ip(gapfnTextSCDMA[i]);
      gapfnFrameTextSCDMA[i] = ip(gapfnFrameTextSCDMA[i]);
      gapfnTextMC[i] = ip(gapfnTextMC[i]);
      gapfnTextMCDMA[i] = ip(gapfnTextMCDMA[i]);
      gapfnFrameTextMCDMA[i] = ip(gapfnFrameTextMCDMA[i]);
      gapfnTextEC[i] = ip(gapfnTextEC[i]);
      gapfnTextECDMA[i] = ip(gapfnTextECDMA[i]);
      gapfnFrameTextECDMA[i] = ip(gapfnFrameTextECDMA[i]);
      gapfnGraphSC[i] = ip(gapfnGraphSC[i]);
      gapfnGraphSCDMA[i] = ip(gapfnGraphSCDMA[i]);
      gapfnFrameGraphSCDMA[i] = ip(gapfnFrameGraphSCDMA[i]);
      gapfnGraphMC[i] = ip(gapfnGraphMC[i]);
      gapfnGraphMCDMA[i] = ip(gapfnGraphMCDMA[i]);
      gapfnFrameGraphMCDMA[i] = ip(gapfnFrameGraphMCDMA[i]);
      gapfnBlack[i] = ip(gapfnBlack[i]);
      gapfnBlackDMA[i] = ip(gapfnBlackDMA[i]);
      gapfnFrameBlackDMA[i] = ip(gapfnFrameBlackDMA[i]);
    }
  };
} CorrectAddressTablesAtInit;

// conversion from iMode to corrensponding display proc table

/*
  #define DMA      1     // bit 0 = DMA running
  #define DISPLAY  2     // bit 1 = character display on
  #define FRAME    4     // bit 2 = top/bottom frame
  int iMode;             // bit 3 = bitmap mode
                         // bit 4 = extended color mode
                         // bit 5 = multicolor mode
*/

pfnv* gappfnMode[8 * 8] = {

  gapfnGhost,
  0,
  gapfnTextSC,
  gapfnTextSCDMA,
  gapfnFrame,
  0,
  gapfnFrame,
  gapfnFrameTextSCDMA,
  
  gapfnGhost,
  0,
  gapfnGraphSC,
  gapfnGraphSCDMA,
  gapfnFrame,
  0,
  gapfnFrame,
  gapfnFrameGraphSCDMA,
  
  gapfnGhost,
  0,
  gapfnTextEC,
  gapfnTextECDMA,
  gapfnFrame,
  0,
  gapfnFrame,
  gapfnFrameTextECDMA,
  
  gapfnGhost,
  0,
  gapfnBlack,
  gapfnBlackDMA,
  gapfnFrame,
  0,
  gapfnFrame,
  gapfnFrameBlackDMA,
  
  gapfnGhost,
  0,
  gapfnTextMC,
  gapfnTextMCDMA,
  gapfnFrame,
  0,
  gapfnFrame,
  gapfnFrameTextMCDMA,
  
  gapfnGhost,
  0,
  gapfnGraphMC,
  gapfnGraphMCDMA,
  gapfnFrame,
  0,
  gapfnFrame,
  gapfnFrameGraphMCDMA,
  
  gapfnGhost,
  0,
  gapfnBlack,
  gapfnBlackDMA,
  gapfnFrame,
  0,
  gapfnFrame,
  gapfnFrameBlackDMA,
  
  gapfnGhost,
  0,
  gapfnBlack,
  gapfnBlackDMA,
  gapfnFrame,
  0,
  gapfnFrame,
  gapfnFrameBlackDMA,

};

proc(Idle1) index(1)
  Next(Idle2)
endp
proc(Idle2) index(2)
  Next(Idle3)
endp
proc(Idle3) index(3)
  Next(Idle4)
endp
proc(Idle4) index(4)
  Next(Idle5)
endp
proc(Idle5) index(5)
  Next(Idle6)
endp
proc(Idle6) index(6)
  Next(Idle7)
endp
proc(Idle7) index(7)
  Next(Idle8)
endp
proc(Idle8) index(8)
  Next(Idle9)
endp
proc(Idle9) index(9)
  Next(Idle10)
endp
proc(Idle10) index(10)
  Next(Idle11)
endp
proc(Idle11) index(11)
  Next(Idle12)
endp
proc(Idle12) index(12)
  Next(Idle13)
endp
proc(Idle13) index(13)
  Next(Idle14)
endp
proc(Idle14) index(14)
  Next(Idle15)
endp
proc(Idle15) index(15)
  Next(Idle16)
endp
proc(Idle16) index(16)
  Next(Idle17)
endp
proc(Idle17) index(17)
  Next(Idle18)
endp
proc(Idle18) index(18)
  Next(Idle19)
endp
proc(Idle19) index(19)
  Next(Idle20)
endp
proc(Idle20) index(20)
  Next(Idle21)
endp
proc(Idle21) index(21)
  Next(Idle22)
endp
proc(Idle22) index(22)
  Next(Idle23)
endp
proc(Idle23) index(23)
  Next(Idle24)
endp
proc(Idle24) index(24)
  Next(Idle25)
endp
proc(Idle25) index(25)
  Next(Idle26)
endp
proc(Idle26) index(26)
  Next(Idle27)
endp
proc(Idle27) index(27)
  Next(Idle28)
endp
proc(Idle28) index(28)
  Next(Idle29)
endp
proc(Idle29) index(29)
  Next(Idle30)
endp
proc(Idle30) index(30)
  Next(Idle31)
endp
proc(Idle31) index(31)
  Next(Idle32)
endp
proc(Idle32) index(32)
  Next(Idle33)
endp
proc(Idle33) index(33)
  Next(Idle34)
endp
proc(Idle34) index(34)
  Next(Idle35)
endp
proc(Idle35) index(35)
  Next(Idle36)
endp
proc(Idle36) index(36)
  Next(Idle37)
endp
proc(Idle37) index(37)
  Next(Idle38)
endp
proc(Idle38) index(38)
  Next(Idle39)
endp
proc(Idle39) index(39)
  Next(Idle40)
endp
proc(Idle40) index(40)
  Next(Idle41)
endp
proc(Idle41) index(41)
  Next(Idle42)
endp
proc(Idle42) index(42)
  Next(Idle43)
endp
proc(Idle43) index(43)
  Next(Idle44)
endp
proc(Idle44) index(44)
  Next(Idle45)
endp
proc(Idle45) index(45)
  Next(Idle46)
endp
proc(Idle46) index(46)
  Next(Idle47)
endp
proc(Idle47) index(47)
  Next(Idle48)
endp
proc(Idle48) index(48)
  Next(Idle49)
endp
proc(Idle49) index(49)
  Next(Idle50)
endp
proc(Idle50) index(50)
  Next(Idle51)
endp
proc(Idle51) index(51)
  Next(Idle52)
endp
proc(Idle52) index(52)
  Next(Idle53)
endp
proc(Idle53) index(53)
  Next(Idle54)
endp
proc(Idle54) index(54)
  Next(Idle55)
endp
proc(Idle55) index(55)
  Next(Idle56)
endp
proc(Idle56) index(56)
  Next(Idle57)
endp
proc(Idle57) index(57)
  Next(Idle58)
endp
proc(Idle58) index(58)
  Next(Idle59)
endp
proc(Idle59) index(59)
  Next(Idle60)
endp
proc(Idle60) index(60)
  Next(Idle61)
endp
proc(Idle61) index(61)
  Next(Idle62)
endp
proc(Idle62) index(62)
  Next(Idle63)
endp

proc(Idle63) index(63)
  mov EAX,mvar(iLine)
  cmp EAX,311
  je NextFrame
  inc EAX
  mov mvar(iLine),EAX
  add mvar(pbLine),512
  add mvar(pbLineShift),512
Continue:
  mov EAX,mvar(iLine)
  cmp EAX,mvar(iIntLine)
  jne NoIRQ
  or mvar(bIRR),1
  test mvar(bIMR),1
  je NoIRQ
  SetLow(mvar(Int), 1)
NoIRQ:
  //call fn(SetBadLine)
  Next(Idle1)
NextFrame:
  mov mvar(iLine),0
  mov mvar(iVideoLatch),0
  mov EAX,mvar(pbBitmap)
  mov mvar(pbLine),EAX
  add EAX,mvar(iXScroll)
  mov mvar(pbLineShift),EAX
  mov mvar(bLPTriggered),0
  } static CDisplay* pDisplay; __asm { 
  mov EAX,mvar(pDisplay)
  mov pDisplay,EAX
  } pDisplay->Refresh(); __asm {
  and EAX,EAX
  je Continue
  Next(Frame1)
endp

/*
proc(Idle63) index(63)
  mov EAX,mvar(iLine)
  cmp EAX,311
  je NextFrame
  inc EAX
  mov mvar(iLine),EAX
  cmp EAX,mvar(iIntLine)
  jne NoIRQ
  or mvar(bIRR),1
  test mvar(bIMR),1
  je NoIRQ
  SetLow(mvar(Int), 1)
NoIRQ:
Idle:
  Next(Idle1)
NextFrame:
  mov mvar(iLine),0
  } CDisplay* pDisplay; __asm { 
  mov EAX,mvar(pDisplay)
  mov pDisplay,EAX
  mov giClockReg,ClockReg
  } pDisplay->Refresh(); __asm {
  mov ClockReg,giClockReg
  and EAX,EAX
  je Idle
  Next(Frame1)
endp
*/
