comparison vdp.c @ 822:ac65086c031e

Pretty decent optimization of vdp_h40 and vdp_h32. Gets reasonably close to the speed of 0.2.0 in the worst case and is faster than 0.2.0 in others
author Michael Pavone <pavone@retrodev.com>
date Mon, 03 Aug 2015 20:06:56 -0700
parents 0565b2c1a034
children 252dfd29831d
comparison
equal deleted inserted replaced
821:21a69dfb6ee7 822:ac65086c031e
493 } 493 }
494 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); 494 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1);
495 if (context->fifo_read == context->fifo_write) { 495 if (context->fifo_read == context->fifo_write) {
496 context->fifo_read = -1; 496 context->fifo_read = -1;
497 } 497 }
498 context->flags &= ~FLAG_UNUSED_SLOT;
498 } else { 499 } else {
499 context->flags |= FLAG_UNUSED_SLOT; 500 context->flags |= FLAG_UNUSED_SLOT;
500 } 501 }
501 } 502 }
502 503
929 } 930 }
930 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 931 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
931 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 932 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
932 } 933 }
933 934
935 uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19};
936
937 void vdp_advance_line(vdp_context *context)
938 {
939 context->vcounter++;
940 context->vcounter &= 0x1FF;
941 if (context->flags2 & FLAG2_REGION_PAL) {
942 if (context->latched_mode & BIT_PAL) {
943 if (context->vcounter == 0x10B) {
944 context->vcounter = 0x1D2;
945 }
946 } else if (context->vcounter == 0x103){
947 context->vcounter = 0x1CA;
948 }
949 } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) {
950 context->vcounter = 0x1E5;
951 }
952
953 if (context->vcounter > (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) {
954 context->hint_counter = context->regs[REG_HINT];
955 } else if (context->hint_counter) {
956 context->hint_counter--;
957 } else {
958 context->flags2 |= FLAG2_HINT_PENDING;
959 context->pending_hint_start = context->cycles;
960 context->hint_counter = context->regs[REG_HINT];
961 }
962 }
963
964 #define CHECK_ONLY if (context->cycles >= target_cycles) { return; }
965 #define CHECK_LIMIT if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, context->hslot); } context->hslot++; context->cycles += slot_cycles; CHECK_ONLY
966
934 #define COLUMN_RENDER_BLOCK(column, startcyc) \ 967 #define COLUMN_RENDER_BLOCK(column, startcyc) \
935 case startcyc:\ 968 case startcyc:\
936 read_map_scroll_a(column, line, context);\ 969 read_map_scroll_a(column, context->vcounter, context);\
937 break;\ 970 CHECK_LIMIT\
938 case (startcyc+1):\ 971 case (startcyc+1):\
939 external_slot(context);\ 972 external_slot(context);\
940 break;\ 973 CHECK_LIMIT\
941 case (startcyc+2):\ 974 case (startcyc+2):\
942 render_map_1(context);\ 975 render_map_1(context);\
943 break;\ 976 CHECK_LIMIT\
944 case (startcyc+3):\ 977 case (startcyc+3):\
945 render_map_2(context);\ 978 render_map_2(context);\
946 break;\ 979 CHECK_LIMIT\
947 case (startcyc+4):\ 980 case (startcyc+4):\
948 read_map_scroll_b(column, line, context);\ 981 read_map_scroll_b(column, context->vcounter, context);\
949 break;\ 982 CHECK_LIMIT\
950 case (startcyc+5):\ 983 case (startcyc+5):\
951 read_sprite_x(line, context);\ 984 read_sprite_x(context->vcounter, context);\
952 break;\ 985 CHECK_LIMIT\
953 case (startcyc+6):\ 986 case (startcyc+6):\
954 render_map_3(context);\ 987 render_map_3(context);\
955 break;\ 988 CHECK_LIMIT\
956 case (startcyc+7):\ 989 case (startcyc+7):\
957 render_map_output(line, column, context);\ 990 render_map_output(context->vcounter, column, context);\
958 break; 991 CHECK_LIMIT
959 992
960 #define COLUMN_RENDER_BLOCK_REFRESH(column, startcyc) \ 993 #define COLUMN_RENDER_BLOCK_REFRESH(column, startcyc) \
961 case startcyc:\ 994 case startcyc:\
962 read_map_scroll_a(column, line, context);\ 995 read_map_scroll_a(column, context->vcounter, context);\
963 break;\ 996 CHECK_LIMIT\
964 case (startcyc+1):\ 997 case (startcyc+1):\
965 break;\ 998 /* refresh, no don't run dma src */\
999 context->hslot++;\
1000 context->cycles += slot_cycles;\
1001 CHECK_ONLY\
966 case (startcyc+2):\ 1002 case (startcyc+2):\
967 render_map_1(context);\ 1003 render_map_1(context);\
968 break;\ 1004 CHECK_LIMIT\
969 case (startcyc+3):\ 1005 case (startcyc+3):\
970 render_map_2(context);\ 1006 render_map_2(context);\
971 break;\ 1007 CHECK_LIMIT\
972 case (startcyc+4):\ 1008 case (startcyc+4):\
973 read_map_scroll_b(column, line, context);\ 1009 read_map_scroll_b(column, context->vcounter, context);\
974 break;\ 1010 CHECK_LIMIT\
975 case (startcyc+5):\ 1011 case (startcyc+5):\
976 read_sprite_x(line, context);\ 1012 read_sprite_x(context->vcounter, context);\
977 break;\ 1013 CHECK_LIMIT\
978 case (startcyc+6):\ 1014 case (startcyc+6):\
979 render_map_3(context);\ 1015 render_map_3(context);\
980 break;\ 1016 CHECK_LIMIT\
981 case (startcyc+7):\ 1017 case (startcyc+7):\
982 render_map_output(line, column, context);\ 1018 render_map_output(context->vcounter, column, context);\
983 break; 1019 if (column == 40 || (column == 32 && startcyc == 124)) {\
984 1020 vdp_advance_line(context);\
985 void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context) 1021 }\
1022 CHECK_LIMIT
1023
1024 #define SPRITE_RENDER_H40(slot) \
1025 case slot:\
1026 render_sprite_cells( context);\
1027 scan_sprite_table(context->vcounter, context);\
1028 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, context->hslot); } \
1029 if (slot == 182) {\
1030 context->hslot = 229;\
1031 context->cycles += slot_cycles;\
1032 } else {\
1033 context->hslot++;\
1034 if (slot >= HSYNC_SLOT_H40 && slot < HSYNC_END_H40) {\
1035 context->cycles += h40_hsync_cycles[slot - HSYNC_SLOT_H40];\
1036 } else {\
1037 context->cycles += slot_cycles;\
1038 }\
1039 }\
1040 CHECK_ONLY
1041
1042 #define SPRITE_RENDER_H32(slot) \
1043 case slot:\
1044 render_sprite_cells( context);\
1045 scan_sprite_table(context->vcounter, context);\
1046 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, context->hslot); } \
1047 if (slot == 147) {\
1048 context->hslot = 233;\
1049 } else {\
1050 context->hslot++;\
1051 }\
1052 context->cycles += slot_cycles;\
1053 CHECK_ONLY
1054
1055
1056 void vdp_h40(vdp_context * context, uint32_t target_cycles)
986 { 1057 {
987 uint16_t address; 1058 uint16_t address;
988 uint32_t mask; 1059 uint32_t mask;
989 switch(linecyc) 1060 uint32_t const slot_cycles = MCLKS_SLOT_H40;
1061 switch(context->hslot)
1062 {
1063 for (;;)
990 { 1064 {
991 case 165: 1065 case 165:
1066 external_slot(context);
1067 CHECK_LIMIT
992 case 166: 1068 case 166:
993 external_slot(context); 1069 external_slot(context);
994 break; 1070 CHECK_LIMIT
995 //sprite render to line buffer starts 1071 //sprite render to line buffer starts
996 case 167: 1072 case 167:
1073 context->cur_slot = MAX_DRAWS-1;
1074 memset(context->linebuf, 0, LINEBUF_SIZE);
1075 if (context->vcounter == 0x1FF) {
1076 external_slot(context);
1077 } else {
1078 render_sprite_cells(context);
1079 }
1080 CHECK_LIMIT
997 case 168: 1081 case 168:
1082 if (context->vcounter == 0x1FF) {
1083 external_slot(context);
1084 } else {
1085 render_sprite_cells(context);
1086 }
1087 CHECK_LIMIT
998 case 169: 1088 case 169:
1089 if (context->vcounter == 0x1FF) {
1090 external_slot(context);
1091 } else {
1092 render_sprite_cells(context);
1093 }
1094 CHECK_LIMIT
999 case 170: 1095 case 170:
1000 if (line == 0xFF) { 1096 if (context->vcounter == 0x1FF) {
1001 external_slot(context); 1097 external_slot(context);
1002 } else { 1098 } else {
1003 render_sprite_cells(context); 1099 render_sprite_cells(context);
1004 } 1100 if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) {
1005 break; 1101 context->hslot++;
1102 context->cycles += slot_cycles;
1103 return;
1104 }
1105 }
1106 CHECK_LIMIT
1006 //sprite attribute table scan starts 1107 //sprite attribute table scan starts
1007 case 171: 1108 case 171:
1109 context->sprite_index = 0x80;
1110 context->slot_counter = MAX_SPRITES_LINE;
1008 render_sprite_cells( context); 1111 render_sprite_cells( context);
1009 scan_sprite_table(line, context); 1112 scan_sprite_table(context->vcounter, context);
1010 break; 1113 CHECK_LIMIT
1011 case 172: 1114 SPRITE_RENDER_H40(172)
1012 case 173: 1115 SPRITE_RENDER_H40(173)
1013 case 174: 1116 SPRITE_RENDER_H40(174)
1014 case 175: 1117 SPRITE_RENDER_H40(175)
1015 case 176: 1118 SPRITE_RENDER_H40(176)
1016 case 177: 1119 SPRITE_RENDER_H40(177)
1017 case 178: 1120 SPRITE_RENDER_H40(178)
1018 case 179: 1121 SPRITE_RENDER_H40(179)
1019 case 180: 1122 SPRITE_RENDER_H40(180)
1020 case 181: 1123 SPRITE_RENDER_H40(181)
1021 case 182: 1124 SPRITE_RENDER_H40(182)
1022 case 229: 1125 SPRITE_RENDER_H40(229)
1023 case 230: 1126 SPRITE_RENDER_H40(230)
1024 case 231: 1127 SPRITE_RENDER_H40(231)
1025 case 232: 1128 SPRITE_RENDER_H40(232)
1026 case 233: 1129 SPRITE_RENDER_H40(233)
1027 //!HSYNC asserted 1130 //!HSYNC asserted
1028 case 234: 1131 SPRITE_RENDER_H40(234)
1029 case 235: 1132 SPRITE_RENDER_H40(235)
1030 render_sprite_cells(context); 1133 SPRITE_RENDER_H40(236)
1031 scan_sprite_table(line, context); 1134 SPRITE_RENDER_H40(237)
1032 break; 1135 SPRITE_RENDER_H40(238)
1033 case 236: 1136 SPRITE_RENDER_H40(239)
1034 external_slot(context); 1137 SPRITE_RENDER_H40(240)
1035 break; 1138 SPRITE_RENDER_H40(241)
1036 case 237: 1139 SPRITE_RENDER_H40(242)
1037 case 238: 1140 SPRITE_RENDER_H40(243)
1038 case 239: 1141 SPRITE_RENDER_H40(244)
1039 case 240: 1142 SPRITE_RENDER_H40(245)
1040 case 241: 1143 SPRITE_RENDER_H40(246)
1041 case 242: 1144 SPRITE_RENDER_H40(247)
1042 case 243:
1043 case 244:
1044 case 245:
1045 case 246:
1046 case 247:
1047 render_sprite_cells(context);
1048 scan_sprite_table(line, context);
1049 break;
1050 case 248: 1145 case 248:
1051 address = (context->regs[REG_HSCROLL] & 0x3F) << 10; 1146 address = (context->regs[REG_HSCROLL] & 0x3F) << 10;
1052 mask = 0; 1147 mask = 0;
1053 if (context->regs[REG_MODE_3] & 0x2) { 1148 if (context->regs[REG_MODE_3] & 0x2) {
1054 mask |= 0xF8; 1149 mask |= 0xF8;
1055 } 1150 }
1056 if (context->regs[REG_MODE_3] & 0x1) { 1151 if (context->regs[REG_MODE_3] & 0x1) {
1057 mask |= 0x7; 1152 mask |= 0x7;
1058 } 1153 }
1059 line &= mask; 1154 address += (context->vcounter & mask) * 4;
1060 address += line * 4;
1061 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; 1155 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
1062 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; 1156 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
1063 //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); 1157 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
1064 break; 1158 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, context->hslot); }
1065 case 249: 1159 context->hslot++;
1160 context->cycles += h40_hsync_cycles[14];
1161 CHECK_ONLY
1066 //!HSYNC high 1162 //!HSYNC high
1067 case 250: 1163 SPRITE_RENDER_H40(249)
1068 case 251: 1164 SPRITE_RENDER_H40(250)
1069 case 252: 1165 SPRITE_RENDER_H40(251)
1070 render_sprite_cells(context); 1166 SPRITE_RENDER_H40(252)
1071 scan_sprite_table(line, context);
1072 break;
1073 case 253: 1167 case 253:
1074 read_map_scroll_a(0, line, context); 1168 read_map_scroll_a(0, context->vcounter, context);
1075 break; 1169 CHECK_LIMIT
1076 case 254: 1170 SPRITE_RENDER_H40(254)
1077 render_sprite_cells(context);
1078 scan_sprite_table(line, context);
1079 break;
1080 case 255: 1171 case 255:
1081 render_map_1(context); 1172 render_map_1(context);
1082 scan_sprite_table(line, context);//Just a guess 1173 scan_sprite_table(context->vcounter, context);//Just a guess
1083 break; 1174 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, context->hslot); }
1175 context->hslot = 0;
1176 context->cycles += slot_cycles;
1177 CHECK_ONLY
1084 case 0: 1178 case 0:
1085 render_map_2(context); 1179 render_map_2(context);
1086 scan_sprite_table(line, context);//Just a guess 1180 scan_sprite_table(context->vcounter, context);//Just a guess
1087 break; 1181 CHECK_LIMIT
1088 case 1: 1182 case 1:
1089 read_map_scroll_b(0, line, context); 1183 read_map_scroll_b(0, context->vcounter, context);
1090 break; 1184 CHECK_LIMIT
1091 case 2: 1185 SPRITE_RENDER_H40(2)
1092 render_sprite_cells(context);
1093 scan_sprite_table(line, context);
1094 break;
1095 case 3: 1186 case 3:
1096 render_map_3(context); 1187 render_map_3(context);
1097 scan_sprite_table(line, context);//Just a guess 1188 scan_sprite_table(context->vcounter, context);//Just a guess
1098 break; 1189 CHECK_LIMIT
1099 case 4: 1190 case 4:
1100 render_map_output(line, 0, context); 1191 if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) {
1101 scan_sprite_table(line, context);//Just a guess 1192 context->flags2 |= FLAG2_VINT_PENDING;
1193 context->pending_vint_start = context->cycles;
1194 }
1195 render_map_output(context->vcounter, 0, context);
1196 scan_sprite_table(context->vcounter, context);//Just a guess
1102 //reverse context slot counter so it counts the number of sprite slots 1197 //reverse context slot counter so it counts the number of sprite slots
1103 //filled rather than the number of available slots 1198 //filled rather than the number of available slots
1104 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; 1199 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter;
1105 context->cur_slot = MAX_SPRITES_LINE-1; 1200 context->cur_slot = MAX_SPRITES_LINE-1;
1106 context->sprite_draws = MAX_DRAWS; 1201 context->sprite_draws = MAX_DRAWS;
1107 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); 1202 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED);
1108 break; 1203 CHECK_LIMIT
1109 COLUMN_RENDER_BLOCK(2, 5) 1204 COLUMN_RENDER_BLOCK(2, 5)
1110 COLUMN_RENDER_BLOCK(4, 13) 1205 COLUMN_RENDER_BLOCK(4, 13)
1111 COLUMN_RENDER_BLOCK(6, 21) 1206 COLUMN_RENDER_BLOCK(6, 21)
1112 COLUMN_RENDER_BLOCK_REFRESH(8, 29) 1207 COLUMN_RENDER_BLOCK_REFRESH(8, 29)
1113 COLUMN_RENDER_BLOCK(10, 37) 1208 COLUMN_RENDER_BLOCK(10, 37)
1125 COLUMN_RENDER_BLOCK(34, 133) 1220 COLUMN_RENDER_BLOCK(34, 133)
1126 COLUMN_RENDER_BLOCK(36, 141) 1221 COLUMN_RENDER_BLOCK(36, 141)
1127 COLUMN_RENDER_BLOCK(38, 149) 1222 COLUMN_RENDER_BLOCK(38, 149)
1128 COLUMN_RENDER_BLOCK_REFRESH(40, 157) 1223 COLUMN_RENDER_BLOCK_REFRESH(40, 157)
1129 } 1224 }
1130 } 1225 default:
1131 1226 context->hslot++;
1132 void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) 1227 context->cycles += slot_cycles;
1228 return;
1229 }
1230 }
1231
1232 void vdp_h32(vdp_context * context, uint32_t target_cycles)
1133 { 1233 {
1134 uint16_t address; 1234 uint16_t address;
1135 uint32_t mask; 1235 uint32_t mask;
1136 switch(linecyc) 1236 uint32_t const slot_cycles = MCLKS_SLOT_H32;
1237 switch(context->hslot)
1238 {
1239 for (;;)
1137 { 1240 {
1138 case 132: 1241 case 132:
1242 external_slot(context);
1243 CHECK_LIMIT
1139 case 133: 1244 case 133:
1140 external_slot(context); 1245 external_slot(context);
1141 break; 1246 CHECK_LIMIT
1142 //sprite render to line buffer starts 1247 //sprite render to line buffer starts
1143 case 134: 1248 case 134:
1249 context->cur_slot = MAX_DRAWS_H32-1;
1250 memset(context->linebuf, 0, LINEBUF_SIZE);
1251 if (context->vcounter == 0x1FF) {
1252 external_slot(context);
1253 } else {
1254 render_sprite_cells(context);
1255 }
1256 CHECK_LIMIT
1144 case 135: 1257 case 135:
1258 if (context->vcounter == 0x1FF) {
1259 external_slot(context);
1260 } else {
1261 render_sprite_cells(context);
1262 }
1263 CHECK_LIMIT
1145 case 136: 1264 case 136:
1265 if (context->vcounter == 0x1FF) {
1266 external_slot(context);
1267 } else {
1268 render_sprite_cells(context);
1269 }
1270 CHECK_LIMIT
1146 case 137: 1271 case 137:
1147 if (line == 0xFF) { 1272 if (context->vcounter == 0x1FF) {
1148 external_slot(context); 1273 external_slot(context);
1149 } else { 1274 } else {
1150 render_sprite_cells(context); 1275 render_sprite_cells(context);
1151 } 1276 if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) {
1152 break; 1277 context->hslot++;
1278 context->cycles += slot_cycles;
1279 return;
1280 }
1281 }
1282 CHECK_LIMIT
1153 //sprite attribute table scan starts 1283 //sprite attribute table scan starts
1154 case 138: 1284 case 138:
1285 context->sprite_index = 0x80;
1286 context->slot_counter = MAX_SPRITES_LINE_H32;
1155 render_sprite_cells( context); 1287 render_sprite_cells( context);
1156 scan_sprite_table(line, context); 1288 scan_sprite_table(context->vcounter, context);
1157 break; 1289 CHECK_LIMIT
1158 case 139: 1290 SPRITE_RENDER_H32(139)
1159 case 140: 1291 SPRITE_RENDER_H32(140)
1160 case 141: 1292 SPRITE_RENDER_H32(141)
1161 case 142: 1293 SPRITE_RENDER_H32(142)
1162 case 143: 1294 SPRITE_RENDER_H32(143)
1163 case 144: 1295 SPRITE_RENDER_H32(144)
1164 case 145: 1296 SPRITE_RENDER_H32(145)
1165 case 146: 1297 SPRITE_RENDER_H32(146)
1166 case 147: 1298 SPRITE_RENDER_H32(147)
1167 render_sprite_cells(context);
1168 scan_sprite_table(line, context);
1169 case 233: 1299 case 233:
1170 external_slot(context); 1300 external_slot(context);
1171 break; 1301 CHECK_LIMIT
1172 case 234: 1302 SPRITE_RENDER_H32(234)
1173 case 235: 1303 SPRITE_RENDER_H32(235)
1174 case 236: 1304 SPRITE_RENDER_H32(236)
1175 case 237: 1305 SPRITE_RENDER_H32(237)
1176 case 238: 1306 SPRITE_RENDER_H32(238)
1177 //HSYNC start 1307 //HSYNC start
1178 case 239: 1308 SPRITE_RENDER_H32(239)
1179 case 240: 1309 SPRITE_RENDER_H32(240)
1180 case 241: 1310 SPRITE_RENDER_H32(241)
1181 case 242: 1311 SPRITE_RENDER_H32(242)
1182 case 243: 1312 SPRITE_RENDER_H32(243)
1183 case 244: 1313 SPRITE_RENDER_H32(244)
1184 case 245: 1314 SPRITE_RENDER_H32(245)
1185 render_sprite_cells(context);
1186 scan_sprite_table(line, context);
1187 break;
1188 case 246: 1315 case 246:
1189 external_slot(context); 1316 external_slot(context);
1190 break; 1317 CHECK_LIMIT
1191 case 247: 1318 case 247:
1192 address = (context->regs[REG_HSCROLL] & 0x3F) << 10; 1319 address = (context->regs[REG_HSCROLL] & 0x3F) << 10;
1193 mask = 0; 1320 mask = 0;
1194 if (context->regs[REG_MODE_3] & 0x2) { 1321 if (context->regs[REG_MODE_3] & 0x2) {
1195 mask |= 0xF8; 1322 mask |= 0xF8;
1196 } 1323 }
1197 if (context->regs[REG_MODE_3] & 0x1) { 1324 if (context->regs[REG_MODE_3] & 0x1) {
1198 mask |= 0x7; 1325 mask |= 0x7;
1199 } 1326 }
1200 line &= mask; 1327 address += (context->vcounter & mask) * 4;
1201 address += line * 4;
1202 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; 1328 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
1203 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; 1329 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
1204 //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); 1330 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
1205 break; 1331 CHECK_LIMIT
1206 case 248: 1332 SPRITE_RENDER_H32(248)
1207 case 249: 1333 SPRITE_RENDER_H32(249)
1208 case 250: 1334 SPRITE_RENDER_H32(250)
1209 case 251: 1335 SPRITE_RENDER_H32(251)
1210 render_sprite_cells(context);
1211 scan_sprite_table(line, context);
1212 break;
1213 //!HSYNC high 1336 //!HSYNC high
1214 case 252: 1337 case 252:
1215 read_map_scroll_a(0, line, context); 1338 read_map_scroll_a(0, context->vcounter, context);
1216 break; 1339 CHECK_LIMIT
1217 case 253: 1340 SPRITE_RENDER_H32(253)
1218 render_sprite_cells(context);
1219 scan_sprite_table(line, context);
1220 break;
1221 case 254: 1341 case 254:
1222 render_map_1(context); 1342 render_map_1(context);
1223 scan_sprite_table(line, context);//Just a guess 1343 scan_sprite_table(context->vcounter, context);//Just a guess
1224 break; 1344 CHECK_LIMIT
1225 case 255: 1345 case 255:
1226 render_map_2(context); 1346 render_map_2(context);
1227 scan_sprite_table(line, context);//Just a guess 1347 scan_sprite_table(context->vcounter, context);//Just a guess
1228 break; 1348 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, context->hslot); }
1349 context->cycles += slot_cycles;
1350 context->hslot = 0;
1351 CHECK_ONLY
1229 case 0: 1352 case 0:
1230 read_map_scroll_b(0, line, context); 1353 read_map_scroll_b(0, context->vcounter, context);
1231 break; 1354 CHECK_LIMIT
1232 case 1: 1355 case 1:
1233 render_sprite_cells(context); 1356 render_sprite_cells(context);
1234 scan_sprite_table(line, context); 1357 scan_sprite_table(context->vcounter, context);
1235 break; 1358 CHECK_LIMIT
1236 case 2: 1359 case 2:
1237 render_map_3(context); 1360 render_map_3(context);
1238 scan_sprite_table(line, context);//Just a guess 1361 scan_sprite_table(context->vcounter, context);//Just a guess
1239 break; 1362 CHECK_LIMIT
1240 case 3: 1363 case 3:
1241 render_map_output(line, 0, context); 1364 render_map_output(context->vcounter, 0, context);
1242 scan_sprite_table(line, context);//Just a guess 1365 scan_sprite_table(context->vcounter, context);//Just a guess
1243 //reverse context slot counter so it counts the number of sprite slots 1366 //reverse context slot counter so it counts the number of sprite slots
1244 //filled rather than the number of available slots 1367 //filled rather than the number of available slots
1245 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; 1368 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter;
1246 context->cur_slot = MAX_SPRITES_LINE_H32-1; 1369 context->cur_slot = MAX_SPRITES_LINE_H32-1;
1247 context->sprite_draws = MAX_DRAWS_H32; 1370 context->sprite_draws = MAX_DRAWS_H32;
1248 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); 1371 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED);
1249 break; 1372 CHECK_LIMIT
1250 COLUMN_RENDER_BLOCK(2, 4) 1373 COLUMN_RENDER_BLOCK(2, 4)
1251 COLUMN_RENDER_BLOCK(4, 12) 1374 COLUMN_RENDER_BLOCK(4, 12)
1252 COLUMN_RENDER_BLOCK(6, 20) 1375 COLUMN_RENDER_BLOCK(6, 20)
1253 COLUMN_RENDER_BLOCK_REFRESH(8, 28) 1376 COLUMN_RENDER_BLOCK_REFRESH(8, 28)
1254 COLUMN_RENDER_BLOCK(10, 36) 1377 COLUMN_RENDER_BLOCK(10, 36)
1262 COLUMN_RENDER_BLOCK(26, 100) 1385 COLUMN_RENDER_BLOCK(26, 100)
1263 COLUMN_RENDER_BLOCK(28, 108) 1386 COLUMN_RENDER_BLOCK(28, 108)
1264 COLUMN_RENDER_BLOCK(30, 116) 1387 COLUMN_RENDER_BLOCK(30, 116)
1265 COLUMN_RENDER_BLOCK_REFRESH(32, 124) 1388 COLUMN_RENDER_BLOCK_REFRESH(32, 124)
1266 } 1389 }
1267 } 1390 default:
1268 1391 context->hslot++;
1269 void vdp_h40_line(uint32_t line, vdp_context * context) 1392 context->cycles += MCLKS_SLOT_H32;
1270 {
1271 context->cur_slot = MAX_DRAWS-1;
1272 memset(context->linebuf, 0, LINEBUF_SIZE);
1273 if (line == 0xFF) {
1274 external_slot(context);
1275 if (context->flags & FLAG_DMA_RUN) {
1276 run_dma_src(context, 0);
1277 }
1278 external_slot(context);
1279 if (context->flags & FLAG_DMA_RUN) {
1280 run_dma_src(context, 0);
1281 }
1282 external_slot(context);
1283 if (context->flags & FLAG_DMA_RUN) {
1284 run_dma_src(context, 0);
1285 }
1286 external_slot(context);
1287 if (context->flags & FLAG_DMA_RUN) {
1288 run_dma_src(context, 0);
1289 }
1290 external_slot(context);
1291 if (context->flags & FLAG_DMA_RUN) {
1292 run_dma_src(context, 0);
1293 }
1294 external_slot(context);
1295 if (context->flags & FLAG_DMA_RUN) {
1296 run_dma_src(context, 0);
1297 }
1298 for (int i = 0; i < 19; i++)
1299 {
1300 scan_sprite_table(line, context);
1301 }
1302 external_slot(context);
1303 for (int i = 0; i < 21; i++)
1304 {
1305 scan_sprite_table(line, context);
1306 }
1307 //reverse context slot counter so it counts the number of sprite slots
1308 //filled rather than the number of available slots
1309 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter;
1310 context->cur_slot = MAX_SPRITES_LINE-1;
1311 context->sprite_draws = MAX_DRAWS;
1312 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED);
1313 for (int column = 2; column < 42; column += 8)
1314 {
1315 external_slot(context);
1316 if (context->flags & FLAG_DMA_RUN) {
1317 run_dma_src(context, 0);
1318 }
1319 read_sprite_x(line, context);
1320
1321 external_slot(context);
1322 if (context->flags & FLAG_DMA_RUN) {
1323 run_dma_src(context, 0);
1324 }
1325 read_sprite_x(line, context);
1326
1327 external_slot(context);
1328 if (context->flags & FLAG_DMA_RUN) {
1329 run_dma_src(context, 0);
1330 }
1331 read_sprite_x(line, context);
1332
1333 read_sprite_x(line, context);
1334 }
1335
1336 return;
1337 }
1338 external_slot(context);
1339 if (context->flags & FLAG_DMA_RUN) {
1340 run_dma_src(context, 0);
1341 }
1342 external_slot(context);
1343 if (context->flags & FLAG_DMA_RUN) {
1344 run_dma_src(context, 0);
1345 }
1346
1347 render_sprite_cells(context);
1348 render_sprite_cells(context);
1349 render_sprite_cells(context);
1350 render_sprite_cells(context);
1351 context->sprite_index = 0x80;
1352 context->slot_counter = MAX_SPRITES_LINE;
1353 for (int i = 0; i < 19; i++)
1354 {
1355 render_sprite_cells(context);
1356 scan_sprite_table(line, context);
1357 }
1358 external_slot(context);
1359 for (int i = 0; i < 11; i++)
1360 {
1361 render_sprite_cells(context);
1362 scan_sprite_table(line, context);
1363 }
1364 uint16_t address;
1365 uint32_t mask;
1366 address = (context->regs[REG_HSCROLL] & 0x3F) << 10;
1367 mask = 0;
1368 if (context->regs[REG_MODE_3] & 0x2) {
1369 mask |= 0xF8;
1370 }
1371 if (context->regs[REG_MODE_3] & 0x1) {
1372 mask |= 0x7;
1373 }
1374 address += (line & mask) * 4;
1375 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
1376 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
1377 render_sprite_cells(context);
1378 scan_sprite_table(line, context);
1379 render_sprite_cells(context);
1380 scan_sprite_table(line, context);
1381 render_sprite_cells(context);
1382 scan_sprite_table(line, context);
1383 render_sprite_cells(context);
1384 scan_sprite_table(line, context);
1385
1386 read_map_scroll_a(0, line, context);
1387 render_sprite_cells(context);
1388 scan_sprite_table(line, context);
1389 render_map_1(context);
1390 scan_sprite_table(line, context);//Just a guess
1391 render_map_2(context);
1392 scan_sprite_table(line, context);//Just a guess
1393 read_map_scroll_b(0, line, context);
1394 render_sprite_cells(context);
1395 scan_sprite_table(line, context);
1396 render_map_3(context);
1397 scan_sprite_table(line, context);//Just a guess
1398 render_map_output(line, 0, context);
1399 scan_sprite_table(line, context);//Just a guess
1400 //reverse context slot counter so it counts the number of sprite slots
1401 //filled rather than the number of available slots
1402 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter;
1403 context->cur_slot = MAX_SPRITES_LINE-1;
1404 context->sprite_draws = MAX_DRAWS;
1405 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED);
1406 for (int column = 2; column < 42; column += 2)
1407 {
1408 read_map_scroll_a(column, line, context);
1409 external_slot(context);
1410 if (context->flags & FLAG_DMA_RUN) {
1411 run_dma_src(context, 0);
1412 }
1413 render_map_1(context);
1414 render_map_2(context);
1415 read_map_scroll_b(column, line, context);
1416 read_sprite_x(line, context);
1417 render_map_3(context);
1418 render_map_output(line, column, context);
1419
1420 column += 2;
1421 read_map_scroll_a(column, line, context);
1422 external_slot(context);
1423 if (context->flags & FLAG_DMA_RUN) {
1424 run_dma_src(context, 0);
1425 }
1426 render_map_1(context);
1427 render_map_2(context);
1428 read_map_scroll_b(column, line, context);
1429 read_sprite_x(line, context);
1430 render_map_3(context);
1431 render_map_output(line, column, context);
1432
1433 column += 2;
1434 read_map_scroll_a(column, line, context);
1435 external_slot(context);
1436 if (context->flags & FLAG_DMA_RUN) {
1437 run_dma_src(context, 0);
1438 }
1439 render_map_1(context);
1440 render_map_2(context);
1441 read_map_scroll_b(column, line, context);
1442 read_sprite_x(line, context);
1443 render_map_3(context);
1444 render_map_output(line, column, context);
1445
1446 column += 2;
1447 read_map_scroll_a(column, line, context);
1448 render_map_1(context);
1449 render_map_2(context);
1450 read_map_scroll_b(column, line, context);
1451 read_sprite_x(line, context);
1452 render_map_3(context);
1453 render_map_output(line, column, context);
1454 } 1393 }
1455 } 1394 }
1456 1395
1457 void latch_mode(vdp_context * context) 1396 void latch_mode(vdp_context * context)
1458 { 1397 {
1481 *(start++) = color; 1420 *(start++) = color;
1482 } 1421 }
1483 } 1422 }
1484 } 1423 }
1485 1424
1486 uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19};
1487
1488 void vdp_advance_line(vdp_context *context)
1489 {
1490 context->vcounter++;
1491 context->vcounter &= 0x1FF;
1492 if (context->flags2 & FLAG2_REGION_PAL) {
1493 if (context->latched_mode & BIT_PAL) {
1494 if (context->vcounter == 0x10B) {
1495 context->vcounter = 0x1D2;
1496 }
1497 } else if (context->vcounter == 0x103){
1498 context->vcounter = 0x1CA;
1499 }
1500 } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) {
1501 context->vcounter = 0x1E5;
1502 }
1503
1504 if (context->vcounter > (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) {
1505 context->hint_counter = context->regs[REG_HINT];
1506 } else if (context->hint_counter) {
1507 context->hint_counter--;
1508 } else {
1509 context->flags2 |= FLAG2_HINT_PENDING;
1510 context->pending_hint_start = context->cycles;
1511 context->hint_counter = context->regs[REG_HINT];
1512 }
1513 }
1514 1425
1515 void vdp_run_context(vdp_context * context, uint32_t target_cycles) 1426 void vdp_run_context(vdp_context * context, uint32_t target_cycles)
1516 { 1427 {
1517 while(context->cycles < target_cycles) 1428 while(context->cycles < target_cycles)
1518 { 1429 {
1519 context->flags &= ~FLAG_UNUSED_SLOT;
1520 uint32_t line = context->vcounter;
1521 uint32_t slot = context->hslot;
1522
1523 if (!line && !slot) {
1524 //TODO: Figure out when this actually happens
1525 latch_mode(context);
1526 }
1527 uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; 1430 uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
1528 1431 //line 0x1FF is basically active even though it's not displayed
1432 uint8_t active_slot = context->vcounter < inactive_start || context->vcounter == 0x1FF;
1529 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; 1433 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
1530 if (is_h40) { 1434 if (context->vcounter == inactive_start) {
1531 if (slot == 167) { 1435 if (is_h40) {
1532 context->cur_slot = MAX_DRAWS-1; 1436 //the first inactive line behaves as an active one for the first 4 slots
1533 memset(context->linebuf, 0, LINEBUF_SIZE); 1437 if (context->hslot > LINE_CHANGE_H40 && context->hslot < 171) {
1534 } else if (slot == 171) { 1438 active_slot = 1;
1535 context->sprite_index = 0x80; 1439 }
1536 context->slot_counter = MAX_SPRITES_LINE;
1537 }
1538 } else {
1539 if (slot == 134) {
1540 context->cur_slot = MAX_DRAWS_H32-1;
1541 memset(context->linebuf, 0, LINEBUF_SIZE);
1542 } else if (slot == 138) {
1543 context->sprite_index = 0x80;
1544 context->slot_counter = MAX_SPRITES_LINE_H32;
1545 }
1546 }
1547 if(line == inactive_start) {
1548 uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32;
1549 if (slot == intslot) {
1550 context->flags2 |= FLAG2_VINT_PENDING;
1551 context->pending_vint_start = context->cycles;
1552 }
1553 }
1554 uint32_t inccycles;
1555 //line 0x1FF is basically active even though it's not displayed
1556 uint8_t active_slot = line < inactive_start || line == 0x1FF;
1557 if (is_h40) {
1558 if (slot < HSYNC_SLOT_H40 || slot >= HSYNC_END_H40) {
1559 inccycles = MCLKS_SLOT_H40;
1560 } else { 1440 } else {
1561 inccycles = h40_hsync_cycles[slot-HSYNC_SLOT_H40]; 1441 //the first inactive line behaves as an active one for the first few slots
1562 } 1442 if (context->hslot > LINE_CHANGE_H32 && context->hslot < 138) {
1563 //the first inactive line behaves as an active one for the first 4 slots 1443 active_slot = 1;
1564 if (line == inactive_start && slot > 166 && slot < 171) { 1444 }
1565 active_slot = 1; 1445 }
1566 } 1446 }
1567 } else {
1568 inccycles = MCLKS_SLOT_H32;
1569 //the first inactive line behaves as an active one for the first 4 slots
1570 if (line == inactive_start && slot > 166 && slot < 171) {
1571 active_slot = 1;
1572 }
1573 }
1574 uint8_t inc_slot = 1;
1575 if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) { 1447 if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) {
1576 //run VDP rendering for a slot or a line
1577 if (is_h40) { 1448 if (is_h40) {
1578 if (slot == LINE_CHANGE_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { 1449 vdp_h40(context, target_cycles);
1579 vdp_h40_line(line, context); 1450 } else {
1580 inccycles = MCLKS_LINE; 1451 vdp_h32(context, target_cycles);
1581 inc_slot = 0; 1452 }
1453 } else {
1454 if (is_h40) {
1455 if (context->hslot == 167) {
1456 context->cur_slot = MAX_DRAWS-1;
1457 memset(context->linebuf, 0, LINEBUF_SIZE);
1458 } else if (context->hslot == 171) {
1459 context->sprite_index = 0x80;
1460 context->slot_counter = MAX_SPRITES_LINE;
1461 }
1462 } else {
1463 if (context->hslot == 134) {
1464 context->cur_slot = MAX_DRAWS_H32-1;
1465 memset(context->linebuf, 0, LINEBUF_SIZE);
1466 } else if (context->hslot == 138) {
1467 context->sprite_index = 0x80;
1468 context->slot_counter = MAX_SPRITES_LINE_H32;
1469 }
1470 }
1471 if(context->vcounter == inactive_start) {
1472 uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32;
1473 if (context->hslot == intslot) {
1474 context->flags2 |= FLAG2_VINT_PENDING;
1475 context->pending_vint_start = context->cycles;
1476 }
1477 }
1478 uint32_t inccycles;
1479 if (is_h40) {
1480 if (context->hslot < HSYNC_SLOT_H40 || context->hslot >= HSYNC_END_H40) {
1481 inccycles = MCLKS_SLOT_H40;
1582 } else { 1482 } else {
1583 vdp_h40(line, slot, context); 1483 inccycles = h40_hsync_cycles[context->hslot-HSYNC_SLOT_H40];
1584 } 1484 }
1585 } else { 1485 } else {
1586 vdp_h32(line, slot, context); 1486 inccycles = MCLKS_SLOT_H32;
1587 } 1487 }
1588 } else { 1488 if (!is_refresh(context, context->hslot)) {
1589 if (!is_refresh(context, slot)) {
1590 external_slot(context); 1489 external_slot(context);
1591 } 1490 }
1592 if (line < inactive_start) { 1491 if (context->vcounter < inactive_start) {
1593 check_render_bg(context, line, slot); 1492 check_render_bg(context, context->vcounter, context->hslot);
1594 } 1493 }
1595 } 1494 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) {
1596 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, slot)) { 1495 run_dma_src(context, context->hslot);
1597 run_dma_src(context, slot); 1496 }
1598 } 1497 context->cycles += inccycles;
1599 context->cycles += inccycles;
1600 if (inc_slot) {
1601 context->hslot++; 1498 context->hslot++;
1602 context->hslot &= 0xFF; 1499 context->hslot &= 0xFF;
1603 if (is_h40) { 1500 if (is_h40) {
1604 if (context->hslot == LINE_CHANGE_H40) { 1501 if (context->hslot == LINE_CHANGE_H40) {
1605 vdp_advance_line(context); 1502 vdp_advance_line(context);
1617 } 1514 }
1618 } else if (context->hslot == 148) { 1515 } else if (context->hslot == 148) {
1619 context->hslot = 233; 1516 context->hslot = 233;
1620 } 1517 }
1621 } 1518 }
1622
1623 } else {
1624 vdp_advance_line(context);
1625 } 1519 }
1626 } 1520 }
1627 } 1521 }
1628 1522
1629 uint32_t vdp_run_to_vblank(vdp_context * context) 1523 uint32_t vdp_run_to_vblank(vdp_context * context)