annotate ymf262.c @ 2558:3f58fec775df

Initial work on YMF262 (aka OPL3) emulation
author Michael Pavone <pavone@retrodev.com>
date Sun, 19 Jan 2025 00:31:16 -0800
parents
children eb588f22ec76
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2558
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
1 #include <stdlib.h>
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
2 #include <string.h>
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
3 #include "ymf262.h"
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
4 #include "render_audio.h"
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
5
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
6 void ymf262_init(ymf262_context *context, uint32_t master_clock, uint32_t clock_div, uint32_t options)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
7 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
8 memset(context, 0, sizeof(*context));
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
9 context->clock_inc = clock_div * 8;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
10 context->audio = render_audio_source("YMF262", master_clock, context->clock_inc * OPL3_NUM_OPERATORS, 2);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
11 ymf262_reset(context);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
12 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
13
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
14 void ymf262_reset(ymf262_context *context)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
15 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
16 //TODO: implement me
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
17 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
18
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
19 void ymf262_free(ymf262_context *context)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
20 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
21 render_free_source(context->audio);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
22 free(context);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
23 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
24
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
25 void ymf262_adjust_master_clock(ymf262_context *context, uint32_t master_clock)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
26 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
27 render_audio_adjust_clock(context->audio, master_clock, context->clock_inc * OPL3_NUM_OPERATORS);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
28 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
29
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
30 void ymf262_adjust_cycles(ymf262_context *context, uint32_t deduction)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
31 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
32 context->cycle -= deduction;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
33 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
34
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
35 void ymf262_run(ymf262_context *context, uint32_t to_cycle)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
36 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
37 for (; context->cycle < to_cycle; context->cycle += context->clock_inc)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
38 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
39 context->current_op++;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
40 if (context->current_op == OPL3_NUM_OPERATORS) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
41 context->current_op = 0;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
42 int16_t left = 0, right = 0;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
43 render_put_stereo_sample(context->audio, left, right);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
44 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
45 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
46 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
47
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
48 void ymf262_address_write_part1(ymf262_context *context, uint8_t address)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
49 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
50 context->selected_reg = address;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
51 context->selected_part = 0;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
52 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
53 void ymf262_address_write_part2(ymf262_context *context, uint8_t address)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
54 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
55 context->selected_reg = address;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
56 context->selected_part = 0;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
57 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
58
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
59 #define OPL3_NTS 0x08
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
60
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
61 void ymf262_data_write(ymf262_context *context, uint8_t value)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
62 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
63 if (!context->selected_reg) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
64 return;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
65 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
66 uint8_t old = 0;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
67 if (context->selected_reg >= OPL3_PARAM_START && context->selected_reg < OPL3_PARAM_END) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
68 if (context->selected_part) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
69 old = context->part2_regs[context->selected_reg - OPL3_PARAM_START];
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
70 context->part2_regs[context->selected_reg - OPL3_PARAM_START] = value;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
71 } else {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
72 old = context->part1_regs[context->selected_reg - OPL3_PARAM_START];
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
73 context->part1_regs[context->selected_reg - OPL3_PARAM_START] = value;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
74 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
75 } else if (context->selected_part) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
76 if (context->selected_reg <= sizeof(context->timer_test)) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
77 old = context->timer_test[context->selected_reg - 1];
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
78 context->timer_test[context->selected_reg - 1] = value;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
79 } else if (context->selected_reg == OPL3_NTS) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
80 old = context->nts;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
81 context->nts = value;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
82 } else {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
83 return;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
84 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
85 } else {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
86 switch (context->selected_reg)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
87 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
88 case 0x01:
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
89 old = context->part2_test;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
90 context->part2_test = value;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
91 break;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
92 case 0x04:
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
93 old = context->connection_sel;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
94 context->connection_sel = value;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
95 break;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
96 case 0x05:
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
97 old = context->opl3_mode;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
98 context->opl3_mode = value;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
99 break;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
100 default:
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
101 return;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
102 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
103 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
104 if (value != old) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
105 if (context->vgm) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
106 if (context->selected_reg) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
107 vgm_ymf262_part2_write(context->vgm, context->cycle, context->selected_reg, value);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
108 } else {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
109 vgm_ymf262_part1_write(context->vgm, context->cycle, context->selected_reg, value);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
110 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
111 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
112 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
113 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
114
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
115 void ymf262_vgm_log(ymf262_context *context, uint32_t master_clock, vgm_writer *vgm)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
116 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
117 vgm_ymf262_init(vgm, 8 * master_clock / context->clock_inc);
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
118 context->vgm = vgm;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
119 //TODO: write initial state
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
120 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
121
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
122 uint8_t ymf262_read_status(ymf262_context *context, uint32_t cycle, uint32_t port)
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
123 {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
124 if (port) {
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
125 //TODO: Investigate behavior of invalid status reads
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
126 return 0xFF;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
127 }
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
128 return context->status;
3f58fec775df Initial work on YMF262 (aka OPL3) emulation
Michael Pavone <pavone@retrodev.com>
parents:
diff changeset
129 }