706
877
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
707
uInt32 TIA::width() const
712
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
713
uInt32 TIA::height() const
715
return myFrameHeight;
718
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
719
uInt32 TIA::scanlines() const
721
// calculate the current scanline
722
uInt32 totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
723
return totalClocks/228;
726
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
727
uInt32 TIA::clocksThisLine() const
729
// calculate the current scanline
730
uInt32 totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted;
731
return totalClocks%228;
734
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
735
void TIA::setSound(Sound& sound)
740
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
741
void TIA::computeBallMaskTable()
743
// First, calculate masks for alignment 0
744
for(Int32 size = 0; size < 4; ++size)
748
// Set all of the masks to false to start with
749
for(x = 0; x < 160; ++x)
751
ourBallMaskTable[0][size][x] = false;
754
// Set the necessary fields true
755
for(x = 0; x < 160 + 8; ++x)
757
if((x >= 0) && (x < (1 << size)))
759
ourBallMaskTable[0][size][x % 160] = true;
763
// Copy fields into the wrap-around area of the mask
764
for(x = 0; x < 160; ++x)
766
ourBallMaskTable[0][size][x + 160] = ourBallMaskTable[0][size][x];
770
// Now, copy data for alignments of 1, 2 and 3
771
for(uInt32 align = 1; align < 4; ++align)
773
for(uInt32 size = 0; size < 4; ++size)
775
for(uInt32 x = 0; x < 320; ++x)
777
ourBallMaskTable[align][size][x] =
778
ourBallMaskTable[0][size][(x + 320 - align) % 320];
784
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
785
void TIA::computeCollisionTable()
787
for(uInt8 i = 0; i < 64; ++i)
789
ourCollisionTable[i] = 0;
791
if((i & myM0Bit) && (i & myP1Bit)) // M0-P1
792
ourCollisionTable[i] |= 0x0001;
794
if((i & myM0Bit) && (i & myP0Bit)) // M0-P0
795
ourCollisionTable[i] |= 0x0002;
797
if((i & myM1Bit) && (i & myP0Bit)) // M1-P0
798
ourCollisionTable[i] |= 0x0004;
800
if((i & myM1Bit) && (i & myP1Bit)) // M1-P1
801
ourCollisionTable[i] |= 0x0008;
803
if((i & myP0Bit) && (i & myPFBit)) // P0-PF
804
ourCollisionTable[i] |= 0x0010;
806
if((i & myP0Bit) && (i & myBLBit)) // P0-BL
807
ourCollisionTable[i] |= 0x0020;
809
if((i & myP1Bit) && (i & myPFBit)) // P1-PF
810
ourCollisionTable[i] |= 0x0040;
812
if((i & myP1Bit) && (i & myBLBit)) // P1-BL
813
ourCollisionTable[i] |= 0x0080;
815
if((i & myM0Bit) && (i & myPFBit)) // M0-PF
816
ourCollisionTable[i] |= 0x0100;
818
if((i & myM0Bit) && (i & myBLBit)) // M0-BL
819
ourCollisionTable[i] |= 0x0200;
821
if((i & myM1Bit) && (i & myPFBit)) // M1-PF
822
ourCollisionTable[i] |= 0x0400;
824
if((i & myM1Bit) && (i & myBLBit)) // M1-BL
825
ourCollisionTable[i] |= 0x0800;
827
if((i & myBLBit) && (i & myPFBit)) // BL-PF
828
ourCollisionTable[i] |= 0x1000;
830
if((i & myP0Bit) && (i & myP1Bit)) // P0-P1
831
ourCollisionTable[i] |= 0x2000;
833
if((i & myM0Bit) && (i & myM1Bit)) // M0-M1
834
ourCollisionTable[i] |= 0x4000;
838
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
839
void TIA::computeMissleMaskTable()
841
// First, calculate masks for alignment 0
842
Int32 x, size, number;
844
// Clear the missle table to start with
845
for(number = 0; number < 8; ++number)
846
for(size = 0; size < 4; ++size)
847
for(x = 0; x < 160; ++x)
848
ourMissleMaskTable[0][number][size][x] = false;
850
for(number = 0; number < 8; ++number)
852
for(size = 0; size < 4; ++size)
854
for(x = 0; x < 160 + 72; ++x)
856
// Only one copy of the missle
857
if((number == 0x00) || (number == 0x05) || (number == 0x07))
859
if((x >= 0) && (x < (1 << size)))
860
ourMissleMaskTable[0][number][size][x % 160] = true;
862
// Two copies - close
863
else if(number == 0x01)
865
if((x >= 0) && (x < (1 << size)))
866
ourMissleMaskTable[0][number][size][x % 160] = true;
867
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
868
ourMissleMaskTable[0][number][size][x % 160] = true;
870
// Two copies - medium
871
else if(number == 0x02)
873
if((x >= 0) && (x < (1 << size)))
874
ourMissleMaskTable[0][number][size][x % 160] = true;
875
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
876
ourMissleMaskTable[0][number][size][x % 160] = true;
878
// Three copies - close
879
else if(number == 0x03)
881
if((x >= 0) && (x < (1 << size)))
882
ourMissleMaskTable[0][number][size][x % 160] = true;
883
else if(((x - 16) >= 0) && ((x - 16) < (1 << size)))
884
ourMissleMaskTable[0][number][size][x % 160] = true;
885
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
886
ourMissleMaskTable[0][number][size][x % 160] = true;
889
else if(number == 0x04)
891
if((x >= 0) && (x < (1 << size)))
892
ourMissleMaskTable[0][number][size][x % 160] = true;
893
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
894
ourMissleMaskTable[0][number][size][x % 160] = true;
896
// Three copies - medium
897
else if(number == 0x06)
899
if((x >= 0) && (x < (1 << size)))
900
ourMissleMaskTable[0][number][size][x % 160] = true;
901
else if(((x - 32) >= 0) && ((x - 32) < (1 << size)))
902
ourMissleMaskTable[0][number][size][x % 160] = true;
903
else if(((x - 64) >= 0) && ((x - 64) < (1 << size)))
904
ourMissleMaskTable[0][number][size][x % 160] = true;
908
// Copy data into wrap-around area
909
for(x = 0; x < 160; ++x)
910
ourMissleMaskTable[0][number][size][x + 160] =
911
ourMissleMaskTable[0][number][size][x];
915
// Now, copy data for alignments of 1, 2 and 3
916
for(uInt32 align = 1; align < 4; ++align)
918
for(number = 0; number < 8; ++number)
920
for(size = 0; size < 4; ++size)
922
for(x = 0; x < 320; ++x)
924
ourMissleMaskTable[align][number][size][x] =
925
ourMissleMaskTable[0][number][size][(x + 320 - align) % 320];
932
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
933
void TIA::computePlayerMaskTable()
935
// First, calculate masks for alignment 0
936
Int32 x, enable, mode;
938
// Set the player mask table to all zeros
939
for(enable = 0; enable < 2; ++enable)
940
for(mode = 0; mode < 8; ++mode)
941
for(x = 0; x < 160; ++x)
942
ourPlayerMaskTable[0][enable][mode][x] = 0x00;
944
// Now, compute the player mask table
945
for(enable = 0; enable < 2; ++enable)
947
for(mode = 0; mode < 8; ++mode)
949
for(x = 0; x < 160 + 72; ++x)
953
if((enable == 0) && (x >= 0) && (x < 8))
954
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
956
else if(mode == 0x01)
958
if((enable == 0) && (x >= 0) && (x < 8))
959
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
960
else if(((x - 16) >= 0) && ((x - 16) < 8))
961
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 16);
963
else if(mode == 0x02)
965
if((enable == 0) && (x >= 0) && (x < 8))
966
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
967
else if(((x - 32) >= 0) && ((x - 32) < 8))
968
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
970
else if(mode == 0x03)
972
if((enable == 0) && (x >= 0) && (x < 8))
973
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
974
else if(((x - 16) >= 0) && ((x - 16) < 8))
975
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 16);
976
else if(((x - 32) >= 0) && ((x - 32) < 8))
977
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
979
else if(mode == 0x04)
981
if((enable == 0) && (x >= 0) && (x < 8))
982
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
983
else if(((x - 64) >= 0) && ((x - 64) < 8))
984
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 64);
986
else if(mode == 0x05)
988
// For some reason in double size mode the player's output
989
// is delayed by one pixel thus we use > instead of >=
990
if((enable == 0) && (x > 0) && (x <= 16))
991
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> ((x - 1)/2);
993
else if(mode == 0x06)
995
if((enable == 0) && (x >= 0) && (x < 8))
996
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> x;
997
else if(((x - 32) >= 0) && ((x - 32) < 8))
998
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 32);
999
else if(((x - 64) >= 0) && ((x - 64) < 8))
1000
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> (x - 64);
1002
else if(mode == 0x07)
1004
// For some reason in quad size mode the player's output
1005
// is delayed by one pixel thus we use > instead of >=
1006
if((enable == 0) && (x > 0) && (x <= 32))
1007
ourPlayerMaskTable[0][enable][mode][x % 160] = 0x80 >> ((x - 1)/4);
1011
// Copy data into wrap-around area
1012
for(x = 0; x < 160; ++x)
1014
ourPlayerMaskTable[0][enable][mode][x + 160] =
1015
ourPlayerMaskTable[0][enable][mode][x];
1020
// Now, copy data for alignments of 1, 2 and 3
1021
for(uInt32 align = 1; align < 4; ++align)
1023
for(enable = 0; enable < 2; ++enable)
1025
for(mode = 0; mode < 8; ++mode)
1027
for(x = 0; x < 320; ++x)
1029
ourPlayerMaskTable[align][enable][mode][x] =
1030
ourPlayerMaskTable[0][enable][mode][(x + 320 - align) % 320];
1037
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1038
void TIA::computePlayerPositionResetWhenTable()
1040
uInt32 mode, oldx, newx;
1042
// Loop through all player modes, all old player positions, and all new
1043
// player positions and determine where the new position is located:
1044
// 1 means the new position is within the display of an old copy of the
1045
// player, -1 means the new position is within the delay portion of an
1046
// old copy of the player, and 0 means it's neither of these two
1047
for(mode = 0; mode < 8; ++mode)
1049
for(oldx = 0; oldx < 160; ++oldx)
1051
// Set everything to 0 for non-delay/non-display section
1052
for(newx = 0; newx < 160; ++newx)
1054
ourPlayerPositionResetWhenTable[mode][oldx][newx] = 0;
1057
// Now, we'll set the entries for non-delay/non-display section
1058
for(newx = 0; newx < 160 + 72 + 5; ++newx)
1062
if((newx >= oldx) && (newx < (oldx + 4)))
1063
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1065
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
1066
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1068
else if(mode == 0x01)
1070
if((newx >= oldx) && (newx < (oldx + 4)))
1071
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1072
else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4)))
1073
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1075
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
1076
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1077
else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8)))
1078
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1080
else if(mode == 0x02)
1082
if((newx >= oldx) && (newx < (oldx + 4)))
1083
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1084
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
1085
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1087
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
1088
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1089
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
1090
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1092
else if(mode == 0x03)
1094
if((newx >= oldx) && (newx < (oldx + 4)))
1095
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1096
else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4)))
1097
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1098
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
1099
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1101
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
1102
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1103
else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8)))
1104
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1105
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
1106
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1108
else if(mode == 0x04)
1110
if((newx >= oldx) && (newx < (oldx + 4)))
1111
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1112
else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4)))
1113
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1115
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
1116
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1117
else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8)))
1118
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1120
else if(mode == 0x05)
1122
if((newx >= oldx) && (newx < (oldx + 4)))
1123
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1125
if((newx >= oldx + 4) && (newx < (oldx + 4 + 16)))
1126
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1128
else if(mode == 0x06)
1130
if((newx >= oldx) && (newx < (oldx + 4)))
1131
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1132
else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4)))
1133
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1134
else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4)))
1135
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1137
if((newx >= oldx + 4) && (newx < (oldx + 4 + 8)))
1138
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1139
else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8)))
1140
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1141
else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8)))
1142
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1144
else if(mode == 0x07)
1146
if((newx >= oldx) && (newx < (oldx + 4)))
1147
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = -1;
1149
if((newx >= oldx + 4) && (newx < (oldx + 4 + 32)))
1150
ourPlayerPositionResetWhenTable[mode][oldx][newx % 160] = 1;
1154
// Let's do a sanity check on our table entries
1155
uInt32 s1 = 0, s2 = 0;
1156
for(newx = 0; newx < 160; ++newx)
1158
if(ourPlayerPositionResetWhenTable[mode][oldx][newx] == -1)
1160
if(ourPlayerPositionResetWhenTable[mode][oldx][newx] == 1)
1163
assert((s1 % 4 == 0) && (s2 % 8 == 0));
1168
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1169
void TIA::computePlayerReflectTable()
1171
for(uInt16 i = 0; i < 256; ++i)
1175
for(uInt16 t = 1; t <= 128; t *= 2)
1177
r = (r << 1) | ((i & t) ? 0x01 : 0x00);
1180
ourPlayerReflectTable[i] = r;
1184
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1185
void TIA::computePlayfieldMaskTable()
1189
// Compute playfield mask table for non-reflected mode
1190
for(x = 0; x < 160; ++x)
1193
ourPlayfieldTable[0][x] = 0x00001 << (x / 4);
1195
ourPlayfieldTable[0][x] = 0x00800 >> ((x - 16) / 4);
1197
ourPlayfieldTable[0][x] = 0x01000 << ((x - 48) / 4);
1199
ourPlayfieldTable[0][x] = 0x00001 << ((x - 80) / 4);
1201
ourPlayfieldTable[0][x] = 0x00800 >> ((x - 96) / 4);
1203
ourPlayfieldTable[0][x] = 0x01000 << ((x - 128) / 4);
1206
// Compute playfield mask table for reflected mode
1207
for(x = 0; x < 160; ++x)
1210
ourPlayfieldTable[1][x] = 0x00001 << (x / 4);
1212
ourPlayfieldTable[1][x] = 0x00800 >> ((x - 16) / 4);
1214
ourPlayfieldTable[1][x] = 0x01000 << ((x - 48) / 4);
1216
ourPlayfieldTable[1][x] = 0x80000 >> ((x - 80) / 4);
1218
ourPlayfieldTable[1][x] = 0x00010 << ((x - 112) / 4);
1220
ourPlayfieldTable[1][x] = 0x00008 >> ((x - 144) / 4);
1224
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1225
inline void TIA::updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos)
1227
// Calculate the ending frame pointer value
1228
uInt8* ending = myFramePointer + clocksToUpdate;
1230
// See if we're in the vertical blank region
1233
memset(myFramePointer, 0, clocksToUpdate);
1235
// Handle all other possible combinations
1238
switch(myEnabledObjects | myPlayfieldPriorityAndScore)
1242
case 0x00 | ScoreBit:
1243
case 0x00 | PriorityBit:
1244
case 0x00 | PriorityBit | ScoreBit:
1246
memset(myFramePointer, myCOLUBK, clocksToUpdate);
1250
// Playfield is enabled and the score bit is not set
1252
case myPFBit | PriorityBit:
1254
uInt32* mask = &myCurrentPFMask[hpos];
1256
// Update a uInt8 at a time until reaching a uInt32 boundary
1257
for(; ((uintptr_t)myFramePointer & 0x03) && (myFramePointer < ending);
1258
++myFramePointer, ++mask)
1260
*myFramePointer = (myPF & *mask) ? myCOLUPF : myCOLUBK;
1263
// Now, update a uInt32 at a time
1264
for(; myFramePointer < ending; myFramePointer += 4, mask += 4)
1266
*((uInt32*)myFramePointer) = (myPF & *mask) ? myCOLUPF : myCOLUBK;
1271
// Playfield is enabled and the score bit is set
1272
case myPFBit | ScoreBit:
1273
case myPFBit | ScoreBit | PriorityBit:
1275
uInt32* mask = &myCurrentPFMask[hpos];
1277
// Update a uInt8 at a time until reaching a uInt32 boundary
1278
for(; ((uintptr_t)myFramePointer & 0x03) && (myFramePointer < ending);
1279
++myFramePointer, ++mask, ++hpos)
1281
*myFramePointer = (myPF & *mask) ?
1282
(hpos < 80 ? myCOLUP0 : myCOLUP1) : myCOLUBK;
1285
// Now, update a uInt32 at a time
1286
for(; myFramePointer < ending;
1287
myFramePointer += 4, mask += 4, hpos += 4)
1289
*((uInt32*)myFramePointer) = (myPF & *mask) ?
1290
(hpos < 80 ? myCOLUP0 : myCOLUP1) : myCOLUBK;
1295
// Player 0 is enabled
1297
case myP0Bit | ScoreBit:
1298
case myP0Bit | PriorityBit:
1299
case myP0Bit | ScoreBit | PriorityBit:
1301
uInt8* mP0 = &myCurrentP0Mask[hpos];
1303
while(myFramePointer < ending)
1305
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
1307
*(uInt32*)myFramePointer = myCOLUBK;
1308
mP0 += 4; myFramePointer += 4;
1312
*myFramePointer = (myCurrentGRP0 & *mP0) ? myCOLUP0 : myCOLUBK;
1313
++mP0; ++myFramePointer;
1319
// Player 1 is enabled
1321
case myP1Bit | ScoreBit:
1322
case myP1Bit | PriorityBit:
1323
case myP1Bit | ScoreBit | PriorityBit:
1325
uInt8* mP1 = &myCurrentP1Mask[hpos];
1327
while(myFramePointer < ending)
1329
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
1331
*(uInt32*)myFramePointer = myCOLUBK;
1332
mP1 += 4; myFramePointer += 4;
1336
*myFramePointer = (myCurrentGRP1 & *mP1) ? myCOLUP1 : myCOLUBK;
1337
++mP1; ++myFramePointer;
1343
// Player 0 and 1 are enabled
1344
case myP0Bit | myP1Bit:
1345
case myP0Bit | myP1Bit | ScoreBit:
1346
case myP0Bit | myP1Bit | PriorityBit:
1347
case myP0Bit | myP1Bit | ScoreBit | PriorityBit:
1349
uInt8* mP0 = &myCurrentP0Mask[hpos];
1350
uInt8* mP1 = &myCurrentP1Mask[hpos];
1352
while(myFramePointer < ending)
1354
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0 &&
1357
*(uInt32*)myFramePointer = myCOLUBK;
1358
mP0 += 4; mP1 += 4; myFramePointer += 4;
1362
*myFramePointer = (myCurrentGRP0 & *mP0) ?
1363
myCOLUP0 : ((myCurrentGRP1 & *mP1) ? myCOLUP1 : myCOLUBK);
1365
if((myCurrentGRP0 & *mP0) && (myCurrentGRP1 & *mP1))
1366
myCollision |= ourCollisionTable[myP0Bit | myP1Bit];
1368
++mP0; ++mP1; ++myFramePointer;
1374
// Missle 0 is enabled
1376
case myM0Bit | ScoreBit:
1377
case myM0Bit | PriorityBit:
1378
case myM0Bit | ScoreBit | PriorityBit:
1380
uInt8* mM0 = &myCurrentM0Mask[hpos];
1382
while(myFramePointer < ending)
1384
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM0)
1386
*(uInt32*)myFramePointer = myCOLUBK;
1387
mM0 += 4; myFramePointer += 4;
1391
*myFramePointer = *mM0 ? myCOLUP0 : myCOLUBK;
1392
++mM0; ++myFramePointer;
1398
// Missle 1 is enabled
1400
case myM1Bit | ScoreBit:
1401
case myM1Bit | PriorityBit:
1402
case myM1Bit | ScoreBit | PriorityBit:
1404
uInt8* mM1 = &myCurrentM1Mask[hpos];
1406
while(myFramePointer < ending)
1408
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM1)
1410
*(uInt32*)myFramePointer = myCOLUBK;
1411
mM1 += 4; myFramePointer += 4;
1415
*myFramePointer = *mM1 ? myCOLUP1 : myCOLUBK;
1416
++mM1; ++myFramePointer;
1424
case myBLBit | ScoreBit:
1425
case myBLBit | PriorityBit:
1426
case myBLBit | ScoreBit | PriorityBit:
1428
uInt8* mBL = &myCurrentBLMask[hpos];
1430
while(myFramePointer < ending)
1432
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL)
1434
*(uInt32*)myFramePointer = myCOLUBK;
1435
mBL += 4; myFramePointer += 4;
1439
*myFramePointer = *mBL ? myCOLUPF : myCOLUBK;
1440
++mBL; ++myFramePointer;
1446
// Missle 0 and 1 are enabled
1447
case myM0Bit | myM1Bit:
1448
case myM0Bit | myM1Bit | ScoreBit:
1449
case myM0Bit | myM1Bit | PriorityBit:
1450
case myM0Bit | myM1Bit | ScoreBit | PriorityBit:
1452
uInt8* mM0 = &myCurrentM0Mask[hpos];
1453
uInt8* mM1 = &myCurrentM1Mask[hpos];
1455
while(myFramePointer < ending)
1457
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mM0 && !*(uInt32*)mM1)
1459
*(uInt32*)myFramePointer = myCOLUBK;
1460
mM0 += 4; mM1 += 4; myFramePointer += 4;
1464
*myFramePointer = *mM0 ? myCOLUP0 : (*mM1 ? myCOLUP1 : myCOLUBK);
1467
myCollision |= ourCollisionTable[myM0Bit | myM1Bit];
1469
++mM0; ++mM1; ++myFramePointer;
1475
// Ball and Missle 0 are enabled and playfield priority is not set
1476
case myBLBit | myM0Bit:
1477
case myBLBit | myM0Bit | ScoreBit:
1479
uInt8* mBL = &myCurrentBLMask[hpos];
1480
uInt8* mM0 = &myCurrentM0Mask[hpos];
1482
while(myFramePointer < ending)
1484
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL && !*(uInt32*)mM0)
1486
*(uInt32*)myFramePointer = myCOLUBK;
1487
mBL += 4; mM0 += 4; myFramePointer += 4;
1491
*myFramePointer = (*mM0 ? myCOLUP0 : (*mBL ? myCOLUPF : myCOLUBK));
1494
myCollision |= ourCollisionTable[myBLBit | myM0Bit];
1496
++mBL; ++mM0; ++myFramePointer;
1502
// Ball and Missle 0 are enabled and playfield priority is set
1503
case myBLBit | myM0Bit | PriorityBit:
1504
case myBLBit | myM0Bit | ScoreBit | PriorityBit:
1506
uInt8* mBL = &myCurrentBLMask[hpos];
1507
uInt8* mM0 = &myCurrentM0Mask[hpos];
1509
while(myFramePointer < ending)
1511
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL && !*(uInt32*)mM0)
1513
*(uInt32*)myFramePointer = myCOLUBK;
1514
mBL += 4; mM0 += 4; myFramePointer += 4;
1518
*myFramePointer = (*mBL ? myCOLUPF : (*mM0 ? myCOLUP0 : myCOLUBK));
1521
myCollision |= ourCollisionTable[myBLBit | myM0Bit];
1523
++mBL; ++mM0; ++myFramePointer;
1529
// Ball and Missle 1 are enabled and playfield priority is not set
1530
case myBLBit | myM1Bit:
1531
case myBLBit | myM1Bit | ScoreBit:
1533
uInt8* mBL = &myCurrentBLMask[hpos];
1534
uInt8* mM1 = &myCurrentM1Mask[hpos];
1536
while(myFramePointer < ending)
1538
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL &&
1541
*(uInt32*)myFramePointer = myCOLUBK;
1542
mBL += 4; mM1 += 4; myFramePointer += 4;
1546
*myFramePointer = (*mM1 ? myCOLUP1 : (*mBL ? myCOLUPF : myCOLUBK));
1549
myCollision |= ourCollisionTable[myBLBit | myM1Bit];
1551
++mBL; ++mM1; ++myFramePointer;
1557
// Ball and Missle 1 are enabled and playfield priority is set
1558
case myBLBit | myM1Bit | PriorityBit:
1559
case myBLBit | myM1Bit | ScoreBit | PriorityBit:
1561
uInt8* mBL = &myCurrentBLMask[hpos];
1562
uInt8* mM1 = &myCurrentM1Mask[hpos];
1564
while(myFramePointer < ending)
1566
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL &&
1569
*(uInt32*)myFramePointer = myCOLUBK;
1570
mBL += 4; mM1 += 4; myFramePointer += 4;
1574
*myFramePointer = (*mBL ? myCOLUPF : (*mM1 ? myCOLUP1 : myCOLUBK));
1577
myCollision |= ourCollisionTable[myBLBit | myM1Bit];
1579
++mBL; ++mM1; ++myFramePointer;
1585
// Ball and Player 1 are enabled and playfield priority is not set
1586
case myBLBit | myP1Bit:
1587
case myBLBit | myP1Bit | ScoreBit:
1589
uInt8* mBL = &myCurrentBLMask[hpos];
1590
uInt8* mP1 = &myCurrentP1Mask[hpos];
1592
while(myFramePointer < ending)
1594
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1 && !*(uInt32*)mBL)
1596
*(uInt32*)myFramePointer = myCOLUBK;
1597
mBL += 4; mP1 += 4; myFramePointer += 4;
1601
*myFramePointer = (myCurrentGRP1 & *mP1) ? myCOLUP1 :
1602
(*mBL ? myCOLUPF : myCOLUBK);
1604
if(*mBL && (myCurrentGRP1 & *mP1))
1605
myCollision |= ourCollisionTable[myBLBit | myP1Bit];
1607
++mBL; ++mP1; ++myFramePointer;
1613
// Ball and Player 1 are enabled and playfield priority is set
1614
case myBLBit | myP1Bit | PriorityBit:
1615
case myBLBit | myP1Bit | PriorityBit | ScoreBit:
1617
uInt8* mBL = &myCurrentBLMask[hpos];
1618
uInt8* mP1 = &myCurrentP1Mask[hpos];
1620
while(myFramePointer < ending)
1622
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1 && !*(uInt32*)mBL)
1624
*(uInt32*)myFramePointer = myCOLUBK;
1625
mBL += 4; mP1 += 4; myFramePointer += 4;
1629
*myFramePointer = *mBL ? myCOLUPF :
1630
((myCurrentGRP1 & *mP1) ? myCOLUP1 : myCOLUBK);
1632
if(*mBL && (myCurrentGRP1 & *mP1))
1633
myCollision |= ourCollisionTable[myBLBit | myP1Bit];
1635
++mBL; ++mP1; ++myFramePointer;
1641
// Playfield and Player 0 are enabled and playfield priority is not set
1642
case myPFBit | myP0Bit:
1644
uInt32* mPF = &myCurrentPFMask[hpos];
1645
uInt8* mP0 = &myCurrentP0Mask[hpos];
1647
while(myFramePointer < ending)
1649
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
1651
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
1652
mPF += 4; mP0 += 4; myFramePointer += 4;
1656
*myFramePointer = (myCurrentGRP0 & *mP0) ?
1657
myCOLUP0 : ((myPF & *mPF) ? myCOLUPF : myCOLUBK);
1659
if((myPF & *mPF) && (myCurrentGRP0 & *mP0))
1660
myCollision |= ourCollisionTable[myPFBit | myP0Bit];
1662
++mPF; ++mP0; ++myFramePointer;
1669
// Playfield and Player 0 are enabled and playfield priority is set
1670
case myPFBit | myP0Bit | PriorityBit:
1672
uInt32* mPF = &myCurrentPFMask[hpos];
1673
uInt8* mP0 = &myCurrentP0Mask[hpos];
1675
while(myFramePointer < ending)
1677
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP0)
1679
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
1680
mPF += 4; mP0 += 4; myFramePointer += 4;
1684
*myFramePointer = (myPF & *mPF) ? myCOLUPF :
1685
((myCurrentGRP0 & *mP0) ? myCOLUP0 : myCOLUBK);
1687
if((myPF & *mPF) && (myCurrentGRP0 & *mP0))
1688
myCollision |= ourCollisionTable[myPFBit | myP0Bit];
1690
++mPF; ++mP0; ++myFramePointer;
1697
// Playfield and Player 1 are enabled and playfield priority is not set
1698
case myPFBit | myP1Bit:
1700
uInt32* mPF = &myCurrentPFMask[hpos];
1701
uInt8* mP1 = &myCurrentP1Mask[hpos];
1703
while(myFramePointer < ending)
1705
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
1707
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
1708
mPF += 4; mP1 += 4; myFramePointer += 4;
1712
*myFramePointer = (myCurrentGRP1 & *mP1) ?
1713
myCOLUP1 : ((myPF & *mPF) ? myCOLUPF : myCOLUBK);
1715
if((myPF & *mPF) && (myCurrentGRP1 & *mP1))
1716
myCollision |= ourCollisionTable[myPFBit | myP1Bit];
1718
++mPF; ++mP1; ++myFramePointer;
1725
// Playfield and Player 1 are enabled and playfield priority is set
1726
case myPFBit | myP1Bit | PriorityBit:
1728
uInt32* mPF = &myCurrentPFMask[hpos];
1729
uInt8* mP1 = &myCurrentP1Mask[hpos];
1731
while(myFramePointer < ending)
1733
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mP1)
1735
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
1736
mPF += 4; mP1 += 4; myFramePointer += 4;
1740
*myFramePointer = (myPF & *mPF) ? myCOLUPF :
1741
((myCurrentGRP1 & *mP1) ? myCOLUP1 : myCOLUBK);
1743
if((myPF & *mPF) && (myCurrentGRP1 & *mP1))
1744
myCollision |= ourCollisionTable[myPFBit | myP1Bit];
1746
++mPF; ++mP1; ++myFramePointer;
1753
// Playfield and Ball are enabled
1754
case myPFBit | myBLBit:
1755
case myPFBit | myBLBit | PriorityBit:
1757
uInt32* mPF = &myCurrentPFMask[hpos];
1758
uInt8* mBL = &myCurrentBLMask[hpos];
1760
while(myFramePointer < ending)
1762
if(!((uintptr_t)myFramePointer & 0x03) && !*(uInt32*)mBL)
1764
*(uInt32*)myFramePointer = (myPF & *mPF) ? myCOLUPF : myCOLUBK;
1765
mPF += 4; mBL += 4; myFramePointer += 4;
1769
*myFramePointer = ((myPF & *mPF) || *mBL) ? myCOLUPF : myCOLUBK;
1771
if((myPF & *mPF) && *mBL)
1772
myCollision |= ourCollisionTable[myPFBit | myBLBit];
1774
++mPF; ++mBL; ++myFramePointer;
1780
// Handle all of the other cases
1783
for(; myFramePointer < ending; ++myFramePointer, ++hpos)
1785
uInt8 enabled = (myPF & myCurrentPFMask[hpos]) ? myPFBit : 0;
1787
if((myEnabledObjects & myBLBit) && myCurrentBLMask[hpos])
1790
if(myCurrentGRP1 & myCurrentP1Mask[hpos])
1793
if((myEnabledObjects & myM1Bit) && myCurrentM1Mask[hpos])
1796
if(myCurrentGRP0 & myCurrentP0Mask[hpos])
1799
if((myEnabledObjects & myM0Bit) && myCurrentM0Mask[hpos])
1802
myCollision |= ourCollisionTable[enabled];
1803
*myFramePointer = myColor[myPriorityEncoder[hpos < 80 ? 0 : 1]
1804
[enabled | myPlayfieldPriorityAndScore]];
1810
myFramePointer = ending;
1813
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1814
inline void TIA::updateFrame(Int32 clock)
1816
// See if we're in the nondisplayable portion of the screen or if
1817
// we've already updated this portion of the screen
1818
if((clock < myClockStartDisplay) ||
1819
(myClockAtLastUpdate >= myClockStopDisplay) ||
1820
(myClockAtLastUpdate >= clock))
878
void TIA::updateFrame(Int32 clock)
880
// See if we've already updated this portion of the screen
881
if((clock < myClockStartDisplay) ||
882
(myClockAtLastUpdate >= myClockStopDisplay) ||
883
(myClockAtLastUpdate >= clock))
1825
886
// Truncate the number of cycles to update to the stop display point
1826
887
if(clock > myClockStopDisplay)
1828
888
clock = myClockStopDisplay;
890
// Determine how many scanlines to process
891
// It's easier to think about this in scanlines rather than color clocks
892
uInt32 startLine = (myClockAtLastUpdate - myClockWhenFrameStarted) / 228;
893
uInt32 endLine = (clock - myClockWhenFrameStarted) / 228;
1831
895
// Update frame one scanline at a time
896
for(uInt32 line = startLine; line <= endLine; ++line)
898
// Only check for inter-line changes after the current scanline
899
// The ideas for much of the following code was inspired by MESS
900
// (used with permission from Wilbert Pol)
901
if(line != startLine)
903
// We're no longer concerned with previously issued HMOVE's
904
myPreviousHMOVEPos = 0x7FFFFFFF;
905
bool posChanged = false;
907
// Apply pending motion clocks from a HMOVE initiated during the scanline
908
if(myCurrentHMOVEPos != 0x7FFFFFFF)
910
if(myCurrentHMOVEPos >= 97 && myCurrentHMOVEPos < 157)
912
myPOSP0 -= myMotionClockP0;
913
myPOSP1 -= myMotionClockP1;
914
myPOSM0 -= myMotionClockM0;
915
myPOSM1 -= myMotionClockM1;
916
myPOSBL -= myMotionClockBL;
917
myPreviousHMOVEPos = myCurrentHMOVEPos;
920
// Indicate that the HMOVE has been completed
921
myCurrentHMOVEPos = 0x7FFFFFFF;
923
#ifdef USE_MMR_LATCHES
924
// Apply extra clocks for 'more motion required/mmr'
925
if(myHMP0mmr) { myPOSP0 -= 17; posChanged = true; }
926
if(myHMP1mmr) { myPOSP1 -= 17; posChanged = true; }
927
if(myHMM0mmr) { myPOSM0 -= 17; posChanged = true; }
928
if(myHMM1mmr) { myPOSM1 -= 17; posChanged = true; }
929
if(myHMBLmmr) { myPOSBL -= 17; posChanged = true; }
931
// Make sure positions are in range
934
if(myPOSP0 < 0) { myPOSP0 += 160; } myPOSP0 %= 160;
935
if(myPOSP1 < 0) { myPOSP1 += 160; } myPOSP1 %= 160;
936
if(myPOSM0 < 0) { myPOSM0 += 160; } myPOSM0 %= 160;
937
if(myPOSM1 < 0) { myPOSM1 += 160; } myPOSM1 %= 160;
938
if(myPOSBL < 0) { myPOSBL += 160; } myPOSBL %= 160;
1834
942
// Compute the number of clocks we're going to update
1835
943
Int32 clocksToUpdate = 0;
2327
1425
// Update the playfield mask based on reflection state if
2328
1426
// we're still on the left hand side of the playfield
2329
1427
if(((clock - myClockWhenFrameStarted) % 228) < (68 + 79))
2331
myCurrentPFMask = ourPlayfieldTable[myCTRLPF & 0x01];
2334
myCurrentBLMask = &ourBallMaskTable[myPOSBL & 0x03]
2335
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
1428
myCurrentPFMask = TIATables::PFMask[myCTRLPF & 0x01];
2340
case 0x0B: // Reflect Player 0
1433
case REFP0: // Reflect Player 0
2342
1435
// See if the reflection state of the player is being changed
2343
1436
if(((value & 0x08) && !myREFP0) || (!(value & 0x08) && myREFP0))
2345
1438
myREFP0 = (value & 0x08);
2346
myCurrentGRP0 = ourPlayerReflectTable[myCurrentGRP0];
1439
myCurrentGRP0 = TIATables::GRPReflect[myCurrentGRP0];
2351
case 0x0C: // Reflect Player 1
1444
case REFP1: // Reflect Player 1
2353
1446
// See if the reflection state of the player is being changed
2354
1447
if(((value & 0x08) && !myREFP1) || (!(value & 0x08) && myREFP1))
2356
1449
myREFP1 = (value & 0x08);
2357
myCurrentGRP1 = ourPlayerReflectTable[myCurrentGRP1];
1450
myCurrentGRP1 = TIATables::GRPReflect[myCurrentGRP1];
2362
case 0x0D: // Playfield register byte 0
1455
case PF0: // Playfield register byte 0
2364
1457
myPF = (myPF & 0x000FFFF0) | ((value >> 4) & 0x0F);
2366
if(!myBitEnabled[TIA::PF] || myPF == 0)
2367
myEnabledObjects &= ~myPFBit;
1460
myEnabledObjects &= ~PFBit;
2369
myEnabledObjects |= myPFBit;
1462
myEnabledObjects |= PFBit;
2374
case 0x0E: // Playfield register byte 1
1467
case PF1: // Playfield register byte 1
2376
1469
myPF = (myPF & 0x000FF00F) | ((uInt32)value << 4);
2378
if(!myBitEnabled[TIA::PF] || myPF == 0)
2379
myEnabledObjects &= ~myPFBit;
1472
myEnabledObjects &= ~PFBit;
2381
myEnabledObjects |= myPFBit;
1474
myEnabledObjects |= PFBit;
2386
case 0x0F: // Playfield register byte 2
1479
case PF2: // Playfield register byte 2
2388
1481
myPF = (myPF & 0x00000FFF) | ((uInt32)value << 12);
2390
if(!myBitEnabled[TIA::PF] || myPF == 0)
2391
myEnabledObjects &= ~myPFBit;
2393
myEnabledObjects |= myPFBit;
2398
case 0x10: // Reset Player 0
2400
Int32 hpos = (clock - myClockWhenFrameStarted) % 228;
2401
Int32 newx = hpos < HBLANK ? 3 : (((hpos - HBLANK) + 5) % 160);
2403
// Find out under what condition the player is being reset
2404
Int8 when = ourPlayerPositionResetWhenTable[myNUSIZ0 & 7][myPOSP0][newx];
2407
if((clock - myLastHMOVEClock) < (24 * 3))
2408
cerr << "Reset Player 0 within 24 cycles of HMOVE: "
2409
<< ((clock - myLastHMOVEClock)/3)
2410
<< " hpos: " << hpos << ", newx = " << newx << endl;
2413
// Player is being reset during the display of one of its copies
2416
// So we go ahead and update the display before moving the player
2417
// TODO: The 11 should depend on how much of the player has already
2418
// been displayed. Probably change table to return the amount to
2419
// delay by instead of just 1 (01/21/99).
2420
updateFrame(clock + 11);
2424
// Setup the mask to skip the first copy of the player
2425
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
2426
[1][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
2428
// Player is being reset in neither the delay nor display section
2433
// So we setup the mask to skip the first copy of the player
2434
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
2435
[1][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
2437
// Player is being reset during the delay section of one of its copies
2442
// So we setup the mask to display all copies of the player
2443
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
2444
[0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
2449
case 0x11: // Reset Player 1
2451
Int32 hpos = (clock - myClockWhenFrameStarted) % 228;
2452
Int32 newx = hpos < HBLANK ? 3 : (((hpos - HBLANK) + 5) % 160);
2454
// Find out under what condition the player is being reset
2455
Int8 when = ourPlayerPositionResetWhenTable[myNUSIZ1 & 7][myPOSP1][newx];
2458
if((clock - myLastHMOVEClock) < (24 * 3))
2459
cerr << "Reset Player 1 within 24 cycles of HMOVE: "
2460
<< ((clock - myLastHMOVEClock)/3)
2461
<< " hpos: " << hpos << ", newx = " << newx << endl;
2464
// Player is being reset during the display of one of its copies
2467
// So we go ahead and update the display before moving the player
2468
// TODO: The 11 should depend on how much of the player has already
2469
// been displayed. Probably change table to return the amount to
2470
// delay by instead of just 1 (01/21/99).
2471
updateFrame(clock + 11);
2475
// Setup the mask to skip the first copy of the player
2476
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
2477
[1][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
2479
// Player is being reset in neither the delay nor display section
2484
// So we setup the mask to skip the first copy of the player
2485
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
2486
[1][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
2488
// Player is being reset during the delay section of one of its copies
2493
// So we setup the mask to display all copies of the player
2494
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
2495
[0][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
2500
case 0x12: // Reset Missle 0
2502
int hpos = (clock - myClockWhenFrameStarted) % 228;
2503
myPOSM0 = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160);
2506
if((clock - myLastHMOVEClock) < (24 * 3))
2507
cerr << "Reset Missle 0 within 24 cycles of HMOVE: "
2508
<< ((clock - myLastHMOVEClock)/3)
2509
<< " hpos: " << hpos << ", myPOSM0 = " << myPOSM0 << endl;
2512
// TODO: Remove the following special hack for Dolphin by
2513
// figuring out what really happens when Reset Missle
2514
// occurs 20 cycles after an HMOVE (04/13/02).
2515
if(((clock - myLastHMOVEClock) == (20 * 3)) && (hpos == 69))
2519
// TODO: Remove the following special hack for Solaris by
2520
// figuring out what really happens when Reset Missle
2521
// occurs 9 cycles after an HMOVE (04/11/08).
2522
else if(((clock - myLastHMOVEClock) == (9 * 3)) && (hpos == 36))
2527
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
2528
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
2532
case 0x13: // Reset Missle 1
2534
int hpos = (clock - myClockWhenFrameStarted) % 228;
2535
myPOSM1 = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160);
2538
if((clock - myLastHMOVEClock) < (24 * 3))
2539
cerr << "Reset Missle 1 within 24 cycles of HMOVE: "
2540
<< ((clock - myLastHMOVEClock)/3)
2541
<< " hpos: " << hpos << ", myPOSM1 = " << myPOSM1 << endl;
2544
// TODO: Remove the following special hack for Pitfall II by
2545
// figuring out what really happens when Reset Missle
2546
// occurs 3 cycles after an HMOVE (04/13/02).
2547
if(((clock - myLastHMOVEClock) == (3 * 3)) && (hpos == 18))
2552
myCurrentM1Mask = &ourMissleMaskTable[myPOSM1 & 0x03]
2553
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
2557
case 0x14: // Reset Ball
2559
int hpos = (clock - myClockWhenFrameStarted) % 228 ;
2560
myPOSBL = hpos < HBLANK ? 2 : (((hpos - HBLANK) + 4) % 160);
2563
if((clock - myLastHMOVEClock) < (24 * 3))
2564
cerr << "Reset Ball within 24 cycles of HMOVE: "
2565
<< ((clock - myLastHMOVEClock)/3)
2566
<< " hpos: " << hpos << ", myPOSBL = " << myPOSBL << endl;
2569
// TODO: Remove the following special hack by figuring out what
2570
// really happens when Reset Ball occurs 18 cycles after an HMOVE.
2571
if((clock - myLastHMOVEClock) == (18 * 3))
2573
// Escape from the Mindmaster (01/09/99)
2574
if((hpos == 60) || (hpos == 69))
2576
// Mission Survive (04/11/08)
2580
// TODO: Remove the following special hack for Escape from the
2581
// Mindmaster by figuring out what really happens when Reset Ball
2582
// occurs 15 cycles after an HMOVE (04/11/08).
2583
else if(((clock - myLastHMOVEClock) == (15 * 3)) && (hpos == 60))
2587
// TODO: Remove the following special hack for Decathlon by
2588
// figuring out what really happens when Reset Ball
2589
// occurs 3 cycles after an HMOVE (04/13/02).
2590
else if(((clock - myLastHMOVEClock) == (3 * 3)) && (hpos == 18))
2594
// TODO: Remove the following special hack for Robot Tank by
2595
// figuring out what really happens when Reset Ball
2596
// occurs 7 cycles after an HMOVE (04/13/02).
2597
else if(((clock - myLastHMOVEClock) == (7 * 3)) && (hpos == 30))
2601
// TODO: Remove the following special hack for Hole Hunter by
2602
// figuring out what really happens when Reset Ball
2603
// occurs 6 cycles after an HMOVE (04/13/02).
2604
else if(((clock - myLastHMOVEClock) == (6 * 3)) && (hpos == 27))
2608
// TODO: Remove the following special hack for Swoops! by
2609
// figuring out what really happens when Reset Ball
2610
// occurs 9 cycles after an HMOVE (04/11/08).
2611
else if(((clock - myLastHMOVEClock) == (9 * 3)) && (hpos == 36))
2615
// TODO: Remove the following special hack for Solaris by
2616
// figuring out what really happens when Reset Ball
2617
// occurs 12 cycles after an HMOVE (04/11/08).
2618
else if(((clock - myLastHMOVEClock) == (12 * 3)) && (hpos == 45))
2623
myCurrentBLMask = &ourBallMaskTable[myPOSBL & 0x03]
2624
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
2628
case 0x15: // Audio control 0
1484
myEnabledObjects &= ~PFBit;
1486
myEnabledObjects |= PFBit;
1491
case RESP0: // Reset Player 0
1493
Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
1496
// Check if HMOVE is currently active
1497
if(myCurrentHMOVEPos != 0x7FFFFFFF)
1499
newx = hpos < 7 ? 3 : ((hpos + 5) % 160);
1500
// If HMOVE is active, adjust for any remaining horizontal move clocks
1501
applyActiveHMOVEMotion(hpos, newx, myMotionClockP0);
1505
newx = hpos < -2 ? 3 : ((hpos + 5) % 160);
1506
applyPreviousHMOVEMotion(hpos, newx, myHMP0);
1510
// Find out under what condition the player is being reset
1511
delay = TIATables::PxPosResetWhen[myNUSIZ0 & 7][myPOSP0][newx];
1515
// Player is being reset during the display of one of its copies
1517
// TODO - 08-20-2009: determine whether we really need to update
1518
// the frame here, and also come up with a way to eliminate the
1519
// 200KB PxPosResetWhen table.
1520
updateFrame(clock + 11);
1524
// Player is being reset in neither the delay nor display section
1529
// Player is being reset during the delay section of one of its copies
1539
case RESP1: // Reset Player 1
1541
Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
1544
// Check if HMOVE is currently active
1545
if(myCurrentHMOVEPos != 0x7FFFFFFF)
1547
newx = hpos < 7 ? 3 : ((hpos + 5) % 160);
1548
// If HMOVE is active, adjust for any remaining horizontal move clocks
1549
applyActiveHMOVEMotion(hpos, newx, myMotionClockP1);
1553
newx = hpos < -2 ? 3 : ((hpos + 5) % 160);
1554
applyPreviousHMOVEMotion(hpos, newx, myHMP1);
1558
// Find out under what condition the player is being reset
1559
delay = TIATables::PxPosResetWhen[myNUSIZ1 & 7][myPOSP1][newx];
1563
// Player is being reset during the display of one of its copies
1565
// TODO - 08-20-2009: determine whether we really need to update
1566
// the frame here, and also come up with a way to eliminate the
1567
// 200KB PxPosResetWhen table.
1568
updateFrame(clock + 11);
1572
// Player is being reset in neither the delay nor display section
1577
// Player is being reset during the delay section of one of its copies
1587
case RESM0: // Reset Missle 0
1589
Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
1592
// Check if HMOVE is currently active
1593
if(myCurrentHMOVEPos != 0x7FFFFFFF)
1595
newx = hpos < 7 ? 2 : ((hpos + 4) % 160);
1596
// If HMOVE is active, adjust for any remaining horizontal move clocks
1597
applyActiveHMOVEMotion(hpos, newx, myMotionClockM0);
1601
newx = hpos < -1 ? 2 : ((hpos + 4) % 160);
1602
applyPreviousHMOVEMotion(hpos, newx, myHMM0);
1611
case RESM1: // Reset Missle 1
1613
Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
1616
// Check if HMOVE is currently active
1617
if(myCurrentHMOVEPos != 0x7FFFFFFF)
1619
newx = hpos < 7 ? 2 : ((hpos + 4) % 160);
1620
// If HMOVE is active, adjust for any remaining horizontal move clocks
1621
applyActiveHMOVEMotion(hpos, newx, myMotionClockM1);
1625
newx = hpos < -1 ? 2 : ((hpos + 4) % 160);
1626
applyPreviousHMOVEMotion(hpos, newx, myHMM1);
1635
case RESBL: // Reset Ball
1637
Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
1639
// Check if HMOVE is currently active
1640
if(myCurrentHMOVEPos != 0x7FFFFFFF)
1642
myPOSBL = hpos < 7 ? 2 : ((hpos + 4) % 160);
1643
// If HMOVE is active, adjust for any remaining horizontal move clocks
1644
applyActiveHMOVEMotion(hpos, myPOSBL, myMotionClockBL);
1648
myPOSBL = hpos < 0 ? 2 : ((hpos + 4) % 160);
1649
applyPreviousHMOVEMotion(hpos, myPOSBL, myHMBL);
1654
case AUDC0: // Audio control 0
2630
1656
myAUDC0 = value & 0x0f;
2631
mySound->set(addr, value, mySystem->cycles());
1657
mySound.set(addr, value, mySystem->cycles());
2635
case 0x16: // Audio control 1
1661
case AUDC1: // Audio control 1
2637
1663
myAUDC1 = value & 0x0f;
2638
mySound->set(addr, value, mySystem->cycles());
1664
mySound.set(addr, value, mySystem->cycles());
2642
case 0x17: // Audio frequency 0
1668
case AUDF0: // Audio frequency 0
2644
1670
myAUDF0 = value & 0x1f;
2645
mySound->set(addr, value, mySystem->cycles());
1671
mySound.set(addr, value, mySystem->cycles());
2649
case 0x18: // Audio frequency 1
1675
case AUDF1: // Audio frequency 1
2651
1677
myAUDF1 = value & 0x1f;
2652
mySound->set(addr, value, mySystem->cycles());
1678
mySound.set(addr, value, mySystem->cycles());
2656
case 0x19: // Audio volume 0
1682
case AUDV0: // Audio volume 0
2658
1684
myAUDV0 = value & 0x0f;
2659
mySound->set(addr, value, mySystem->cycles());
1685
mySound.set(addr, value, mySystem->cycles());
2663
case 0x1A: // Audio volume 1
1689
case AUDV1: // Audio volume 1
2665
1691
myAUDV1 = value & 0x0f;
2666
mySound->set(addr, value, mySystem->cycles());
1692
mySound.set(addr, value, mySystem->cycles());
2670
case 0x1B: // Graphics Player 0
1696
case GRP0: // Graphics Player 0
2672
1698
// Set player 0 graphics
2673
myGRP0 = (myBitEnabled[TIA::P0] ? value : 0);
2675
1701
// Copy player 1 graphics into its delayed register
2676
1702
myDGRP1 = myGRP1;
2678
1704
// Get the "current" data for GRP0 base on delay register and reflect
2679
1705
uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0;
2680
myCurrentGRP0 = myREFP0 ? ourPlayerReflectTable[grp0] : grp0;
1706
myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0;
2682
1708
// Get the "current" data for GRP1 base on delay register and reflect
2683
1709
uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1;
2684
myCurrentGRP1 = myREFP1 ? ourPlayerReflectTable[grp1] : grp1;
1710
myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1;
2686
1712
// Set enabled object bits
2687
1713
if(myCurrentGRP0 != 0)
2688
myEnabledObjects |= myP0Bit;
1714
myEnabledObjects |= P0Bit;
2690
myEnabledObjects &= ~myP0Bit;
1716
myEnabledObjects &= ~P0Bit;
2692
1718
if(myCurrentGRP1 != 0)
2693
myEnabledObjects |= myP1Bit;
1719
myEnabledObjects |= P1Bit;
2695
myEnabledObjects &= ~myP1Bit;
1721
myEnabledObjects &= ~P1Bit;
2700
case 0x1C: // Graphics Player 1
1726
case GRP1: // Graphics Player 1
2702
1728
// Set player 1 graphics
2703
myGRP1 = (myBitEnabled[TIA::P1] ? value : 0);
2705
1731
// Copy player 0 graphics into its delayed register
2706
1732
myDGRP0 = myGRP0;
2711
1737
// Get the "current" data for GRP0 base on delay register
2712
1738
uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0;
2713
myCurrentGRP0 = myREFP0 ? ourPlayerReflectTable[grp0] : grp0;
1739
myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0;
2715
1741
// Get the "current" data for GRP1 base on delay register
2716
1742
uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1;
2717
myCurrentGRP1 = myREFP1 ? ourPlayerReflectTable[grp1] : grp1;
1743
myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1;
2719
1745
// Set enabled object bits
2720
1746
if(myCurrentGRP0 != 0)
2721
myEnabledObjects |= myP0Bit;
1747
myEnabledObjects |= P0Bit;
2723
myEnabledObjects &= ~myP0Bit;
1749
myEnabledObjects &= ~P0Bit;
2725
1751
if(myCurrentGRP1 != 0)
2726
myEnabledObjects |= myP1Bit;
1752
myEnabledObjects |= P1Bit;
2728
myEnabledObjects &= ~myP1Bit;
1754
myEnabledObjects &= ~P1Bit;
2730
1756
if(myVDELBL ? myDENABL : myENABL)
2731
myEnabledObjects |= myBLBit;
1757
myEnabledObjects |= BLBit;
2733
myEnabledObjects &= ~myBLBit;
1759
myEnabledObjects &= ~BLBit;
2738
case 0x1D: // Enable Missile 0 graphics
1764
case ENAM0: // Enable Missile 0 graphics
2740
myENAM0 = (myBitEnabled[TIA::M0] ? value & 0x02 : 0);
1766
myENAM0 = value & 0x02;
2742
1768
if(myENAM0 && !myRESMP0)
2743
myEnabledObjects |= myM0Bit;
1769
myEnabledObjects |= M0Bit;
2745
myEnabledObjects &= ~myM0Bit;
1771
myEnabledObjects &= ~M0Bit;
2749
case 0x1E: // Enable Missile 1 graphics
1775
case ENAM1: // Enable Missile 1 graphics
2751
myENAM1 = (myBitEnabled[TIA::M1] ? value & 0x02 : 0);
1777
myENAM1 = value & 0x02;
2753
1779
if(myENAM1 && !myRESMP1)
2754
myEnabledObjects |= myM1Bit;
1780
myEnabledObjects |= M1Bit;
2756
myEnabledObjects &= ~myM1Bit;
1782
myEnabledObjects &= ~M1Bit;
2760
case 0x1F: // Enable Ball graphics
1786
case ENABL: // Enable Ball graphics
2762
myENABL = (myBitEnabled[TIA::BL] ? value & 0x02 : 0);
1788
myENABL = value & 0x02;
2764
1790
if(myVDELBL ? myDENABL : myENABL)
2765
myEnabledObjects |= myBLBit;
1791
myEnabledObjects |= BLBit;
2767
myEnabledObjects &= ~myBLBit;
2772
case 0x20: // Horizontal Motion Player 0
2774
myHMP0 = value >> 4;
2778
case 0x21: // Horizontal Motion Player 1
2780
myHMP1 = value >> 4;
2784
case 0x22: // Horizontal Motion Missle 0
2786
Int8 tmp = value >> 4;
2788
// Should we enabled TIA M0 "bug" used for stars in Cosmic Ark?
2789
if((clock == (myLastHMOVEClock + 21 * 3)) && (myHMM0 == 7) && (tmp == 6))
2791
myM0CosmicArkMotionEnabled = true;
2792
myM0CosmicArkCounter = 0;
2799
case 0x23: // Horizontal Motion Missle 1
2801
myHMM1 = value >> 4;
2805
case 0x24: // Horizontal Motion Ball
2807
myHMBL = value >> 4;
2811
case 0x25: // Vertial Delay Player 0
1793
myEnabledObjects &= ~BLBit;
1798
case HMP0: // Horizontal Motion Player 0
1800
pokeHMP0(value, clock);
1804
case HMP1: // Horizontal Motion Player 1
1806
pokeHMP1(value, clock);
1810
case HMM0: // Horizontal Motion Missle 0
1812
pokeHMM0(value, clock);
1816
case HMM1: // Horizontal Motion Missle 1
1818
pokeHMM1(value, clock);
1822
case HMBL: // Horizontal Motion Ball
1824
pokeHMBL(value, clock);
1828
case VDELP0: // Vertical Delay Player 0
2813
1830
myVDELP0 = value & 0x01;
2815
1832
uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0;
2816
myCurrentGRP0 = myREFP0 ? ourPlayerReflectTable[grp0] : grp0;
1833
myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0;
2818
1835
if(myCurrentGRP0 != 0)
2819
myEnabledObjects |= myP0Bit;
1836
myEnabledObjects |= P0Bit;
2821
myEnabledObjects &= ~myP0Bit;
1838
myEnabledObjects &= ~P0Bit;
2825
case 0x26: // Vertial Delay Player 1
1842
case VDELP1: // Vertical Delay Player 1
2827
1844
myVDELP1 = value & 0x01;
2829
1846
uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1;
2830
myCurrentGRP1 = myREFP1 ? ourPlayerReflectTable[grp1] : grp1;
1847
myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1;
2832
1849
if(myCurrentGRP1 != 0)
2833
myEnabledObjects |= myP1Bit;
1850
myEnabledObjects |= P1Bit;
2835
myEnabledObjects &= ~myP1Bit;
1852
myEnabledObjects &= ~P1Bit;
2839
case 0x27: // Vertial Delay Ball
1856
case VDELBL: // Vertical Delay Ball
2841
1858
myVDELBL = value & 0x01;
2843
1860
if(myVDELBL ? myDENABL : myENABL)
2844
myEnabledObjects |= myBLBit;
1861
myEnabledObjects |= BLBit;
2846
myEnabledObjects &= ~myBLBit;
1863
myEnabledObjects &= ~BLBit;
2850
case 0x28: // Reset missle 0 to player 0
1867
case RESMP0: // Reset missle 0 to player 0
2852
1869
if(myRESMP0 && !(value & 0x02))
2856
if((myNUSIZ0 & 0x07) == 0x05)
2858
else if((myNUSIZ0 & 0x07) == 0x07)
2863
myPOSM0 = (myPOSP0 + middle) % 160;
2864
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
2865
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
1872
switch(myNUSIZ0 & 0x07)
1874
case 0x05: middle = 8; break; // double size
1875
case 0x07: middle = 16; break; // quad size
1877
myPOSM0 = myPOSP0 + middle;
1878
if(myCurrentHMOVEPos != 0x7FFFFFFF)
1880
myPOSM0 -= (8 - myMotionClockP0);
1881
myPOSM0 += (8 - myMotionClockM0);
1882
if(myPOSM0 < 0) myPOSM0 += 160;
2868
1886
myRESMP0 = value & 0x02;
2870
1888
if(myENAM0 && !myRESMP0)
2871
myEnabledObjects |= myM0Bit;
1889
myEnabledObjects |= M0Bit;
2873
myEnabledObjects &= ~myM0Bit;
1891
myEnabledObjects &= ~M0Bit;
2878
case 0x29: // Reset missle 1 to player 1
1896
case RESMP1: // Reset missle 1 to player 1
2880
1898
if(myRESMP1 && !(value & 0x02))
2884
if((myNUSIZ1 & 0x07) == 0x05)
2886
else if((myNUSIZ1 & 0x07) == 0x07)
2891
myPOSM1 = (myPOSP1 + middle) % 160;
2892
myCurrentM1Mask = &ourMissleMaskTable[myPOSM1 & 0x03]
2893
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
1901
switch(myNUSIZ1 & 0x07)
1903
case 0x05: middle = 8; break; // double size
1904
case 0x07: middle = 16; break; // quad size
1906
myPOSM1 = myPOSP1 + middle;
1907
if(myCurrentHMOVEPos != 0x7FFFFFFF)
1909
myPOSM1 -= (8 - myMotionClockP1);
1910
myPOSM1 += (8 - myMotionClockM1);
1911
if(myPOSM1 < 0) myPOSM1 += 160;
2896
1915
myRESMP1 = value & 0x02;
2898
1917
if(myENAM1 && !myRESMP1)
2899
myEnabledObjects |= myM1Bit;
1918
myEnabledObjects |= M1Bit;
2901
myEnabledObjects &= ~myM1Bit;
1920
myEnabledObjects &= ~M1Bit;
2905
case 0x2A: // Apply horizontal motion
1924
case HMOVE: // Apply horizontal motion
2907
// Figure out what cycle we're at
2908
Int32 x = ((clock - myClockWhenFrameStarted) % 228) / 3;
1926
int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
1927
myCurrentHMOVEPos = hpos;
2910
1929
// See if we need to enable the HMOVE blank bug
2911
if(myAllowHMOVEBlanks && ourHMOVEBlankEnableCycles[x])
2913
// TODO: Allow this to be turned off using properties...
2914
myHMOVEBlankEnabled = true;
2917
myPOSP0 += ourCompleteMotionTable[x][myHMP0];
2918
myPOSP1 += ourCompleteMotionTable[x][myHMP1];
2919
myPOSM0 += ourCompleteMotionTable[x][myHMM0];
2920
myPOSM1 += ourCompleteMotionTable[x][myHMM1];
2921
myPOSBL += ourCompleteMotionTable[x][myHMBL];
2925
else if(myPOSP0 < 0)
2930
else if(myPOSP1 < 0)
2935
else if(myPOSM0 < 0)
2940
else if(myPOSM1 < 0)
2945
else if(myPOSBL < 0)
2948
myCurrentBLMask = &ourBallMaskTable[myPOSBL & 0x03]
2949
[(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)];
2951
myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03]
2952
[0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)];
2953
myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03]
2954
[0][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)];
2956
myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03]
2957
[myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)];
2958
myCurrentM1Mask = &ourMissleMaskTable[myPOSM1 & 0x03]
2959
[myNUSIZ1 & 0x07][(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFC)];
2961
// Remember what clock HMOVE occured at
2962
myLastHMOVEClock = clock;
2964
// Disable TIA M0 "bug" used for stars in Cosmic ark
2965
myM0CosmicArkMotionEnabled = false;
1930
myHMOVEBlankEnabled = myAllowHMOVEBlanks ?
1931
TIATables::HMOVEBlankEnableCycles[((clock - myClockWhenFrameStarted) % 228) / 3] : false;
1933
#ifdef USE_MMR_LATCHES
1934
// Do we have to undo some of the already applied cycles from an
1935
// active graphics latch?
1936
if(hpos + HBLANK < 17 * 4)
1938
Int16 cycle_fix = 17 - ((hpos + VBLANK + 7) / 4);
1939
if(myHMP0mmr) myPOSP0 = (myPOSP0 + cycle_fix) % 160;
1940
if(myHMP1mmr) myPOSP1 = (myPOSP1 + cycle_fix) % 160;
1941
if(myHMM0mmr) myPOSM0 = (myPOSM0 + cycle_fix) % 160;
1942
if(myHMM1mmr) myPOSM1 = (myPOSM1 + cycle_fix) % 160;
1943
if(myHMBLmmr) myPOSBL = (myPOSBL + cycle_fix) % 160;
1945
myHMP0mmr = myHMP1mmr = myHMM0mmr = myHMM1mmr = myHMBLmmr = false;
1947
// Can HMOVE activities be ignored?
1948
if(hpos >= -5 && hpos < 97 )
1950
myMotionClockP0 = 0;
1951
myMotionClockP1 = 0;
1952
myMotionClockM0 = 0;
1953
myMotionClockM1 = 0;
1954
myMotionClockBL = 0;
1955
myHMOVEBlankEnabled = false;
1956
myCurrentHMOVEPos = 0x7FFFFFFF;
1960
myMotionClockP0 = (myHMP0 ^ 0x80) >> 4;
1961
myMotionClockP1 = (myHMP1 ^ 0x80) >> 4;
1962
myMotionClockM0 = (myHMM0 ^ 0x80) >> 4;
1963
myMotionClockM1 = (myHMM1 ^ 0x80) >> 4;
1964
myMotionClockBL = (myHMBL ^ 0x80) >> 4;
1966
// Adjust number of graphics motion clocks for active display
1967
if(hpos >= 97 && hpos < 151)
1969
Int16 skip_motclks = (160 - myCurrentHMOVEPos - 6) >> 2;
1970
myMotionClockP0 -= skip_motclks;
1971
myMotionClockP1 -= skip_motclks;
1972
myMotionClockM0 -= skip_motclks;
1973
myMotionClockM1 -= skip_motclks;
1974
myMotionClockBL -= skip_motclks;
1975
if(myMotionClockP0 < 0) myMotionClockP0 = 0;
1976
if(myMotionClockP1 < 0) myMotionClockP1 = 0;
1977
if(myMotionClockM0 < 0) myMotionClockM0 = 0;
1978
if(myMotionClockM1 < 0) myMotionClockM1 = 0;
1979
if(myMotionClockBL < 0) myMotionClockBL = 0;
1982
if(hpos >= -56 && hpos < -5)
1984
Int16 max_motclks = (7 - (myCurrentHMOVEPos + 5)) >> 2;
1985
if(myMotionClockP0 > max_motclks) myMotionClockP0 = max_motclks;
1986
if(myMotionClockP1 > max_motclks) myMotionClockP1 = max_motclks;
1987
if(myMotionClockM0 > max_motclks) myMotionClockM0 = max_motclks;
1988
if(myMotionClockM1 > max_motclks) myMotionClockM1 = max_motclks;
1989
if(myMotionClockBL > max_motclks) myMotionClockBL = max_motclks;
1992
// Apply horizontal motion
1993
if(hpos < -5 || hpos >= 157)
1995
myPOSP0 += 8 - myMotionClockP0;
1996
myPOSP1 += 8 - myMotionClockP1;
1997
myPOSM0 += 8 - myMotionClockM0;
1998
myPOSM1 += 8 - myMotionClockM1;
1999
myPOSBL += 8 - myMotionClockBL;
2002
// Make sure positions are in range
2003
if(myPOSP0 < 0) { myPOSP0 += 160; } myPOSP0 %= 160;
2004
if(myPOSP1 < 0) { myPOSP1 += 160; } myPOSP1 %= 160;
2005
if(myPOSM0 < 0) { myPOSM0 += 160; } myPOSM0 %= 160;
2006
if(myPOSM1 < 0) { myPOSM1 += 160; } myPOSM1 %= 160;
2007
if(myPOSBL < 0) { myPOSBL += 160; } myPOSBL %= 160;
2009
mySuppressP0 = mySuppressP1 = 0;
2969
case 0x2b: // Clear horizontal motion registers
2013
case HMCLR: // Clear horizontal motion registers
2979
case 0x2c: // Clear collision latches
2023
case CXCLR: // Clear collision latches
2981
2025
myCollision = 0;
2995
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2996
uInt8 TIA::ourBallMaskTable[4][4][320];
2998
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2999
uInt16 TIA::ourCollisionTable[64];
3001
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3002
uInt8 TIA::ourDisabledMaskTable[640];
3004
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3005
const Int16 TIA::ourPokeDelayTable[64] = {
3006
0, 1, 0, 0, 8, 8, 0, 0, 0, 0, 0, 1, 1, -1, -1, -1,
3007
0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
3008
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3009
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3012
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3013
uInt8 TIA::ourMissleMaskTable[4][8][4][320];
3015
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3016
const bool TIA::ourHMOVEBlankEnableCycles[76] = {
3017
true, true, true, true, true, true, true, true, true, true, // 00
3018
true, true, true, true, true, true, true, true, true, true, // 10
3019
true, false, false, false, false, false, false, false, false, false, // 20
3020
false, false, false, false, false, false, false, false, false, false, // 30
3021
false, false, false, false, false, false, false, false, false, false, // 40
3022
false, false, false, false, false, false, false, false, false, false, // 50
3023
false, false, false, false, false, false, false, false, false, false, // 60
3024
false, false, false, false, false, true // 70
3027
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3028
const Int32 TIA::ourCompleteMotionTable[76][16] = {
3029
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3030
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3031
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3032
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3033
{ 0, -1, -2, -3, -4, -5, -6, -6, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3034
{ 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3035
{ 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3036
{ 0, -1, -2, -3, -4, -4, -4, -4, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3037
{ 0, -1, -2, -3, -3, -3, -3, -3, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3038
{ 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3039
{ 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3040
{ 0, -1, -1, -1, -1, -1, -1, -1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3041
{ 0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3042
{ 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3043
{ 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK
3044
{ 2, 2, 2, 2, 2, 2, 2, 2, 8, 7, 6, 5, 4, 3, 2, 2}, // HBLANK
3045
{ 3, 3, 3, 3, 3, 3, 3, 3, 8, 7, 6, 5, 4, 3, 3, 3}, // HBLANK
3046
{ 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK
3047
{ 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK
3048
{ 5, 5, 5, 5, 5, 5, 5, 5, 8, 7, 6, 5, 5, 5, 5, 5}, // HBLANK
3049
{ 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 6, 6, 6, 6, 6}, // HBLANK
3050
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3051
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3052
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3053
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3054
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3055
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3056
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3057
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3058
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3059
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3060
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3061
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3062
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3063
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3064
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3065
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3066
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3067
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3068
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3069
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3070
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3071
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3072
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3073
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3074
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3075
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3076
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3077
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3078
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3079
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3080
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3081
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3082
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3083
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
3084
{ 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0},
3085
{ 0, 0, 0, 0, 0, 0, -1, -2, 0, 0, 0, 0, 0, 0, 0, 0},
3086
{ 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0},
3087
{ 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0},
3088
{ 0, 0, 0, 0, -1, -2, -3, -4, 0, 0, 0, 0, 0, 0, 0, 0},
3089
{ 0, 0, 0, -1, -2, -3, -4, -5, 0, 0, 0, 0, 0, 0, 0, 0},
3090
{ 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0},
3091
{ 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0},
3092
{ 0, -1, -2, -3, -4, -5, -6, -7, 0, 0, 0, 0, 0, 0, 0, 0},
3093
{-1, -2, -3, -4, -5, -6, -7, -8, 0, 0, 0, 0, 0, 0, 0, 0},
3094
{-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1},
3095
{-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1},
3096
{-3, -4, -5, -6, -7, -8, -9,-10, 0, 0, 0, 0, 0, 0, -1, -2},
3097
{-4, -5, -6, -7, -8, -9,-10,-11, 0, 0, 0, 0, 0, -1, -2, -3},
3098
{-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4},
3099
{-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4},
3100
{-6, -7, -8, -9,-10,-11,-12,-13, 0, 0, 0, -1, -2, -3, -4, -5},
3101
{-7, -8, -9,-10,-11,-12,-13,-14, 0, 0, -1, -2, -3, -4, -5, -6},
3102
{-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7},
3103
{-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7},
3104
{ 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1} // HBLANK
3107
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3108
uInt8 TIA::ourPlayerMaskTable[4][2][8][320];
3110
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3111
Int8 TIA::ourPlayerPositionResetWhenTable[8][160][160];
3113
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3114
uInt8 TIA::ourPlayerReflectTable[256];
3116
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3117
uInt32 TIA::ourPlayfieldTable[2][160];
2040
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2041
// Note that the following methods to change the horizontal motion registers
2042
// are not completely accurate. We should be taking care of the following
2043
// explanation from A. Towers Hardware Notes:
2045
// Much more interesting is this: if the counter has not yet
2046
// reached the value in HMxx (or has reached it but not yet
2047
// commited the comparison) and a value with at least one bit
2048
// in common with all remaining internal counter states is
2049
// written (zeros or ones), the stopping condition will never be
2050
// reached and the object will be moved a full 15 pixels left.
2051
// In addition to this, the HMOVE will complete without clearing
2052
// the "more movement required" latch, and so will continue to send
2053
// an additional clock signal every 4 CLK (during visible and
2054
// non-visible parts of the scanline) until another HMOVE operation
2055
// clears the latch. The HMCLR command does not reset these latches.
2057
// This condition is what causes the 'starfield effect' in Cosmic Ark,
2058
// and the 'snow' in Stay Frosty. Ideally, we'd trace the counter and
2059
// do a compare every colour clock, updating the horizontal positions
2060
// when applicable. We can save time by cheating, and noting that the
2061
// effect only occurs for 'magic numbers' 0x70 and 0x80.
2063
// Most of the ideas in these methods come from MESS.
2064
// (used with permission from Wilbert Pol)
2065
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2066
void TIA::pokeHMP0(uInt8 value, Int32 clock)
2072
int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
2074
// Check if HMOVE is currently active
2075
if(myCurrentHMOVEPos != 0x7FFFFFFF &&
2076
hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockP0 * 4, 7))
2078
Int32 newMotion = (value ^ 0x80) >> 4;
2079
// Check if new horizontal move can still be applied normally
2080
if(newMotion > myMotionClockP0 ||
2081
hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7))
2083
myPOSP0 -= (newMotion - myMotionClockP0);
2084
myMotionClockP0 = newMotion;
2088
myPOSP0 -= (15 - myMotionClockP0);
2089
myMotionClockP0 = 15;
2090
if(value != 0x70 && value != 0x80)
2093
if(myPOSP0 < 0) { myPOSP0 += 160; } myPOSP0 %= 160;
2098
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2099
void TIA::pokeHMP1(uInt8 value, Int32 clock)
2105
int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
2107
// Check if HMOVE is currently active
2108
if(myCurrentHMOVEPos != 0x7FFFFFFF &&
2109
hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockP1 * 4, 7))
2111
Int32 newMotion = (value ^ 0x80) >> 4;
2112
// Check if new horizontal move can still be applied normally
2113
if(newMotion > myMotionClockP1 ||
2114
hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7))
2116
myPOSP1 -= (newMotion - myMotionClockP1);
2117
myMotionClockP1 = newMotion;
2121
myPOSP1 -= (15 - myMotionClockP1);
2122
myMotionClockP1 = 15;
2123
if(value != 0x70 && value != 0x80)
2126
if(myPOSP1 < 0) { myPOSP1 += 160; } myPOSP1 %= 160;
2131
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2132
void TIA::pokeHMM0(uInt8 value, Int32 clock)
2138
int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
2140
// Check if HMOVE is currently active
2141
if(myCurrentHMOVEPos != 0x7FFFFFFF &&
2142
hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockM0 * 4, 7))
2144
Int32 newMotion = (value ^ 0x80) >> 4;
2145
// Check if new horizontal move can still be applied normally
2146
if(newMotion > myMotionClockM0 ||
2147
hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7))
2149
myPOSM0 -= (newMotion - myMotionClockM0);
2150
myMotionClockM0 = newMotion;
2154
myPOSM0 -= (15 - myMotionClockM0);
2155
myMotionClockM0 = 15;
2156
if(value != 0x70 && value != 0x80)
2159
if(myPOSM0 < 0) { myPOSM0 += 160; } myPOSM0 %= 160;
2164
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2165
void TIA::pokeHMM1(uInt8 value, Int32 clock)
2171
int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
2173
// Check if HMOVE is currently active
2174
if(myCurrentHMOVEPos != 0x7FFFFFFF &&
2175
hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockM1 * 4, 7))
2177
Int32 newMotion = (value ^ 0x80) >> 4;
2178
// Check if new horizontal move can still be applied normally
2179
if(newMotion > myMotionClockM1 ||
2180
hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7))
2182
myPOSM1 -= (newMotion - myMotionClockM1);
2183
myMotionClockM1 = newMotion;
2187
myPOSM1 -= (15 - myMotionClockM1);
2188
myMotionClockM1 = 15;
2189
if(value != 0x70 && value != 0x80)
2192
if(myPOSM1 < 0) { myPOSM1 += 160; } myPOSM1 %= 160;
2197
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2198
void TIA::pokeHMBL(uInt8 value, Int32 clock)
2204
int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK;
2206
// Check if HMOVE is currently active
2207
if(myCurrentHMOVEPos != 0x7FFFFFFF &&
2208
hpos < BSPF_min(myCurrentHMOVEPos + 6 + myMotionClockBL * 4, 7))
2210
Int32 newMotion = (value ^ 0x80) >> 4;
2211
// Check if new horizontal move can still be applied normally
2212
if(newMotion > myMotionClockBL ||
2213
hpos <= BSPF_min(myCurrentHMOVEPos + 6 + newMotion * 4, 7))
2215
myPOSBL -= (newMotion - myMotionClockBL);
2216
myMotionClockBL = newMotion;
2220
myPOSBL -= (15 - myMotionClockBL);
2221
myMotionClockBL = 15;
2222
if(value != 0x70 && value != 0x80)
2225
if(myPOSBL < 0) { myPOSBL += 160; } myPOSBL %= 160;
2230
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2231
// The following two methods apply extra clocks when a horizontal motion
2232
// register (HMxx) is modified during an HMOVE, before waiting for the
2233
// documented time of at least 24 CPU cycles. The applicable explanation
2234
// from A. Towers Hardware Notes is as follows:
2236
// In theory then the side effects of modifying the HMxx registers
2237
// during HMOVE should be quite straight-forward. If the internal
2238
// counter has not yet reached the value in HMxx, a new value greater
2239
// than this (in 0-15 terms) will work normally. Conversely, if
2240
// the counter has already reached the value in HMxx, new values
2241
// will have no effect because the latch will have been cleared.
2243
// Most of the ideas in these methods come from MESS.
2244
// (used with permission from Wilbert Pol)
2245
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2246
inline void TIA::applyActiveHMOVEMotion(int hpos, Int16& pos, Int32 motionClock)
2248
if(hpos < BSPF_min(myCurrentHMOVEPos + 6 + 16 * 4, 7))
2250
Int32 decrements_passed = (hpos - (myCurrentHMOVEPos + 4)) >> 2;
2252
if((motionClock - decrements_passed) > 0)
2254
pos -= (motionClock - decrements_passed);
2255
if(pos < 0) pos += 160;
2260
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2261
inline void TIA::applyPreviousHMOVEMotion(int hpos, Int16& pos, uInt8 motion)
2263
if(myPreviousHMOVEPos != 0x7FFFFFFF)
2265
uInt8 motclk = (motion ^ 0x80) >> 4;
2266
if(hpos <= myPreviousHMOVEPos - 228 + 5 + motclk * 4)
2268
uInt8 motclk_passed = (hpos - (myPreviousHMOVEPos - 228 + 6)) >> 2;
2269
pos -= (motclk - motclk_passed);
3119
2274
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3120
2275
TIA::TIA(const TIA& c)
3121
: myConsole(c.myConsole),
3122
mySettings(c.mySettings),
3124
myCOLUBK(myColor[0]),
3125
myCOLUPF(myColor[1]),
3126
myCOLUP0(myColor[2]),
3127
myCOLUP1(myColor[3])
2276
: myConsole(c.myConsole),
2278
mySettings(c.mySettings)