summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blastem.c53
-rw-r--r--vdp.c167
-rw-r--r--vdp.h4
3 files changed, 168 insertions, 56 deletions
diff --git a/blastem.c b/blastem.c
index c4072e3..83c2c23 100644
--- a/blastem.c
+++ b/blastem.c
@@ -33,7 +33,7 @@
#define MAX_SOUND_CYCLES 100000
-uint32_t mclks_per_frame = MCLKS_LINE*LINES_NTSC;
+uint32_t mclk_target = 0;
uint16_t cart[CARTRIDGE_WORDS];
uint16_t ram[RAM_WORDS];
@@ -231,15 +231,15 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
z80_context * z_context = gen->z80;
uint32_t mclks = context->current_cycle * MCLKS_PER_68K;
sync_z80(z_context, mclks);
- if (mclks >= mclks_per_frame) {
+ if (mclks >= mclk_target) {
sync_sound(gen, mclks);
- gen->ym->current_cycle -= mclks_per_frame;
- gen->psg->cycles -= mclks_per_frame;
+ gen->ym->current_cycle -= mclk_target;
+ gen->psg->cycles -= mclk_target;
if (gen->ym->write_cycle != CYCLE_NEVER) {
- gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0;
+ gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target/MCLKS_PER_68K ? gen->ym->write_cycle - mclk_target/MCLKS_PER_68K : 0;
}
//printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks);
- vdp_run_context(v_context, mclks_per_frame);
+ vdp_run_context(v_context, mclk_target);
if (!headless) {
break_on_sync |= wait_render_frame(v_context, frame_limit);
@@ -250,28 +250,29 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
}
}
frame++;
- mclks -= mclks_per_frame;
- vdp_adjust_cycles(v_context, mclks_per_frame);
- io_adjust_cycles(gen->ports, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
- io_adjust_cycles(gen->ports+1, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
- io_adjust_cycles(gen->ports+2, context->current_cycle, mclks_per_frame/MCLKS_PER_68K);
+ mclks -= mclk_target;
+ vdp_adjust_cycles(v_context, mclk_target);
+ io_adjust_cycles(gen->ports, context->current_cycle, mclk_target/MCLKS_PER_68K);
+ io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target/MCLKS_PER_68K);
+ io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target/MCLKS_PER_68K);
if (busack_cycle != CYCLE_NEVER) {
- if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) {
- busack_cycle -= mclks_per_frame/MCLKS_PER_68K;
+ if (busack_cycle > mclk_target/MCLKS_PER_68K) {
+ busack_cycle -= mclk_target/MCLKS_PER_68K;
} else {
busack_cycle = CYCLE_NEVER;
busack = new_busack;
}
}
- context->current_cycle -= mclks_per_frame/MCLKS_PER_68K;
- if (z_context->current_cycle >= mclks_per_frame/MCLKS_PER_Z80) {
- z_context->current_cycle -= mclks_per_frame/MCLKS_PER_Z80;
+ context->current_cycle -= mclk_target/MCLKS_PER_68K;
+ if (z_context->current_cycle >= mclk_target/MCLKS_PER_Z80) {
+ z_context->current_cycle -= mclk_target/MCLKS_PER_Z80;
} else {
z_context->current_cycle = 0;
}
if (mclks) {
vdp_run_context(v_context, mclks);
}
+ mclk_target = vdp_cycles_to_frame_end(v_context);
} else {
//printf("running VDP for %d cycles\n", mclks - v_context->cycles);
vdp_run_context(v_context, mclks);
@@ -317,10 +318,10 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_
gen->bus_busy = 1;
while (vdp_data_port_write(v_context, value) < 0) {
while(v_context->flags & FLAG_DMA_RUN) {
- vdp_run_dma_done(v_context, mclks_per_frame);
- if (v_context->cycles >= mclks_per_frame) {
+ vdp_run_dma_done(v_context, mclk_target);
+ if (v_context->cycles >= mclk_target) {
context->current_cycle = v_context->cycles / MCLKS_PER_68K;
- if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) {
+ if (context->current_cycle * MCLKS_PER_68K < mclk_target) {
++context->current_cycle;
}
sync_components(context, 0);
@@ -334,10 +335,10 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_
if (blocked) {
while (blocked) {
while(v_context->flags & FLAG_DMA_RUN) {
- vdp_run_dma_done(v_context, mclks_per_frame);
- if (v_context->cycles >= mclks_per_frame) {
+ vdp_run_dma_done(v_context, mclk_target);
+ if (v_context->cycles >= mclk_target) {
context->current_cycle = v_context->cycles / MCLKS_PER_68K;
- if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) {
+ if (context->current_cycle * MCLKS_PER_68K < mclk_target) {
++context->current_cycle;
}
sync_components(context, 0);
@@ -966,7 +967,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u
context.system = gen;
//cartridge ROM
context.mem_pointers[0] = cart;
- context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K;
+ context.target_cycle = context.sync_cycle = mclk_target/MCLKS_PER_68K;
//work RAM
context.mem_pointers[1] = ram;
//save RAM/map
@@ -1210,7 +1211,6 @@ int main(int argc, char ** argv)
height = height < 240 ? (width/320) * 240 : height;
uint32_t fps = 60;
if (version_reg & 0x40) {
- mclks_per_frame = MCLKS_LINE * LINES_PAL;
fps = 50;
}
if (!headless) {
@@ -1221,7 +1221,8 @@ int main(int argc, char ** argv)
memset(&gen, 0, sizeof(gen));
gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL;
- init_vdp_context(&v_context);
+ init_vdp_context(&v_context, version_reg & 0x40);
+ mclk_target = vdp_cycles_to_frame_end(&v_context);
ym2612_context y_context;
ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0);
@@ -1236,7 +1237,7 @@ int main(int argc, char ** argv)
z_context.system = &gen;
z_context.mem_pointers[0] = z80_ram;
- z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80;
+ z_context.sync_cycle = z_context.target_cycle = mclk_target/MCLKS_PER_Z80;
z_context.int_cycle = CYCLE_NEVER;
z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart;
diff --git a/vdp.c b/vdp.c
index ad8ed00..126e3be 100644
--- a/vdp.c
+++ b/vdp.c
@@ -46,7 +46,7 @@ uint8_t debug_base[][3] = {
uint8_t color_map_init_done;
-void init_vdp_context(vdp_context * context)
+void init_vdp_context(vdp_context * context, uint8_t region_pal)
{
memset(context, 0, sizeof(*context));
context->vdpmem = malloc(VRAM_SIZE);
@@ -133,6 +133,9 @@ void init_vdp_context(vdp_context * context)
context->debugcolors[color] = render_map_color(r, g, b);
}
}
+ if (region_pal) {
+ context->flags2 |= FLAG2_REGION_PAL;
+ }
}
int is_refresh(vdp_context * context, uint32_t slot)
@@ -1428,7 +1431,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
latch_mode(context);
}
uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
- if (is_h40 && slot == 167 || !is_h40 && slot == 134) {
+ if (is_h40 && slot == HBLANK_START_H40 || !is_h40 && slot == 134) {
if (line >= inactive_start) {
context->hint_counter = context->regs[REG_HINT];
} else if (context->hint_counter) {
@@ -1467,7 +1470,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) {
//run VDP rendering for a slot or a line
if (is_h40) {
- if (slot == 167 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) {
+ if (slot == HBLANK_START_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) {
vdp_h40_line(line, context);
inccycles = MCLKS_LINE;
context->vcounter++;
@@ -1493,7 +1496,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
context->hslot++;
context->hslot &= 0xFF;
if (is_h40) {
- if (context->hslot == 167) {
+ if (context->hslot == HBLANK_START_H40) {
context->vcounter++;
} else if (context->hslot == 183) {
context->hslot = 229;
@@ -1507,10 +1510,17 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
}
}
- if (context->vcounter == 0xEA) {
- context->vcounter += 0xFA;
- } else {
- context->vcounter &= 0x1FF;
+ context->vcounter &= 0x1FF;
+ if (context->flags2 & FLAG2_REGION_PAL) {
+ if (context->latched_mode & BIT_PAL) {
+ if (context->vcounter == 0x10B) {
+ context->vcounter = 0x1D2;
+ }
+ } else if (context->vcounter == 0x103){
+ context->vcounter = 0x1CA;
+ }
+ } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) {
+ context->vcounter = 0x1E5;
}
context->cycles += inccycles;
}
@@ -1757,6 +1767,7 @@ uint16_t vdp_hv_counter_read(vdp_context * context)
line |= 1;
}
}
+ printf("hv_counter_read line: %d, horiz: %d, cycles: %d\n", line, linecyc, context->cycles);
return (line << 8) | linecyc;
}
@@ -1782,6 +1793,88 @@ void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
}
}
+uint32_t vdp_cycles_next_line(vdp_context * context)
+{
+ if (context->regs[REG_MODE_4] & BIT_H40) {
+ if (context->hslot < HBLANK_START_H40) {
+ return (HBLANK_START_H40 - context->hslot) * MCLKS_SLOT_H40;
+ } else if (context->hslot < 183) {
+ return MCLKS_LINE - (context->hslot - HBLANK_START_H40) * MCLKS_SLOT_H40;
+ } else {
+ return (256-context->hslot + HBLANK_START_H40) * MCLKS_SLOT_H40;
+ }
+ } else {
+ if (context->hslot < HBLANK_START_H32) {
+ return (HBLANK_START_H32 - context->hslot) * MCLKS_SLOT_H32;
+ } else if (context->hslot < 148) {
+ return MCLKS_LINE - (context->hslot - HBLANK_START_H32) * MCLKS_SLOT_H32;
+ } else {
+ return (256-context->hslot + HBLANK_START_H32) * MCLKS_SLOT_H32;
+ }
+ }
+}
+
+uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target)
+{
+ uint32_t jump_start, jump_dst;
+ if (context->flags2 & FLAG2_REGION_PAL) {
+ if (context->latched_mode & BIT_PAL) {
+ jump_start = 0x10B;
+ jump_dst = 0x1D2;
+ } else {
+ jump_start = 0x103;
+ jump_dst = 0x1CA;
+ }
+ } else {
+ if (context->latched_mode & BIT_PAL) {
+ jump_start = 0;
+ jump_dst = 0;
+ } else {
+ jump_start = 0xEB;
+ jump_dst = 0x1E5;
+ }
+ }
+ uint32_t lines;
+ if (context->vcounter < target) {
+ if (target < jump_start) {
+ lines = target - context->vcounter;
+ } else {
+ lines = jump_start - context->vcounter + target - jump_dst;
+ }
+ } else {
+ if (context->vcounter < jump_start) {
+ lines = jump_start - context->vcounter + 512 - jump_dst;
+ } else {
+ lines = 512 - context->vcounter;
+ }
+ if (target < jump_start) {
+ lines += target;
+ } else {
+ lines += jump_start + target - jump_dst;
+ }
+ }
+ return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context);
+}
+
+uint32_t vdp_cycles_to_frame_end(vdp_context * context)
+{
+ uint32_t frame_end;
+ if (context->flags2 & FLAG2_REGION_PAL) {
+ if (context->latched_mode & BIT_PAL) {
+ frame_end = PAL_INACTIVE_START + 8;
+ } else {
+ frame_end = NTSC_INACTIVE_START + 8;
+ }
+ } else {
+ if (context->latched_mode & BIT_PAL) {
+ frame_end = 512;
+ } else {
+ frame_end = NTSC_INACTIVE_START + 8;
+ }
+ }
+ return context->cycles + vdp_cycles_to_line(context, frame_end);
+}
+
uint32_t vdp_next_hint(vdp_context * context)
{
if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) {
@@ -1791,13 +1884,14 @@ uint32_t vdp_next_hint(vdp_context * context)
return context->cycles;
}
uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
- uint32_t line = context->cycles / MCLKS_LINE;
- if (line >= inactive_start) {
- return 0xFFFFFFFF;
+ uint32_t hint_line;
+ if (context->vcounter >= inactive_start) {
+ hint_line = context->regs[REG_HINT];
+ } else {
+ hint_line = context->vcounter + context->hint_counter + 1;
}
- uint32_t linecyc = context->cycles % MCLKS_LINE;
- uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc;
- return hcycle;
+
+ return context->cycles + vdp_cycles_to_line(context, hint_line);
}
uint32_t vdp_next_vint(vdp_context * context)
@@ -1808,29 +1902,44 @@ uint32_t vdp_next_vint(vdp_context * context)
if (context->flags2 & FLAG2_VINT_PENDING) {
return context->cycles;
}
- uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
- uint32_t vcycle = MCLKS_LINE * inactive_start;
- if (context->regs[REG_MODE_4] & BIT_H40) {
- vcycle += VINT_SLOT_H40 * MCLKS_SLOT_H40;
- } else {
- vcycle += VINT_SLOT_H32 * MCLKS_SLOT_H32;
- }
- if (vcycle < context->cycles) {
- return 0xFFFFFFFF;
- }
- return vcycle;
+
+
+ return vdp_next_vint_z80(context);
}
uint32_t vdp_next_vint_z80(vdp_context * context)
{
uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
- uint32_t vcycle = MCLKS_LINE * inactive_start;
+ if (context->vcounter == inactive_start) {
+ if (context->regs[REG_MODE_4] & BIT_H40) {
+ if (context->hslot >= HBLANK_START_H40) {
+ if (context->hslot < 183) {
+ return context->cycles + (VINT_SLOT_H40 + 183 - context->hslot + 256 - 229) * MCLKS_SLOT_H40;
+ } else {
+ return context->cycles + (VINT_SLOT_H40 + 256 - context->hslot) * MCLKS_SLOT_H40;
+ }
+ } else if (context->hslot < VINT_SLOT_H40) {
+ return context->cycles + (VINT_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40;
+ }
+ } else {
+ if (context->hslot >= HBLANK_START_H32) {
+ if (context->hslot < 148) {
+ return context->cycles + (VINT_SLOT_H32 + 148 - context->hslot + 256 - 233) * MCLKS_SLOT_H32;
+ } else {
+ return context->cycles + (VINT_SLOT_H32 + 256 - context->hslot) * MCLKS_SLOT_H32;
+ }
+ } else if (context->hslot < VINT_SLOT_H32) {
+ return context->cycles + (VINT_SLOT_H32 - context->hslot) * MCLKS_SLOT_H32;
+ }
+ }
+ }
+ int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start);
if (context->regs[REG_MODE_4] & BIT_H40) {
- vcycle += VINT_SLOT_H40 * MCLKS_SLOT_H40;
+ cycles_to_vint += (VINT_SLOT_H40 + 183 - HBLANK_START_H40 + 256 - 229) * MCLKS_SLOT_H40;
} else {
- vcycle += VINT_SLOT_H32 * MCLKS_SLOT_H32;
+ cycles_to_vint += (VINT_SLOT_H32 + 148 - HBLANK_START_H32 + 256 - 233) * MCLKS_SLOT_H32;
}
- return vcycle;
+ return context->cycles + cycles_to_vint;
}
void vdp_int_ack(vdp_context * context, uint16_t int_num)
diff --git a/vdp.h b/vdp.h
index 2fa8f36..184521a 100644
--- a/vdp.h
+++ b/vdp.h
@@ -49,6 +49,7 @@
#define FLAG2_HINT_PENDING 0x02
#define FLAG2_READ_PENDING 0x04
#define FLAG2_SPRITE_COLLIDE 0x08
+#define FLAG2_REGION_PAL 0x10
#define DISPLAY_ENABLE 0x40
@@ -169,7 +170,7 @@ typedef struct {
uint8_t *tmp_buf_b;
} vdp_context;
-void init_vdp_context(vdp_context * context);
+void init_vdp_context(vdp_context * context, uint8_t region_pal);
void vdp_run_context(vdp_context * context, uint32_t target_cycles);
//runs from current cycle count to VBLANK for the current mode, returns ending cycle count
uint32_t vdp_run_to_vblank(vdp_context * context);
@@ -192,6 +193,7 @@ void vdp_int_ack(vdp_context * context, uint16_t int_num);
void vdp_print_sprite_table(vdp_context * context);
void vdp_print_reg_explain(vdp_context * context);
void latch_mode(vdp_context * context);
+uint32_t vdp_cycles_to_frame_end(vdp_context * context);
extern int32_t color_map[1 << 12];