summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blastem.c42
-rw-r--r--m68k_to_x86.h2
-rw-r--r--runtime.S1
-rw-r--r--vdp.c80
-rw-r--r--vdp.h24
5 files changed, 127 insertions, 22 deletions
diff --git a/blastem.c b/blastem.c
index f1fc062..e8abe63 100644
--- a/blastem.c
+++ b/blastem.c
@@ -107,21 +107,39 @@ uint16_t read_dma_value(uint32_t address)
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 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
//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 --git a/m68k_to_x86.h b/m68k_to_x86.h
index 7a80517..3a8e08d 100644
--- a/m68k_to_x86.h
+++ b/m68k_to_x86.h
@@ -28,7 +28,7 @@ typedef struct {
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 --git a/runtime.S b/runtime.S
index 0cd5a27..8c8473b 100644
--- a/runtime.S
+++ b/runtime.S
@@ -42,6 +42,7 @@ already_supervisor:
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 --git a/vdp.c b/vdp.c
index edff0d0..095b9c4 100644
--- a/vdp.c
+++ b/vdp.c
@@ -1028,18 +1028,34 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
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 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
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 @@ uint16_t vdp_control_port_read(vdp_context * context)
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 @@ uint16_t vdp_control_port_read(vdp_context * context)
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 @@ void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
}
}
+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 --git a/vdp.h b/vdp.h
index 650c372..435ccf0 100644
--- a/vdp.h
+++ b/vdp.h
@@ -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 @@ typedef struct {
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_control_port_read(vdp_context * context);
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_