shrooms-vb-core/web/wasm.c

188 lines
5.7 KiB
C
Raw Normal View History

2024-11-01 20:03:49 +00:00
#include <stdlib.h>
#include <stdio.h>
#include <emscripten/emscripten.h>
#include <vb.h>
#include <vbu.h>
////////////////////////////////// Constants //////////////////////////////////
// Break conditions
#define BREAK_FRAME 1
#define BREAK_POINT 2
// Extra properties
#define EXT_PIXELS 0
#define EXT_SAMPLES 1
//////////////////////////////////// Types ////////////////////////////////////
// Additional monitor state for simulations
typedef struct {
int32_t breaks;
uint32_t left[256];
uint8_t pixels[384 * 224 * 4];
uint32_t right[256];
float samples[41700 * 2];
} Ext;
////////////////////////////////// Callbacks //////////////////////////////////
// Frame callback
int wasmOnFrame(VB *sim) {
((Ext *) vbGetUserData(sim))->breaks |= BREAK_FRAME;
return 1;
}
/////////////////////////////// Module Exports ////////////////////////////////
// Instantiate a simulation
EMSCRIPTEN_KEEPALIVE void* CreateSim() {
size_t sizeOfSim = vbSizeOf();
uint8_t *pointer = malloc(sizeOfSim + sizeof (Ext));
// Configure sim
VB *sim = vbInit((VB *) pointer);
vbSetFrameCallback(sim, &wasmOnFrame);
vbSetOption(sim, VB_PSEUDO_HALT, 1);
// Configure extra
Ext *ext = (Ext *) (pointer + sizeOfSim);
ext->breaks = 0;
vbSetUserData(sim, ext);
// Initialize pixels with opaque black
for (unsigned x = 0; x < 384 * 224; x++)
((uint32_t *) ext->pixels)[x] = 0xFF000000;
return sim;
}
// Disassemble from a simulation
EMSCRIPTEN_KEEPALIVE void* Disassemble(
int bcondNotation, int conditionCase, int conditionCL, int conditionEZ,
int conditionNotation, int hexCase, int hexNotation, int memoryNotation,
int mnemonicCase, int operandOrder, int programCase, int programNotation,
int setfNotation, int systemCase, int systemNotation,
VB *sim, uint32_t address, unsigned length, int line
) {
VBU_DasmConfig config;
config.bcondNotation = bcondNotation;
config.conditionCase = conditionCase;
config.conditionCL = conditionCL;
config.conditionEZ = conditionEZ;
config.conditionNotation = conditionNotation;
config.hexCase = hexCase;
config.hexNotation = hexNotation;
config.memoryNotation = memoryNotation;
config.mnemonicCase = mnemonicCase;
config.operandOrder = operandOrder;
config.programCase = programCase;
config.programNotation = programNotation;
config.setfNotation = setfNotation;
config.systemCase = systemCase;
config.systemNotation = systemNotation;
return vbuDisassemble(sim, address, &config, length, line);
}
// Process simulations
EMSCRIPTEN_KEEPALIVE int Emulate(VB **sims, unsigned count, uint32_t *clocks) {
for (unsigned x = 0; x < count; x++)
((Ext *) vbGetUserData(sims[x]))->breaks = 0;
return vbEmulateEx(sims, count, clocks);
}
// Retrieve the break condition flags for a sim
EMSCRIPTEN_KEEPALIVE int32_t GetBreaks(VB *sim) {
return ((Ext *) vbGetUserData(sim))->breaks;
}
// Serialize disassembled lines into a linear buffer
EMSCRIPTEN_KEEPALIVE void GetDasm(uint32_t *buffer, void *dasm, int count) {
for (int x = 0; x < count; x++) {
VBU_DasmLine *line = &((VBU_DasmLine *) dasm)[x];
// Numeric data
*buffer++ = line->address;
*buffer++ = line->codeLength;
for (int y = 0; y < 4; y++)
*buffer++ = line->code[y];
*buffer++ = line->isPC;
// Text data -- Store offset of string pointer from start of dasm
*buffer++ = (uint32_t) ((void *) &line->text.address - dasm);
for (int y = 0; y < 4; y++)
*buffer++ = (uint32_t) ((void *) &line->text.code[y] - dasm);
*buffer++ = (uint32_t) ((void *) &line->text.mnemonic - dasm);
*buffer++ = line->text.operandsLength;
for (int y = 0; y < 3; y++)
*buffer++ = (uint32_t) ((void *) &line->text.operands[y] - dasm);
}
}
// Retrieve an extra property
EMSCRIPTEN_KEEPALIVE void* GetExt(VB *sim, int id) {
Ext *ext = (Ext *) vbGetUserData(sim);
switch (id) {
case EXT_PIXELS : return ext->pixels;
case EXT_SAMPLES: return ext->samples;
}
return NULL;
}
// Retrieve anaglyph-tinted pixels from a sim
EMSCRIPTEN_KEEPALIVE void GetPixels(VB *sim) {
Ext *ext = (Ext *) vbGetUserData(sim);
uint8_t *pixels = ext->pixels;
vbGetPixels(sim, pixels, 4, 384 * 4, pixels + 1, 4, 384 * 4);
for (unsigned x = 0; x < 384 * 224 * 4; x += 4, pixels += 4)
*(uint32_t *) pixels = ext->left[pixels[0]] | ext->right[pixels[1]];
}
// Determine the size in bytes of a pointer
EMSCRIPTEN_KEEPALIVE int PointerSize() {
return sizeof (void *);
}
// Memory management
EMSCRIPTEN_KEEPALIVE void* Realloc(void *data, size_t size) {
return realloc(data, size);
}
// Specify anaglyph colors
EMSCRIPTEN_KEEPALIVE void SetAnaglyph(VB *sim, uint32_t left, uint32_t right) {
Ext *ext = (Ext *) vbGetUserData(sim);
// Erase all RGB values
for (int x = 0; x < 256; x++)
ext->left[x] = ext->right[x] = 0xFF000000;
// Process all RGB channels
for (int c = 0, shift = 16; c < 3; c++, shift -= 8) {
double max; // Magnitude of channel value
uint32_t *dest; // Lookup data
// Select the magnitude and lookup channel
dest = ext->left;
max = (left >> shift & 0xFF) / 255.0;
if (max == 0) {
dest = ext->right;
max = (right >> shift & 0xFF) / 255.0;
if (max == 0)
continue;
}
// Compute the resulting RGB values
for (int x = 0; x < 256; x++)
*dest++ |= (uint32_t) (x * max + 0.5) << (16 - shift);
}
}