From c06da323218071719c1500379e84008c369169d7 Mon Sep 17 00:00:00 2001 From: Guy Perfect Date: Mon, 21 Oct 2024 19:39:35 -0500 Subject: [PATCH] VSU works now --- core/vb.c | 5 +-- core/vip.c | 16 +++++++- core/vsu.c | 116 ++++++++++++++++++++++++++++++----------------------- makefile | 8 ++-- 4 files changed, 87 insertions(+), 58 deletions(-) diff --git a/core/vb.c b/core/vb.c index 12b7d3e..a188324 100644 --- a/core/vb.c +++ b/core/vb.c @@ -64,8 +64,7 @@ typedef struct { } wave; /* Other state */ - uint32_t clocks; /* Clocks until next sample */ - uint16_t output[2]; /* Current output sample */ + uint32_t clocks; /* Clocks until next sample */ } Channel; /* Simulation state */ @@ -297,7 +296,7 @@ struct VB { float o1[2]; /* Previous analog output sample */ uint32_t capacity; /* Number of audio frames in samples */ uint32_t offset; /* Position in output buffer */ - int16_t *samples; /* Output memory */ + int16_t *samples; /* Output memory */ } out; /* Memory */ diff --git a/core/vip.c b/core/vip.c index 962a1a6..eeb2628 100644 --- a/core/vip.c +++ b/core/vip.c @@ -40,6 +40,18 @@ static const uint8_t BG_TEMPLATES[][64] = { 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7 } }; +/* 8-bit color magnitude by brightness level */ +static const uint8_t BRIGHT8[] = { + 0, 10, 16, 21, 25, 30, 33, 37, 40, 44, 47, 50, 53, 56, 59, 61, + 64, 67, 69, 72, 74, 77, 79, 82, 84, 86, 89, 91, 93, 95, 97,100, + 102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,131, + 133,135,137,139,141,142,144,146,148,149,151,153,155,156,158,160, + 161,163,165,166,168,170,171,173,175,176,178,179,181,183,184,186, + 187,189,190,192,194,195,197,198,200,201,203,204,206,207,209,210, + 212,213,215,216,217,219,220,222,223,225,226,227,229,230,232,233, + 235,236,237,239,240,241,243,244,246,247,248,250,251,252,254,255 +}; + /***************************** Module Functions ******************************/ @@ -392,9 +404,9 @@ static void vipComputeBrightness(VB *sim) { brt[2] = repeat * sim->vip.brtRest[1]; brt[3] = repeat * sim->vip.brtRest[2] + brt[2] + brt[1]; - /* Scale brightness values to 0..255 */ + /* Transform brightness values to 0..255 */ for (x = 1; x < 4; x++) - sim->vip.dp.brt[x] = ((brt[x] > 127 ? 127 : brt[x]) * 510 + 127) / 254; + sim->vip.dp.brt[x] = brt[x] > 127 ? 255 : BRIGHT8[brt[x]]; } /* Transfer one column of frame buffer pixels to output */ diff --git a/core/vsu.c b/core/vsu.c index 283efa4..891cb0a 100644 --- a/core/vsu.c +++ b/core/vsu.c @@ -5,7 +5,7 @@ /********************************* Constants *********************************/ -/* Analog output low-pass filter coefficient = 0.022 / (0.022 + 1 / 41700) */ +/* Analog output high-pass filter coefficient = 0.022 / (0.022 + 1 / 41700) */ #define RC_A (float) (1 - 1 / 918.4) @@ -39,7 +39,7 @@ static void vsuOnSamples(VB *sim) { if (sim->onSamples != NULL) VB_ON_SAMPLES(sim, sim->vsu.out.samples, sim->vsu.out.capacity); } -#undef VB_ON_EXCEPTION +#undef VB_ON_SAMPLES @@ -78,29 +78,11 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) { uint32_t bit; /* Pseudorandom bit */ Channel *chan; /* Channel handle */ int freqmod; /* Frequency modifications enabled */ - uint32_t level; /* Stereo output level */ - uint32_t sample; /* Input sample */ uint32_t until; /* Clocks to process sub-channel components */ - int e; /* Iterator */ /* Select channel */ chan = &sim->vsu.channels[index]; - /* Select input sample */ - sample = - !chan->int_.enb ? 0 : /* Disabled */ - index == 5 ? (sim->vsu.noise.register_ & 1) ? 63 : 0 : /* Noise */ - chan->wave.wave > 4 ? 0 : /* Wave range */ - sim->vsu.waves[chan->wave.wave][chan->wave.sample] /* Wave */ - ; - - /* Compute output samples */ - for (e = 0; e < 2; e++) { - level = e == 0 ? chan->lrv.left : chan->lrv.right; - level = (level * chan->env.value >> 3) + (level && chan->env.value); - chan->output[e] = level * sample; - } - /* Channel is disabled */ if (!chan->int_.enb) return; @@ -147,7 +129,7 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) { /* Wave */ if (index != 5) { - chan->clocks = 4 * (2048 - (uint32_t) chan->freq.current); + chan->clocks = 4 * (2048 - (uint32_t) chan->freq.current); chan->wave.sample = (chan->wave.sample + 1) & 31; } @@ -157,7 +139,7 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) { bit = (( sim->vsu.noise.register_ >> NOISE_TAPS[sim->vsu.noise.tap]^ sim->vsu.noise.register_ >> 7 - ) & 1) ^ 1; + ) & 1) ^ 1; sim->vsu.noise.register_ = bit | (sim->vsu.noise.register_ << 1 & 0x7FFE); } @@ -172,7 +154,6 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) { chan->env.value++; else if (chan->env.rep) chan->env.value = chan->env.reload; - else chan->env.enb = 0; chan->env.clocks = ((uint32_t) chan->env.interval + 1) * 307220; } @@ -190,6 +171,33 @@ static void vsuEmulateChannel(VB *sim, int index, uint32_t clocks) { } +/* Produce output for a channel */ +static void vsuOutputChannel(VB *sim, int index, uint16_t *output) { + Channel *chan; /* Channel handle */ + uint32_t level; /* Stereo output level */ + uint32_t sample; /* Input sample */ + int e; /* Iterator */ + + /* Select channel */ + chan = &sim->vsu.channels[index]; + + /* Select input sample */ + sample = + !chan->int_.enb ? 0 : /* Disabled */ + index == 5 ? (sim->vsu.noise.register_ & 1) ? 63 : 0 : /* Noise */ + chan->wave.wave > 4 ? 0 : /* Wave range */ + sim->vsu.waves[chan->wave.wave][chan->wave.sample] /* Wave */ + ; + + /* Compute output samples */ + for (e = 0; e < 2; e++) { + level = e == 0 ? chan->lrv.left : chan->lrv.right; + level = (level * chan->env.value >> 3) + (level && chan->env.value); + output[e] += level * sample; + } + +} + /* Write a value to S*EV0 */ static void vsuWriteEV0(VB *sim, int index, uint8_t value) { Channel *chan = &sim->vsu.channels[index]; @@ -201,7 +209,7 @@ static void vsuWriteEV0(VB *sim, int index, uint8_t value) { chan->env.reload = chan->env.value; /* Configure state */ - chan->env.clocks = (uint32_t) chan->env.interval * 307220; + chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1); } /* Write a value to S*EV1 */ @@ -254,12 +262,16 @@ static void vsuWriteINT(VB *sim, int index, uint8_t value) { chan->int_.interval = value & 31; /* Update state */ - chan->int_.clocks = 76805 * (uint32_t) chan->int_.interval; - chan->clocks = (index == 5 ? 40 : 4) * - ((uint32_t) 2048 - chan->freq.current); - if (index != 5) + chan->int_.clocks = 76805 * ((uint32_t) chan->int_.interval + 1); + if (chan->env.enb) + chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1); + if (index != 5) { chan->wave.sample = 0; - else sim->vsu.noise.register_ = 0x0000; + chan->clocks = 4 * (2048 - (uint32_t) chan->freq.current); + } else { + sim->vsu.noise.register_ = 0x0000; + chan->clocks = 40 * (2048 - (uint32_t) chan->freq.current); + } if (index == 4) { sim->vsu.freqmod.clocks = (uint32_t) sim->vsu.freqmod.interval * (sim->vsu.freqmod.clk ? 153610 : 19201); @@ -303,12 +315,11 @@ static void vsuWriteSWP(VB *sim, uint8_t value) { /* Process component */ static void vsuEmulate(VB *sim, uint32_t clocks) { - Channel *chan; /* Channel handle */ - uint32_t digital[2]; /* Digital output samples */ - float i0; /* Current analog input sample */ - float o0; /* Current analog output sample */ - uint32_t until; /* Clocks to process channels */ - int e, x; /* Iterators */ + float i0; /* Current analog input sample */ + float o0; /* Current analog output sample */ + uint16_t output[2]; /* Digital output samples */ + uint32_t until; /* Clocks to process channels */ + int e, x; /* Iterators */ /* Process all clocks */ do { @@ -318,23 +329,28 @@ static void vsuEmulate(VB *sim, uint32_t clocks) { if (sim->vsu.clocks < until) until = sim->vsu.clocks; - /* Working variables */ - clocks -= until; - digital[0] = digital[1] = 0; + /* Manage clocks */ + clocks -= until; + sim->vsu.clocks -= until; /* Process all channels */ - for (x = 0; x < 6; x++) { - chan = &sim->vsu.channels[x]; + for (x = 0; x < 6; x++) vsuEmulateChannel(sim, x, until); - digital[0] += chan->output[0]; - digital[1] += chan->output[1]; - } + + /* Wait for the current sample to finish */ + if (sim->vsu.clocks != 0) + continue; + + /* Compute the output sample */ + output[0] = output[1] = 0; + for (x = 0; x < 6; x++) + vsuOutputChannel(sim, x, output); /* Output sample */ for (e = 0; e < 2; e++) { /* Compute the output sample for this stereo channel */ - i0 = (digital[e] >> 4) / 685.0f; + i0 = (output[e] >> 4) / 685.0f; o0 = RC_A * (sim->vsu.out.o1[e] + i0 - sim->vsu.out.i1[e]); if (o0 < -1.0f) o0 = -1.0f; if (o0 > +1.0f) o0 = +1.0f; @@ -501,12 +517,12 @@ static void vsuWrite(VB*sim,uint32_t address,int type,int32_t value,int debug){ case 0x518>>2: vsuWriteRAM(sim, 4, value); break; /* S5RAM */ case 0x51C>>2: vsuWriteSWP(sim, value); break; /* S5SWP */ - case 0x540>>2: vsuWriteINT(sim, 5, value); break; /* S5INT */ - case 0x544>>2: vsuWriteLRV(sim, 5, value); break; /* S5LRV */ - case 0x548>>2: vsuWriteFQL(sim, 5, value); break; /* S5FQL */ - case 0x54C>>2: vsuWriteFQH(sim, 5, value); break; /* S5FQH */ - case 0x550>>2: vsuWriteEV0(sim, 5, value); break; /* S5EV0 */ - case 0x554>>2: vsuWriteEV1(sim, 5, value); break; /* S5EV1 */ + case 0x540>>2: vsuWriteINT(sim, 5, value); break; /* S6INT */ + case 0x544>>2: vsuWriteLRV(sim, 5, value); break; /* S6LRV */ + case 0x548>>2: vsuWriteFQL(sim, 5, value); break; /* S6FQL */ + case 0x54C>>2: vsuWriteFQH(sim, 5, value); break; /* S6FQH */ + case 0x550>>2: vsuWriteEV0(sim, 5, value); break; /* S6EV0 */ + case 0x554>>2: vsuWriteEV1(sim, 5, value); break; /* S6EV1 */ case 0x580>>2: /* SSTOP */ if ((value & 1) == 0) diff --git a/makefile b/makefile index 0565716..e9b61d1 100644 --- a/makefile +++ b/makefile @@ -28,7 +28,8 @@ core: -D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \ -D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \ -D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_FRAME=testFrame \ - -D VB_DIRECT_WRITE=testWrite -D VB_DIRECT_READ=testRead + -D VB_DIRECT_WRITE=testWrite -D VB_DIRECT_SAMPLES=testSamples \ + -D VB_DIRECT_READ=testRead # Clang generic @emcc core/vb.c -I core -c -o /dev/null -O3 \ -Werror -std=c90 -Wall -Wextra -Wpedantic -fno-strict-aliasing @@ -38,14 +39,15 @@ core: -D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \ -D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \ -D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_FRAME=testFrame \ - -D VB_DIRECT_WRITE=testWrite -D VB_DIRECT_READ=testRead + -D VB_DIRECT_WRITE=testWrite -D VB_DIRECT_SAMPLES=testSamples \ + -D VB_DIRECT_READ=testRead .PHONY: wasm wasm: @emcc -o web/core.wasm web/wasm.c core/vb.c -I core \ -D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE \ -D "VBAPI=__attribute__((used))" \ - --no-entry -O2 -flto -s WASM=1 \ + --no-entry -O2 -flto -s WASM=1 -s WARN_ON_UNDEFINED_SYMBOLS=0 \ -s EXPORTED_RUNTIME_METHODS=[] -s ALLOW_MEMORY_GROWTH \ -s MAXIMUM_MEMORY=4GB -fno-strict-aliasing @rm -f web/*.wasm.tmp*