aboutsummaryrefslogtreecommitdiff
path: root/src/chips/esfmu/esfm.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/chips/esfmu/esfm.h')
-rw-r--r--src/chips/esfmu/esfm.h293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/chips/esfmu/esfm.h b/src/chips/esfmu/esfm.h
new file mode 100644
index 0000000..5ea9607
--- /dev/null
+++ b/src/chips/esfmu/esfm.h
@@ -0,0 +1,293 @@
+/*
+ * ESFMu: emulator for the ESS "ESFM" enhanced OPL3 clone
+ * Copyright (C) 2023 Kagamiin~
+ *
+ * ESFMu is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * ESFMu is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ESFMu. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/*
+ * ESFMu wouldn't have been possible without the hard work and dedication of
+ * the retro computer hardware research and preservation community.
+ *
+ * I'd like to thank:
+ * - Nuke.YKT
+ * Developer of Nuked OPL3, which was the basis for ESFMu's code and
+ * also a great learning resource on Yamaha FM synthesis for myself.
+ * Nuke.YKT also gives shoutouts on behalf of Nuked OPL3 to:
+ * - MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
+ * Feedback and Rhythm part calculation information.
+ * - forums.submarine.org.uk(carbon14, opl3):
+ * Tremolo and phase generator calculation information.
+ * - OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
+ * OPL2 ROMs.
+ * - siliconpr0n.org(John McMaster, digshadow):
+ * YMF262 and VRC VII decaps and die shots.
+ * - rainwarrior
+ * For performing the initial research on ESFM drivers and documenting
+ * ESS's patent on native mode operator organization.
+ * - jwt27
+ * For kickstarting the ESFM research project and compiling rainwarrior's
+ * findings and more in an accessible document ("ESFM Demystified").
+ * - pachuco/CatButts
+ * For documenting ESS's patent on ESFM's feedback implementation, which
+ * was vital in getting ESFMu's sound output to be accurate.
+ * - akumanatt
+ * For helping out with code optimization.
+ * - And everybody who helped out with real hardware testing
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _esfm_slot esfm_slot;
+/* typedef struct _esfm_slot_internal esfm_slot_internal; */
+typedef struct _esfm_channel esfm_channel;
+typedef struct _esfm_chip esfm_chip;
+
+
+void ESFM_init (esfm_chip *chip);
+void ESFM_write_reg (esfm_chip *chip, uint16_t address, uint8_t data);
+void ESFM_write_reg_buffered (esfm_chip *chip, uint16_t address, uint8_t data);
+void ESFM_write_reg_buffered_fast (esfm_chip *chip, uint16_t address, uint8_t data);
+void ESFM_write_port (esfm_chip *chip, uint8_t offset, uint8_t data);
+uint8_t ESFM_readback_reg (esfm_chip *chip, uint16_t address);
+uint8_t ESFM_read_port (esfm_chip *chip, uint8_t offset);
+void ESFM_generate(esfm_chip *chip, int16_t *buf);
+void ESFM_generate_stream(esfm_chip *chip, int16_t *sndptr, uint32_t num_samples);
+int16_t ESFM_get_channel_output_native(esfm_chip *chip, int channel_idx);
+
+
+/* These are fake types just for syntax sugar. */
+/* Beware of their underlying types when reading/writing to them. */
+typedef int esbool;
+#define estrue 1
+#define esfalse 0
+typedef uint8_t flag;
+typedef uint8_t uint2;
+typedef uint8_t uint3;
+typedef uint8_t uint4;
+typedef uint8_t uint5;
+typedef uint8_t uint6;
+typedef uint8_t uint8;
+typedef uint16_t uint9;
+typedef uint16_t uint10;
+typedef uint16_t uint11;
+typedef uint16_t uint12;
+typedef uint16_t uint16;
+typedef uint32_t uint19;
+typedef uint32_t uint23;
+typedef uint32_t uint32;
+typedef uint64_t uint36;
+
+typedef int16_t int13;
+typedef int16_t int14;
+typedef int16_t int16;
+typedef int32_t int32;
+
+enum eg_states
+{
+ EG_ATTACK,
+ EG_DECAY,
+ EG_SUSTAIN,
+ EG_RELEASE
+};
+
+
+typedef struct _esfm_write_buf
+{
+ uint64_t timestamp;
+ uint16_t address;
+ uint8_t data;
+ flag valid;
+
+} esfm_write_buf;
+
+typedef struct _emu_slot_channel_mapping
+{
+ int channel_idx;
+ int slot_idx;
+
+} emu_slot_channel_mapping;
+
+typedef struct _esfm_slot_internal
+{
+ uint9 eg_position;
+ uint9 eg_ksl_offset;
+ uint10 eg_output;
+
+ uint4 keyscale;
+
+ int13 output;
+ int13 emu_output_enable;
+ int13 emu_mod_enable;
+ int13 feedback_buf;
+ int13 *mod_input;
+
+ uint19 phase_acc;
+ uint10 phase_out;
+ flag phase_reset;
+ flag *key_on;
+ flag key_on_gate;
+
+ uint2 eg_state;
+ flag eg_delay_run;
+ flag eg_delay_transitioned_10;
+ flag eg_delay_transitioned_10_gate;
+ flag eg_delay_transitioned_01;
+ flag eg_delay_transitioned_01_gate;
+ uint16 eg_delay_counter;
+ uint16 eg_delay_counter_compare;
+
+} esfm_slot_internal;
+
+struct _esfm_slot
+{
+ /* Metadata */
+ esfm_channel *channel;
+ esfm_chip *chip;
+ uint2 slot_idx;
+
+ /* Register data */
+ int13 out_enable[2];
+ uint10 f_num;
+ uint3 block;
+ uint3 output_level;
+ /* a.k.a. feedback level in emu mode */
+ uint3 mod_in_level;
+
+ uint6 t_level;
+ uint4 mult;
+ uint3 waveform;
+ /* Only for 4th slot */
+ uint2 rhy_noise;
+
+ uint4 attack_rate;
+ uint4 decay_rate;
+ uint4 sustain_lvl;
+ uint4 release_rate;
+
+ flag tremolo_en;
+ flag tremolo_deep;
+ flag vibrato_en;
+ flag vibrato_deep;
+ flag emu_connection_typ;
+ flag env_sustaining;
+ flag ksr;
+ uint2 ksl;
+ uint3 env_delay;
+ /* overlaps with env_delay bit 0 */
+ /* TODO: check if emu mode only uses this, or if it actually overwrites the channel field used by native mode */
+ flag emu_key_on;
+
+ /* Internal state */
+ esfm_slot_internal in;
+};
+
+struct _esfm_channel
+{
+ esfm_chip *chip;
+ esfm_slot slots[4];
+ uint5 channel_idx;
+ int16 output[2];
+ flag key_on;
+ flag emu_mode_4op_enable;
+ /* Only for 17th and 18th channels */
+ flag key_on_2;
+ flag emu_mode_4op_enable_2;
+};
+
+#define ESFM_WRITEBUF_SIZE 1024
+#define ESFM_WRITEBUF_DELAY 2
+
+struct _esfm_chip
+{
+ esfm_channel channels[18];
+ int32 output_accm[2];
+ uint16 addr_latch;
+
+ flag emu_wavesel_enable;
+ flag emu_newmode;
+ flag native_mode;
+
+ flag keyscale_mode;
+
+ /* Global state */
+ uint36 eg_timer;
+ uint10 global_timer;
+ uint8 eg_clocks;
+ flag eg_tick;
+ flag eg_timer_overflow;
+ uint8 tremolo;
+ uint8 tremolo_pos;
+ uint8 vibrato_pos;
+ uint23 lfsr;
+
+ flag rm_hh_bit2;
+ flag rm_hh_bit3;
+ flag rm_hh_bit7;
+ flag rm_hh_bit8;
+ flag rm_tc_bit3;
+ flag rm_tc_bit5;
+
+
+ /* 0xbd register in emulation mode, exposed in 0x4bd in native mode */
+ /* ("bass drum" register */
+ uint8 emu_rhy_mode_flags;
+
+ flag emu_vibrato_deep;
+ flag emu_tremolo_deep;
+
+ double timer_accumulator[2];
+ uint8 timer_reload[2];
+ uint8 timer_counter[2];
+ flag timer_enable[2];
+ flag timer_mask[2];
+ flag timer_overflow[2];
+ flag irq_bit;
+
+ /* -- Test bits (NOT IMPLEMENTED) -- */
+ /* Halts the envelope generators from advancing. Written on bit 0, read back from bit 5. */
+ flag test_bit_w0_r5_eg_halt;
+ /*
+ * Activates some sort of waveform test mode that amplifies the output volume greatly
+ * and continuously shifts the waveform table downwards, possibly also outputting the
+ * waveform's derivative? (it's so weird!)
+ */
+ flag test_bit_1_distort;
+ /* Seems to do nothing. */
+ flag test_bit_2;
+ /* Seems to do nothing. */
+ flag test_bit_3;
+ /* Appears to attenuate the output by about 3 dB. */
+ flag test_bit_4_attenuate;
+ /* Written on bit 5, read back from bit 0. Seems to do nothing. */
+ flag test_bit_w5_r0;
+ /* Resets all phase generators and holds them in the reset state while this bit is set. */
+ flag test_bit_6_phase_stop_reset;
+ /* Seems to do nothing. */
+ flag test_bit_7;
+
+ esfm_write_buf write_buf[ESFM_WRITEBUF_SIZE];
+ size_t write_buf_start;
+ size_t write_buf_end;
+ uint64_t write_buf_timestamp;
+};
+
+#ifdef __cplusplus
+}
+#endif