Skip to content

Commit 549b5ef

Browse files
committed
Integrate SGU-1 chip support
1 parent ff28e34 commit 549b5ef

9 files changed

Lines changed: 320 additions & 279 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ add_executable(emu
5353
src/ui/ui_app_log.cc
5454
src/ui/ui_x65.cc
5555
src/util/ringbuffer.c
56-
ext/firmware/src/audio/snd/su.c
56+
ext/firmware/src/audio/snd/sgu.c
5757
${CMAKE_CURRENT_BINARY_DIR}/version.c
5858
)
5959
target_link_libraries(emu

src/chips/sgu1.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,23 @@
1616
/* move bit into first position */
1717
#define SGU1_BIT(val, bitnr) ((val >> bitnr) & 1)
1818

19-
#define SGU1_CHIP_CLOCK (48000) // 48kHz
20-
2119
void sgu1_init(sgu1_t* sgu, const sgu1_desc_t* desc) {
2220
CHIPS_ASSERT(sgu && desc);
2321
CHIPS_ASSERT(desc->tick_hz > 0);
2422
memset(sgu, 0, sizeof(*sgu));
2523
sgu->sample_mag = desc->magnitude;
26-
sgu->tick_period = (desc->tick_hz * SGU1_FIXEDPOINT_SCALE) / SGU1_CHIP_CLOCK;
24+
sgu->tick_period = (desc->tick_hz * SGU1_FIXEDPOINT_SCALE) / SGU_CHIP_CLOCK;
2725
sgu->tick_counter = sgu->tick_period;
28-
SoundUnit_Init(&sgu->su, 65536);
26+
SGU_Init(&sgu->sgu, 65536);
2927
}
3028

3129
void sgu1_reset(sgu1_t* sgu) {
3230
CHIPS_ASSERT(sgu);
33-
SoundUnit_Reset(&sgu->su);
34-
memset(sgu->reg, 0, sizeof(sgu->reg));
31+
SGU_Reset(&sgu->sgu);
3532
sgu->tick_counter = sgu->tick_period;
3633
sgu->sample[0] = sgu->sample[1] = 0.0f;
3734
sgu->pins = 0;
35+
sgu->selected_channel = 0;
3836
}
3937

4038
/* tick the sound generation, return true when new sample ready */
@@ -45,13 +43,13 @@ static uint64_t _sgu1_tick(sgu1_t* sgu, uint64_t pins) {
4543
while (sgu->tick_counter <= 0) {
4644
sgu->tick_counter += sgu->tick_period;
4745
int32_t l, r;
48-
SoundUnit_NextSample(&sgu->su, &l, &r);
46+
SGU_NextSample(&sgu->sgu, &l, &r);
4947
sgu->sample[0] = sgu->sample_mag * (float)l / 32767.0f;
5048
sgu->sample[1] = sgu->sample_mag * (float)r / 32767.0f;
5149
pins |= SGU1_SAMPLE;
5250

53-
for (uint8_t i = 0; i < SGU1_NUM_CHANNELS; i++) {
54-
sgu->voice[i].sample_buffer[sgu->voice[i].sample_pos++] = (float)(SoundUnit_GetSample(&sgu->su, i));
51+
for (uint8_t i = 0; i < SGU_CHNS; i++) {
52+
sgu->voice[i].sample_buffer[sgu->voice[i].sample_pos++] = (float)(SGU_GetSample(&sgu->sgu, i));
5553
if (sgu->voice[i].sample_pos >= SGU1_AUDIO_SAMPLES) {
5654
sgu->voice[i].sample_pos = 0;
5755
}
@@ -60,34 +58,32 @@ static uint64_t _sgu1_tick(sgu1_t* sgu, uint64_t pins) {
6058
return pins;
6159
}
6260

63-
static inline uint8_t _sgu1_selected_channel(sgu1_t* sgu) {
64-
return sgu->reg[SGU1_REG_CHANNEL_SELECT] & (SGU1_NUM_CHANNELS - 1);
65-
}
66-
6761
uint8_t sgu1_reg_read(sgu1_t* sgu, uint8_t reg) {
6862
uint8_t data;
69-
if (reg < 32) {
70-
data = sgu->reg[reg];
63+
if (reg == SGU_REGS_PER_CH - 1) {
64+
data = sgu->selected_channel;
7165
}
7266
else {
73-
uint8_t chan = _sgu1_selected_channel(sgu);
74-
data = ((unsigned char*)sgu->su.chan)[chan << 5 | (reg & (SGU1_NUM_CHANNEL_REGS - 1))];
67+
data = ((unsigned char*)sgu->sgu.chan)[(sgu->selected_channel % SGU_CHNS) << 6 | (reg & (SGU_REGS_PER_CH - 1))];
7568
}
7669
return data;
7770
}
7871

7972
void sgu1_reg_write(sgu1_t* sgu, uint8_t reg, uint8_t data) {
80-
if (reg < 32) {
81-
if (reg == SGU1_REG_CHANNEL_SELECT) {
82-
sgu->reg[reg] = data;
83-
}
73+
if (reg == SGU_REGS_PER_CH - 1) {
74+
sgu->selected_channel = data;
8475
}
8576
else {
86-
uint8_t chan = _sgu1_selected_channel(sgu);
87-
((unsigned char*)sgu->su.chan)[chan << 5 | (reg & (SGU1_NUM_CHANNEL_REGS - 1))] = data;
77+
// ((unsigned char*)sgu->sgu.chan)[(sgu->selected_channel % SGU_CHNS) << 6 | (reg & (SGU_REGS_PER_CH - 1))] =
78+
// data;
79+
SGU_Write(&sgu->sgu, (uint16_t)((sgu->selected_channel % SGU_CHNS) << 6) | (reg & (SGU_REGS_PER_CH - 1)), data);
8880
}
8981
}
9082

83+
void sgu1_direct_reg_write(sgu1_t* sgu, uint16_t reg, uint8_t data) {
84+
SGU_Write(&sgu->sgu, reg, data);
85+
}
86+
9187
/* read a register */
9288
static uint64_t _sgu1_read(sgu1_t* sgu, uint64_t pins) {
9389
uint8_t reg = pins & SGU1_ADDR_MASK;

src/chips/sgu1.h

Lines changed: 5 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
#include <speex_resampler.h>
4646
#include <stdint.h>
4747
#include <stdbool.h>
48-
#include "snd/su.h"
48+
#include "snd/sgu.h"
4949

5050
#ifdef __cplusplus
5151
extern "C" {
@@ -96,79 +96,6 @@ extern "C" {
9696
#define SGU1_CS (1ULL << SGU1_PIN_CS)
9797
#define SGU1_SAMPLE (1ULL << SGU1_PIN_SAMPLE)
9898

99-
#define SGU1_NUM_CHANNELS (8)
100-
#define SGU1_NUM_CHANNEL_REGS (32)
101-
102-
// control registers
103-
#define SGU1_REG_CHANNEL_SELECT (0x00)
104-
105-
// channel registers
106-
#define SGU1_CHAN_FREQ_LO (0x00)
107-
#define SGU1_CHAN_FREQ_HI (0x01)
108-
#define SGU1_CHAN_VOL (0x02)
109-
#define SGU1_CHAN_PAN (0x03)
110-
#define SGU1_CHAN_FLAGS0 (0x04)
111-
#define SGU1_CHAN_FLAGS1 (0x05)
112-
#define SGU1_CHAN_CUTOFF_LO (0x06)
113-
#define SGU1_CHAN_CUTOFF_HI (0x07)
114-
#define SGU1_CHAN_DUTY (0x08)
115-
#define SGU1_CHAN_RESON (0x09)
116-
#define SGU1_CHAN_PCMPOS_LO (0x0A)
117-
#define SGU1_CHAN_PCMPOS_HI (0x0B)
118-
#define SGU1_CHAN_PCMBND_LO (0x0C)
119-
#define SGU1_CHAN_PCMBND_HI (0x0D)
120-
#define SGU1_CHAN_PCMRST_LO (0x0E)
121-
#define SGU1_CHAN_PCMRST_HI (0x0F)
122-
#define SGU1_CHAN_SWFREQ_SPEED_LO (0x10)
123-
#define SGU1_CHAN_SWFREQ_SPEED_HI (0x11)
124-
#define SGU1_CHAN_SWFREQ_AMT (0x12)
125-
#define SGU1_CHAN_SWFREQ_BOUND (0x13)
126-
#define SGU1_CHAN_SWVOL_SPEED_LO (0x14)
127-
#define SGU1_CHAN_SWVOL_SPEED_HI (0x15)
128-
#define SGU1_CHAN_SWVOL_AMT (0x16)
129-
#define SGU1_CHAN_SWVOL_BOUND (0x17)
130-
#define SGU1_CHAN_SWCUT_SPEED_LO (0x18)
131-
#define SGU1_CHAN_SWCUT_SPEED_HI (0x19)
132-
#define SGU1_CHAN_SWCUT_AMT (0x1A)
133-
#define SGU1_CHAN_SWCUT_BOUND (0x1B)
134-
#define SGU1_CHAN_SPECIAL1C (0x1C)
135-
#define SGU1_CHAN_SPECIAL1D (0x1D)
136-
#define SGU1_CHAN_RESTIMER_LO (0x1E)
137-
#define SGU1_CHAN_RESTIMER_HI (0x1F)
138-
139-
// channel control bits
140-
#define SGU1_FLAGS0_WAVE_SHIFT (0)
141-
#define SGU1_FLAGS0_WAVE_MASK (0x7 << SGU1_FLAGS0_WAVE_SHIFT)
142-
#define SGU1_FLAGS0_PCM_SHIFT (3)
143-
#define SGU1_FLAGS0_PCM_MASK (0x1 << SGU1_FLAGS0_PCM_SHIFT)
144-
#define SGU1_FLAGS0_CONTROL_SHIFT (4)
145-
#define SGU1_FLAGS0_CONTROL_MASK (0xF << SGU1_FLAGS0_CONTROL_SHIFT)
146-
#define SGU1_FLAGS0_CTL_RING_MOD (1 << 4)
147-
#define SGU1_FLAGS0_CTL_NSLOW (1 << 5)
148-
#define SGU1_FLAGS0_CTL_NSHIGH (1 << 6)
149-
#define SGU1_FLAGS0_CTL_NSBAND (1 << 7)
150-
151-
#define SGU1_FLAGS0_WAVE_PULSE (0)
152-
#define SGU1_FLAGS0_WAVE_SAWTOOTH (1)
153-
#define SGU1_FLAGS0_WAVE_SINE (2)
154-
#define SGU1_FLAGS0_WAVE_TRIANGLE (3)
155-
#define SGU1_FLAGS0_WAVE_NOISE (4)
156-
#define SGU1_FLAGS0_WAVE_PERIODIC_NOISE (5)
157-
#define SGU1_FLAGS0_WAVE_XOR_SINE (6)
158-
#define SGU1_FLAGS0_WAVE_XOR_TRIANGLE (7)
159-
160-
#define SGU1_FLAGS1_PHASE_RESET (1 << 0)
161-
#define SGU1_FLAGS1_FILTER_PHASE_RESET (1 << 1)
162-
#define SGU1_FLAGS1_PCM_LOOP (1 << 2)
163-
#define SGU1_FLAGS1_TIMER_SYNC (1 << 3)
164-
#define SGU1_FLAGS1_FREQ_SWEEP (1 << 4)
165-
#define SGU1_FLAGS1_VOL_SWEEP (1 << 5)
166-
#define SGU1_FLAGS1_CUT_SWEEP (1 << 6)
167-
168-
#define SGU1_VOL_SWEEP_INC (1 << 5)
169-
#define SGU1_VOL_SWEEP_WRAP (1 << 6)
170-
#define SGU1_VOL_SWEEP_BOUNCE (1 << 7)
171-
17299
#define SGU1_AUDIO_CHANNELS (2)
173100
#define SGU1_AUDIO_SAMPLES (1024)
174101

@@ -180,10 +107,9 @@ typedef struct {
180107

181108
// tsu instance state
182109
typedef struct {
183-
int sound_hz;
184110
// sound unit instance
185-
SoundUnit su;
186-
uint8_t reg[32];
111+
struct SGU sgu;
112+
uint8_t selected_channel;
187113
int tick_period;
188114
int tick_counter;
189115
// sample generation state
@@ -193,7 +119,7 @@ typedef struct {
193119
struct {
194120
int sample_pos;
195121
float sample_buffer[SGU1_AUDIO_SAMPLES];
196-
} voice[SGU1_NUM_CHANNELS];
122+
} voice[SGU_CHNS];
197123
// debug inspection
198124
uint64_t pins;
199125
} sgu1_t;
@@ -208,6 +134,7 @@ uint64_t sgu1_tick(sgu1_t* sgu, uint64_t pins);
208134
// for use by debugger
209135
uint8_t sgu1_reg_read(sgu1_t* sgu, uint8_t reg);
210136
void sgu1_reg_write(sgu1_t* sgu, uint8_t reg, uint8_t data);
137+
void sgu1_direct_reg_write(sgu1_t* sgu, uint16_t reg, uint8_t data);
211138

212139
#ifdef __cplusplus
213140
} // extern "C"

src/systems/x65.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void x65_init(x65_t* sys, const x65_desc_t* desc) {
3838
sys->joystick_type = desc->joystick_type;
3939
sys->debug = desc->debug;
4040
sys->audio.callback = desc->audio.callback;
41-
sys->audio.num_samples = _X65_DEFAULT(desc->audio.num_samples, X65_DEFAULT_AUDIO_SAMPLES) * X65_AUDIO_CHANNELS;
41+
sys->audio.num_samples = _X65_DEFAULT(desc->audio.num_samples, X65_DEFAULT_AUDIO_SAMPLES) * SGU_AUDIO_CHANNELS;
4242
CHIPS_ASSERT(sys->audio.num_samples <= X65_MAX_AUDIO_SAMPLES);
4343

4444
// initialize the hardware

src/systems/x65.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ extern "C" {
5050
#define X65_FREQUENCY (3140000) // clock frequency in Hz
5151
#define X65_MAX_AUDIO_SAMPLES (2048) // max number of audio samples in internal sample buffer
5252
#define X65_DEFAULT_AUDIO_SAMPLES (512) // default number of samples in internal sample buffer
53-
#define X65_AUDIO_CHANNELS (2) // stereo output
5453

5554
// X65 joystick types
5655
typedef enum {

0 commit comments

Comments
 (0)