Mercurial > repos > blastem
view ym2612.c @ 345:29d2ca563499
Don't sync the 68K clock to the VDP clock unless the 68K had to wait for the VDP. This unfortunately breaks the direct color DMA demos, but should be more correct overall.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 19 May 2013 13:47:47 -0700 |
parents | a8ee7934a1f8 |
children | cc39629e8d06 |
line wrap: on
line source
#include <string.h> #include "ym2612.h" #define BUSY_CYCLES 17 #define TIMERA_UPDATE_PERIOD 144 #define REG_TIMERA_HIGH 0x3 // 0x24 #define REG_TIMERA_LOW 0x4 // 0x25 #define REG_TIMERB 0x5 // 0x26 #define REG_TIME_CTRL 0x6 // 0x27 #define BIT_TIMERA_ENABLE 0x1 #define BIT_TIMERB_ENABLE 0x2 #define BIT_TIMERA_OVEREN 0x4 #define BIT_TIMERB_OVEREN 0x8 #define BIT_TIMERA_RESET 0x10 #define BIT_TIMERB_RESET 0x20 #define BIT_STATUS_TIMERA 0x1 #define BIT_STATUS_TIMERB 0x2 void ym_init(ym2612_context * context) { memset(context, 0, sizeof(*context)); } void ym_run(ym2612_context * context, uint32_t to_cycle) { uint32_t delta = to_cycle - context->current_cycle; //Timers won't be perfect with this, but it's good enough for now //once actual FM emulation is in place the timers should just be //decremented/reloaded on the appropriate ticks uint32_t timer_delta = to_cycle / TIMERA_UPDATE_PERIOD; if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_ENABLE) { if (timer_delta > context->timer_a) { if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_OVEREN) { context->status |= BIT_STATUS_TIMERA; } uint32_t rem_delta = timer_delta - (context->timer_a+1); uint16_t timer_val = (context->part1_regs[REG_TIMERA_HIGH] << 2) | (context->part1_regs[REG_TIMERA_LOW] & 0x3); context->timer_a = timer_val - (rem_delta % (timer_val + 1)); } else { context->timer_a -= timer_delta; } } timer_delta /= 16; //Timer B runs at 1/16th the speed of Timer A if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_ENABLE) { if (timer_delta > context->timer_b) { if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_OVEREN) { context->status |= BIT_STATUS_TIMERB; } uint32_t rem_delta = timer_delta - (context->timer_b+1); uint8_t timer_val = context->part1_regs[REG_TIMERB]; context->timer_b = timer_val - (rem_delta % (timer_val + 1)); } else { context->timer_a -= timer_delta; } } context->current_cycle = to_cycle; if (to_cycle >= context->write_cycle + BUSY_CYCLES) { context->status &= 0x7F; } } void ym_address_write_part1(ym2612_context * context, uint8_t address) { if (address >= 0x21 && address < 0xB7) { context->selected_reg = context->part1_regs + address - 0x21; } else { context->selected_reg = NULL; } } void ym_address_write_part2(ym2612_context * context, uint8_t address) { if (address >= 0x30 && address < 0xB7) { context->selected_reg = context->part1_regs + address - 0x30; } else { context->selected_reg = NULL; } } void ym_data_write(ym2612_context * context, uint8_t value) { if (context->selected_reg && !(context->status & 0x80)) { *context->selected_reg = value; context->write_cycle = context->current_cycle; context->selected_reg = NULL;//TODO: Verify this } } uint8_t ym_read_status(ym2612_context * context) { return context->status; }