|
| 1 | +#pragma once |
| 2 | +/*# |
| 3 | + # sgu1.h |
| 4 | +
|
| 5 | + SGU-1 Sound Generator Unit 1 emulation |
| 6 | +
|
| 7 | + ## Emulated Pins |
| 8 | +
|
| 9 | + *********************************** |
| 10 | + * +-----------+ * |
| 11 | + * CS --->| |<--- A0 * |
| 12 | + * RW --->| |... * |
| 13 | + * | |<--- A4 * |
| 14 | + * | SGU-1 | * |
| 15 | + * | |<--> D0 * |
| 16 | + * | |... * |
| 17 | + * | |<--> D7 * |
| 18 | + * | | * |
| 19 | + * +-----------+ * |
| 20 | + *********************************** |
| 21 | +
|
| 22 | + The emulation has an additional "virtual pin" which is set to active |
| 23 | + whenever a new sample is ready (SGU1_SAMPLE). |
| 24 | +
|
| 25 | + ## Links |
| 26 | +
|
| 27 | + - |
| 28 | +
|
| 29 | + ## 0BSD license |
| 30 | +
|
| 31 | + Copyright (c) 2025 Tomasz Sterna |
| 32 | +
|
| 33 | + Permission to use, copy, modify, and/or distribute this software for any |
| 34 | + purpose with or without fee is hereby granted. |
| 35 | +
|
| 36 | + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 37 | + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 38 | + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 39 | + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 40 | + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 41 | + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 42 | + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 43 | +#*/ |
| 44 | + |
| 45 | +#include <stdint.h> |
| 46 | +#include <stdbool.h> |
| 47 | + |
| 48 | +#ifdef __cplusplus |
| 49 | +extern "C" { |
| 50 | +#endif |
| 51 | + |
| 52 | +// address bus pins A0..A5 |
| 53 | +#define SGU1_PIN_A0 (0) |
| 54 | +#define SGU1_PIN_A1 (1) |
| 55 | +#define SGU1_PIN_A2 (2) |
| 56 | +#define SGU1_PIN_A3 (3) |
| 57 | +#define SGU1_PIN_A4 (4) |
| 58 | +#define SGU1_PIN_A5 (5) |
| 59 | + |
| 60 | +// data bus pins D0..D7 |
| 61 | +#define SGU1_PIN_D0 (16) |
| 62 | +#define SGU1_PIN_D1 (17) |
| 63 | +#define SGU1_PIN_D2 (18) |
| 64 | +#define SGU1_PIN_D3 (19) |
| 65 | +#define SGU1_PIN_D4 (20) |
| 66 | +#define SGU1_PIN_D5 (21) |
| 67 | +#define SGU1_PIN_D6 (22) |
| 68 | +#define SGU1_PIN_D7 (23) |
| 69 | + |
| 70 | +// shared control pins |
| 71 | +#define SGU1_PIN_RW (24) /* same as M6502_RW */ |
| 72 | + |
| 73 | +// chip-specific pins |
| 74 | +#define SGU1_PIN_CS (40) /* chip-select */ |
| 75 | +#define SGU1_PIN_SAMPLE (41) /* virtual "audio sample ready" pin */ |
| 76 | + |
| 77 | +// pin bit masks |
| 78 | +#define SGU1_A0 (1ULL << SGU1_PIN_A0) |
| 79 | +#define SGU1_A1 (1ULL << SGU1_PIN_A1) |
| 80 | +#define SGU1_A2 (1ULL << SGU1_PIN_A2) |
| 81 | +#define SGU1_A3 (1ULL << SGU1_PIN_A3) |
| 82 | +#define SGU1_A4 (1ULL << SGU1_PIN_A4) |
| 83 | +#define SGU1_A5 (1ULL << SGU1_PIN_A5) |
| 84 | +#define SGU1_ADDR_MASK (0x3F) |
| 85 | +#define SGU1_D0 (1ULL << SGU1_PIN_D0) |
| 86 | +#define SGU1_D1 (1ULL << SGU1_PIN_D1) |
| 87 | +#define SGU1_D2 (1ULL << SGU1_PIN_D2) |
| 88 | +#define SGU1_D3 (1ULL << SGU1_PIN_D3) |
| 89 | +#define SGU1_D4 (1ULL << SGU1_PIN_D4) |
| 90 | +#define SGU1_D5 (1ULL << SGU1_PIN_D5) |
| 91 | +#define SGU1_D6 (1ULL << SGU1_PIN_D6) |
| 92 | +#define SGU1_D7 (1ULL << SGU1_PIN_D7) |
| 93 | +#define SGU1_RW (1ULL << SGU1_PIN_RW) |
| 94 | +#define SGU1_CS (1ULL << SGU1_PIN_CS) |
| 95 | +#define SGU1_SAMPLE (1ULL << SGU1_PIN_SAMPLE) |
| 96 | + |
| 97 | +// channel registers |
| 98 | +#define SGU1_CHAN_FREQ_LO (0) |
| 99 | +#define SGU1_CHAN_FREQ_HI (1) |
| 100 | +#define SGU1_CHAN_VOL (2) |
| 101 | +#define SGU1_CHAN_PAN (3) |
| 102 | +#define SGU1_CHAN_FLAGS0 (4) |
| 103 | +#define SGU1_CHAN_FLAGS1 (5) |
| 104 | +#define SGU1_CHAN_CUTOFF_LO (6) |
| 105 | +#define SGU1_CHAN_CUTOFF_HI (7) |
| 106 | +#define SGU1_CHAN_DUTY (8) |
| 107 | +#define SGU1_CHAN_RESON (9) |
| 108 | +#define SGU1_CHAN_PCMPOS_LO (10) |
| 109 | +#define SGU1_CHAN_PCMPOS_HI (11) |
| 110 | +#define SGU1_CHAN_PCMBND_LO (12) |
| 111 | +#define SGU1_CHAN_PCMBND_HI (13) |
| 112 | +#define SGU1_CHAN_PCMRST_LO (14) |
| 113 | +#define SGU1_CHAN_PCMRST_HI (15) |
| 114 | +#define SGU1_CHAN_SWFREQ_SPEED_LO (16) |
| 115 | +#define SGU1_CHAN_SWFREQ_SPEED_HI (17) |
| 116 | +#define SGU1_CHAN_SWFREQ_AMT (18) |
| 117 | +#define SGU1_CHAN_SWFREQ_BOUND (19) |
| 118 | +#define SGU1_CHAN_SWVOL_SPEED_LO (20) |
| 119 | +#define SGU1_CHAN_SWVOL_SPEED_HI (21) |
| 120 | +#define SGU1_CHAN_SWVOL_AMT (22) |
| 121 | +#define SGU1_CHAN_SWVOL_BOUND (23) |
| 122 | +#define SGU1_CHAN_SWCUT_SPEED_LO (24) |
| 123 | +#define SGU1_CHAN_SWCUT_SPEED_HI (25) |
| 124 | +#define SGU1_CHAN_SWCUT_AMT (26) |
| 125 | +#define SGU1_CHAN_SWCUT_BOUND (27) |
| 126 | +#define SGU1_CHAN_SPECIAL1C (28) |
| 127 | +#define SGU1_CHAN_SPECIAL1D (29) |
| 128 | +#define SGU1_CHAN_RESTIMER_LO (20) |
| 129 | +#define SGU1_CHAN_RESTIMER_HI (31) |
| 130 | + |
| 131 | +// setup parameters for sgu1_init() |
| 132 | +typedef struct { |
| 133 | + int tick_hz; // frequency at which sgu1_tick() will be called in Hz |
| 134 | + int sound_hz; // sound sample frequency |
| 135 | + float magnitude; // output sample magnitude (0=silence to 1=max volume) |
| 136 | +} sgu1_desc_t; |
| 137 | + |
| 138 | +// tsu instance state |
| 139 | +typedef struct { |
| 140 | + int sound_hz; |
| 141 | + // sound unit instance |
| 142 | + void* su; |
| 143 | + // sample generation state |
| 144 | + int sample_period; |
| 145 | + int sample_counter; |
| 146 | + float sample_mag; |
| 147 | + float sample; |
| 148 | + // debug inspection |
| 149 | + uint64_t pins; |
| 150 | +} sgu1_t; |
| 151 | + |
| 152 | +// initialize a new sgu1_t instance |
| 153 | +void sgu1_init(sgu1_t* sgu, const sgu1_desc_t* desc); |
| 154 | +// reset a sgu1_t instance |
| 155 | +void sgu1_reset(sgu1_t* sgu); |
| 156 | +// tick a sgu1_t instance |
| 157 | +uint64_t sgu1_tick(sgu1_t* sgu, uint64_t pins); |
| 158 | + |
| 159 | +#ifdef __cplusplus |
| 160 | +} // extern "C" |
| 161 | +#endif |
0 commit comments