# HG changeset patch # User Mike Pavone # Date 1368251876 25200 # Node ID e5e8b48ad1575ab9971e15910825eac212d85523 # Parent fd7c24b97ebfefbbbe427b92ae6935f70ad3da7a Initial stab at horizontal interrupts and improving accuracy of vertical interrupts. Also added the VINT pending flag to status port. diff -r fd7c24b97ebf -r e5e8b48ad157 blastem.c --- a/blastem.c Thu May 09 20:59:49 2013 -0700 +++ b/blastem.c Fri May 10 22:57:56 2013 -0700 @@ -107,21 +107,39 @@ return 0; } -#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_68K) -#define ZVINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) +//TODO: Make these dependent on the video mode +//#define VINT_CYCLE ((MCLKS_LINE * 225 + (148 + 40) * 4)/MCLKS_PER_68K) +#define ZVINT_CYCLE ((MCLKS_LINE * 225 + (148 + 40) * 4)/MCLKS_PER_Z80) +//#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_68K) +//#define ZVINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) void adjust_int_cycle(m68k_context * context, vdp_context * v_context) { - if (!(v_context->regs[REG_MODE_2] & 0x20 && ((context->status & 0x7) < 6)) || context->current_cycle >= VINT_CYCLE) { - context->int_cycle = CYCLE_NEVER; - context->target_cycle = context->sync_cycle; - } else if (context->int_cycle > VINT_CYCLE) { - context->int_cycle = VINT_CYCLE; - context->int_num = 6; - if (context->int_cycle < context->sync_cycle) { - context->target_cycle = context->int_cycle; + context->int_cycle = CYCLE_NEVER; + if ((context->status & 0x7) < 6) { + uint32_t next_vint = vdp_next_vint(v_context); + if (next_vint != CYCLE_NEVER) { + next_vint /= MCLKS_PER_68K; + context->int_cycle = next_vint; + context->int_num = 6; + } + if ((context->status & 0x7) < 4) { + uint32_t next_hint = vdp_next_hint(v_context); + if (next_hint != CYCLE_NEVER) { + next_hint /= MCLKS_PER_68K; + if (next_hint < context->int_cycle) { + context->int_cycle = next_hint; + context->int_num = 4; + + } + } } } + + context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; + /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", + context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), + v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/ } int break_on_sync = 0; @@ -196,6 +214,10 @@ //printf("running VDP for %d cycles\n", mclks - v_context->cycles); vdp_run_context(v_context, mclks); } + if (context->int_ack) { + vdp_int_ack(v_context, context->int_ack); + context->int_ack = 0; + } adjust_int_cycle(context, v_context); if (break_on_sync && address) { break_on_sync = 0; diff -r fd7c24b97ebf -r e5e8b48ad157 m68k_to_x86.h --- a/m68k_to_x86.h Thu May 09 20:59:49 2013 -0700 +++ b/m68k_to_x86.h Fri May 10 22:57:56 2013 -0700 @@ -28,7 +28,7 @@ typedef struct { uint8_t flags[5]; uint8_t status; - uint16_t reserved; + uint16_t int_ack; uint32_t dregs[8]; uint32_t aregs[9]; uint32_t target_cycle; //cycle at which the next synchronization or interrupt occurs diff -r fd7c24b97ebf -r e5e8b48ad157 runtime.S --- a/runtime.S Thu May 09 20:59:49 2013 -0700 +++ b/runtime.S Fri May 10 22:57:56 2013 -0700 @@ -42,6 +42,7 @@ or %cl, 5(%rsi) /* calculate interrupt vector address */ mov 92(%rsi), %ecx + mov %cx, 6(%rsi) /* interrupt acknowlege */ shl $2, %ecx add $0x60, %ecx call m68k_read_long_scratch1 diff -r fd7c24b97ebf -r e5e8b48ad157 vdp.c --- a/vdp.c Thu May 09 20:59:49 2013 -0700 +++ b/vdp.c Fri May 10 22:57:56 2013 -0700 @@ -1028,18 +1028,34 @@ if (!line) { latch_mode(context); } + uint32_t linecyc = context->cycles % MCLKS_LINE; + if (linecyc == 0) { + if (line <= 1 || line >= active_lines) { + context->hint_counter = context->regs[REG_HINT]; + } else if (context->hint_counter) { + context->hint_counter--; + } else { + context->flags2 |= FLAG2_HINT_PENDING; + context->hint_counter = context->regs[REG_HINT]; + } + } else if(line == active_lines) { + uint32_t intcyc = context->latched_mode & BIT_H40 ? (148 + 40) * 4 : (132 + 28) * 5;; + if (linecyc == intcyc) { + context->flags2 |= FLAG2_VINT_PENDING; + } + } if (line < active_lines && context->regs[REG_MODE_2] & DISPLAY_ENABLE) { //first sort-of active line is treated as 255 internally //it's used for gathering sprite info for line line = (line - 1) & 0xFF; - uint32_t linecyc = context->cycles % MCLKS_LINE; //Convert to slot number if (context->latched_mode & BIT_H40){ //TODO: Deal with nasty clock switching during HBLANK + uint32_t clock_inc = MCLKS_LINE-linecyc < 16 ? MCLKS_LINE-linecyc : 16; linecyc = linecyc/16; vdp_h40(line, linecyc, context); - context->cycles += 16; + context->cycles += clock_inc; } else { linecyc = linecyc/20; vdp_h32(line, linecyc, context); @@ -1053,8 +1069,9 @@ check_render_bg(context, line); } if (context->latched_mode & BIT_H40){ + uint32_t clock_inc = MCLKS_LINE-linecyc < 16 ? MCLKS_LINE-linecyc : 16; //TODO: Deal with nasty clock switching during HBLANK - context->cycles += 16; + context->cycles += clock_inc; } else { context->cycles += 20; } @@ -1173,6 +1190,9 @@ if (context->fifo_cur == context->fifo_end) { value |= 0x100; } + if (context->flags2 & FLAG2_VINT_PENDING) { + value |- 0x80; + } if (context->flags & FLAG_DMA_RUN) { value |= 0x2; } @@ -1180,6 +1200,9 @@ if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE)) { value |= 0x8; } + if (context->latched_mode & BIT_PAL) {//Not sure about this, need to verify + value |= 0x1; + } //TODO: Lots of other bits in status port return value; } @@ -1268,6 +1291,57 @@ } } +uint32_t vdp_next_hint(vdp_context * context) +{ + if (!(context->regs[REG_MODE_1] & 0x10)) { + return 0xFFFFFFFF; + } + if (context->flags2 & FLAG2_HINT_PENDING) { + return context->cycles; + } + uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; + uint32_t line = context->cycles / MCLKS_LINE; + if (line >= active_lines) { + return 0xFFFFFFFF; + } + uint32_t linecyc = context->cycles % MCLKS_LINE; + uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc; + if (!line) { + hcycle += MCLKS_LINE; + } + return hcycle; +} + +uint32_t vdp_next_vint(vdp_context * context) +{ + if (!(context->regs[REG_MODE_2] & 0x20)) { + return 0xFFFFFFFF; + } + if (context->flags2 & FLAG2_VINT_PENDING) { + return context->cycles; + } + uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; + uint32_t vcycle = MCLKS_LINE * active_lines; + if (context->latched_mode & BIT_H40) { + vcycle += (148 + 40) * 4; + } else { + vcycle += (132 + 28) * 5; + } + if (vcycle < context->cycles) { + return 0xFFFFFFFF; + } + return vcycle; +} + +void vdp_int_ack(vdp_context * context, uint16_t int_num) +{ + if (int_num == 6) { + context->flags2 &= ~FLAG2_VINT_PENDING; + } else if(int_num ==4) { + context->flags2 &= ~FLAG2_HINT_PENDING; + } +} + #define GST_VDP_REGS 0xFA #define GST_VDP_MEM 0x12478 diff -r fd7c24b97ebf -r e5e8b48ad157 vdp.h --- a/vdp.h Thu May 09 20:59:49 2013 -0700 +++ b/vdp.h Fri May 10 22:57:56 2013 -0700 @@ -30,14 +30,17 @@ #define MCLKS_LINE 3420 -#define FLAG_DOT_OFLOW 0x1 -#define FLAG_CAN_MASK 0x2 -#define FLAG_MASKED 0x4 -#define FLAG_WINDOW 0x8 -#define FLAG_PENDING 0x10 -#define FLAG_UNUSED_SLOT 0x20 -#define FLAG_DMA_RUN 0x40 -#define FLAG_DMA_PROG 0x80 +#define FLAG_DOT_OFLOW 0x01 +#define FLAG_CAN_MASK 0x02 +#define FLAG_MASKED 0x04 +#define FLAG_WINDOW 0x08 +#define FLAG_PENDING 0x10 +#define FLAG_UNUSED_SLOT 0x20 +#define FLAG_DMA_RUN 0x40 +#define FLAG_DMA_PROG 0x80 + +#define FLAG2_VINT_PENDING 0x01 +#define FLAG2_HINT_PENDING 0x02 #define DISPLAY_ENABLE 0x40 @@ -115,6 +118,8 @@ uint16_t dma_val; uint8_t v_offset; uint8_t dma_cd; + uint8_t hint_counter; + uint8_t flags2; uint8_t *tmp_buf_a; uint8_t *tmp_buf_b; } vdp_context; @@ -133,5 +138,8 @@ uint16_t vdp_data_port_read(vdp_context * context); uint16_t vdp_hv_counter_read(vdp_context * context); void vdp_adjust_cycles(vdp_context * context, uint32_t deduction); +uint32_t vdp_next_hint(vdp_context * context); +uint32_t vdp_next_vint(vdp_context * context); +void vdp_int_ack(vdp_context * context, uint16_t int_num); #endif //VDP_H_