Mercurial > repos > blastem
comparison vdp.c @ 2686:05915f01046d
WIP attempt to move VDP rendering to a separate thread
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 31 Mar 2025 21:02:17 -0700 |
parents | da2e06c42d16 |
children |
comparison
equal
deleted
inserted
replaced
2685:da2e06c42d16 | 2686:05915f01046d |
---|---|
154 } | 154 } |
155 } | 155 } |
156 | 156 |
157 static uint8_t static_table_init_done; | 157 static uint8_t static_table_init_done; |
158 | 158 |
159 vdp_context *init_vdp_context(uint8_t region_pal, uint8_t has_max_vsram, uint8_t type) | 159 vdp_context *init_vdp_context_int(uint8_t region_pal, uint8_t has_max_vsram, uint8_t type) |
160 { | 160 { |
161 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE); | 161 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE); |
162 if (headless) { | |
163 context->fb = malloc(512 * LINEBUF_SIZE * sizeof(pixel_t)); | |
164 context->output_pitch = LINEBUF_SIZE * sizeof(pixel_t); | |
165 } else { | |
166 context->cur_buffer = FRAMEBUFFER_ODD; | |
167 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); | |
168 } | |
169 context->sprite_draws = MAX_SPRITES_LINE; | 162 context->sprite_draws = MAX_SPRITES_LINE; |
170 context->fifo_write = 0; | 163 context->fifo_write = 0; |
171 context->fifo_read = -1; | 164 context->fifo_read = -1; |
172 context->regs[REG_HINT] = context->hint_counter = 0xFF; | 165 context->regs[REG_HINT] = context->hint_counter = 0xFF; |
173 context->vsram_size = has_max_vsram ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE; | 166 context->vsram_size = has_max_vsram ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE; |
337 } | 330 } |
338 if (region_pal) { | 331 if (region_pal) { |
339 context->flags2 |= FLAG2_REGION_PAL; | 332 context->flags2 |= FLAG2_REGION_PAL; |
340 } | 333 } |
341 update_video_params(context); | 334 update_video_params(context); |
335 | |
336 return context; | |
337 } | |
338 | |
339 static uint32_t mode5_sat_address(vdp_context *context) | |
340 { | |
341 uint32_t addr = context->regs[REG_SAT] << 9; | |
342 if (!(context->regs[REG_MODE_2] & BIT_128K_VRAM)) { | |
343 addr &= 0xFFFF; | |
344 } | |
345 if (context->regs[REG_MODE_4] & BIT_H40) { | |
346 addr &= 0x1FC00; | |
347 } | |
348 return addr; | |
349 } | |
350 | |
351 static void vdp_check_update_sat(vdp_context *context, uint32_t address, uint16_t value) | |
352 { | |
353 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | |
354 if (!(address & 4)) { | |
355 uint32_t sat_address = mode5_sat_address(context); | |
356 if(address >= sat_address && address < (sat_address + SAT_CACHE_SIZE*2)) { | |
357 uint16_t cache_address = address - sat_address; | |
358 cache_address = (cache_address & 3) | (cache_address >> 1 & 0x1FC); | |
359 context->sat_cache[cache_address] = value >> 8; | |
360 context->sat_cache[cache_address^1] = value; | |
361 } | |
362 } | |
363 } | |
364 } | |
365 | |
366 void vdp_check_update_sat_byte(vdp_context *context, uint32_t address, uint8_t value) | |
367 { | |
368 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | |
369 if (!(address & 4)) { | |
370 uint32_t sat_address = mode5_sat_address(context); | |
371 if(address >= sat_address && address < (sat_address + SAT_CACHE_SIZE*2)) { | |
372 uint16_t cache_address = address - sat_address; | |
373 cache_address = (cache_address & 3) | (cache_address >> 1 & 0x1FC); | |
374 context->sat_cache[cache_address] = value; | |
375 } | |
376 } | |
377 } | |
378 } | |
379 | |
380 static void write_vram_word(vdp_context *context, uint32_t address, uint16_t value) | |
381 { | |
382 address = (address & 0x3FC) | (address >> 1 & 0xFC01) | (address >> 9 & 0x2); | |
383 address ^= 1; | |
384 //TODO: Support an option to actually have 128KB of VRAM | |
385 context->vdpmem[address] = value; | |
386 } | |
387 | |
388 static void write_vram_byte(vdp_context *context, uint32_t address, uint8_t value) | |
389 { | |
390 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | |
391 address &= 0xFFFF; | |
392 } else { | |
393 address = mode4_address_map[address & 0x3FFF]; | |
394 } | |
395 context->vdpmem[address] = value; | |
396 } | |
397 | |
398 #define VSRAM_DIRTY_BITS 0xF800 | |
399 | |
400 //rough estimate of slot number at which border display starts | |
401 #define BG_START_SLOT 6 | |
402 | |
403 static void update_color_map(vdp_context *context, uint16_t index, uint16_t value) | |
404 { | |
405 context->colors[index] = context->color_map[value & CRAM_BITS]; | |
406 context->colors[index + SHADOW_OFFSET] = context->color_map[(value & CRAM_BITS) | FBUF_SHADOW]; | |
407 context->colors[index + HIGHLIGHT_OFFSET] = context->color_map[(value & CRAM_BITS) | FBUF_HILIGHT]; | |
408 if (context->type == VDP_GAMEGEAR) { | |
409 context->colors[index + MODE4_OFFSET] = context->color_map[value & 0xFFF]; | |
410 } else { | |
411 context->colors[index + MODE4_OFFSET] = context->color_map[(value & CRAM_BITS) | FBUF_MODE4]; | |
412 } | |
413 } | |
414 | |
415 void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value) | |
416 { | |
417 context->cram[addr] = value; | |
418 update_color_map(context, addr, value); | |
419 } | |
420 | |
421 static void write_cram(vdp_context * context, uint16_t address, uint16_t value) | |
422 { | |
423 uint16_t addr; | |
424 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | |
425 addr = (address/2) & (CRAM_SIZE-1); | |
426 } else if (context->type == VDP_GAMEGEAR) { | |
427 addr = (address/2) & 31; | |
428 } else { | |
429 addr = address & 0x1F; | |
430 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00); | |
431 } | |
432 write_cram_internal(context, addr, value); | |
433 | |
434 if (context->output && context->hslot >= BG_START_SLOT && ( | |
435 context->vcounter < context->inactive_start + context->border_bot | |
436 || context->vcounter > 0x200 - context->border_top | |
437 )) { | |
438 uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2; | |
439 if (context->hslot < bg_end_slot) { | |
440 pixel_t color = (context->regs[REG_MODE_2] & BIT_MODE_5) ? context->colors[addr] : context->colors[addr + MODE4_OFFSET]; | |
441 context->output[(context->hslot - BG_START_SLOT)*2 + 1] = color; | |
442 } | |
443 } | |
444 } | |
445 | |
446 #ifndef _WIN32 | |
447 static int vdp_render_thread_main(void *vcontext) | |
448 { | |
449 vdp_context *context = vcontext; | |
450 event_out event; | |
451 for (;;) | |
452 { | |
453 event.autoinc = context->regs[REG_AUTOINC]; | |
454 uint8_t etype = mem_reader_next_event(&event); | |
455 if (etype == EVENT_EOF) { | |
456 break; | |
457 } | |
458 vdp_run_context(context, event.cycle); | |
459 switch (etype) | |
460 { | |
461 case EVENT_ADJUST: | |
462 vdp_adjust_cycles(context, event.address); | |
463 break; | |
464 case EVENT_VDP_REG: | |
465 context->regs[event.address] = event.value; | |
466 if (event.address == REG_MODE_4) { | |
467 context->double_res = (event.value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); | |
468 if (!context->double_res) { | |
469 context->flags2 &= ~FLAG2_EVEN_FIELD; | |
470 } | |
471 } | |
472 if (event.address == REG_MODE_1 || event.address == REG_MODE_2 || event.address == REG_MODE_4) { | |
473 update_video_params(context); | |
474 } | |
475 break; | |
476 case EVENT_VRAM_BYTE: | |
477 case EVENT_VRAM_BYTE_DELTA: | |
478 case EVENT_VRAM_BYTE_ONE: | |
479 case EVENT_VRAM_BYTE_AUTO: | |
480 vdp_check_update_sat_byte(context, event.address ^ 1, event.value); | |
481 write_vram_byte(context, event.address ^ 1, event.value); | |
482 break; | |
483 case EVENT_VRAM_WORD: | |
484 case EVENT_VRAM_WORD_DELTA: | |
485 vdp_check_update_sat(context, event.address, event.value); | |
486 write_vram_word(context, event.address, event.value); | |
487 break; | |
488 case EVENT_VDP_INTRAM: | |
489 if (event.address < 128) { | |
490 write_cram(context, event.address, event.value); | |
491 } else { | |
492 context->vsram[event.address&63] = event.value; | |
493 } | |
494 break; | |
495 } | |
496 } | |
497 return 0; | |
498 } | |
499 #endif | |
500 | |
501 static render_thread vdp_thread; | |
502 vdp_context *init_vdp_context(uint8_t region_pal, uint8_t has_max_vsram, uint8_t type) | |
503 { | |
504 vdp_context *ret = init_vdp_context_int(region_pal, has_max_vsram, type); | |
505 vdp_context *context; | |
506 #ifndef _WIN32 | |
507 if (render_is_threaded_video()) { | |
508 context = ret->renderer = init_vdp_context_int(region_pal, has_max_vsram, type); | |
509 } else | |
510 #endif | |
511 { | |
512 context = ret; | |
513 } | |
514 if (headless) { | |
515 context->fb = malloc(512 * LINEBUF_SIZE * sizeof(pixel_t)); | |
516 context->output_pitch = LINEBUF_SIZE * sizeof(pixel_t); | |
517 } else { | |
518 context->cur_buffer = FRAMEBUFFER_ODD; | |
519 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); | |
520 } | |
342 context->output = (pixel_t *)(((char *)context->fb) + context->output_pitch * context->border_top); | 521 context->output = (pixel_t *)(((char *)context->fb) + context->output_pitch * context->border_top); |
343 return context; | 522 #ifndef _WIN32 |
523 if (ret->renderer) { | |
524 event_log_mem(); | |
525 render_create_thread(&vdp_thread, "vdp_render", vdp_render_thread_main, ret->renderer); | |
526 } | |
527 #endif | |
528 return ret; | |
344 } | 529 } |
345 | 530 |
346 void vdp_free(vdp_context *context) | 531 void vdp_free(vdp_context *context) |
347 { | 532 { |
348 if (headless) { | 533 if (headless) { |
352 { | 537 { |
353 if (context->enabled_debuggers & (1 << i)) { | 538 if (context->enabled_debuggers & (1 << i)) { |
354 vdp_toggle_debug_view(context, i); | 539 vdp_toggle_debug_view(context, i); |
355 } | 540 } |
356 } | 541 } |
542 #ifndef _WIN32 | |
543 if (context->renderer) { | |
544 event_log_mem_stop(); | |
545 vdp_free(context->renderer); | |
546 } | |
547 #endif | |
357 free(context); | 548 free(context); |
358 } | 549 } |
359 | 550 |
360 static int is_refresh(vdp_context * context, uint32_t slot) | 551 static int is_refresh(vdp_context * context, uint32_t slot) |
361 { | 552 { |
516 } | 707 } |
517 } | 708 } |
518 } | 709 } |
519 context->sprite_index--; | 710 context->sprite_index--; |
520 } | 711 } |
521 } | |
522 | |
523 static uint32_t mode5_sat_address(vdp_context *context) | |
524 { | |
525 uint32_t addr = context->regs[REG_SAT] << 9; | |
526 if (!(context->regs[REG_MODE_2] & BIT_128K_VRAM)) { | |
527 addr &= 0xFFFF; | |
528 } | |
529 if (context->regs[REG_MODE_4] & BIT_H40) { | |
530 addr &= 0x1FC00; | |
531 } | |
532 return addr; | |
533 } | 712 } |
534 | 713 |
535 void vdp_print_sprite_table(vdp_context * context) | 714 void vdp_print_sprite_table(vdp_context * context) |
536 { | 715 { |
537 if (context->type == VDP_GENESIS && context->regs[REG_MODE_2] & BIT_MODE_5) { | 716 if (context->type == VDP_GENESIS && context->regs[REG_MODE_2] & BIT_MODE_5) { |
955 context->sprite_draw_list[context->sprite_draws].address = tile_address; | 1134 context->sprite_draw_list[context->sprite_draws].address = tile_address; |
956 context->cur_slot--; | 1135 context->cur_slot--; |
957 } | 1136 } |
958 } | 1137 } |
959 | 1138 |
960 #define VSRAM_DIRTY_BITS 0xF800 | |
961 | |
962 //rough estimate of slot number at which border display starts | |
963 #define BG_START_SLOT 6 | |
964 | |
965 static void update_color_map(vdp_context *context, uint16_t index, uint16_t value) | |
966 { | |
967 context->colors[index] = context->color_map[value & CRAM_BITS]; | |
968 context->colors[index + SHADOW_OFFSET] = context->color_map[(value & CRAM_BITS) | FBUF_SHADOW]; | |
969 context->colors[index + HIGHLIGHT_OFFSET] = context->color_map[(value & CRAM_BITS) | FBUF_HILIGHT]; | |
970 if (context->type == VDP_GAMEGEAR) { | |
971 context->colors[index + MODE4_OFFSET] = context->color_map[value & 0xFFF]; | |
972 } else { | |
973 context->colors[index + MODE4_OFFSET] = context->color_map[(value & CRAM_BITS) | FBUF_MODE4]; | |
974 } | |
975 } | |
976 | |
977 void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value) | |
978 { | |
979 context->cram[addr] = value; | |
980 update_color_map(context, addr, value); | |
981 } | |
982 | |
983 static void write_cram(vdp_context * context, uint16_t address, uint16_t value) | |
984 { | |
985 uint16_t addr; | |
986 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | |
987 addr = (address/2) & (CRAM_SIZE-1); | |
988 } else if (context->type == VDP_GAMEGEAR) { | |
989 addr = (address/2) & 31; | |
990 } else { | |
991 addr = address & 0x1F; | |
992 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00); | |
993 } | |
994 write_cram_internal(context, addr, value); | |
995 | |
996 if (context->output && context->hslot >= BG_START_SLOT && ( | |
997 context->vcounter < context->inactive_start + context->border_bot | |
998 || context->vcounter > 0x200 - context->border_top | |
999 )) { | |
1000 uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2; | |
1001 if (context->hslot < bg_end_slot) { | |
1002 pixel_t color = (context->regs[REG_MODE_2] & BIT_MODE_5) ? context->colors[addr] : context->colors[addr + MODE4_OFFSET]; | |
1003 context->output[(context->hslot - BG_START_SLOT)*2 + 1] = color; | |
1004 } | |
1005 } | |
1006 } | |
1007 | |
1008 static void vdp_advance_dma(vdp_context * context) | 1139 static void vdp_advance_dma(vdp_context * context) |
1009 { | 1140 { |
1010 context->regs[REG_DMASRC_L] += 1; | 1141 context->regs[REG_DMASRC_L] += 1; |
1011 if (!context->regs[REG_DMASRC_L]) { | 1142 if (!context->regs[REG_DMASRC_L]) { |
1012 context->regs[REG_DMASRC_M] += 1; | 1143 context->regs[REG_DMASRC_M] += 1; |
1017 context->regs[REG_DMALEN_L] = dma_len; | 1148 context->regs[REG_DMALEN_L] = dma_len; |
1018 if (!dma_len) { | 1149 if (!dma_len) { |
1019 context->flags &= ~FLAG_DMA_RUN; | 1150 context->flags &= ~FLAG_DMA_RUN; |
1020 context->cd &= 0xF; | 1151 context->cd &= 0xF; |
1021 } | 1152 } |
1022 } | |
1023 | |
1024 static void vdp_check_update_sat(vdp_context *context, uint32_t address, uint16_t value) | |
1025 { | |
1026 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | |
1027 if (!(address & 4)) { | |
1028 uint32_t sat_address = mode5_sat_address(context); | |
1029 if(address >= sat_address && address < (sat_address + SAT_CACHE_SIZE*2)) { | |
1030 uint16_t cache_address = address - sat_address; | |
1031 cache_address = (cache_address & 3) | (cache_address >> 1 & 0x1FC); | |
1032 context->sat_cache[cache_address] = value >> 8; | |
1033 context->sat_cache[cache_address^1] = value; | |
1034 } | |
1035 } | |
1036 } | |
1037 } | |
1038 | |
1039 void vdp_check_update_sat_byte(vdp_context *context, uint32_t address, uint8_t value) | |
1040 { | |
1041 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | |
1042 if (!(address & 4)) { | |
1043 uint32_t sat_address = mode5_sat_address(context); | |
1044 if(address >= sat_address && address < (sat_address + SAT_CACHE_SIZE*2)) { | |
1045 uint16_t cache_address = address - sat_address; | |
1046 cache_address = (cache_address & 3) | (cache_address >> 1 & 0x1FC); | |
1047 context->sat_cache[cache_address] = value; | |
1048 } | |
1049 } | |
1050 } | |
1051 } | |
1052 | |
1053 static void write_vram_word(vdp_context *context, uint32_t address, uint16_t value) | |
1054 { | |
1055 address = (address & 0x3FC) | (address >> 1 & 0xFC01) | (address >> 9 & 0x2); | |
1056 address ^= 1; | |
1057 //TODO: Support an option to actually have 128KB of VRAM | |
1058 context->vdpmem[address] = value; | |
1059 } | |
1060 | |
1061 static void write_vram_byte(vdp_context *context, uint32_t address, uint8_t value) | |
1062 { | |
1063 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | |
1064 address &= 0xFFFF; | |
1065 } else { | |
1066 address = mode4_address_map[address & 0x3FFF]; | |
1067 } | |
1068 context->vdpmem[address] = value; | |
1069 } | 1153 } |
1070 | 1154 |
1071 #define DMA_FILL 0x80 | 1155 #define DMA_FILL 0x80 |
1072 #define DMA_COPY 0xC0 | 1156 #define DMA_COPY 0xC0 |
1073 #define DMA_TYPE_MASK 0xC0 | 1157 #define DMA_TYPE_MASK 0xC0 |
2146 } | 2230 } |
2147 } | 2231 } |
2148 } | 2232 } |
2149 | 2233 |
2150 context->vcounter++; | 2234 context->vcounter++; |
2235 if (context->renderer && context->vcounter == context->inactive_start) { | |
2236 context->frame++; | |
2237 } | |
2151 if (is_mode_5) { | 2238 if (is_mode_5) { |
2152 context->window_h_latch = context->regs[REG_WINDOW_H]; | 2239 context->window_h_latch = context->regs[REG_WINDOW_H]; |
2153 context->window_v_latch = context->regs[REG_WINDOW_V]; | 2240 context->window_v_latch = context->regs[REG_WINDOW_V]; |
2154 } | 2241 } |
2155 if (context->vcounter == jump_start) { | 2242 if (context->vcounter == jump_start) { |
3109 case (startcyc+7):\ | 3196 case (startcyc+7):\ |
3110 OUTPUT_PIXEL((startcyc+7)&0xFF)\ | 3197 OUTPUT_PIXEL((startcyc+7)&0xFF)\ |
3111 render_map_output(context->vcounter, column, context);\ | 3198 render_map_output(context->vcounter, column, context);\ |
3112 CHECK_LIMIT | 3199 CHECK_LIMIT |
3113 | 3200 |
3201 #define COLUMN_RENDER_BLOCK_PHONY(column, startcyc) \ | |
3202 case startcyc:\ | |
3203 CHECK_LIMIT\ | |
3204 case ((startcyc+1)&0xFF):\ | |
3205 external_slot(context);\ | |
3206 CHECK_LIMIT\ | |
3207 case ((startcyc+2)&0xFF):\ | |
3208 CHECK_LIMIT\ | |
3209 case ((startcyc+3)&0xFF):\ | |
3210 CHECK_LIMIT\ | |
3211 case ((startcyc+4)&0xFF):\ | |
3212 CHECK_LIMIT\ | |
3213 case ((startcyc+5)&0xFF):\ | |
3214 read_sprite_x(context->vcounter, context);\ | |
3215 CHECK_LIMIT\ | |
3216 case ((startcyc+6)&0xFF):\ | |
3217 CHECK_LIMIT\ | |
3218 case ((startcyc+7)&0xFF):\ | |
3219 CHECK_LIMIT | |
3220 | |
3221 #define COLUMN_RENDER_BLOCK_REFRESH_PHONY(column, startcyc) \ | |
3222 case startcyc:\ | |
3223 CHECK_LIMIT\ | |
3224 case (startcyc+1):\ | |
3225 /* refresh, so don't run dma src */\ | |
3226 context->hslot++;\ | |
3227 context->cycles += slot_cycles;\ | |
3228 CHECK_ONLY\ | |
3229 case (startcyc+2):\ | |
3230 CHECK_LIMIT\ | |
3231 case (startcyc+3):\ | |
3232 CHECK_LIMIT\ | |
3233 case (startcyc+4):\ | |
3234 CHECK_LIMIT\ | |
3235 case (startcyc+5):\ | |
3236 read_sprite_x(context->vcounter, context);\ | |
3237 CHECK_LIMIT\ | |
3238 case (startcyc+6):\ | |
3239 CHECK_LIMIT\ | |
3240 case (startcyc+7):\ | |
3241 CHECK_LIMIT | |
3242 | |
3114 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \ | 3243 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \ |
3115 case startcyc:\ | 3244 case startcyc:\ |
3116 OUTPUT_PIXEL_MODE4(startcyc)\ | 3245 OUTPUT_PIXEL_MODE4(startcyc)\ |
3117 read_map_mode4(column, context->vcounter, context);\ | 3246 read_map_mode4(column, context->vcounter, context);\ |
3118 CHECK_LIMIT\ | 3247 CHECK_LIMIT\ |
3181 draw_right_border(context);\ | 3310 draw_right_border(context);\ |
3182 }\ | 3311 }\ |
3183 scan_sprite_table(context->vcounter, context);\ | 3312 scan_sprite_table(context->vcounter, context);\ |
3184 CHECK_LIMIT_HSYNC(slot) | 3313 CHECK_LIMIT_HSYNC(slot) |
3185 | 3314 |
3315 #define SPRITE_RENDER_H40_PHONY(slot) \ | |
3316 case slot:\ | |
3317 render_sprite_cells( context);\ | |
3318 scan_sprite_table(context->vcounter, context);\ | |
3319 CHECK_LIMIT_HSYNC(slot) | |
3320 | |
3186 //Note that the line advancement check will fail if BG_START_SLOT is > 6 | 3321 //Note that the line advancement check will fail if BG_START_SLOT is > 6 |
3187 //as we're bumping up against the hcounter jump | 3322 //as we're bumping up against the hcounter jump |
3188 #define SPRITE_RENDER_H32(slot) \ | 3323 #define SPRITE_RENDER_H32(slot) \ |
3189 case slot:\ | 3324 case slot:\ |
3190 OUTPUT_PIXEL_H32(slot)\ | 3325 OUTPUT_PIXEL_H32(slot)\ |
3208 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;\ | 3343 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;\ |
3209 }\ | 3344 }\ |
3210 } else if (slot == 137) {\ | 3345 } else if (slot == 137) {\ |
3211 draw_right_border(context);\ | 3346 draw_right_border(context);\ |
3212 }\ | 3347 }\ |
3348 scan_sprite_table(context->vcounter, context);\ | |
3349 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \ | |
3350 if (slot == 147) {\ | |
3351 context->hslot = 233;\ | |
3352 } else {\ | |
3353 context->hslot++;\ | |
3354 }\ | |
3355 context->cycles += slot_cycles;\ | |
3356 CHECK_ONLY | |
3357 | |
3358 #define SPRITE_RENDER_H32_PHONY(slot) \ | |
3359 case slot:\ | |
3360 render_sprite_cells( context);\ | |
3213 scan_sprite_table(context->vcounter, context);\ | 3361 scan_sprite_table(context->vcounter, context);\ |
3214 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \ | 3362 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \ |
3215 if (slot == 147) {\ | 3363 if (slot == 147) {\ |
3216 context->hslot = 233;\ | 3364 context->hslot = 233;\ |
3217 } else {\ | 3365 } else {\ |
3705 context->cycles += slot_cycles; | 3853 context->cycles += slot_cycles; |
3706 return; | 3854 return; |
3707 } | 3855 } |
3708 } | 3856 } |
3709 | 3857 |
3858 static void vdp_h40_phony(vdp_context * context, uint32_t target_cycles) | |
3859 { | |
3860 uint32_t const slot_cycles = MCLKS_SLOT_H40; | |
3861 switch(context->hslot) | |
3862 { | |
3863 for (;;) | |
3864 { | |
3865 case 165: | |
3866 if (context->state == PREPARING) { | |
3867 external_slot(context); | |
3868 } else { | |
3869 render_sprite_cells(context); | |
3870 } | |
3871 CHECK_LIMIT | |
3872 case 166: | |
3873 if (context->state == PREPARING) { | |
3874 external_slot(context); | |
3875 } else { | |
3876 render_sprite_cells(context); | |
3877 } | |
3878 if (context->vcounter == context->inactive_start) { | |
3879 context->hslot++; | |
3880 context->cycles += slot_cycles; | |
3881 return; | |
3882 } | |
3883 CHECK_LIMIT | |
3884 //sprite attribute table scan starts | |
3885 case 167: | |
3886 context->sprite_index = 0x80; | |
3887 context->slot_counter = 0; | |
3888 render_sprite_cells(context); | |
3889 scan_sprite_table(context->vcounter, context); | |
3890 CHECK_LIMIT | |
3891 SPRITE_RENDER_H40_PHONY(168) | |
3892 SPRITE_RENDER_H40_PHONY(169) | |
3893 SPRITE_RENDER_H40_PHONY(170) | |
3894 SPRITE_RENDER_H40_PHONY(171) | |
3895 SPRITE_RENDER_H40_PHONY(172) | |
3896 SPRITE_RENDER_H40_PHONY(173) | |
3897 SPRITE_RENDER_H40_PHONY(174) | |
3898 SPRITE_RENDER_H40_PHONY(175) | |
3899 SPRITE_RENDER_H40_PHONY(176) | |
3900 SPRITE_RENDER_H40_PHONY(177)//End of border? | |
3901 SPRITE_RENDER_H40_PHONY(178) | |
3902 SPRITE_RENDER_H40_PHONY(179) | |
3903 SPRITE_RENDER_H40_PHONY(180) | |
3904 SPRITE_RENDER_H40_PHONY(181) | |
3905 SPRITE_RENDER_H40_PHONY(182) | |
3906 SPRITE_RENDER_H40_PHONY(229) | |
3907 //!HSYNC asserted | |
3908 SPRITE_RENDER_H40_PHONY(230) | |
3909 SPRITE_RENDER_H40_PHONY(231) | |
3910 case 232: | |
3911 external_slot(context); | |
3912 CHECK_LIMIT_HSYNC(232) | |
3913 SPRITE_RENDER_H40_PHONY(233) | |
3914 SPRITE_RENDER_H40_PHONY(234) | |
3915 SPRITE_RENDER_H40_PHONY(235) | |
3916 SPRITE_RENDER_H40_PHONY(236) | |
3917 SPRITE_RENDER_H40_PHONY(237) | |
3918 SPRITE_RENDER_H40_PHONY(238) | |
3919 SPRITE_RENDER_H40_PHONY(239) | |
3920 SPRITE_RENDER_H40_PHONY(240) | |
3921 SPRITE_RENDER_H40_PHONY(241) | |
3922 SPRITE_RENDER_H40_PHONY(242) | |
3923 SPRITE_RENDER_H40_PHONY(243) //provides "garbage" for border when plane A selected | |
3924 case 244: | |
3925 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } | |
3926 context->hslot++; | |
3927 context->cycles += h40_hsync_cycles[14]; | |
3928 CHECK_ONLY //provides "garbage" for border when plane A selected | |
3929 //!HSYNC high | |
3930 SPRITE_RENDER_H40_PHONY(245) | |
3931 SPRITE_RENDER_H40_PHONY(246) | |
3932 SPRITE_RENDER_H40_PHONY(247) //provides "garbage" for border when plane B selected | |
3933 SPRITE_RENDER_H40_PHONY(248) //provides "garbage" for border when plane B selected | |
3934 case 249: | |
3935 CHECK_LIMIT | |
3936 SPRITE_RENDER_H40_PHONY(250) | |
3937 case 251: | |
3938 scan_sprite_table(context->vcounter, context);//Just a guess | |
3939 CHECK_LIMIT | |
3940 case 252: | |
3941 scan_sprite_table(context->vcounter, context);//Just a guess | |
3942 CHECK_LIMIT | |
3943 case 253: | |
3944 CHECK_LIMIT | |
3945 SPRITE_RENDER_H40_PHONY(254) | |
3946 case 255: | |
3947 scan_sprite_table(context->vcounter, context);//Just a guess | |
3948 CHECK_LIMIT | |
3949 case 0: | |
3950 scan_sprite_table(context->vcounter, context);//Just a guess | |
3951 //seems like the sprite table scan fills a shift register | |
3952 //values are FIFO, but unused slots precede used slots | |
3953 //so we set cur_slot to slot_counter and let it wrap around to | |
3954 //the beginning of the list | |
3955 context->cur_slot = context->slot_counter; | |
3956 context->sprite_x_offset = 0; | |
3957 context->sprite_draws = MAX_SPRITES_LINE; | |
3958 CHECK_LIMIT | |
3959 COLUMN_RENDER_BLOCK_PHONY(2, 1) | |
3960 COLUMN_RENDER_BLOCK_PHONY(4, 9) | |
3961 COLUMN_RENDER_BLOCK_PHONY(6, 17) | |
3962 COLUMN_RENDER_BLOCK_REFRESH_PHONY(8, 25) | |
3963 COLUMN_RENDER_BLOCK_PHONY(10, 33) | |
3964 COLUMN_RENDER_BLOCK_PHONY(12, 41) | |
3965 COLUMN_RENDER_BLOCK_PHONY(14, 49) | |
3966 COLUMN_RENDER_BLOCK_REFRESH_PHONY(16, 57) | |
3967 COLUMN_RENDER_BLOCK_PHONY(18, 65) | |
3968 COLUMN_RENDER_BLOCK_PHONY(20, 73) | |
3969 COLUMN_RENDER_BLOCK_PHONY(22, 81) | |
3970 COLUMN_RENDER_BLOCK_REFRESH_PHONY(24, 89) | |
3971 COLUMN_RENDER_BLOCK_PHONY(26, 97) | |
3972 COLUMN_RENDER_BLOCK_PHONY(28, 105) | |
3973 COLUMN_RENDER_BLOCK_PHONY(30, 113) | |
3974 COLUMN_RENDER_BLOCK_REFRESH_PHONY(32, 121) | |
3975 COLUMN_RENDER_BLOCK_PHONY(34, 129) | |
3976 COLUMN_RENDER_BLOCK_PHONY(36, 137) | |
3977 COLUMN_RENDER_BLOCK_PHONY(38, 145) | |
3978 COLUMN_RENDER_BLOCK_REFRESH_PHONY(40, 153) | |
3979 case 161: | |
3980 external_slot(context); | |
3981 CHECK_LIMIT | |
3982 case 162: | |
3983 external_slot(context); | |
3984 CHECK_LIMIT | |
3985 //sprite render to line buffer starts | |
3986 case 163: | |
3987 context->cur_slot = MAX_SPRITES_LINE-1; | |
3988 memset(context->linebuf, 0, LINEBUF_SIZE); | |
3989 context->flags &= ~FLAG_MASKED; | |
3990 while (context->sprite_draws) { | |
3991 context->sprite_draws--; | |
3992 context->sprite_draw_list[context->sprite_draws].x_pos = 0; | |
3993 } | |
3994 render_sprite_cells(context); | |
3995 CHECK_LIMIT | |
3996 case 164: | |
3997 render_sprite_cells(context); | |
3998 if (context->flags & FLAG_DMA_RUN) { | |
3999 run_dma_src(context, -1); | |
4000 } | |
4001 context->hslot++; | |
4002 context->cycles += slot_cycles; | |
4003 vdp_advance_line(context); | |
4004 CHECK_ONLY | |
4005 } | |
4006 default: | |
4007 context->hslot++; | |
4008 context->cycles += slot_cycles; | |
4009 return; | |
4010 } | |
4011 } | |
4012 | |
3710 static void vdp_h32(vdp_context * context, uint32_t target_cycles) | 4013 static void vdp_h32(vdp_context * context, uint32_t target_cycles) |
3711 { | 4014 { |
3712 uint16_t address; | 4015 uint16_t address; |
3713 uint32_t mask; | 4016 uint32_t mask; |
3714 uint32_t const slot_cycles = MCLKS_SLOT_H32; | 4017 uint32_t const slot_cycles = MCLKS_SLOT_H32; |
3909 context, | 4212 context, |
3910 context->serial_address, | 4213 context->serial_address, |
3911 context->tmp_buf_a, context->buf_a_off + 8, | 4214 context->tmp_buf_a, context->buf_a_off + 8, |
3912 context->col_2 | 4215 context->col_2 |
3913 ); | 4216 ); |
4217 if (context->flags & FLAG_DMA_RUN) { | |
4218 run_dma_src(context, -1); | |
4219 } | |
4220 context->hslot++; | |
4221 context->cycles += slot_cycles; | |
4222 vdp_advance_line(context); | |
4223 CHECK_ONLY | |
4224 } | |
4225 default: | |
4226 context->hslot++; | |
4227 context->cycles += MCLKS_SLOT_H32; | |
4228 } | |
4229 } | |
4230 | |
4231 static void vdp_h32_phony(vdp_context * context, uint32_t target_cycles) | |
4232 { | |
4233 uint32_t const slot_cycles = MCLKS_SLOT_H32; | |
4234 switch(context->hslot) | |
4235 { | |
4236 for (;;) | |
4237 { | |
4238 case 133: | |
4239 if (context->state == PREPARING) { | |
4240 external_slot(context); | |
4241 } else { | |
4242 render_sprite_cells(context); | |
4243 } | |
4244 CHECK_LIMIT | |
4245 case 134: | |
4246 if (context->state == PREPARING) { | |
4247 external_slot(context); | |
4248 } else { | |
4249 render_sprite_cells(context); | |
4250 } | |
4251 if (context->vcounter == context->inactive_start) { | |
4252 context->hslot++; | |
4253 context->cycles += slot_cycles; | |
4254 return; | |
4255 } | |
4256 CHECK_LIMIT | |
4257 //sprite attribute table scan starts | |
4258 case 135: | |
4259 context->sprite_index = 0x80; | |
4260 context->slot_counter = 0; | |
4261 render_sprite_cells(context); | |
4262 scan_sprite_table(context->vcounter, context); | |
4263 CHECK_LIMIT | |
4264 SPRITE_RENDER_H32_PHONY(136) | |
4265 SPRITE_RENDER_H32_PHONY(137) | |
4266 SPRITE_RENDER_H32_PHONY(138) | |
4267 SPRITE_RENDER_H32_PHONY(139) | |
4268 SPRITE_RENDER_H32_PHONY(140) | |
4269 SPRITE_RENDER_H32_PHONY(141) | |
4270 SPRITE_RENDER_H32_PHONY(142) | |
4271 SPRITE_RENDER_H32_PHONY(143) | |
4272 SPRITE_RENDER_H32_PHONY(144) | |
4273 case 145: | |
4274 external_slot(context); | |
4275 CHECK_LIMIT | |
4276 SPRITE_RENDER_H32_PHONY(146) | |
4277 SPRITE_RENDER_H32_PHONY(147) | |
4278 SPRITE_RENDER_H32_PHONY(233) | |
4279 SPRITE_RENDER_H32_PHONY(234) | |
4280 SPRITE_RENDER_H32_PHONY(235) | |
4281 //HSYNC start | |
4282 SPRITE_RENDER_H32_PHONY(236) | |
4283 SPRITE_RENDER_H32_PHONY(237) | |
4284 SPRITE_RENDER_H32_PHONY(238) | |
4285 SPRITE_RENDER_H32_PHONY(239) | |
4286 SPRITE_RENDER_H32_PHONY(240) | |
4287 SPRITE_RENDER_H32_PHONY(241) | |
4288 SPRITE_RENDER_H32_PHONY(242) | |
4289 case 243: | |
4290 external_slot(context); | |
4291 CHECK_LIMIT | |
4292 case 244: | |
4293 CHECK_LIMIT //provides "garbage" for border when plane A selected | |
4294 SPRITE_RENDER_H32_PHONY(245) | |
4295 SPRITE_RENDER_H32_PHONY(246) | |
4296 SPRITE_RENDER_H32_PHONY(247) //provides "garbage" for border when plane B selected | |
4297 SPRITE_RENDER_H32_PHONY(248) //provides "garbage" for border when plane B selected | |
4298 //!HSYNC high | |
4299 case 249: | |
4300 CHECK_LIMIT | |
4301 SPRITE_RENDER_H32_PHONY(250) | |
4302 case 251: | |
4303 scan_sprite_table(context->vcounter, context);//Just a guess | |
4304 CHECK_LIMIT | |
4305 case 252: | |
4306 scan_sprite_table(context->vcounter, context);//Just a guess | |
4307 CHECK_LIMIT | |
4308 case 253: | |
4309 CHECK_LIMIT | |
4310 case 254: | |
4311 render_sprite_cells(context); | |
4312 scan_sprite_table(context->vcounter, context); | |
4313 CHECK_LIMIT | |
4314 case 255: | |
4315 scan_sprite_table(context->vcounter, context);//Just a guess | |
4316 CHECK_LIMIT | |
4317 case 0: | |
4318 scan_sprite_table(context->vcounter, context);//Just a guess | |
4319 //reverse context slot counter so it counts the number of sprite slots | |
4320 //filled rather than the number of available slots | |
4321 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; | |
4322 context->cur_slot = context->slot_counter; | |
4323 context->sprite_x_offset = 0; | |
4324 context->sprite_draws = MAX_SPRITES_LINE_H32; | |
4325 CHECK_LIMIT | |
4326 COLUMN_RENDER_BLOCK_PHONY(2, 1) | |
4327 COLUMN_RENDER_BLOCK_PHONY(4, 9) | |
4328 COLUMN_RENDER_BLOCK_PHONY(6, 17) | |
4329 COLUMN_RENDER_BLOCK_REFRESH_PHONY(8, 25) | |
4330 COLUMN_RENDER_BLOCK_PHONY(10, 33) | |
4331 COLUMN_RENDER_BLOCK_PHONY(12, 41) | |
4332 COLUMN_RENDER_BLOCK_PHONY(14, 49) | |
4333 COLUMN_RENDER_BLOCK_REFRESH_PHONY(16, 57) | |
4334 COLUMN_RENDER_BLOCK_PHONY(18, 65) | |
4335 COLUMN_RENDER_BLOCK_PHONY(20, 73) | |
4336 COLUMN_RENDER_BLOCK_PHONY(22, 81) | |
4337 COLUMN_RENDER_BLOCK_REFRESH_PHONY(24, 89) | |
4338 COLUMN_RENDER_BLOCK_PHONY(26, 97) | |
4339 COLUMN_RENDER_BLOCK_PHONY(28, 105) | |
4340 COLUMN_RENDER_BLOCK_PHONY(30, 113) | |
4341 COLUMN_RENDER_BLOCK_REFRESH_PHONY(32, 121) | |
4342 case 129: | |
4343 external_slot(context); | |
4344 CHECK_LIMIT | |
4345 case 130: { | |
4346 external_slot(context); | |
4347 CHECK_LIMIT | |
4348 } | |
4349 //sprite render to line buffer starts | |
4350 case 131: | |
4351 context->cur_slot = MAX_SPRITES_LINE_H32-1; | |
4352 context->flags &= ~FLAG_MASKED; | |
4353 while (context->sprite_draws) { | |
4354 context->sprite_draws--; | |
4355 context->sprite_draw_list[context->sprite_draws].x_pos = 0; | |
4356 } | |
4357 render_sprite_cells(context); | |
4358 CHECK_LIMIT | |
4359 case 132: | |
4360 render_sprite_cells(context); | |
3914 if (context->flags & FLAG_DMA_RUN) { | 4361 if (context->flags & FLAG_DMA_RUN) { |
3915 run_dma_src(context, -1); | 4362 run_dma_src(context, -1); |
3916 } | 4363 } |
3917 context->hslot++; | 4364 context->hslot++; |
3918 context->cycles += slot_cycles; | 4365 context->cycles += slot_cycles; |
4952 } | 5399 } |
4953 } | 5400 } |
4954 } | 5401 } |
4955 } | 5402 } |
4956 | 5403 |
4957 void vdp_run_context_full(vdp_context * context, uint32_t target_cycles) | 5404 static void vdp_inactive_phony(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5) |
4958 { | 5405 { |
4959 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; | 5406 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest, latch_slot; |
4960 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; | 5407 uint8_t index_reset_value, max_draws, max_sprites; |
5408 uint16_t vint_line, active_line; | |
5409 | |
5410 if (mode_5) { | |
5411 if (is_h40) { | |
5412 latch_slot = 165; | |
5413 buf_clear_slot = 163; | |
5414 index_reset_slot = 167; | |
5415 bg_end_slot = BG_START_SLOT + LINEBUF_SIZE/2; | |
5416 max_draws = MAX_SPRITES_LINE-1; | |
5417 max_sprites = MAX_SPRITES_LINE; | |
5418 index_reset_value = 0x80; | |
5419 vint_slot = VINT_SLOT_H40; | |
5420 line_change = LINE_CHANGE_H40; | |
5421 jump_start = 182; | |
5422 jump_dest = 229; | |
5423 } else { | |
5424 bg_end_slot = BG_START_SLOT + (256+HORIZ_BORDER)/2; | |
5425 max_draws = MAX_SPRITES_LINE_H32-1; | |
5426 max_sprites = MAX_SPRITES_LINE_H32; | |
5427 buf_clear_slot = 128; | |
5428 index_reset_slot = 132; | |
5429 index_reset_value = 0x80; | |
5430 vint_slot = VINT_SLOT_H32; | |
5431 line_change = LINE_CHANGE_H32; | |
5432 jump_start = 147; | |
5433 jump_dest = 233; | |
5434 latch_slot = 243; | |
5435 } | |
5436 vint_line = context->inactive_start; | |
5437 active_line = 0x1FF; | |
5438 if (context->regs[REG_MODE_3] & BIT_VSCROLL) { | |
5439 latch_slot = 220; | |
5440 } | |
5441 } else { | |
5442 latch_slot = 220; | |
5443 bg_end_slot = BG_START_SLOT + (256+HORIZ_BORDER)/2; | |
5444 max_draws = MAX_DRAWS_H32_MODE4; | |
5445 max_sprites = 8; | |
5446 buf_clear_slot = 136; | |
5447 index_reset_slot = 253; | |
5448 index_reset_value = 0; | |
5449 vint_line = context->inactive_start + 1; | |
5450 vint_slot = VINT_SLOT_MODE4; | |
5451 line_change = LINE_CHANGE_MODE4; | |
5452 jump_start = 147; | |
5453 jump_dest = 233; | |
5454 if ((context->regs[REG_MODE_1] & BIT_MODE_4) || context->type != VDP_GENESIS) { | |
5455 active_line = 0x1FF; | |
5456 } else { | |
5457 //never active unless either mode 4 or mode 5 is turned on | |
5458 active_line = 0x200; | |
5459 } | |
5460 } | |
5461 | |
4961 while(context->cycles < target_cycles) | 5462 while(context->cycles < target_cycles) |
4962 { | 5463 { |
4963 check_switch_inactive(context, is_h40); | 5464 check_switch_inactive(context, is_h40); |
4964 | 5465 //this will need some tweaking to properly interact with 128K mode, |
4965 if (is_active(context)) { | 5466 //but this should be good enough for now |
5467 context->serial_address += 1024; | |
5468 | |
5469 if (context->hslot == buf_clear_slot) { | |
4966 if (mode_5) { | 5470 if (mode_5) { |
4967 if (is_h40) { | 5471 context->cur_slot = max_draws; |
4968 vdp_h40(context, target_cycles); | 5472 } else if ((context->regs[REG_MODE_1] & BIT_MODE_4) || context->type == VDP_GENESIS) { |
5473 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1; | |
5474 context->sprite_draws = MAX_DRAWS_H32_MODE4; | |
5475 } else { | |
5476 context->sprite_draws = 0; | |
5477 } | |
5478 memset(context->linebuf, 0, LINEBUF_SIZE); | |
5479 } else if (context->hslot == index_reset_slot) { | |
5480 context->sprite_index = index_reset_value; | |
5481 context->slot_counter = mode_5 ? 0 : max_sprites; | |
5482 } else if (context->vcounter == vint_line && context->hslot == vint_slot) { | |
5483 context->flags2 |= FLAG2_VINT_PENDING; | |
5484 context->pending_vint_start = context->cycles; | |
5485 } else if (context->vcounter == context->inactive_start && context->hslot == 1 && (context->regs[REG_MODE_4] & BIT_INTERLACE)) { | |
5486 context->flags2 ^= FLAG2_EVEN_FIELD; | |
5487 } | |
5488 | |
5489 if (!is_refresh(context, context->hslot)) { | |
5490 external_slot(context); | |
5491 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) { | |
5492 run_dma_src(context, context->hslot); | |
5493 } | |
5494 } | |
5495 | |
5496 if (is_h40) { | |
5497 if (context->hslot >= HSYNC_SLOT_H40 && context->hslot < HSYNC_END_H40) { | |
5498 context->cycles += h40_hsync_cycles[context->hslot - HSYNC_SLOT_H40]; | |
5499 } else { | |
5500 context->cycles += MCLKS_SLOT_H40; | |
5501 } | |
5502 } else { | |
5503 context->cycles += MCLKS_SLOT_H32; | |
5504 } | |
5505 if (context->hslot == jump_start) { | |
5506 context->hslot = jump_dest; | |
5507 } else { | |
5508 context->hslot++; | |
5509 } | |
5510 if (context->hslot == line_change) { | |
5511 vdp_advance_line(context); | |
5512 if (context->vcounter == active_line) { | |
5513 context->state = PREPARING; | |
5514 return; | |
5515 } | |
5516 } | |
5517 } | |
5518 } | |
5519 | |
5520 void vdp_run_context_full(vdp_context * context, uint32_t target_cycles) | |
5521 { | |
5522 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; | |
5523 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; | |
5524 if (context->renderer) { | |
5525 while(context->cycles < target_cycles) | |
5526 { | |
5527 check_switch_inactive(context, is_h40); | |
5528 | |
5529 if (is_active(context)) { | |
5530 if (mode_5) { | |
5531 if (is_h40) { | |
5532 vdp_h40_phony(context, target_cycles); | |
5533 } else { | |
5534 vdp_h32_phony(context, target_cycles); | |
5535 } | |
5536 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) { | |
5537 //TODO: phonyfy this | |
5538 vdp_h32_mode4(context, target_cycles); | |
5539 } else if (context->regs[REG_MODE_2] & BIT_M1) { | |
5540 vdp_tms_text(context, target_cycles); | |
4969 } else { | 5541 } else { |
4970 vdp_h32(context, target_cycles); | 5542 vdp_tms_graphics(context, target_cycles); |
4971 } | 5543 } |
4972 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) { | |
4973 vdp_h32_mode4(context, target_cycles); | |
4974 } else if (context->regs[REG_MODE_2] & BIT_M1) { | |
4975 vdp_tms_text(context, target_cycles); | |
4976 } else { | 5544 } else { |
4977 vdp_tms_graphics(context, target_cycles); | 5545 vdp_inactive_phony(context, target_cycles, is_h40, mode_5); |
4978 } | 5546 } |
4979 } else { | 5547 } |
4980 vdp_inactive(context, target_cycles, is_h40, mode_5); | 5548 } else { |
5549 while(context->cycles < target_cycles) | |
5550 { | |
5551 check_switch_inactive(context, is_h40); | |
5552 | |
5553 if (is_active(context)) { | |
5554 if (mode_5) { | |
5555 if (is_h40) { | |
5556 vdp_h40(context, target_cycles); | |
5557 } else { | |
5558 vdp_h32(context, target_cycles); | |
5559 } | |
5560 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) { | |
5561 vdp_h32_mode4(context, target_cycles); | |
5562 } else if (context->regs[REG_MODE_2] & BIT_M1) { | |
5563 vdp_tms_text(context, target_cycles); | |
5564 } else { | |
5565 vdp_tms_graphics(context, target_cycles); | |
5566 } | |
5567 } else { | |
5568 vdp_inactive(context, target_cycles, is_h40, mode_5); | |
5569 } | |
4981 } | 5570 } |
4982 } | 5571 } |
4983 } | 5572 } |
4984 | 5573 |
4985 void vdp_run_context(vdp_context *context, uint32_t target_cycles) | 5574 void vdp_run_context(vdp_context *context, uint32_t target_cycles) |