Compare commits
3 Commits
155a3aa678
...
4f0b889b74
Author | SHA1 | Date |
---|---|---|
|
4f0b889b74 | |
|
8ae8980fc8 | |
|
10505e9e98 |
|
@ -29,6 +29,7 @@ typedef struct {
|
||||||
|
|
||||||
/* Other state */
|
/* Other state */
|
||||||
uint32_t clocks; /* Clocks until modification */
|
uint32_t clocks; /* Clocks until modification */
|
||||||
|
uint8_t modmask; /* Modifications masked */
|
||||||
uint8_t reload; /* Automatic reload value */
|
uint8_t reload; /* Automatic reload value */
|
||||||
} env;
|
} env;
|
||||||
|
|
||||||
|
@ -360,6 +361,7 @@ struct VB {
|
||||||
|
|
||||||
/* Other state */
|
/* Other state */
|
||||||
uint32_t clocks; /* Clocks until modification */
|
uint32_t clocks; /* Clocks until modification */
|
||||||
|
uint8_t modmask; /* Modifications masked */
|
||||||
uint16_t next; /* Next frequency value */
|
uint16_t next; /* Next frequency value */
|
||||||
int sample; /* Current sample index */
|
int sample; /* Current sample index */
|
||||||
} freqmod;
|
} freqmod;
|
||||||
|
|
55
core/vsu.c
55
core/vsu.c
|
@ -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,18 +70,34 @@ 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)
|
|
||||||
|
/* Last modulation sample processed */
|
||||||
|
else {
|
||||||
|
sim->vsu.freqmod.modmask = 1;
|
||||||
|
if (sim->vsu.freqmod.rep)
|
||||||
sim->vsu.freqmod.sample = 0;
|
sim->vsu.freqmod.sample = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Configure state */
|
/* Configure state */
|
||||||
sim->vsu.freqmod.next = next;
|
sim->vsu.freqmod.next = next;
|
||||||
}
|
}
|
||||||
|
@ -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,6 +270,7 @@ 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.modmask = 0;
|
||||||
sim->vsu.freqmod.sample = 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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
let Constants = {
|
"use strict";
|
||||||
|
export default {
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
VB: {
|
VB: {
|
||||||
|
@ -85,5 +86,3 @@ let Constants = {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { Constants };
|
|
||||||
|
|
37
web/Core.js
37
web/Core.js
|
@ -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);
|
||||||
|
|
26
web/VB.js
26
web/VB.js
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue