Mercurial > repos > blastem
view ymf262.c @ 2563:f51d750b4d06
Fix sprite overflow regression in Super Hang-On and other games
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 25 Jan 2025 23:54:13 -0800 |
parents | 3f58fec775df |
children | eb588f22ec76 |
line wrap: on
line source
#include <stdlib.h> #include <string.h> #include "ymf262.h" #include "render_audio.h" void ymf262_init(ymf262_context *context, uint32_t master_clock, uint32_t clock_div, uint32_t options) { memset(context, 0, sizeof(*context)); context->clock_inc = clock_div * 8; context->audio = render_audio_source("YMF262", master_clock, context->clock_inc * OPL3_NUM_OPERATORS, 2); ymf262_reset(context); } void ymf262_reset(ymf262_context *context) { //TODO: implement me } void ymf262_free(ymf262_context *context) { render_free_source(context->audio); free(context); } void ymf262_adjust_master_clock(ymf262_context *context, uint32_t master_clock) { render_audio_adjust_clock(context->audio, master_clock, context->clock_inc * OPL3_NUM_OPERATORS); } void ymf262_adjust_cycles(ymf262_context *context, uint32_t deduction) { context->cycle -= deduction; } void ymf262_run(ymf262_context *context, uint32_t to_cycle) { for (; context->cycle < to_cycle; context->cycle += context->clock_inc) { context->current_op++; if (context->current_op == OPL3_NUM_OPERATORS) { context->current_op = 0; int16_t left = 0, right = 0; render_put_stereo_sample(context->audio, left, right); } } } void ymf262_address_write_part1(ymf262_context *context, uint8_t address) { context->selected_reg = address; context->selected_part = 0; } void ymf262_address_write_part2(ymf262_context *context, uint8_t address) { context->selected_reg = address; context->selected_part = 0; } #define OPL3_NTS 0x08 void ymf262_data_write(ymf262_context *context, uint8_t value) { if (!context->selected_reg) { return; } uint8_t old = 0; if (context->selected_reg >= OPL3_PARAM_START && context->selected_reg < OPL3_PARAM_END) { if (context->selected_part) { old = context->part2_regs[context->selected_reg - OPL3_PARAM_START]; context->part2_regs[context->selected_reg - OPL3_PARAM_START] = value; } else { old = context->part1_regs[context->selected_reg - OPL3_PARAM_START]; context->part1_regs[context->selected_reg - OPL3_PARAM_START] = value; } } else if (context->selected_part) { if (context->selected_reg <= sizeof(context->timer_test)) { old = context->timer_test[context->selected_reg - 1]; context->timer_test[context->selected_reg - 1] = value; } else if (context->selected_reg == OPL3_NTS) { old = context->nts; context->nts = value; } else { return; } } else { switch (context->selected_reg) { case 0x01: old = context->part2_test; context->part2_test = value; break; case 0x04: old = context->connection_sel; context->connection_sel = value; break; case 0x05: old = context->opl3_mode; context->opl3_mode = value; break; default: return; } } if (value != old) { if (context->vgm) { if (context->selected_reg) { vgm_ymf262_part2_write(context->vgm, context->cycle, context->selected_reg, value); } else { vgm_ymf262_part1_write(context->vgm, context->cycle, context->selected_reg, value); } } } } void ymf262_vgm_log(ymf262_context *context, uint32_t master_clock, vgm_writer *vgm) { vgm_ymf262_init(vgm, 8 * master_clock / context->clock_inc); context->vgm = vgm; //TODO: write initial state } uint8_t ymf262_read_status(ymf262_context *context, uint32_t cycle, uint32_t port) { if (port) { //TODO: Investigate behavior of invalid status reads return 0xFF; } return context->status; }