Mercurial > repos > blastem
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 |
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 } |