Compare commits

...
6 Commits
11 changed files with 488 additions and 66 deletions
-4
View File
@@ -153,10 +153,6 @@ static void busRead(VB *sim, uint32_t address, int type, int32_t *value) {
case 0: /* VIP */ case 0: /* VIP */
vipRead(sim, address, type, value); vipRead(sim, address, type, value);
switch (type) {
case VB_S8 : *value = (int8_t ) *value; break;
case VB_S16: *value = (int16_t) *value; break;
}
break; break;
case 1: break; /* VSU */ case 1: break; /* VSU */
+2
View File
@@ -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;
+20 -15
View File
@@ -546,7 +546,7 @@ static void vipWriteIO(
break; break;
case 0x5F870>>1: /* BKCOL */ case 0x5F870>>1: /* BKCOL */
sim->vip.bkcol = (sim->vip.bkcol & mask) | (value & 3 * ~mask); sim->vip.bkcol = (sim->vip.bkcol & mask) | (value & 3 & ~mask);
break; break;
} }
@@ -654,29 +654,29 @@ static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
vipThrow(sim, 0x0010); /* FRAMESTART */ vipThrow(sim, 0x0010); /* FRAMESTART */
/* Game frame */ /* Game frame */
if (sim->vip.xp.xpen) {
if (sim->vip.xp.frame >= sim->vip.frmcyc) { if (sim->vip.xp.frame >= sim->vip.frmcyc) {
sim->vip.dp.buffer ^= sim->vip.xp.toggle;
sim->vip.xp.frame = 0; sim->vip.xp.frame = 0;
sim->vip.xp.toggle = 0;
/* Initiate drawing procedure */
if (sim->vip.xp.step == 0) {
sim->vip.xp.enabled = 1;
sim->vip.xp.overtime = 0;
sim->vip.xp.step = 1;
vipThrow(sim, 0x0008); /* GAMESTART */ vipThrow(sim, 0x0008); /* GAMESTART */
} if (sim->vip.xp.step != 0) {
/* Drawing procedure has run into overtime */
else {
sim->vip.xp.overtime = 1; sim->vip.xp.overtime = 1;
vipThrow(sim, 0x8000); /* TIMEERR */ vipThrow(sim, 0x8000); /* TIMEERR */
} }
} else sim->vip.xp.frame++; /* Initiate drawing procedure */
else if (sim->vip.xp.xpen) {
sim->vip.dp.buffer ^= sim->vip.xp.toggle;
sim->vip.xp.enabled = 1;
sim->vip.xp.overtime = 0;
sim->vip.xp.step = 1;
sim->vip.xp.toggle = 0;
} }
}
/* Not a game frame */
else sim->vip.xp.frame++;
break; break;
/* 0ms-3ms - Idle */ /* 0ms-3ms - Idle */
@@ -1316,8 +1316,13 @@ static void vipRead(VB *sim, uint32_t address, int type, int32_t *value) {
*value = 0; *value = 0;
/* I/O register */ /* I/O register */
else if (address < 0x60000) else if (address < 0x60000) {
*value = vipReadIO(sim, address, type); *value = vipReadIO(sim, address, type);
switch (type) {
case VB_S8 : *value = (int8_t ) *value; break;
case VB_S16: *value = (int16_t) *value; break;
}
}
/* Unmapped */ /* Unmapped */
else if (address < 0x78000) else if (address < 0x78000)
+85 -24
View File
@@ -45,9 +45,28 @@ 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 != 2 || (
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;
/* Modulation mask control */
if (sim->vsu.freqmod.modmask == 1 && sim->vsu.freqmod.func == 1) {
sim->vsu.freqmod.modmask = 2;
chan->freqmod = vsuCheckFreqMod(sim);
}
/* Sweep */ /* Sweep */
if (sim->vsu.freqmod.func == 0) { if (sim->vsu.freqmod.func == 0) {
@@ -57,25 +76,37 @@ 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 + next = (int32_t) chan->freq.written +
sim->vsu.modulation[sim->vsu.freqmod.sample]) & 2047; sim->vsu.modulation[sim->vsu.freqmod.sample];
if (sim->vsu.freqmod.sample != 31) if (next < 0)
sim->vsu.freqmod.sample++; next = 0;
else if (sim->vsu.freqmod.rep) if (next > 2047)
sim->vsu.freqmod.sample = 0; next = 2047;
} }
/* Configure state */ /* Configure state */
if (chan->freqmod)
sim->vsu.freqmod.next = next; sim->vsu.freqmod.next = next;
} }
/* Advance the noise channel's shift register */
static void vsuNextNoise(VB *sim) {
uint32_t bit = ((
sim->vsu.noise.register_ >> NOISE_TAPS[sim->vsu.noise.tap] ^
sim->vsu.noise.register_ >> 7
) & 1) ^ 1;
sim->vsu.noise.register_ = bit |
(sim->vsu.noise.register_ << 1 & 0x7FFE);
}
/* Process one channel */ /* Process one channel */
static void vsuEmulateChannel(VB *sim, Channel *chan) { static void vsuEmulateChannel(VB *sim, Channel *chan) {
uint32_t bit; /* Pseudorandom bit */
/* Automatic shutoff */ /* Automatic shutoff */
if (chan->int_.auto_ && chan->int_.clocks == 0) { if (chan->int_.auto_ && chan->int_.clocks == 0) {
@@ -95,37 +126,57 @@ static void vsuEmulateChannel(VB *sim, Channel *chan) {
/* Noise */ /* Noise */
else { else {
chan->clocks = 40 * (2048 - (uint32_t) chan->freq.current); chan->clocks = 40 * (2048 - (uint32_t) chan->freq.current);
bit = (( vsuNextNoise(sim);
sim->vsu.noise.register_ >> NOISE_TAPS[sim->vsu.noise.tap]^
sim->vsu.noise.register_ >> 7
) & 1) ^ 1;
sim->vsu.noise.register_ = bit |
(sim->vsu.noise.register_ << 1 & 0x7FFE);
} }
} }
/* 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;
} }
/* Frequency modification */ /* Frequency modification */
if (chan->freqmod && sim->vsu.freqmod.clocks == 0) { if (chan == &sim->vsu.channels[4] && sim->vsu.freqmod.clocks == 0) {
/* Apply previously computed frequency modification */
if (chan->freqmod)
chan->freq.current = sim->vsu.freqmod.next; chan->freq.current = sim->vsu.freqmod.next;
vsuNextFreqMod(sim, chan);
/* Channel itself is disabled */
if (!chan->int_.enb) if (!chan->int_.enb)
return; return;
/* Frequency modifications are enabled */
if (chan->freqmod) {
/* Not the final modulation sample */
if (sim->vsu.freqmod.sample != 31)
sim->vsu.freqmod.sample++;
/* Last modulation sample processed */
else {
sim->vsu.freqmod.modmask = 1;
if (sim->vsu.freqmod.rep)
sim->vsu.freqmod.sample = 0;
}
/* Schedule next modification */
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);
} }
/* Always process and validate next frequency value */
vsuNextFreqMod(sim, chan);
}
} }
/* Produce output for a channel */ /* Produce output for a channel */
@@ -164,8 +215,10 @@ static void vsuWriteEV0(VB *sim, int index, uint8_t value) {
chan->env.interval = value & 7; chan->env.interval = value & 7;
chan->env.value = value >> 4 & 15; chan->env.value = value >> 4 & 15;
chan->env.reload = chan->env.value; chan->env.reload = chan->env.value;
if (index == 4) if (index == 4) {
chan->freqmod = vsuCheckFreqMod(sim);
vsuNextFreqMod(sim, chan); vsuNextFreqMod(sim, chan);
}
/* Configure state */ /* Configure state */
chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1); chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1);
@@ -186,14 +239,14 @@ 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 */
sim->vsu.noise.tap = value >> 4 & 7; sim->vsu.noise.tap = value >> 4 & 7;
sim->vsu.noise.register_ = 0x0000; sim->vsu.noise.register_ = 0x0000;
vsuNextNoise(sim);
} }
} }
@@ -228,6 +281,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) {
@@ -235,12 +289,16 @@ static void vsuWriteINT(VB *sim, int index, uint8_t value) {
chan->clocks = 4 * (2048 - (uint32_t) chan->freq.current); chan->clocks = 4 * (2048 - (uint32_t) chan->freq.current);
} else { } else {
sim->vsu.noise.register_ = 0x0000; sim->vsu.noise.register_ = 0x0000;
vsuNextNoise(sim);
chan->clocks = 40 * (2048 - (uint32_t) chan->freq.current); chan->clocks = 40 * (2048 - (uint32_t) chan->freq.current);
} }
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;
chan->freqmod = vsuCheckFreqMod(sim);
vsuNextFreqMod(sim, chan);
} }
} }
@@ -272,8 +330,8 @@ 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; vsuNextFreqMod(sim, &sim->vsu.channels[4]);
} }
@@ -315,7 +373,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 +383,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 +486,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 +509,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;
+297
View File
@@ -0,0 +1,297 @@
/* This file is included into vbu.c and cannot be compiled on its own. */
#ifdef VBUAPI
/********************************* Constants *********************************/
/* Range types */
/*
0x41 ('A') 8-bit integer (.db), string
0x42 ('B') 8-bit integer (.db), numeric
0x43 ('C') Compiled C code
0x44 ('D') 16-bit integer (.dd, high byte first)
0x45 ('E') 65C816 code (8-bit accumulator, 8-bit index)
0x46 ('F') 65C816 code (8-bit accumulator, 16-bit index)
0x47 ('G') 65C816 code (16-bit accumulator, 8-bit index)
0x48 ('H') 65C816 code (16-bit accumulator, 16-bit index)
0x4C ('L') 32-bit integer (.dl SNES, .dw Virtual Boy, low byte first)
0x53 ('S') Size reservation, as in .bss allocation (.ds)
0x57 ('W') 16-bit integer (.dw SNES, .dh Virtual Boy, low byte first)
*/
/***************************** Module Functions ******************************/
/* Skip ISX record type 0x01 */
static size_t isx01(uint8_t *bytes, size_t length, size_t src) {
/*
u8 Type =0x01
u8 Bank Cartridge bank number
u8 BankHigh Only if Bank >= 0x80
u16 Address CPU bus address
u16 DataLength Number of bytes in Data
u8[] Data Code bytes
*/
/* Bank field is not present */
if (src + 2 > length)
return (size_t) -1;
/* Advance to DataLength field */
src += bytes[src + 1] >= 0x80 ? 5 : 4;
/* DataLength field is not present */
if (src + 2 > length)
return (size_t) -1;
/* Advance past Data field */
return src + 2 + ((uint16_t) bytes[src + 1] << 8 | bytes[src]);
}
/* Decode ISX record type 0x11 */
static size_t isx11(uint8_t *bytes, size_t length, size_t src,
uint32_t *address, uint32_t *size) {
/*
u8 Type =0x11
u32 Address CPU bus address
u32 DataLength Number of bytes in Data
u8[] Data Code bytes
*/
/* DataLength field is not present */
if (src + 9 > length)
return (size_t) -1;
/* Parse Address and DataLength fields */
*address = (uint32_t) bytes[src+4] << 24 | (uint32_t) bytes[src+3] << 16 |
(uint32_t) bytes[src+2] << 8 | bytes[src+1];
*size = (uint32_t) bytes[src+8] << 24 | (uint32_t) bytes[src+7] << 16 |
(uint32_t) bytes[src+6] << 8 | bytes[src+5];
/* Advance past Data field */
return src + 9 + *size;
}
/* Skip ISX range records */
static size_t isxRange(uint8_t *bytes,size_t length,size_t src,size_t size) {
/*
u8 Type =0x03 (SNES) or 0x13 (Virtual Boy)
u16 Count Number of ranges
Range[] Ranges
=== SNES fields ===
u8 Bank Cartridge bank number
u16 StartAddress Lowest CPU bus address
u16 EndAddress Highest CPU bus address
u8 RangeType See range types
=== Virtual Boy fields ===
u32 StartAddress Lowest CPU bus address
u32 EndAddress Highest CPU bus address
u8 RangeType See range types
*/
/* Count field is not present */
if (src + 3 > length)
return (size_t) -1;
/* Advance past Ranges field */
return src + 3 + size * ((uint16_t) bytes[src + 2] << 8 | bytes[src + 1]);
}
/* Skip ISX symbol record */
static size_t isxSymbol(uint8_t *bytes,size_t length,size_t src,size_t size) {
size_t count; /* Number of symbols */
size_t x; /* Iterator */
/*
u8 Type =0x04 (SNES) or 0x14 (Virtual Boy)
u16 Count Number of symbols
Symbol[] Symbols
u8 NameLength Number of bytes in Name
u8[] Name Symbol name
=== SNES fields ===
u8 Flags Undocumented
u8 Bank Cartridge bank number
u16 Address CPU bus address
=== Virtual Boy fields ===
u16 Flags Undocumented
u32 Address CPU bus address
*/
/* Count field is not present */
if (src + 3 > length)
return (size_t) -1;
/* Working variables */
count = (uint16_t) bytes[src + 2] << 8 | bytes[src + 1];
src += 3;
/* Process all symbols */
for (x = 0; x < count; x++) {
/* NameLength field is not present */
if (src > length)
return (size_t) -1;
/* Advance past remainder of symbol */
src += size + bytes[src];
/* Remainder of symbol is not present */
if (src > length)
return (size_t) -1;
}
return src;
}
/* Skip ISX system record */
static size_t isxSystem(uint8_t *bytes, size_t length, size_t src) {
/*
u8 Type =0x20, 0x21 or 0x22
u32 DataLength Number of bytes in Data
u8[] Data Record data
*/
/* DataLength field is not present */
if (src + 5 > length)
return (size_t) -1;
/* Advance past Data field */
return src + 5 + (
(uint32_t) bytes[src + 4] << 24 | (uint32_t) bytes[src + 3] << 16 |
(uint32_t) bytes[src + 2] << 8 | bytes[src + 1]
);
}
/***************************** Library Functions *****************************/
/* Decode an ISX debugger file to a Virtual Boy ROM */
static void* isxFrom(uint8_t *bytes, size_t length, size_t *romLength) {
uint32_t addr; /* Code record base address */
uint32_t highMin; /* Lowest address in upper half of ROM */
uint32_t lowMax; /* Highest address in lower half of ROM */
uint8_t *rom; /* Output ROM */
uint32_t size; /* Code record size in bytes */
size_t src; /* Input position */
size_t start; /* Offset of first record */
/* Error checking */
if (length < 3)
return NULL;
/* Working variables */
highMin = 0xFFFFFF;
lowMax = 0x000000;
size = 0;
start = strncmp((char *) bytes, "ISX", 3) ? 0 : 32;
/* First pass: determine the size of the ROM */
for (src = start; src < length;) {
switch (bytes[src]) {
case 0x11: /* Code (Virtual Boy) */
/* Decode record fields */
src = isx11(bytes, length, src, &addr, &size);
if (src > length)
return NULL;
/* Validate address and data size */
addr &= 0x07FFFFFF;
if (
addr < 0x07000000 ||
0x08000000 - addr < size
) return NULL;
addr &= 0x00FFFFFF;
/* Requires 16 MiB */
if (addr < 0x800000 && addr + size > 0x800000) {
highMin = 0x800000;
lowMax = 0x7FFFFF;
}
/* Map from top of ROM space */
else if (addr & 0x800000) {
if (addr < highMin)
highMin = addr;
}
/* Map from bottom of ROM space */
else {
addr += size - 1;
if (addr > lowMax)
lowMax = addr;
}
break;
case 0x01: /* Code (SNES) */
src = isx01 (bytes, length, src ); break;
case 0x03: /* Range (SNES) */
src = isxRange (bytes, length, src, 6); break;
case 0x04: /* Symbol (SNES) */
src = isxSymbol(bytes, length, src, 5); break;
case 0x13: /* Range (Virtual Boy) */
src = isxRange (bytes, length, src, 9); break;
case 0x14: /* Symbol (Virtual Boy) */
src = isxSymbol(bytes, length, src, 7); break;
case 0x20: /* System (undocumented) */
case 0x21: /* System (undocumented) */
case 0x22: /* System (undocumented) */
src = isxSystem(bytes, length, src ); break;
default: /* Invalid record type */
return NULL;
}
/* Record contains invalid data */
if (src > length)
return NULL;
}
/* Produce a ROM buffer of minimal size to fit all the code records */
for (
src = 1;
src < lowMax + 0x1000001 - highMin;
src <<= 1
);
rom = VBU_REALLOC(NULL, src);
if (rom == NULL)
return NULL;
*romLength = src;
memset(rom, 0x00, src);
/* Second pass: fill the ROM buffer with the code records */
for (src = start; src < length;) {
switch (bytes[src]) {
case 0x11: /* Code (Virtual Boy) */
src = isx11(bytes, length, src, &addr, &size);
memcpy(&rom[addr & (*romLength-1)], &bytes[src - size], size);
break;
case 0x01: /* Code (SNES) */
src = isx01 (bytes, length, src ); break;
case 0x03: /* Range (SNES) */
src = isxRange (bytes, length, src, 9); break;
case 0x04: /* Symbol (SNES) */
src = isxSymbol(bytes, length, src, 5); break;
case 0x13: /* Range (Virtual Boy) */
src = isxRange (bytes, length, src, 12); break;
case 0x14: /* Symbol (Virtual Boy) */
src = isxSymbol(bytes, length, src, 7); break;
case 0x20: /* System (undocumented) */
case 0x21: /* System (undocumented) */
case 0x22: /* System (undocumented) */
src = isxSystem(bytes, length, src ); break;
}
}
return rom;
}
#endif /* VBUAPI */
+6
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);
}
+1
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);
-2
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 {
+2 -3
View File
@@ -1,4 +1,5 @@
let Constants = { "use strict";
export default {
// Core // Core
VB: { VB: {
@@ -85,5 +86,3 @@ let Constants = {
} }
}; };
export { Constants };
+36 -1
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);
+24 -2
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;