Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c06da32321 | ||
|
|
0a57ef0faf | ||
|
|
a285065102 | ||
|
|
3afe0282c2 |
+5
-2
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
|
||||
/********************************* Constants *********************************/
|
||||
/******************************** Lookup Data ********************************/
|
||||
|
||||
/* Memory access address masks by data type */
|
||||
static const uint32_t TYPE_MASKS[] = {
|
||||
@@ -20,6 +20,7 @@ static const uint32_t TYPE_MASKS[] = {
|
||||
|
||||
static void vipRead (VB *, uint32_t, int, int32_t *);
|
||||
static void vipWrite(VB *, uint32_t, int, int32_t, int);
|
||||
static void vsuWrite(VB *, uint32_t, int, int32_t, int);
|
||||
|
||||
|
||||
|
||||
@@ -197,7 +198,9 @@ static void busWrite(VB*sim,uint32_t address,int type,int32_t value,int debug){
|
||||
vipWrite(sim, address, type, value, debug);
|
||||
break;
|
||||
|
||||
case 1: break; /* VSU */
|
||||
case 1: /* VSU */
|
||||
vsuWrite(sim, address, type, value, debug);
|
||||
break;
|
||||
|
||||
case 2: /* Misc. I/O */
|
||||
busWriteMisc(sim, address, type, value);
|
||||
|
||||
+5
-5
@@ -857,7 +857,7 @@ static int cpuFloatCommon(VB *sim, double value, int32_t *bits) {
|
||||
}
|
||||
|
||||
/* Underflow */
|
||||
if (value < 0 ? value > -FLT_MIN : value < FLT_MIN) {
|
||||
if (value != 0 && value > -FLT_MIN && value < FLT_MIN) {
|
||||
sim->cpu.psw.fud = 1;
|
||||
floatVal = 0;
|
||||
/* TODO: Can this produce negative zero? */
|
||||
@@ -872,10 +872,10 @@ static int cpuFloatCommon(VB *sim, double value, int32_t *bits) {
|
||||
|
||||
/* Update state */
|
||||
*bits = cpuFloatToWord(floatVal);
|
||||
sim->cpu.psw.cy = floatVal < 0;
|
||||
sim->cpu.psw.ov = 0;
|
||||
sim->cpu.psw.s = floatVal < 0;
|
||||
sim->cpu.psw.z = floatVal == 0;
|
||||
sim->cpu.psw.cy = floatVal < 0;
|
||||
sim->cpu.psw.ov = 0;
|
||||
sim->cpu.psw.s = floatVal < 0;
|
||||
sim->cpu.psw.z = floatVal == 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -6,16 +6,16 @@
|
||||
/***************************** Library Functions *****************************/
|
||||
|
||||
/* Process component */
|
||||
static int padEmulate(VB *sim, uint32_t clocks) {
|
||||
static void padEmulate(VB *sim, uint32_t clocks) {
|
||||
|
||||
/* No hardware read in progress */
|
||||
if (sim->pad.si_stat == 0)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/* Hardware read completes after time to process */
|
||||
if (sim->pad.si_stat > clocks) {
|
||||
sim->pad.si_stat -= clocks;
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Complete hardware read */
|
||||
@@ -30,7 +30,6 @@ static int padEmulate(VB *sim, uint32_t clocks) {
|
||||
(sim->pad.keys & 0x000E) == 0
|
||||
) sim->cpu.irq |= 0x0001;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read a value from SCR */
|
||||
|
||||
+3
-3
@@ -21,11 +21,11 @@ static void tmrUpdate(VB *sim, uint16_t value) {
|
||||
/***************************** Library Functions *****************************/
|
||||
|
||||
/* Process component */
|
||||
static int tmrEmulate(VB *sim, uint32_t clocks) {
|
||||
static void tmrEmulate(VB *sim, uint32_t clocks) {
|
||||
|
||||
/* Timer is disabled */
|
||||
if (!sim->tmr.t_enb)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/* Process all clocks */
|
||||
for (;;) {
|
||||
@@ -34,7 +34,7 @@ static int tmrEmulate(VB *sim, uint32_t clocks) {
|
||||
if (sim->tmr.clocks > clocks) {
|
||||
sim->tmr.clocks -= clocks;
|
||||
sim->tmr.until -= clocks;
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Advance forward the component's number of clocks */
|
||||
|
||||
@@ -11,6 +11,62 @@
|
||||
/* Output image */
|
||||
typedef uint8_t Pixels[2][384*224];
|
||||
|
||||
/* VSU channel */
|
||||
typedef struct {
|
||||
|
||||
/* Envelope */
|
||||
struct {
|
||||
|
||||
/* Register state */
|
||||
uint8_t enb; /* Modifications enabled */
|
||||
uint8_t dir; /* Modification direction */
|
||||
uint8_t interval; /* Modification interval */
|
||||
uint8_t rep; /* Repeat modifications */
|
||||
uint8_t value; /* Master output level */
|
||||
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Clocks until modification */
|
||||
uint8_t reload; /* Automatic reload value */
|
||||
} env;
|
||||
|
||||
/* Frequency */
|
||||
struct {
|
||||
uint16_t current; /* Current value */
|
||||
uint16_t written; /* Last value written */
|
||||
} freq;
|
||||
|
||||
/* Stereo levels */
|
||||
struct {
|
||||
uint8_t left; /* Left output level */
|
||||
uint8_t right; /* Right output level */
|
||||
} lrv;
|
||||
|
||||
/* Control */
|
||||
struct {
|
||||
|
||||
/* Register state */
|
||||
uint8_t auto_; /* Shutoff enabled */
|
||||
uint8_t enb; /* Sound generation enabled */
|
||||
uint8_t interval; /* Shutoff interval */
|
||||
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Clocks until shutoff */
|
||||
} int_;
|
||||
|
||||
/* Waveform */
|
||||
struct {
|
||||
|
||||
/* Register state */
|
||||
uint8_t wave; /* Waveform index */
|
||||
|
||||
/* Other state */
|
||||
int sample; /* Current sample index */
|
||||
} wave;
|
||||
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Clocks until next sample */
|
||||
} Channel;
|
||||
|
||||
/* Simulation state */
|
||||
struct VB {
|
||||
|
||||
@@ -93,7 +149,7 @@ struct VB {
|
||||
/* Game pad */
|
||||
struct {
|
||||
|
||||
/* Hardware state */
|
||||
/* Register state */
|
||||
uint8_t k_int_inh; /* Interrupt acknowledge/disable */
|
||||
uint8_t para_si; /* Read reset signal */
|
||||
uint8_t s_abt_dis; /* Abort hardware read */
|
||||
@@ -102,7 +158,7 @@ struct VB {
|
||||
uint32_t si_stat; /* Hardware read in progress */
|
||||
uint8_t soft_ck; /* Controller communication signal */
|
||||
|
||||
/* Simulation state */
|
||||
/* Other state */
|
||||
uint16_t keys; /* Next input bits */
|
||||
int step; /* Software read processing phase */
|
||||
} pad;
|
||||
@@ -110,13 +166,13 @@ struct VB {
|
||||
/* Timer */
|
||||
struct {
|
||||
|
||||
/* Hardware state */
|
||||
/* Register state */
|
||||
uint8_t t_clk_sel; /* Counter tick duration */
|
||||
uint8_t t_enb; /* Enable timer */
|
||||
uint8_t tim_z_int; /* Enable interrupt */
|
||||
uint8_t z_stat; /* Zero status */
|
||||
|
||||
/* Simulation state */
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Master clocks to wait */
|
||||
uint16_t counter; /* Current counter value */
|
||||
uint16_t reload; /* Reload counter value */
|
||||
@@ -135,7 +191,7 @@ struct VB {
|
||||
/* Display processor */
|
||||
struct {
|
||||
|
||||
/* Hardware state */
|
||||
/* Register state */
|
||||
uint8_t disp; /* Display enabled */
|
||||
uint8_t fclk; /* Frame clock signal high */
|
||||
uint8_t l0bsy; /* Displaying left frame buffer 0 */
|
||||
@@ -147,7 +203,7 @@ struct VB {
|
||||
uint8_t scanrdy; /* Mirrors are stable */
|
||||
uint8_t synce; /* Servo enabled */
|
||||
|
||||
/* Simulation state */
|
||||
/* Other state */
|
||||
uint8_t brt[4]; /* Precomputed brightness */
|
||||
int buffer; /* Index of frame buffer to display */
|
||||
uint32_t clocks; /* Master clocks to wait */
|
||||
@@ -163,7 +219,7 @@ struct VB {
|
||||
/* Pixel processor */
|
||||
struct {
|
||||
|
||||
/* Hardware state */
|
||||
/* Register state */
|
||||
uint8_t f0bsy; /* Drawing into frame buffer 0 */
|
||||
uint8_t f1bsy; /* Drawing into frame buffer 1 */
|
||||
uint8_t overtime; /* Drawing extends into display interval */
|
||||
@@ -172,7 +228,7 @@ struct VB {
|
||||
uint32_t sbout; /* Drawing specified vertical output position */
|
||||
uint8_t xpen; /* Drawing enabled */
|
||||
|
||||
/* Simulation state */
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Master clocks to wait */
|
||||
int column; /* Current horizontal output position */
|
||||
int frame; /* FRMCYC counter */
|
||||
@@ -200,6 +256,58 @@ struct VB {
|
||||
uint8_t ram[0x40000]; /* Video memory */
|
||||
} vip;
|
||||
|
||||
/* VSU */
|
||||
struct {
|
||||
|
||||
/* Audio sources */
|
||||
Channel channels[6];
|
||||
|
||||
/* Channel 5 frequency modification */
|
||||
struct {
|
||||
|
||||
/* Register state */
|
||||
uint8_t clk; /* Base modification clock */
|
||||
uint8_t dir; /* Sweep direction */
|
||||
uint8_t enb; /* Modifications enabled */
|
||||
uint8_t func; /* Modification function */
|
||||
uint8_t interval; /* Modification interval */
|
||||
uint8_t rep; /* Repeat modulation */
|
||||
uint8_t shift; /* Sweep shift amount */
|
||||
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Clocks until modification */
|
||||
uint16_t next; /* Next frequency value */
|
||||
int sample; /* Current sample index */
|
||||
} freqmod;
|
||||
|
||||
/* Channel 6 noise generator */
|
||||
struct {
|
||||
|
||||
/* Register state */
|
||||
uint8_t tap; /* LSFR feedback bit position */
|
||||
|
||||
/* Other state */
|
||||
uint16_t register_; /* Pseudorandom bits */
|
||||
} noise;
|
||||
|
||||
/* Sample output */
|
||||
struct {
|
||||
float i1[2]; /* Previous analog input sample */
|
||||
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 */
|
||||
} out;
|
||||
|
||||
/* Memory */
|
||||
int8_t modulation[32]; /* Modulation amounts */
|
||||
uint8_t waves[5][32]; /* Wafeform samples */
|
||||
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Clocks until next output sample */
|
||||
int sample; /* Output sample index, period 417 */
|
||||
} vsu;
|
||||
|
||||
/* Other state */
|
||||
uint8_t wcr; /* Wait controller state */
|
||||
uint8_t wram[0x10000]; /* System RAM */
|
||||
@@ -210,6 +318,7 @@ struct VB {
|
||||
vbOnFetch onFetch; /* CPU instruction fetch */
|
||||
vbOnFrame onFrame; /* VIP frame ready */
|
||||
vbOnRead onRead; /* CPU instruction read */
|
||||
vbOnSamples onSamples; /* VSU samples full */
|
||||
vbOnWrite onWrite; /* CPU instruction write */
|
||||
void *tag; /* User data */
|
||||
};
|
||||
@@ -238,6 +347,7 @@ static int32_t SignExtend(int32_t value, int32_t bits) {
|
||||
#include "bus.c"
|
||||
#include "cpu.c"
|
||||
#include "vip.c"
|
||||
#include "vsu.c"
|
||||
|
||||
|
||||
|
||||
@@ -245,20 +355,21 @@ static int32_t SignExtend(int32_t value, int32_t bits) {
|
||||
|
||||
/* Process a simulation for a given number of clocks */
|
||||
static int sysEmulate(VB *sim, uint32_t clocks) {
|
||||
return
|
||||
cpuEmulate(sim, clocks) |
|
||||
vipEmulate(sim, clocks) |
|
||||
padEmulate(sim, clocks) |
|
||||
tmrEmulate(sim, clocks)
|
||||
;
|
||||
int ret;
|
||||
ret = cpuEmulate(sim, clocks);
|
||||
padEmulate(sim, clocks);
|
||||
tmrEmulate(sim, clocks);
|
||||
vsuEmulate(sim, clocks);
|
||||
ret |= vipEmulate(sim, clocks);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Determine how many clocks are guaranteed to process */
|
||||
static uint32_t sysUntil(VB *sim, uint32_t clocks) {
|
||||
clocks = cpuUntil(sim, clocks);
|
||||
clocks = vipUntil(sim, clocks);
|
||||
clocks = padUntil(sim, clocks);
|
||||
clocks = tmrUntil(sim, clocks);
|
||||
clocks = vipUntil(sim, clocks);
|
||||
return clocks;
|
||||
}
|
||||
|
||||
@@ -395,6 +506,27 @@ VBAPI vbOnRead vbGetReadCallback(VB *sim) {
|
||||
return sim->onRead;
|
||||
}
|
||||
|
||||
/* Retrieve the audio samples buffer */
|
||||
VBAPI void* vbGetSamples(VB *sim, uint32_t *capacity, uint32_t *position) {
|
||||
if (sim->vsu.out.samples == NULL) {
|
||||
if (capacity != NULL)
|
||||
*capacity = 0;
|
||||
if (position != NULL)
|
||||
*position = 0;
|
||||
} else {
|
||||
if (capacity != NULL)
|
||||
*capacity = sim->vsu.out.capacity;
|
||||
if (position != NULL)
|
||||
*position = sim->vsu.out.offset >> 1;
|
||||
}
|
||||
return sim->vsu.out.samples;
|
||||
}
|
||||
|
||||
/* Retrieve the samples callback handler */
|
||||
VBAPI vbOnSamples vbGetSamplesCallback(VB *sim) {
|
||||
return sim->onSamples;
|
||||
}
|
||||
|
||||
/* Retrieve the value in a system register */
|
||||
VBAPI uint32_t vbGetSystemRegister(VB *sim, int index) {
|
||||
return index < 0 || index > 31 ? 0 : cpuGetSystemRegister(sim, index);
|
||||
@@ -412,13 +544,15 @@ VBAPI vbOnWrite vbGetWriteCallback(VB *sim) {
|
||||
|
||||
/* Initialize a simulation instance */
|
||||
VBAPI VB* vbInit(VB *sim) {
|
||||
sim->cart.ram = NULL;
|
||||
sim->cart.rom = NULL;
|
||||
sim->onExecute = NULL;
|
||||
sim->onFetch = NULL;
|
||||
sim->onFrame = NULL;
|
||||
sim->onRead = NULL;
|
||||
sim->onWrite = NULL;
|
||||
sim->cart.ram = NULL;
|
||||
sim->cart.rom = NULL;
|
||||
sim->vsu.out.samples = NULL;
|
||||
sim->onExecute = NULL;
|
||||
sim->onFetch = NULL;
|
||||
sim->onFrame = NULL;
|
||||
sim->onRead = NULL;
|
||||
sim->onSamples = NULL;
|
||||
sim->onWrite = NULL;
|
||||
vbReset(sim);
|
||||
return sim;
|
||||
}
|
||||
@@ -445,9 +579,10 @@ VBAPI VB* vbReset(VB *sim) {
|
||||
|
||||
/* Components */
|
||||
cpuReset(sim);
|
||||
vipReset(sim);
|
||||
padReset(sim);
|
||||
tmrReset(sim);
|
||||
vipReset(sim);
|
||||
vsuReset(sim);
|
||||
return sim;
|
||||
}
|
||||
|
||||
@@ -526,6 +661,23 @@ VBAPI vbOnRead vbSetReadCallback(VB *sim, vbOnRead callback) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* Specify a new audio samples buffer */
|
||||
VBAPI int vbSetSamples(VB *sim, void *samples, uint32_t capacity) {
|
||||
if (samples != NULL && (capacity == 0 || capacity > 0x40000000))
|
||||
return 1;
|
||||
sim->vsu.out.capacity = samples == NULL ? 0 : capacity;
|
||||
sim->vsu.out.offset = 0;
|
||||
sim->vsu.out.samples = samples;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Specify a new samples callback handler */
|
||||
VBAPI vbOnSamples vbSetSamplesCallback(VB *sim, vbOnSamples callback) {
|
||||
vbOnSamples prev = sim->onSamples;
|
||||
sim->onSamples = callback;
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* Specify a new value for a system register */
|
||||
VBAPI uint32_t vbSetSystemRegister(VB *sim, int index, uint32_t value) {
|
||||
return index < 0 || index > 31 ? 0 :
|
||||
|
||||
@@ -23,6 +23,7 @@ extern "C" {
|
||||
VB_DIRECT_FETCH
|
||||
VB_DIRECT_FRAME
|
||||
VB_DIRECT_READ
|
||||
VB_DIRECT_SAMPLES
|
||||
VB_DIRECT_WRITE
|
||||
|
||||
Implements callbacks as direct function calls with names given by the above
|
||||
@@ -86,12 +87,13 @@ extern "C" {
|
||||
typedef struct VB VB;
|
||||
|
||||
/* Callbacks */
|
||||
typedef int (*vbOnException)(VB *sim, uint16_t *cause);
|
||||
typedef int (*vbOnExecute )(VB *sim, uint32_t address, const uint16_t *code, int length);
|
||||
typedef int (*vbOnFetch )(VB *sim, int fetch, uint32_t address, int32_t *value, uint32_t *cycles);
|
||||
typedef int (*vbOnFrame )(VB *sim);
|
||||
typedef int (*vbOnRead )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles);
|
||||
typedef int (*vbOnWrite )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles, int *cancel);
|
||||
typedef int (*vbOnException)(VB *sim, uint16_t *cause);
|
||||
typedef int (*vbOnExecute )(VB *sim, uint32_t address, const uint16_t *code, int length);
|
||||
typedef int (*vbOnFetch )(VB *sim, int fetch, uint32_t address, int32_t *value, uint32_t *cycles);
|
||||
typedef int (*vbOnFrame )(VB *sim);
|
||||
typedef int (*vbOnRead )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles);
|
||||
typedef void (*vbOnSamples )(VB *sim, int16_t *buffer, uint32_t capacity);
|
||||
typedef int (*vbOnWrite )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles, int *cancel);
|
||||
|
||||
|
||||
|
||||
@@ -112,6 +114,8 @@ VBAPI void vbGetPixels (VB *sim, void *left, int leftStrideX,
|
||||
VBAPI uint32_t vbGetProgramCounter (VB *sim);
|
||||
VBAPI int32_t vbGetProgramRegister (VB *sim, int index);
|
||||
VBAPI vbOnRead vbGetReadCallback (VB *sim);
|
||||
VBAPI void* vbGetSamples (VB *sim, uint32_t *capacity, uint32_t *position);
|
||||
VBAPI vbOnSamples vbGetSamplesCallback (VB *sim);
|
||||
VBAPI uint32_t vbGetSystemRegister (VB *sim, int index);
|
||||
VBAPI void* vbGetUserData (VB *sim);
|
||||
VBAPI vbOnWrite vbGetWriteCallback (VB *sim);
|
||||
@@ -128,6 +132,8 @@ VBAPI uint16_t vbSetKeys (VB *sim, uint16_t keys);
|
||||
VBAPI uint32_t vbSetProgramCounter (VB *sim, uint32_t value);
|
||||
VBAPI int32_t vbSetProgramRegister (VB *sim, int index, int32_t value);
|
||||
VBAPI vbOnRead vbSetReadCallback (VB *sim, vbOnRead callback);
|
||||
VBAPI int vbSetSamples (VB *sim, void *samples, uint32_t capacity);
|
||||
VBAPI vbOnSamples vbSetSamplesCallback (VB *sim, vbOnSamples callback);
|
||||
VBAPI uint32_t vbSetSystemRegister (VB *sim, int index, uint32_t value);
|
||||
VBAPI void* vbSetUserData (VB *sim, void *tag);
|
||||
VBAPI vbOnWrite vbSetWriteCallback (VB *sim, vbOnWrite callback);
|
||||
|
||||
+14
-2
@@ -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 */
|
||||
|
||||
+542
@@ -0,0 +1,542 @@
|
||||
/* This file is included into vb.c and cannot be compiled on its own. */
|
||||
#ifdef VBAPI
|
||||
|
||||
|
||||
|
||||
/********************************* Constants *********************************/
|
||||
|
||||
/* Analog output high-pass filter coefficient = 0.022 / (0.022 + 1 / 41700) */
|
||||
#define RC_A (float) (1 - 1 / 918.4)
|
||||
|
||||
|
||||
|
||||
/******************************** Lookup Data ********************************/
|
||||
|
||||
/* Noise feedback bit positions by tap field */
|
||||
static uint8_t NOISE_TAPS[] = { 14, 10, 13, 4, 8, 6, 9, 11 };
|
||||
|
||||
/* Clock flags per output sample -- 479 clocks plus bit value */
|
||||
/* Ensures exactly 200,000 clocks every 417 samples = 41,700 Hz */
|
||||
static uint32_t SAMPLE_CLOCKS[] = {
|
||||
0xD6B6B5B5, 0x5ADAD6D6, 0x6D6B6B5B, 0xB5B5ADAD,
|
||||
0xD6D6B6B5, 0x6B5B5ADA, 0xAD6D6D6B, 0xB6B5B5AD,
|
||||
0x5ADAD6D6, 0x6B6B5B5B, 0xB5ADAD6D, 0xD6D6B6B5,
|
||||
0x5B5ADAD6, 1
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************** Callback Handlers *****************************/
|
||||
|
||||
/* Samples buffer is full */
|
||||
#ifndef VB_DIRECT_SAMPLES
|
||||
#define VB_ON_SAMPLES sim->onSamples
|
||||
#else
|
||||
extern void VB_DIRECT_SAMPLES(VB *, void *, uint32_t);
|
||||
#define VB_ON_SAMPLES VB_DIRECT_SAMPLES
|
||||
#endif
|
||||
static void vsuOnSamples(VB *sim) {
|
||||
if (sim->onSamples != NULL)
|
||||
VB_ON_SAMPLES(sim, sim->vsu.out.samples, sim->vsu.out.capacity);
|
||||
}
|
||||
#undef VB_ON_SAMPLES
|
||||
|
||||
|
||||
|
||||
/***************************** Module Functions ******************************/
|
||||
|
||||
/* Stage the next frequency modification value */
|
||||
static void vsuNextFreqMod(VB *sim, Channel *chan) {
|
||||
uint16_t next;
|
||||
|
||||
/* Sweep */
|
||||
if (sim->vsu.freqmod.func == 0) {
|
||||
next = chan->freq.current >> sim->vsu.freqmod.shift;
|
||||
if (sim->vsu.freqmod.dir == 0)
|
||||
next = chan->freq.current - next;
|
||||
else next = chan->freq.current + next;
|
||||
if (next > 2047)
|
||||
chan->int_.enb = 0;
|
||||
}
|
||||
|
||||
/* Modulation */
|
||||
else {
|
||||
next = (chan->freq.written +
|
||||
sim->vsu.modulation[sim->vsu.freqmod.sample]) & 2047;
|
||||
if (sim->vsu.freqmod.sample != 31)
|
||||
sim->vsu.freqmod.sample++;
|
||||
else if (sim->vsu.freqmod.rep)
|
||||
sim->vsu.freqmod.sample = 0;
|
||||
}
|
||||
|
||||
/* Configure state */
|
||||
sim->vsu.freqmod.next = next;
|
||||
}
|
||||
|
||||
/* Process one channel */
|
||||
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 until; /* Clocks to process sub-channel components */
|
||||
|
||||
/* Select channel */
|
||||
chan = &sim->vsu.channels[index];
|
||||
|
||||
/* Channel is disabled */
|
||||
if (!chan->int_.enb)
|
||||
return;
|
||||
|
||||
/* Process all clocks */
|
||||
do {
|
||||
|
||||
/* Frequency modifications are active */
|
||||
freqmod =
|
||||
index == 4 && /* Channel 5 */
|
||||
sim->vsu.freqmod.enb && /* Modifications enabled */
|
||||
sim->vsu.freqmod.interval != 0 /* Modifications valid */
|
||||
;
|
||||
|
||||
/* Clocks until next state change */
|
||||
until = clocks;
|
||||
if (chan->clocks < until)
|
||||
until = chan->clocks;
|
||||
if (chan->env.enb && chan->env.clocks < until)
|
||||
until = chan->env.clocks;
|
||||
if (chan->int_.auto_ && chan->int_.clocks < until)
|
||||
until = chan->int_.clocks;
|
||||
if (freqmod && sim->vsu.freqmod.clocks < until)
|
||||
until = sim->vsu.freqmod.clocks;
|
||||
|
||||
/* Manage clocks */
|
||||
clocks -= until;
|
||||
chan->clocks -= until;
|
||||
if (chan->env.enb)
|
||||
chan->env.clocks -= until;
|
||||
if (chan->int_.auto_)
|
||||
chan->int_.clocks -= until;
|
||||
if (freqmod)
|
||||
sim->vsu.freqmod.clocks -= until;
|
||||
|
||||
/* Automatic shutoff */
|
||||
if (chan->int_.auto_ && chan->int_.clocks == 0) {
|
||||
chan->int_.enb = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Next sample */
|
||||
if (chan->clocks == 0) {
|
||||
|
||||
/* Wave */
|
||||
if (index != 5) {
|
||||
chan->clocks = 4 * (2048 - (uint32_t) chan->freq.current);
|
||||
chan->wave.sample = (chan->wave.sample + 1) & 31;
|
||||
}
|
||||
|
||||
/* Noise */
|
||||
else {
|
||||
chan->clocks = 40 * (2048 - (uint32_t) chan->freq.current);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Envelope modification */
|
||||
if (chan->env.enb && chan->env.clocks == 0) {
|
||||
if (chan->env.dir == 0 && chan->env.value != 0)
|
||||
chan->env.value--;
|
||||
else if (chan->env.dir == 1 && chan->env.value != 15)
|
||||
chan->env.value++;
|
||||
else if (chan->env.rep)
|
||||
chan->env.value = chan->env.reload;
|
||||
chan->env.clocks = ((uint32_t) chan->env.interval + 1) * 307220;
|
||||
}
|
||||
|
||||
/* Frequency modification */
|
||||
if (freqmod && sim->vsu.freqmod.clocks == 0) {
|
||||
chan->freq.current = sim->vsu.freqmod.next;
|
||||
vsuNextFreqMod(sim, chan);
|
||||
if (!chan->int_.enb)
|
||||
return;
|
||||
sim->vsu.freqmod.clocks = (uint32_t) sim->vsu.freqmod.interval *
|
||||
(sim->vsu.freqmod.clk == 0 ? 19201 : 153610);
|
||||
}
|
||||
|
||||
} while (clocks != 0);
|
||||
|
||||
}
|
||||
|
||||
/* 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];
|
||||
|
||||
/* Parse fields */
|
||||
chan->env.dir = value >> 3 & 1;
|
||||
chan->env.interval = value & 7;
|
||||
chan->env.value = value >> 4 & 15;
|
||||
chan->env.reload = chan->env.value;
|
||||
|
||||
/* Configure state */
|
||||
chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1);
|
||||
}
|
||||
|
||||
/* Write a value to S*EV1 */
|
||||
static void vsuWriteEV1(VB *sim, int index, uint8_t value) {
|
||||
Channel *chan = &sim->vsu.channels[index];
|
||||
|
||||
/* Parse fields */
|
||||
chan->env.enb = value & 1;
|
||||
chan->env.rep = value >> 1 & 1;
|
||||
|
||||
/* Processing by channel */
|
||||
switch (index) {
|
||||
|
||||
case 4: /* Channel 5 */
|
||||
sim->vsu.freqmod.enb = value >> 6 & 1;
|
||||
sim->vsu.freqmod.func = value >> 4 & 1;
|
||||
sim->vsu.freqmod.rep = value >> 5 & 1;
|
||||
vsuNextFreqMod(sim, chan);
|
||||
break;
|
||||
|
||||
case 5: /* Channel 6 */
|
||||
sim->vsu.noise.tap = value >> 4 & 7;
|
||||
sim->vsu.noise.register_ = 0x0000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write a value to S*FQH */
|
||||
static void vsuWriteFQH(VB *sim, int index, uint16_t value) {
|
||||
Channel *chan = &sim->vsu.channels[index];
|
||||
value = value << 8 & 0x0700;
|
||||
chan->freq.current = (chan->freq.current & 0x00FF) | value;
|
||||
chan->freq.written = (chan->freq.written & 0x00FF) | value;
|
||||
}
|
||||
|
||||
/* Write a value to S*FQL */
|
||||
static void vsuWriteFQL(VB *sim, int index, uint8_t value) {
|
||||
Channel *chan = &sim->vsu.channels[index];
|
||||
chan->freq.current = (chan->freq.current & 0x0700) | value;
|
||||
chan->freq.written = (chan->freq.written & 0x0700) | value;
|
||||
}
|
||||
|
||||
/* Write a value to S*INT */
|
||||
static void vsuWriteINT(VB *sim, int index, uint8_t value) {
|
||||
Channel *chan = &sim->vsu.channels[index];
|
||||
|
||||
/* Parse fields */
|
||||
chan->int_.auto_ = value >> 5 & 1;
|
||||
chan->int_.enb = value >> 7 & 1;
|
||||
chan->int_.interval = value & 31;
|
||||
|
||||
/* Update state */
|
||||
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;
|
||||
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);
|
||||
sim->vsu.freqmod.sample = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write a value to S*LRV */
|
||||
static void vsuWriteLRV(VB *sim, int index, uint8_t value) {
|
||||
Channel *chan = &sim->vsu.channels[index];
|
||||
chan->lrv.left = value >> 4 & 15;
|
||||
chan->lrv.right = value & 15;
|
||||
}
|
||||
|
||||
/* Write a value to S*RAM */
|
||||
static void vsuWriteRAM(VB *sim, int index, uint8_t value) {
|
||||
sim->vsu.channels[index].wave.wave = value & 7;
|
||||
}
|
||||
|
||||
/* Write a value to S5SWP */
|
||||
static void vsuWriteSWP(VB *sim, uint8_t value) {
|
||||
uint32_t clocks;
|
||||
|
||||
/* Parse fields */
|
||||
sim->vsu.freqmod.clk = value >> 7 & 1;
|
||||
sim->vsu.freqmod.dir = value >> 3 & 1;
|
||||
sim->vsu.freqmod.interval = value >> 4 & 15;
|
||||
sim->vsu.freqmod.shift = value & 7;
|
||||
|
||||
/* Configure state */
|
||||
clocks = (uint32_t) sim->vsu.freqmod.interval *
|
||||
(sim->vsu.freqmod.clk ? 153610 : 19201);
|
||||
if (clocks < sim->vsu.freqmod.clocks)
|
||||
sim->vsu.freqmod.clocks = clocks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************** Module Functions ******************************/
|
||||
|
||||
/* Process component */
|
||||
static void vsuEmulate(VB *sim, uint32_t clocks) {
|
||||
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 {
|
||||
|
||||
/* Clocks until next sample */
|
||||
until = clocks;
|
||||
if (sim->vsu.clocks < until)
|
||||
until = sim->vsu.clocks;
|
||||
|
||||
/* Manage clocks */
|
||||
clocks -= until;
|
||||
sim->vsu.clocks -= until;
|
||||
|
||||
/* Process all channels */
|
||||
for (x = 0; x < 6; x++)
|
||||
vsuEmulateChannel(sim, x, until);
|
||||
|
||||
/* 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 = (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;
|
||||
sim->vsu.out.i1[e] = i0;
|
||||
sim->vsu.out.o1[e] = o0;
|
||||
|
||||
/* Output the sample to caller memory */
|
||||
if (
|
||||
sim->vsu.out.samples != NULL &&
|
||||
sim->vsu.out.offset >> 1 < sim->vsu.out.capacity
|
||||
) {
|
||||
sim->vsu.out.samples[sim->vsu.out.offset++] =
|
||||
(int16_t) (o0 * 32767.0f + (o0 < 0.0f ? -0.5f : +0.5f));
|
||||
if (
|
||||
e == 1 &&
|
||||
sim->vsu.out.offset >> 1 == sim->vsu.out.capacity
|
||||
) vsuOnSamples(sim);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Advance to the next sample */
|
||||
sim->vsu.sample += sim->vsu.sample == 416 ? -416 : 1;
|
||||
sim->vsu.clocks = 479 + (1 &
|
||||
SAMPLE_CLOCKS[sim->vsu.sample >> 5] >> (sim->vsu.sample & 31));
|
||||
|
||||
} while (clocks != 0);
|
||||
|
||||
}
|
||||
|
||||
/* Simulate a hardware reset */
|
||||
static void vsuReset(VB *sim) {
|
||||
Channel *chan; /* Channel handle */
|
||||
int x, y; /* Iterators */
|
||||
|
||||
/* Memory */
|
||||
for (x = 0; x < 32; x++) {
|
||||
sim->vsu.modulation[x] = 0;
|
||||
for (y = 0; y < 5; y++)
|
||||
sim->vsu.waves[y][x] = 0;
|
||||
}
|
||||
|
||||
/* Channel state */
|
||||
for (x = 0; x < 6; x++) {
|
||||
chan = &sim->vsu.channels[x];
|
||||
chan->clocks = 0;
|
||||
chan->env.clocks = 0;
|
||||
chan->env.enb = 0;
|
||||
chan->env.dir = 0;
|
||||
chan->env.interval = 0;
|
||||
chan->env.reload = 0;
|
||||
chan->env.rep = 0;
|
||||
chan->env.value = 0;
|
||||
chan->freq.current = 0x000;
|
||||
chan->freq.written = 0x000;
|
||||
chan->lrv.left = 0;
|
||||
chan->lrv.right = 0;
|
||||
chan->int_.auto_ = 0;
|
||||
chan->int_.clocks = 0;
|
||||
chan->int_.enb = 0;
|
||||
chan->int_.interval = 0;
|
||||
chan->wave.sample = 0;
|
||||
chan->wave.wave = 0;
|
||||
}
|
||||
|
||||
/* Other channel state */
|
||||
sim->vsu.freqmod.clk = 0;
|
||||
sim->vsu.freqmod.clocks = 0;
|
||||
sim->vsu.freqmod.dir = 0;
|
||||
sim->vsu.freqmod.enb = 0;
|
||||
sim->vsu.freqmod.func = 0;
|
||||
sim->vsu.freqmod.interval = 0;
|
||||
sim->vsu.freqmod.next = 0;
|
||||
sim->vsu.freqmod.rep = 0;
|
||||
sim->vsu.freqmod.sample = 0;
|
||||
sim->vsu.freqmod.shift = 0;
|
||||
sim->vsu.noise.register_ = 0;
|
||||
sim->vsu.noise.tap = 0;
|
||||
|
||||
/* Other */
|
||||
sim->vsu.clocks = 479 + (SAMPLE_CLOCKS[0] & 1);
|
||||
sim->vsu.sample = 0;
|
||||
for (x = 0; x < 2; x++)
|
||||
sim->vsu.out.i1[x] = sim->vsu.out.o1[x] = 0;
|
||||
}
|
||||
|
||||
/* Write a typed value to the VSU bus */
|
||||
static void vsuWrite(VB*sim,uint32_t address,int type,int32_t value,int debug){
|
||||
|
||||
/* Only byte writes are allowed */
|
||||
switch (type) {
|
||||
case VB_S16:
|
||||
case VB_U16:
|
||||
case VB_S32:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unmapped */
|
||||
if (address & 3)
|
||||
return;
|
||||
|
||||
/* Working variables */
|
||||
address &= 0x7FF;
|
||||
|
||||
/* Wave memory */
|
||||
if (address < 0x280) {
|
||||
if (debug || !(
|
||||
sim->vsu.channels[0].int_.enb |
|
||||
sim->vsu.channels[1].int_.enb |
|
||||
sim->vsu.channels[2].int_.enb |
|
||||
sim->vsu.channels[3].int_.enb |
|
||||
sim->vsu.channels[4].int_.enb |
|
||||
sim->vsu.channels[5].int_.enb
|
||||
)) sim->vsu.waves[address >> 7][address >> 2 & 31] = value & 63;
|
||||
}
|
||||
|
||||
/* Modulation memory */
|
||||
else if (address < 0x300) {
|
||||
if (debug || !sim->vsu.channels[4].int_.enb)
|
||||
sim->vsu.modulation[address >> 2 & 31] = value;
|
||||
}
|
||||
|
||||
/* I/O register */
|
||||
else switch (address >> 2) {
|
||||
|
||||
case 0x400>>2: vsuWriteINT(sim, 0, value); break; /* S1INT */
|
||||
case 0x404>>2: vsuWriteLRV(sim, 0, value); break; /* S1LRV */
|
||||
case 0x408>>2: vsuWriteFQL(sim, 0, value); break; /* S1FQL */
|
||||
case 0x40C>>2: vsuWriteFQH(sim, 0, value); break; /* S1FQH */
|
||||
case 0x410>>2: vsuWriteEV0(sim, 0, value); break; /* S1EV0 */
|
||||
case 0x414>>2: vsuWriteEV1(sim, 0, value); break; /* S1EV1 */
|
||||
case 0x418>>2: vsuWriteRAM(sim, 0, value); break; /* S1RAM */
|
||||
|
||||
case 0x440>>2: vsuWriteINT(sim, 1, value); break; /* S2INT */
|
||||
case 0x444>>2: vsuWriteLRV(sim, 1, value); break; /* S2LRV */
|
||||
case 0x448>>2: vsuWriteFQL(sim, 1, value); break; /* S2FQL */
|
||||
case 0x44C>>2: vsuWriteFQH(sim, 1, value); break; /* S2FQH */
|
||||
case 0x450>>2: vsuWriteEV0(sim, 1, value); break; /* S2EV0 */
|
||||
case 0x454>>2: vsuWriteEV1(sim, 1, value); break; /* S2EV1 */
|
||||
case 0x458>>2: vsuWriteRAM(sim, 1, value); break; /* S2RAM */
|
||||
|
||||
case 0x480>>2: vsuWriteINT(sim, 2, value); break; /* S3INT */
|
||||
case 0x484>>2: vsuWriteLRV(sim, 2, value); break; /* S3LRV */
|
||||
case 0x488>>2: vsuWriteFQL(sim, 2, value); break; /* S3FQL */
|
||||
case 0x48C>>2: vsuWriteFQH(sim, 2, value); break; /* S3FQH */
|
||||
case 0x490>>2: vsuWriteEV0(sim, 2, value); break; /* S3EV0 */
|
||||
case 0x494>>2: vsuWriteEV1(sim, 2, value); break; /* S3EV1 */
|
||||
case 0x498>>2: vsuWriteRAM(sim, 2, value); break; /* S3RAM */
|
||||
|
||||
case 0x4C0>>2: vsuWriteINT(sim, 3, value); break; /* S4INT */
|
||||
case 0x4C4>>2: vsuWriteLRV(sim, 3, value); break; /* S4LRV */
|
||||
case 0x4C8>>2: vsuWriteFQL(sim, 3, value); break; /* S4FQL */
|
||||
case 0x4CC>>2: vsuWriteFQH(sim, 3, value); break; /* S4FQH */
|
||||
case 0x4D0>>2: vsuWriteEV0(sim, 3, value); break; /* S4EV0 */
|
||||
case 0x4D4>>2: vsuWriteEV1(sim, 3, value); break; /* S4EV1 */
|
||||
case 0x4D8>>2: vsuWriteRAM(sim, 3, value); break; /* S4RAM */
|
||||
|
||||
case 0x500>>2: vsuWriteINT(sim, 4, value); break; /* S5INT */
|
||||
case 0x504>>2: vsuWriteLRV(sim, 4, value); break; /* S5LRV */
|
||||
case 0x508>>2: vsuWriteFQL(sim, 4, value); break; /* S5FQL */
|
||||
case 0x50C>>2: vsuWriteFQH(sim, 4, value); break; /* S5FQH */
|
||||
case 0x510>>2: vsuWriteEV0(sim, 4, value); break; /* S5EV0 */
|
||||
case 0x514>>2: vsuWriteEV1(sim, 4, value); break; /* S5EV1 */
|
||||
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; /* 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)
|
||||
break;
|
||||
sim->vsu.channels[0].int_.enb =
|
||||
sim->vsu.channels[1].int_.enb =
|
||||
sim->vsu.channels[2].int_.enb =
|
||||
sim->vsu.channels[3].int_.enb =
|
||||
sim->vsu.channels[4].int_.enb =
|
||||
sim->vsu.channels[5].int_.enb = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* VBAPI */
|
||||
@@ -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*
|
||||
|
||||
Reference in New Issue
Block a user