Implement VSU
This commit is contained in:
		
							parent
							
								
									50903c7513
								
							
						
					
					
						commit
						3afe0282c2
					
				| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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? */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										185
									
								
								core/vb.c
								
								
								
								
							
							
						
						
									
										185
									
								
								core/vb.c
								
								
								
								
							| 
						 | 
				
			
			@ -11,6 +11,63 @@
 | 
			
		|||
/* 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 */
 | 
			
		||||
    uint16_t output[2]; /* Current output sample */
 | 
			
		||||
} Channel;
 | 
			
		||||
 | 
			
		||||
/* Simulation state */
 | 
			
		||||
struct VB {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +150,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 +159,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 +167,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 +192,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 +204,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 +220,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 +229,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 +257,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 +319,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 +348,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 +356,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 +507,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 (capacity == 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);
 | 
			
		||||
| 
						 | 
				
			
			@ -414,10 +547,12 @@ VBAPI vbOnWrite vbGetWriteCallback(VB *sim) {
 | 
			
		|||
VBAPI VB* vbInit(VB *sim) {
 | 
			
		||||
    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 +580,10 @@ VBAPI VB* vbReset(VB *sim) {
 | 
			
		|||
 | 
			
		||||
    /* Components */
 | 
			
		||||
    cpuReset(sim);
 | 
			
		||||
    vipReset(sim);
 | 
			
		||||
    padReset(sim);
 | 
			
		||||
    tmrReset(sim);
 | 
			
		||||
    vipReset(sim);
 | 
			
		||||
    vsuReset(sim);
 | 
			
		||||
    return sim;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -526,6 +662,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 (capacity == 0 || capacity > 0x40000000)
 | 
			
		||||
        return 1;
 | 
			
		||||
    sim->vsu.out.capacity = 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
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +92,7 @@ typedef int (*vbOnExecute  )(VB *sim, uint32_t address, const uint16_t *code, in
 | 
			
		|||
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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,530 @@
 | 
			
		|||
/* This file is included into vb.c and cannot be compiled on its own. */
 | 
			
		||||
#ifdef VBAPI
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/********************************* Constants *********************************/
 | 
			
		||||
 | 
			
		||||
/* Analog output low-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_EXCEPTION
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************** 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 */
 | 
			
		||||
    uint32_t level;  /* Stereo output level */
 | 
			
		||||
    uint32_t sample; /* Input sample */
 | 
			
		||||
    uint32_t until;  /* Clocks to process sub-channel components */
 | 
			
		||||
    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);
 | 
			
		||||
        chan->output[e] = level * sample;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Channel is disabled */
 | 
			
		||||
    if (!chan->int_.enb)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    /* Process all clocks */
 | 
			
		||||
    do {
 | 
			
		||||
 | 
			
		||||
        /* Clocks until next state change */
 | 
			
		||||
        until = clocks;
 | 
			
		||||
        if (chan->clocks < until) /* Next sample */
 | 
			
		||||
            until = chan->clocks;
 | 
			
		||||
        if (
 | 
			
		||||
            chan->env.enb &&         /* Modifications enabled */
 | 
			
		||||
            chan->env.clocks < until /* Next modification */
 | 
			
		||||
        ) until = chan->env.clocks;
 | 
			
		||||
        if (
 | 
			
		||||
            chan->int_.auto_ &&       /* Shutoff enabled */
 | 
			
		||||
            chan->int_.clocks < until /* Shutoff */
 | 
			
		||||
        ) until = chan->int_.clocks;
 | 
			
		||||
        if (
 | 
			
		||||
            index == 4                     && /* Channel 5 */
 | 
			
		||||
            sim->vsu.freqmod.enb           && /* Modifications enabled */
 | 
			
		||||
            sim->vsu.freqmod.interval != 0 && /* Modifications valid */
 | 
			
		||||
            sim->vsu.freqmod.clocks < until   /* Next modification */
 | 
			
		||||
        ) until = sim->vsu.freqmod.clocks;
 | 
			
		||||
 | 
			
		||||
        /* Manage clocks */
 | 
			
		||||
        clocks -= until;
 | 
			
		||||
 | 
			
		||||
        /* Automatic shutoff */
 | 
			
		||||
        if (
 | 
			
		||||
            chan->int_.auto_ && /* Shutoff enabled */
 | 
			
		||||
            chan->int_.clocks == until
 | 
			
		||||
        ) {
 | 
			
		||||
            chan->int_.enb = 0;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Next sample */
 | 
			
		||||
        if (chan->clocks == until) {
 | 
			
		||||
 | 
			
		||||
            /* 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 && /* Modifications enabled */
 | 
			
		||||
            chan->env.clocks == until
 | 
			
		||||
        ) {
 | 
			
		||||
            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;
 | 
			
		||||
            else chan->env.enb = 0;
 | 
			
		||||
            chan->env.clocks = (uint32_t) chan->env.interval * 307220;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Frequency modification */
 | 
			
		||||
        if (
 | 
			
		||||
            index == 4                     && /* Channel 5 */
 | 
			
		||||
            sim->vsu.freqmod.enb           && /* Modifications enabled */
 | 
			
		||||
            sim->vsu.freqmod.interval != 0 && /* Modifications valid */
 | 
			
		||||
            sim->vsu.freqmod.clocks == until
 | 
			
		||||
        ) {
 | 
			
		||||
            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);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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 = (uint32_t) chan->env.interval * 307220;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 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 >> 4 & 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;
 | 
			
		||||
    chan->clocks      = (index == 5 ? 40 : 4) *
 | 
			
		||||
        ((uint32_t) 2048 - chan->freq.current);
 | 
			
		||||
    if (index != 5)
 | 
			
		||||
        chan->wave.sample = 0;
 | 
			
		||||
    else sim->vsu.noise.register_ = 0x0000;
 | 
			
		||||
    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) {
 | 
			
		||||
    Channel *chan;       /* Channel handle */
 | 
			
		||||
    uint32_t digital[2]; /* Digital output samples */
 | 
			
		||||
    float    i0;         /* Current analog input sample */
 | 
			
		||||
    float    o0;         /* Current analog output sample */
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
        /* Working variables */
 | 
			
		||||
        clocks    -= until;
 | 
			
		||||
        digital[0] = digital[1] = 0;
 | 
			
		||||
 | 
			
		||||
        /* Process all channels */
 | 
			
		||||
        for (x = 0; x < 6; x++) {
 | 
			
		||||
            chan = &sim->vsu.channels[x];
 | 
			
		||||
            vsuEmulateChannel(sim, x, until);
 | 
			
		||||
            digital[0] += chan->output[0];
 | 
			
		||||
            digital[1] += chan->output[1];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Output sample */
 | 
			
		||||
        for (e = 0; e < 2; e++) {
 | 
			
		||||
 | 
			
		||||
            /* Compute the output sample for this stereo channel */
 | 
			
		||||
            i0 = (digital[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; /* S5INT */
 | 
			
		||||
        case 0x544>>2: vsuWriteLRV(sim, 5, value); break; /* S5LRV */
 | 
			
		||||
        case 0x548>>2: vsuWriteFQL(sim, 5, value); break; /* S5FQL */
 | 
			
		||||
        case 0x54C>>2: vsuWriteFQH(sim, 5, value); break; /* S5FQH */
 | 
			
		||||
        case 0x550>>2: vsuWriteEV0(sim, 5, value); break; /* S5EV0 */
 | 
			
		||||
        case 0x554>>2: vsuWriteEV1(sim, 5, value); break; /* S5EV1 */
 | 
			
		||||
 | 
			
		||||
        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 */
 | 
			
		||||
		Loading…
	
		Reference in New Issue