Compare commits

..

3 Commits

8 changed files with 122 additions and 26 deletions

View File

@ -28,8 +28,9 @@ typedef struct {
uint8_t value; /* Master output level */ uint8_t value; /* Master output level */
/* Other state */ /* Other state */
uint32_t clocks; /* Clocks until modification */ uint32_t clocks; /* Clocks until modification */
uint8_t reload; /* Automatic reload value */ uint8_t modmask; /* Modifications masked */
uint8_t reload; /* Automatic reload value */
} env; } env;
/* Frequency */ /* Frequency */
@ -359,9 +360,10 @@ struct VB {
uint8_t shift; /* Sweep shift amount */ uint8_t shift; /* Sweep shift amount */
/* Other state */ /* Other state */
uint32_t clocks; /* Clocks until modification */ uint32_t clocks; /* Clocks until modification */
uint16_t next; /* Next frequency value */ uint8_t modmask; /* Modifications masked */
int sample; /* Current sample index */ uint16_t next; /* Next frequency value */
int sample; /* Current sample index */
} freqmod; } freqmod;
/* Channel 6 noise generator */ /* Channel 6 noise generator */

View File

@ -45,9 +45,22 @@ static void vsuOnSamples(VB *sim) {
/***************************** Module Functions ******************************/ /***************************** Module Functions ******************************/
/* Determine while frequency modifications should be processed */
static uint8_t vsuCheckFreqMod(VB *sim) {
return
sim->vsu.freqmod.enb &&
sim->vsu.freqmod.interval != 0 && (
!sim->vsu.freqmod.modmask || (
sim->vsu.freqmod.func == 1 &&
sim->vsu.freqmod.rep
)
)
;
}
/* Stage the next frequency modification value */ /* Stage the next frequency modification value */
static void vsuNextFreqMod(VB *sim, Channel *chan) { static void vsuNextFreqMod(VB *sim, Channel *chan) {
uint16_t next; int32_t next;
/* Sweep */ /* Sweep */
if (sim->vsu.freqmod.func == 0) { if (sim->vsu.freqmod.func == 0) {
@ -57,16 +70,32 @@ static void vsuNextFreqMod(VB *sim, Channel *chan) {
else next = chan->freq.current + next; else next = chan->freq.current + next;
if (next > 2047) if (next > 2047)
chan->int_.enb = 0; chan->int_.enb = 0;
if (next < 0)
next = 0;
} }
/* Modulation */ /* Modulation */
else { else {
next = (chan->freq.written +
sim->vsu.modulation[sim->vsu.freqmod.sample]) & 2047; /* Compute the modulated value */
next = (int32_t) chan->freq.written +
sim->vsu.modulation[sim->vsu.freqmod.sample];
if (next < 0)
next = 0;
if (next > 2047)
next = 2047;
/* Not the final modulation sample */
if (sim->vsu.freqmod.sample != 31) if (sim->vsu.freqmod.sample != 31)
sim->vsu.freqmod.sample++; sim->vsu.freqmod.sample++;
else if (sim->vsu.freqmod.rep)
sim->vsu.freqmod.sample = 0; /* Last modulation sample processed */
else {
sim->vsu.freqmod.modmask = 1;
if (sim->vsu.freqmod.rep)
sim->vsu.freqmod.sample = 0;
}
} }
/* Configure state */ /* Configure state */
@ -106,13 +135,14 @@ static void vsuEmulateChannel(VB *sim, Channel *chan) {
} }
/* Envelope modification */ /* Envelope modification */
if (chan->env.enb && chan->env.clocks == 0) { if (chan->env.enb && !chan->env.modmask && chan->env.clocks == 0) {
if (chan->env.dir == 0 && chan->env.value != 0) if (chan->env.dir == 0 && chan->env.value != 0)
chan->env.value--; chan->env.value--;
else if (chan->env.dir == 1 && chan->env.value != 15) else if (chan->env.dir == 1 && chan->env.value != 15)
chan->env.value++; chan->env.value++;
else if (chan->env.rep) else if (chan->env.rep)
chan->env.value = chan->env.reload; chan->env.value = chan->env.reload;
else chan->env.modmask = 1;
chan->env.clocks = ((uint32_t) chan->env.interval + 1) * 307220; chan->env.clocks = ((uint32_t) chan->env.interval + 1) * 307220;
} }
@ -186,9 +216,8 @@ static void vsuWriteEV1(VB *sim, int index, uint8_t value) {
sim->vsu.freqmod.enb = value >> 6 & 1; sim->vsu.freqmod.enb = value >> 6 & 1;
sim->vsu.freqmod.func = value >> 4 & 1; sim->vsu.freqmod.func = value >> 4 & 1;
sim->vsu.freqmod.rep = value >> 5 & 1; sim->vsu.freqmod.rep = value >> 5 & 1;
chan->freqmod = vsuCheckFreqMod(sim);
vsuNextFreqMod(sim, chan); vsuNextFreqMod(sim, chan);
chan->freqmod =
sim->vsu.freqmod.enb && sim->vsu.freqmod.interval != 0;
break; break;
case 5: /* Channel 6 */ case 5: /* Channel 6 */
@ -228,6 +257,7 @@ static void vsuWriteINT(VB *sim, int index, uint8_t value) {
/* Update state */ /* Update state */
chan->int_.clocks = 76805 * ((uint32_t) chan->int_.interval + 1); chan->int_.clocks = 76805 * ((uint32_t) chan->int_.interval + 1);
chan->env.modmask = 0;
if (chan->env.enb) if (chan->env.enb)
chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1); chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1);
if (index != 5) { if (index != 5) {
@ -240,7 +270,8 @@ static void vsuWriteINT(VB *sim, int index, uint8_t value) {
if (index == 4) { if (index == 4) {
sim->vsu.freqmod.clocks = (uint32_t) sim->vsu.freqmod.interval * sim->vsu.freqmod.clocks = (uint32_t) sim->vsu.freqmod.interval *
(sim->vsu.freqmod.clk == 0 ? 19200 : 153600); (sim->vsu.freqmod.clk == 0 ? 19200 : 153600);
sim->vsu.freqmod.sample = 0; sim->vsu.freqmod.modmask = 0;
sim->vsu.freqmod.sample = 0;
} }
} }
@ -272,8 +303,7 @@ static void vsuWriteSWP(VB *sim, uint8_t value) {
(sim->vsu.freqmod.clk == 0 ? 19200 : 153600); (sim->vsu.freqmod.clk == 0 ? 19200 : 153600);
if (clocks < sim->vsu.freqmod.clocks) if (clocks < sim->vsu.freqmod.clocks)
sim->vsu.freqmod.clocks = clocks; sim->vsu.freqmod.clocks = clocks;
sim->vsu.channels[4].freqmod = sim->vsu.channels[4].freqmod = vsuCheckFreqMod(sim);
sim->vsu.freqmod.enb && sim->vsu.freqmod.interval != 0;
} }
@ -315,7 +345,8 @@ static void vsuEmulate(VB *sim, uint32_t clocks) {
/* Clocks until next state change */ /* Clocks until next state change */
chan->until = chan->clocks; chan->until = chan->clocks;
if (chan->env.enb && chan->env.clocks < chan->until) if (chan->env.enb && !chan->env.modmask &&
chan->env.clocks < chan->until)
chan->until = chan->env.clocks; chan->until = chan->env.clocks;
if (chan->int_.auto_ && chan->int_.clocks < chan->until) if (chan->int_.auto_ && chan->int_.clocks < chan->until)
chan->until = chan->int_.clocks; chan->until = chan->int_.clocks;
@ -324,7 +355,7 @@ static void vsuEmulate(VB *sim, uint32_t clocks) {
/* Manage clocks */ /* Manage clocks */
chan->clocks -= chan->until; chan->clocks -= chan->until;
if (chan->env.enb) if (chan->env.enb && !chan->env.modmask)
chan->env.clocks -= chan->until; chan->env.clocks -= chan->until;
if (chan->int_.auto_) if (chan->int_.auto_)
chan->int_.clocks -= chan->until; chan->int_.clocks -= chan->until;
@ -427,6 +458,7 @@ static void vsuReset(VB *sim) {
chan->env.enb = 0; chan->env.enb = 0;
chan->env.dir = 0; chan->env.dir = 0;
chan->env.interval = 0; chan->env.interval = 0;
chan->env.modmask = 0;
chan->env.reload = 0; chan->env.reload = 0;
chan->env.rep = 0; chan->env.rep = 0;
chan->env.value = 0; chan->env.value = 0;
@ -449,6 +481,7 @@ static void vsuReset(VB *sim) {
sim->vsu.freqmod.enb = 0; sim->vsu.freqmod.enb = 0;
sim->vsu.freqmod.func = 0; sim->vsu.freqmod.func = 0;
sim->vsu.freqmod.interval = 0; sim->vsu.freqmod.interval = 0;
sim->vsu.freqmod.modmask = 0;
sim->vsu.freqmod.next = 0; sim->vsu.freqmod.next = 0;
sim->vsu.freqmod.rep = 0; sim->vsu.freqmod.rep = 0;
sim->vsu.freqmod.sample = 0; sim->vsu.freqmod.sample = 0;

View File

@ -33,6 +33,7 @@ static int32_t SignExtend(int32_t value, int32_t bits) {
/******************************** Sub-Modules ********************************/ /******************************** Sub-Modules ********************************/
#include "disassembler.c" #include "disassembler.c"
#include "isx.c"
@ -70,3 +71,8 @@ VBUAPI VBU_DasmLine* vbuDisassemble(VB *sim, uint32_t address,
VBU_DasmConfig *config, unsigned length, int line) { VBU_DasmConfig *config, unsigned length, int line) {
return dasmDisassemble(sim, address, config, length, line); return dasmDisassemble(sim, address, config, length, line);
} }
/* Decode an ISX debugger file to a Virtual Boy ROM */
VBUAPI void* vbuFromISX(void *bytes, size_t length, size_t *romLength) {
return isxFrom(bytes, length, romLength);
}

View File

@ -88,6 +88,7 @@ typedef struct {
VBUAPI int vbuCodeSize (VB *sim, uint32_t address); VBUAPI int vbuCodeSize (VB *sim, uint32_t address);
VBUAPI VBU_DasmConfig* vbuDasmInit (VBU_DasmConfig *config); VBUAPI VBU_DasmConfig* vbuDasmInit (VBU_DasmConfig *config);
VBUAPI VBU_DasmLine* vbuDisassemble(VB *sim, uint32_t address, VBU_DasmConfig *config, unsigned length, int line); VBUAPI VBU_DasmLine* vbuDisassemble(VB *sim, uint32_t address, VBU_DasmConfig *config, unsigned length, int line);
VBUAPI void* vbuFromISX (void *bytes, size_t length, size_t *romLength);

View File

@ -1,7 +1,5 @@
"use strict"; "use strict";
//////////////////////////////////// Audio ////////////////////////////////////
// Dedicated audio output processor // Dedicated audio output processor
class Audio extends AudioWorkletProcessor { class Audio extends AudioWorkletProcessor {

View File

@ -1,4 +1,5 @@
let Constants = { "use strict";
export default {
// Core // Core
VB: { VB: {
@ -85,5 +86,3 @@ let Constants = {
} }
}; };
export { Constants };

View File

@ -1,5 +1,5 @@
"use strict"; "use strict";
import { Constants } from "./Constants.js"; import Constants from /***/"./Constants.js";
@ -258,6 +258,41 @@ new class Core {
}); });
} }
// Attempt to produce a ROM from an ISX debugger file
fromISX(message) {
// Transfer the input data into WebAssembly memory
let input = new Uint8Array(message.data);
let inPtr = this.Realloc(0, input.length);
let inMem = new Uint8Array(this.memory.buffer, inPtr, input.length);
for (let x = 0; x < input.length; x++)
inMem[x] = input[x];
// Attempt to decode the ISX file as a ROM
let outPtr = this.FromISX(inPtr, input.length);
this.Realloc(inPtr, 0);
// The data is not an ISX file
if (outPtr == 0) {
this.dom.postMessage({ promised: true, data: null });
return;
}
// Transfer the decoded ROM from WebAssembly memory
let output = new Uint8Array(this.GetISXLength(outPtr));
let outMem = new Uint8Array(this.memory.buffer,
this.GetISXROM(outPtr), output.length);
for (let x = 0; x < output.length; x++)
output[x] = outMem[x];
this.Realloc(outPtr, 0);
// Notify DOM thread
this.dom.postMessage({
promised: true,
data : output.buffer
}, [ output.buffer ]);
}
// Specify anaglyph colors // Specify anaglyph colors
setAnaglyph(message) { setAnaglyph(message) {
this.SetAnaglyph(message.sim, message.left, message.right); this.SetAnaglyph(message.sim, message.left, message.right);

View File

@ -1,5 +1,5 @@
"use strict"; "use strict";
import { Constants } from "./Constants.js"; import Constants from /**/"./Constants.js";
// Instantiation guard // Instantiation guard
const GUARD = Symbol(); const GUARD = Symbol();
@ -864,6 +864,28 @@ class VB {
return true; return true;
} }
// Decode an ISX debugger file to a Virtual Boy ROM
async fromISX(data) {
// Validation
if (data instanceof ArrayBuffer)
data = new Uint8Array(data);
if (
!(data instanceof Uint8Array) &&
!(data instanceof Uint8ClampedArray)
) data = Uint8Array.from(data);
// Send the memory to the core
data = data.slice();
let response = await this.#toCore({
command : "fromISX",
promised : true,
data : data.buffer,
transfers: [ data.buffer ]
});
return response.data == null ? null : new Uint8Array(response.data);
}
// Suspend automatic emulation // Suspend automatic emulation
async suspend() { async suspend() {
@ -932,4 +954,4 @@ class VB {
} }
export { VB }; export default VB;