Discrete Updates:

Added DISCRETE_LOGIC_SHIFT - generic shift register
  Fixed DISCRETE_BIT_DECODE to apply proper voltage instead of clipping to INT.

Sky Raider - Partial discrete sound
This commit is contained in:
Derrick Renaud 2009-09-21 23:20:32 +00:00
parent 1031a08ed8
commit ecffbf4c3b
9 changed files with 605 additions and 25 deletions

2
.gitattributes vendored
View File

@ -1207,6 +1207,7 @@ src/mame/audio/seibu.c svneol=native#text/plain
src/mame/audio/seibu.h svneol=native#text/plain
src/mame/audio/senjyo.c svneol=native#text/plain
src/mame/audio/skydiver.c svneol=native#text/plain
src/mame/audio/skyraid.c svneol=native#text/plain
src/mame/audio/snes.c svneol=native#text/plain
src/mame/audio/snk6502.c svneol=native#text/plain
src/mame/audio/spacefb.c svneol=native#text/plain
@ -2533,6 +2534,7 @@ src/mame/includes/shuuz.h svneol=native#text/plain
src/mame/includes/simpsons.h svneol=native#text/plain
src/mame/includes/skullxbo.h svneol=native#text/plain
src/mame/includes/skydiver.h svneol=native#text/plain
src/mame/includes/skyraid.h svneol=native#text/plain
src/mame/includes/slapfght.h svneol=native#text/plain
src/mame/includes/slapstic.h svneol=native#text/plain
src/mame/includes/snes.h svneol=native#text/plain

View File

@ -10,6 +10,7 @@
************************************************************************
*
* DST_ADDDER - Multichannel adder
* DST_BITS_DECODE - Decode Bits from input node
* DST_CLAMP - Simple signal clamping circuit
* DST_COMP_ADDER - Selectable parallel component circuit
* DST_DAC_R1 - R1 Ladder DAC with cap filtering
@ -26,6 +27,7 @@
* DST_LOGIC_NXOR - Logic NXOR gate 2 input
* DST_LOGIC_DFF - Logic D-type flip/flop
* DST_LOGIC_JKFF - Logic JK-type flip/flop
* DST_LOGIC_SHIFT - Logic Shift Register
* DST_LOOKUP_TABLE - Return value from lookup table
* DST_MIXER - Final Mixer Stage
* DST_MULTIPLEX - 1 of x Multiplexer/switch
@ -53,7 +55,6 @@ struct dst_bits_decode_context
int from;
int count;
int last_val;
int v_out;
};
struct dst_dac_r1_context
@ -123,6 +124,17 @@ struct dst_samphold_context
int clocktype;
};
struct dst_shift_context
{
double t_left; /* time unused during last sample in seconds */
UINT32 shift_data;
UINT32 bit_mask;
UINT8 clock_type;
UINT8 reset_on_high;
UINT8 shift_r;
UINT8 last;
};
struct dst_size_context
{
int size;
@ -681,7 +693,7 @@ static DISCRETE_STEP(dst_bits_decode)
{
context->last_val = v;
for (i = 0; i < context->count; i++ )
node->output[i] = ((v >> (i+context->from)) & 1) * context->v_out;
node->output[i] = ((v >> (i+context->from)) & 1) * DST_BITS_DECODE__VOUT;
}
}
@ -691,7 +703,6 @@ static DISCRETE_RESET(dst_bits_decode)
context->from = DST_BITS_DECODE__FROM;
context->count = DST_BITS_DECODE__TO - context->from + 1;
context->v_out = DST_BITS_DECODE__VOUT;
DISCRETE_STEP_CALL(dst_bits_decode);
}
@ -899,6 +910,108 @@ static DISCRETE_STEP(dst_logic_jkff)
}
/************************************************************************
*
* DST_LOGIC_SHIFT - Shift Register implementation
*
************************************************************************/
#define DST_LOGIC_SHIFT__IN DISCRETE_INPUT(0)
#define DST_LOGIC_SHIFT__RESET DISCRETE_INPUT(1)
#define DST_LOGIC_SHIFT__CLK DISCRETE_INPUT(2)
#define DST_LOGIC_SHIFT__SIZE DISCRETE_INPUT(3)
#define DST_LOGIC_SHIFT__OPTIONS DISCRETE_INPUT(4)
static DISCRETE_STEP(dst_logic_shift)
{
struct dst_shift_context *context = (struct dst_shift_context *)node->context;
double cycles;
double ds_clock;
int clock = 0, inc = 0;
int input_bit = (DST_LOGIC_SHIFT__IN != 0) ? 1 : 0;
ds_clock = DST_LOGIC_SHIFT__CLK;
if (context->clock_type == DISC_CLK_IS_FREQ)
{
/* We need to keep clocking the internal clock even if in reset. */
cycles = (context->t_left + node->info->sample_time) * ds_clock;
inc = (int)cycles;
context->t_left = (cycles - inc) / ds_clock;
}
else
{
clock = (int)ds_clock;
}
/* If reset enabled then set output to the reset value. No x_time in reset. */
if(((DST_LOGIC_SHIFT__RESET == 0) ? 0 : 1) == context->reset_on_high)
{
context->shift_data = 0;
node->output[0] = 0;
return;
}
/* increment clock */
switch (context->clock_type)
{
case DISC_CLK_ON_F_EDGE:
case DISC_CLK_ON_R_EDGE:
/* See if the clock has toggled to the proper edge */
clock = (clock != 0);
if (context->last != clock)
{
context->last = clock;
if (context->clock_type == clock)
{
/* Toggled */
inc = 1;
}
}
break;
case DISC_CLK_BY_COUNT:
/* Clock number of times specified. */
inc = clock;
break;
}
if (inc > 0)
{
if (context->shift_r)
{
context->shift_data >>= 1;
context->shift_data |= input_bit << ((int)DST_LOGIC_SHIFT__SIZE - 1);
inc--;
context->shift_data >>= inc;
}
else
{
context->shift_data <<= 1;
context->shift_data |= input_bit;
inc--;
context->shift_data <<= inc;
}
context->shift_data &= context->bit_mask;
}
node->output[0] = context->shift_data;
}
static DISCRETE_RESET(dst_logic_shift)
{
struct dst_shift_context *context = (struct dst_shift_context *)node->context;
context->bit_mask = (1 << (int)DST_LOGIC_SHIFT__SIZE) - 1;
context->clock_type = (int)DST_LOGIC_SHIFT__OPTIONS & DISC_CLK_MASK;
context->reset_on_high = ((int)DST_LOGIC_SHIFT__OPTIONS & DISC_LOGIC_SHIFT__RESET_H) ? 1 : 0;
context->shift_r = ((int)DST_LOGIC_SHIFT__OPTIONS & DISC_LOGIC_SHIFT__RIGHT) ? 1 : 0;
context->t_left = 0;
context->last = 0;
context->shift_data = 0;
node->output[0] = 0;
}
/************************************************************************
*
* DST_LOOKUP_TABLE - Return value from lookup table

View File

@ -407,7 +407,7 @@ static DISCRETE_STEP(dss_lfsr)
}
/* Reset everything if necessary */
if((DSS_LFSR_NOISE__RESET ? 1 : 0) == context->reset_on_high)
if(((DSS_LFSR_NOISE__RESET == 0) ? 0 : 1) == context->reset_on_high)
{
DISCRETE_RESET_CALL(dss_lfsr);
return;

View File

@ -19,7 +19,7 @@
* file. All discrete sound primatives MUST implement the following
* API:
*
* dsX_NAME_step(inputs, context,float timestep) - Perform time step
* dsX_NAME_step(inputs, context, float timestep) - Perform time step
* return output value
* dsX_NAME_reset(context) - Reset to initial state
*
@ -231,6 +231,7 @@ static const discrete_module module_list[] =
{ DST_LOGIC_NXOR ,"DST_LOGIC_NXOR" , 1 ,0 ,NULL ,dst_logic_nxor_step ,NULL ,NULL },
{ DST_LOGIC_DFF ,"DST_LOGIC_DFF" , 1 ,sizeof(struct dst_flipflop_context) ,dst_logic_ff_reset ,dst_logic_dff_step ,NULL ,NULL },
{ DST_LOGIC_JKFF ,"DST_LOGIC_JKFF" , 1 ,sizeof(struct dst_flipflop_context) ,dst_logic_ff_reset ,dst_logic_jkff_step ,NULL ,NULL },
{ DST_LOGIC_SHIFT ,"DST_LOGIC_SHIFT" , 1 ,sizeof(struct dst_shift_context) ,dst_logic_shift_reset ,dst_logic_shift_step ,NULL ,NULL },
{ DST_LOOKUP_TABLE,"DST_LOOKUP_TABLE", 1 ,0 ,NULL ,dst_lookup_table_step,NULL ,NULL },
{ DST_MULTIPLEX ,"DST_MULTIPLEX" , 1 ,sizeof(struct dst_size_context) ,dst_multiplex_reset ,dst_multiplex_step ,NULL ,NULL },
{ DST_ONESHOT ,"DST_ONESHOT" , 1 ,sizeof(struct dst_oneshot_context) ,dst_oneshot_reset ,dst_oneshot_step ,NULL ,NULL },

View File

@ -275,6 +275,7 @@
* DISCRETE_LOGIC_NXOR(NODE,INP0,INP1)
* DISCRETE_LOGIC_DFLIPFLOP(NODE,RESET,SET,CLK,INP)
* DISCRETE_LOGIC_JKFLIPFLOP(NODE,RESET,SET,CLK,J,K)
* DISCRETE_LOGIC_SHIFT(NODE,INP0,RESET,CLK,SIZE,OPTIONS)
* DISCRETE_MULTIPLEX2(NODE,ADDR,INP0,INP1)
* DISCRETE_MULTIPLEX4(NODE,ADDR,INP0,INP1,INP2,INP3)
* DISCRETE_MULTIPLEX8(NODE,ADDR,INP0,INP1,INP2,INP3,INP4,INP5,INP6,INP7)
@ -1286,7 +1287,7 @@
*
***********************************************************************
*
* DISCRETE_LOGIC_INVERT - Logic invertor
* DISCRETE_LOGIC_INVERT - Logic invertor
* DISCRETE_LOGIC_AND - Logic AND gate (3 & 4 input also available)
* DISCRETE_LOGIC_NAND - Logic NAND gate (3 & 4 input also available)
* DISCRETE_LOGIC_OR - Logic OR gate (3 & 4 input also available)
@ -1309,7 +1310,7 @@
* Declaration syntax
*
* DISCRETE_LOGIC_XXXn(name of node,
* (X=INV/AND/etc)
* (X=INV/AND/etc)
* (n=Blank/2/3) input0 node or static value,
* [input1 node or static value],
* [input2 node or static value],
@ -1432,6 +1433,31 @@
*
***********************************************************************
*
* DISCRETE_LOGIC_SHIFT - shift register
*
* Declaration syntax
*
* DISCRETE_LOGIC_SHIFT(name of node,
* input node,
* reset node or static value,
* clock node or static value,
* size static value,
* options static value)
*
* Options:
* reset type: DISC_LOGIC_SHIFT__RESET_L
* DISC_LOGIC_SHIFT__RESET_H
* shift type: DISC_LOGIC_SHIFT__LEFT
* DISC_LOGIC_SHIFT__RIGHT
* clock type: DISC_CLK_ON_F_EDGE - toggle on falling edge.
* DISC_CLK_ON_R_EDGE - toggle on rising edge.
* DISC_CLK_BY_COUNT - toggle specified number of times.
* DISC_CLK_IS_FREQ - internally clock at this frequency.
*
* EXAMPLES: see Sky Raider
*
***********************************************************************
*
* DISCRETE_GAIN - Node multiplication function output is equal
* DISCRETE_MULTIPLY to INPUT0 * INPUT1
* DISCRETE_MULTADD to (INPUT0 * INPUT1) + INPUT 2
@ -3236,7 +3262,7 @@
* if you have used DISCRETE_STEP(basename) and DISCRETE_RESET(basename) to define
* the step/reset procedures.
*
* EXAMPLES: see Donkey Kong, Mario Bros.
* EXAMPLES: see Donkey Kong, Mario Bros., Sky Raider
*
***********************************************************************
=======================================================================
@ -3406,7 +3432,7 @@
#define DISC_COUNT_DOWN 0
#define DISC_COUNT_UP 1
#define DISC_COUNTER_IS_7492 0x08
#define DISC_OUT_MASK 0x30
@ -3443,6 +3469,12 @@
#define DISC_SAMPHOLD_HLATCH 2
#define DISC_SAMPHOLD_LLATCH 3
/* Shift options */
#define DISC_LOGIC_SHIFT__RESET_L 0x00
#define DISC_LOGIC_SHIFT__RESET_H 0x10
#define DISC_LOGIC_SHIFT__LEFT 0x00
#define DISC_LOGIC_SHIFT__RIGHT 0x20
/* Maximum number of resistors in ladder chain */
#define DISC_LADDER_MAXRES 8
@ -3548,7 +3580,7 @@ enum
/* 566 output flags */
#define DISC_566_OUT_DC 0x00
#define DISC_566_OUT_AC 0x01
#define DISC_566_OUT_SQUARE 0x00 /* Squarewave */
#define DISC_566_OUT_TRIANGLE 0x10 /* Triangle waveform */
#define DISC_566_OUT_LOGIC 0x20 /* 0/1 logic output */
@ -4149,6 +4181,7 @@ enum
DST_LOGIC_NXOR,
DST_LOGIC_DFF,
DST_LOGIC_JKFF,
DST_LOGIC_SHIFT,
DST_LOOKUP_TABLE, /* return value from lookup table */
DST_MULTIPLEX, /* 1 of x multiplexer */
DST_ONESHOT, /* One-shot pulse generator */
@ -4309,6 +4342,7 @@ enum
#define DISCRETE_LOGIC_NXOR(NODE,INP0,INP1) { NODE, DST_LOGIC_NXOR , 2, { INP0,INP1 }, { INP0,INP1 }, NULL, "DISCRETE_LOGIC_NXOR" },
#define DISCRETE_LOGIC_DFLIPFLOP(NODE,RESET,SET,CLK,INP) { NODE, DST_LOGIC_DFF , 4, { RESET,SET,CLK,INP }, { RESET,SET,CLK,INP }, NULL, "DISCRETE_LOGIC_DFLIPFLOP" },
#define DISCRETE_LOGIC_JKFLIPFLOP(NODE,RESET,SET,CLK,J,K) { NODE, DST_LOGIC_JKFF , 5, { RESET,SET,CLK,J,K }, { RESET,SET,CLK,J,K }, NULL, "DISCRETE_LOGIC_JKFLIPFLOP" },
#define DISCRETE_LOGIC_SHIFT(NODE,INP0,RESET,CLK,SIZE,OPTIONS) { NODE, DST_LOGIC_SHIFT , 5, { INP0,RESET,CLK,NODE_NC,NODE_NC }, { INP0,RESET,CLK,SIZE,OPTIONS }, NULL, "DISCRETE_LOGIC_SHIFT" },
#define DISCRETE_LOOKUP_TABLE(NODE,ADDR,SIZE,TABLE) { NODE, DST_LOOKUP_TABLE, 2, { ADDR,NODE_NC }, { ADDR,SIZE }, TABLE, "DISCRETE_LOOKUP_TABLE" },
#define DISCRETE_MULTIPLEX2(NODE,ADDR,INP0,INP1) { NODE, DST_MULTIPLEX , 3, { ADDR,INP0,INP1 }, { ADDR,INP0,INP1 }, NULL, "DISCRETE_MULTIPLEX2" },
#define DISCRETE_MULTIPLEX4(NODE,ADDR,INP0,INP1,INP2,INP3) { NODE, DST_MULTIPLEX , 5, { ADDR,INP0,INP1,INP2,INP3 }, { ADDR,INP0,INP1,INP2,INP3 }, NULL, "DISCRETE_MULTIPLEX4" },

427
src/mame/audio/skyraid.c Normal file
View File

@ -0,0 +1,427 @@
/************************************************************************
* skyraid Sound System Analog emulation
* Sept 2009, Derrick Renaud
************************************************************************/
#include "driver.h"
#include "skyraid.h"
/* Discrete Sound Input Nodes */
#define SKYRAID_PLANE_SWEEP_EN NODE_01
#define SKYRAID_MISSILE_EN NODE_02
#define SKYRAID_EXPLOSION_EN NODE_03
#define SKYRAID_PLANE_ON_EN NODE_04
#define SKYRAID_PLANE_ON__IC_E8 SKYRAID_PLANE_ON_EN
#define SKYRAID_ATTRACT_EN NODE_05
/* Discrete Sound Output Nodes */
#define SKYRAID_NOISE NODE_10
#define SKYRAID_EXPLOSION_SND NODE_11
#define SKYRAID_JET_A_SND NODE_12
#define SKYRAID_JET_B_SND NODE_13
#define SKYRAID_MSL_A_SND NODE_14
#define SKYRAID_MSL_B_SND NODE_15
#define SKYRAID_PLANE_SND NODE_16
/* Parts List - Resistors */
#define SKYRAID_R12 RES_K(1)
#define SKYRAID_R13 RES_K(10)
#define SKYRAID_R14 RES_K(100)
#define SKYRAID_R16 RES_M(10)
#define SKYRAID_R18 RES_K(10)
#define SKYRAID_R19 RES_K(10)
#define SKYRAID_R20 RES_K(47)
#define SKYRAID_R24 RES_M(10)
#define SKYRAID_R25 RES_M(3.9)
#define SKYRAID_R27 RES_M(1.5)
#define SKYRAID_R28 RES_M(1.5)
#define SKYRAID_R29 RES_M(4.7)
#define SKYRAID_R30 RES_M(1)
#define SKYRAID_R31 RES_M(1)
#define SKYRAID_R32 RES_M(4.7)
#define SKYRAID_R84 RES_K(22)
#define SKYRAID_R85 RES_K(100)
#define SKYRAID_R86 820
#define SKYRAID_R110 RES_K(330)
#define SKYRAID_R118 RES_K(470)
#define SKYRAID_R119 RES_K(10)
#define SKYRAID_R120 RES_K(220)
#define SKYRAID_R121 RES_K(1)
#define SKYRAID_R122 RES_K(150)
/* Parts List - Capacitors */
#define SKYRAID_C44 CAP_U(4.7)
#define SKYRAID_C45 CAP_U(.0047)
#define SKYRAID_C46 CAP_U(.001)
#define SKYRAID_C48 CAP_U(.0047)
#define SKYRAID_C49 CAP_U(.1)
#define SKYRAID_C50 CAP_U(.001)
#define SKYRAID_C51 CAP_U(.01)
#define SKYRAID_C68 CAP_U(10)
#define SKYRAID_C85 CAP_U(.068)
#define SKYRAID_C86 CAP_U(.1)
#define SKYRAID_C93 CAP_U(.1)
static const discrete_lfsr_desc skyraid_lfsr =
{
DISC_CLK_IS_FREQ,
16, /* Bit Length */
0, /* Reset Value */
0, /* Use Bit 0 as XOR input 0 */
14, /* Use Bit 14 as XOR input 1 */
DISC_LFSR_XNOR, /* Feedback stage1 is XNOR */
DISC_LFSR_OR, /* Feedback stage2 is just stage 1 output OR with external feed */
DISC_LFSR_REPLACE, /* Feedback stage3 replaces the shifted register contents */
0x000001, /* Everything is shifted into the first bit only */
DISC_LFSR_FLAG_RESET_TYPE_H, /* Output is not inverted */
15 /* Output bit */
};
static const discrete_op_amp_filt_info skyraid_explosion_filter =
{
SKYRAID_R85, 0, SKYRAID_R86, 0, SKYRAID_R110, /* r1, r2, r3, r4, rF*/
SKYRAID_C85, SKYRAID_C86, 0, /* c1, c2, c3 */
0, 12, -5, /* vRef, vP, vN */
};
static const discrete_566_desc skyraid_566_desc =
{
DISC_566_OUT_LOGIC,
5, /* v_pos */
-5, /* v_neg */
5 /* v_charge */
};
static const discrete_dac_r1_ladder skyraid_plane_dac =
{
2, {SKYRAID_R28, SKYRAID_R27},
0, 0, 0, 0 /* no vBias, rBias, rGnd, cFilter */
};
static const discrete_mixer_desc skyraid_mixer =
{
DISC_MIXER_IS_RESISTOR,
{SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31, RES_2_PARALLEL(SKYRAID_R28, SKYRAID_R27)},
{0, 0, 0, 0, 0, SKYRAID_PLANE_ON__IC_E8}, /* r_nodes */
{0}, 0, 0, 0, 0, 0, 1 /* no c, rI, rF, cF, cAmp, vRef, gain */
};
/************************************************************************
*
* Custom skyraid explosion charge
*
* input[0] - In1 (Logic)
* input[1] - In2 (Logic)
* input[2] - R
* input[3] - C
*
* 5V
* v
* |
* .-------.
* | 4066 |
* In1 >---|c |
* '-------'
* |
* +------------.
* | |
* .-------. --- C
* | 4066 | ---
* In2 >---|c | |
* '-------' gnd
* |
* +----> Node Output
* |
* Z
* Z R
* Z
* |
* gnd
*
************************************************************************/
#define SKYRAID_EXPLOSION_CUSTOM_IN1 DISCRETE_INPUT(0)
#define SKYRAID_EXPLOSION_CUSTOM_IN2 DISCRETE_INPUT(1)
#define SKYRAID_EXPLOSION_CUSTOM_R DISCRETE_INPUT(2)
#define SKYRAID_EXPLOSION_CUSTOM_C DISCRETE_INPUT(3)
#define SKYRAID_4066_R_ON 270
static struct skyraid_explosion_custom_charge_context
{
double v_cap;
double v_charge_1_2;
double v_drop;
double exp_1;
double exp_1_2;
double exp_2;
};
static DISCRETE_STEP( skyraid_explosion_custom_charge )
{
struct skyraid_explosion_custom_charge_context *context = (struct skyraid_explosion_custom_charge_context *)node->context;
if (SKYRAID_EXPLOSION_CUSTOM_IN1 == 0)
if (SKYRAID_EXPLOSION_CUSTOM_IN2 == 0)
/* cap is floating and does not change charge */
/* output is pulled to ground */
node->output[0] = 0;
else
{
/* cap is discharged */
context->v_cap -= context->v_cap * context->exp_2;
node->output[0] = context->v_cap * context->v_drop;
}
else
if (SKYRAID_EXPLOSION_CUSTOM_IN2 == 0)
{
/* cap is charged */
context->v_cap += (5.0 - context->v_cap) * context->exp_1;
/* output is pulled to ground */
node->output[0] = 0;
}
else
{
/* cap is charged slightly less */
context->v_cap += (context->v_charge_1_2 - context->v_cap) * context->exp_1_2;
node->output[0] = context->v_cap * context->v_drop;
}
}
static DISCRETE_RESET( skyraid_explosion_custom_charge )
{
struct skyraid_explosion_custom_charge_context *context = (struct skyraid_explosion_custom_charge_context *)node->context;
/* the charging voltage across the cap based on in2*/
context->v_drop = RES_VOLTAGE_DIVIDER(SKYRAID_4066_R_ON, SKYRAID_4066_R_ON + SKYRAID_EXPLOSION_CUSTOM_R);
context->v_charge_1_2 = 5.0 * context->v_drop;
context->v_cap = 0;
/* precalculate charging exponents */
/* discharge cap - in1 = 0, in2 = 1*/
context->exp_2 = RC_CHARGE_EXP((SKYRAID_4066_R_ON + SKYRAID_EXPLOSION_CUSTOM_R) * SKYRAID_EXPLOSION_CUSTOM_C);
/* charge cap - in1 = 1, in2 = 0 */
context->exp_1 = RC_CHARGE_EXP(SKYRAID_4066_R_ON * SKYRAID_EXPLOSION_CUSTOM_C);
/* charge cap - in1 = 1, in2 = 1 */
context->exp_1_2 = RC_CHARGE_EXP(RES_2_PARALLEL(SKYRAID_4066_R_ON, SKYRAID_4066_R_ON + SKYRAID_EXPLOSION_CUSTOM_R) * SKYRAID_EXPLOSION_CUSTOM_C);
/* starts at 0 until cap starts charging */
node->output[0] = 0;
}
static const discrete_custom_info skyraid_explosion_custom_charge =
{
DISCRETE_CUSTOM_MODULE(skyraid_explosion_custom_charge, struct skyraid_explosion_custom_charge_context),
NULL
};
/************************************************************************
*
* Custom skyraid missle charge
*
* input[0] - In1 (Logic)
* input[1] - R1
* input[2] - R2
* input[3] - R3
* input[4] - C
*
* 12V 5V
* v v
* | |
* Z ---
* Z R1 ^ 1N914
* Z / \ Diode
* | -----
* | |
* +--------------+
* | |
* --- Z
* --- C Z R2
* | Z
* | |
* +--------------+----> Node Output
* |
* Z
* Z R3
* O.C. Z
* |\ |
* In1 >--| o--+
* |/
*
************************************************************************/
#define SKYRAID_MISSLE_CUSTOM_IN1 DISCRETE_INPUT(0)
#define SKYRAID_MISSLE_CUSTOM_R1 DISCRETE_INPUT(1)
#define SKYRAID_MISSLE_CUSTOM_R2 DISCRETE_INPUT(2)
#define SKYRAID_MISSLE_CUSTOM_R3 DISCRETE_INPUT(3)
#define SKYRAID_MISSLE_CUSTOM_C DISCRETE_INPUT(4)
static struct skyraid_missle_custom_charge_context
{
double v_charge[2];
double v_cap;
double exp[2];
};
/* the high charge is clamped by the diode to 0.7V above the 5V line */
#define SKYRAID_MISSLE_CHARGE_PLUS (5.0 + 0.7)
static DISCRETE_STEP( skyraid_missle_custom_charge )
{
struct skyraid_missle_custom_charge_context *context = (struct skyraid_missle_custom_charge_context *)node->context;
int in_1 = (SKYRAID_MISSLE_CUSTOM_IN1 == 0) ? 0 : 1;
/* charge/discharge cap */
context->v_cap += (context->v_charge[in_1] - context->v_cap) * context->exp[in_1];
node->output[0] = SKYRAID_MISSLE_CHARGE_PLUS - context->v_cap;
}
static DISCRETE_RESET( skyraid_missle_custom_charge )
{
struct skyraid_missle_custom_charge_context *context = (struct skyraid_missle_custom_charge_context *)node->context;
/* everything is based on the input to the O.C. inverter */
/* the charging voltage across the cap */
context->v_charge[0] = 0;
context->v_charge[1] = SKYRAID_MISSLE_CHARGE_PLUS * RES_VOLTAGE_DIVIDER(SKYRAID_MISSLE_CUSTOM_R1 + SKYRAID_MISSLE_CUSTOM_R2, SKYRAID_MISSLE_CUSTOM_R3);
context->v_charge[1] = SKYRAID_MISSLE_CHARGE_PLUS - context->v_charge[1];
context->v_cap = 0;
/* precalculate charging exponents */
/* discharge cap */
context->exp[0] = RC_CHARGE_EXP(SKYRAID_MISSLE_CUSTOM_R2 * SKYRAID_MISSLE_CUSTOM_C);
/* charge cap */
context->exp[1] = RC_CHARGE_EXP(RES_2_PARALLEL(SKYRAID_MISSLE_CUSTOM_R1 + SKYRAID_MISSLE_CUSTOM_R2, SKYRAID_MISSLE_CUSTOM_R3) * SKYRAID_MISSLE_CUSTOM_C);
/* starts at full voltage until cap starts charging */
node->output[0] = SKYRAID_MISSLE_CHARGE_PLUS;
}
static const discrete_custom_info skyraid_missle_custom_charge =
{
DISCRETE_CUSTOM_MODULE( skyraid_missle_custom_charge, struct skyraid_missle_custom_charge_context),
NULL
};
DISCRETE_SOUND_START( skyraid )
/************************************************
* Input register mapping
************************************************/
/* convert the PLANE_SWEEP line to voltage*/
DISCRETE_INPUTX_LOGIC(SKYRAID_PLANE_SWEEP_EN, DEFAULT_TTL_V_LOGIC_1 * RES_VOLTAGE_DIVIDER(SKYRAID_R25, SKYRAID_R24), 0, 0)
DISCRETE_INPUT_LOGIC(SKYRAID_MISSILE_EN)
DISCRETE_INPUT_LOGIC(SKYRAID_EXPLOSION_EN)
/* convert PLANE_ON into 4066 Ron value of 270 ohms @ 5V */
DISCRETE_INPUTX_LOGIC(SKYRAID_PLANE_ON__IC_E8, 270, 0, 0)
DISCRETE_INPUT_LOGIC(SKYRAID_ATTRACT_EN)
/************************************************
* Noise Generator, Explosion sound
************************************************/
/* Note: the noise reset is not emulated 100% accurate */
/* According to the schematics, Attract only clears the lower 8 bits. */
/* I may modify the noise module in the future to properly emulate this, */
/* but you will never hear the difference. */
/* It only wrong for 8 cycles of the 555 while no sound is being generated. */
DISCRETE_LFSR_NOISE(SKYRAID_NOISE, /* IC F7, pin 13 */
1, /* ENAB */
SKYRAID_ATTRACT_EN, /* RESET */
1.49 / ((SKYRAID_R20 + 2 * SKYRAID_R19) * SKYRAID_C51), /* CLK - 555 astable source */
1, 0, 0.5, &skyraid_lfsr) /* AMPL,FEED,BIAS,LFSRTB */
DISCRETE_LOGIC_NOR(NODE_20, SKYRAID_EXPLOSION_EN, SKYRAID_NOISE)
DISCRETE_CUSTOM4(NODE_21, SKYRAID_EXPLOSION_EN, NODE_20, RES_2_PARALLEL(SKYRAID_R84, SKYRAID_R85 + SKYRAID_R86), SKYRAID_C68, &skyraid_explosion_custom_charge)
DISCRETE_OP_AMP_FILTER(NODE_22,
1, /* ENAB */
NODE_21, 0, /* INP0,INP1 */
DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &skyraid_explosion_filter) /* TYPE,INFO */
/* IC E10, pin 14 gain and clipping */
DISCRETE_GAIN(NODE_23, NODE_22, SKYRAID_R119 / SKYRAID_R121 + 1)
DISCRETE_CLAMP(SKYRAID_EXPLOSION_SND, 1, NODE_23, -5, 12.0 - 1.5, 0)
/************************************************
* Jet, Plane sound
************************************************/
DISCRETE_RCFILTER(NODE_30, /* IC J6, pin 5 */
1, /* ENAB */
SKYRAID_PLANE_SWEEP_EN, /* IN0 */
RES_2_PARALLEL(SKYRAID_R25, SKYRAID_R24), SKYRAID_C49)
DISCRETE_566(NODE_31, /* IC J6, pin 3 */
1, /* ENAB */
NODE_30, /* VMOD */
SKYRAID_R18, SKYRAID_C48, &skyraid_566_desc)
DISCRETE_LOGIC_SHIFT(NODE_32, /* IC H7, J7 output */
SKYRAID_NOISE, /* IC H7, J7 pins 1 & 2 */
1, NODE_31, 16, /* RESET, CLK, SIZE */
DISC_LOGIC_SHIFT__RESET_L | DISC_LOGIC_SHIFT__LEFT | DISC_CLK_ON_R_EDGE)
/* move bits together for ease of use */
DISCRETE_TRANSFORM4(NODE_33, NODE_32, 1, 1 << 14, 2, "01&02/3&|")
DISCRETE_DAC_R1(SKYRAID_PLANE_SND,
1, /* ENAB */
NODE_33, /* DATA */
DEFAULT_TTL_V_LOGIC_1, &skyraid_plane_dac)
DISCRETE_BIT_DECODE(SKYRAID_JET_A_SND, NODE_32, 0, DEFAULT_TTL_V_LOGIC_1) /* IC H7, pin 3 */
DISCRETE_BIT_DECODE(SKYRAID_JET_B_SND, NODE_32, 15, DEFAULT_TTL_V_LOGIC_1) /* IC J7, pin 13 */
/************************************************
* Missle sound
************************************************/
DISCRETE_CUSTOM5(NODE_40, SKYRAID_MISSILE_EN, SKYRAID_R12, SKYRAID_R14, SKYRAID_R13, SKYRAID_C44, &skyraid_missle_custom_charge)
DISCRETE_566(NODE_41, /* IC K6, pin 3 */
1, /* ENAB */
NODE_40, /* VMOD */
SKYRAID_R16, SKYRAID_C45, &skyraid_566_desc)
DISCRETE_LOGIC_SHIFT(NODE_42, /* IC K7, L7 output */
SKYRAID_NOISE, /* IC K7, L7 pins 1 & 2 */
1, NODE_41, 16, /* RESET, CLK, SIZE */
DISC_LOGIC_SHIFT__RESET_L | DISC_LOGIC_SHIFT__LEFT | DISC_CLK_ON_R_EDGE)
DISCRETE_BIT_DECODE(SKYRAID_MSL_A_SND, NODE_42, 0, DEFAULT_TTL_V_LOGIC_1) /* IC K7, pin 3 */
DISCRETE_BIT_DECODE(SKYRAID_MSL_B_SND, NODE_42, 15, DEFAULT_TTL_V_LOGIC_1) /* IC L7, pin 13 */
/************************************************
* Final Mix
************************************************/
DISCRETE_LOGIC_INVERT(NODE_91, SKYRAID_ATTRACT_EN)
DISCRETE_MIXER6(NODE_92,
NODE_91, /* ENAB */
SKYRAID_EXPLOSION_SND,
SKYRAID_JET_A_SND,
SKYRAID_JET_B_SND,
SKYRAID_MSL_A_SND,
SKYRAID_MSL_B_SND,
SKYRAID_PLANE_SND,
&skyraid_mixer)
DISCRETE_CRFILTER(NODE_93,
1, /* ENAB */
NODE_92, /* IN0 */
SKYRAID_R122 + RES_6_PARALLEL(SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31, RES_2_PARALLEL(SKYRAID_R27, SKYRAID_R28)),
SKYRAID_C93)
/* IC E10, pin 1 gain and clipping */
DISCRETE_GAIN(NODE_94, NODE_93, - SKYRAID_R118 / (SKYRAID_R122 + RES_5_PARALLEL(SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31)))
DISCRETE_CLAMP(NODE_95, 1, NODE_94, -5, 12.0 - 1.5, 0)
DISCRETE_OUTPUT(NODE_95, 32700.0/12)
DISCRETE_SOUND_END
WRITE8_DEVICE_HANDLER( skyraid_sound_w )
{
/* BIT0 => PLANE SWEEP */
/* BIT1 => MISSILE */
/* BIT2 => EXPLOSION */
/* BIT3 => START LAMP */
/* BIT4 => PLANE ON */
/* BIT5 => ATTRACT */
discrete_sound_w(device, SKYRAID_PLANE_SWEEP_EN, data & 0x01);
discrete_sound_w(device, SKYRAID_MISSILE_EN, data & 0x02);
discrete_sound_w(device, SKYRAID_EXPLOSION_EN, data & 0x04);
set_led_status(0, !(data & 0x08));
discrete_sound_w(device, SKYRAID_PLANE_ON_EN, data & 0x10);
discrete_sound_w(device, SKYRAID_ATTRACT_EN, data & 0x20);
}

View File

@ -6,6 +6,7 @@ Atari Sky Raider driver
#include "driver.h"
#include "cpu/m6502/m6502.h"
#include "skyraid.h"
extern UINT8* skyraid_alpha_num_ram;
extern UINT8* skyraid_pos_ram;
@ -56,18 +57,6 @@ static READ8_HANDLER( skyraid_port_0_r )
return val;
}
static WRITE8_HANDLER( skyraid_sound_w )
{
/* BIT0 => PLANE SWEEP */
/* BIT1 => MISSILE */
/* BIT2 => EXPLOSION */
/* BIT3 => START LAMP */
/* BIT4 => PLANE ON */
/* BIT5 => ATTRACT */
set_led_status(0, !(data & 0x08));
}
static WRITE8_HANDLER( skyraid_range_w )
{
@ -97,7 +86,7 @@ static ADDRESS_MAP_START( skyraid_map, ADDRESS_SPACE_PROGRAM, 8 )
AM_RANGE(0x1400, 0x1401) AM_READ_PORT("SYSTEM")
AM_RANGE(0x1c00, 0x1c0f) AM_WRITEONLY AM_BASE(&skyraid_obj_ram)
AM_RANGE(0x4000, 0x4000) AM_WRITE(skyraid_scroll_w)
AM_RANGE(0x4400, 0x4400) AM_WRITE(skyraid_sound_w)
AM_RANGE(0x4400, 0x4400) AM_DEVWRITE("discrete", skyraid_sound_w)
AM_RANGE(0x4800, 0x4800) AM_WRITE(skyraid_range_w)
AM_RANGE(0x5000, 0x5000) AM_WRITE(watchdog_reset_w)
AM_RANGE(0x5800, 0x5800) AM_WRITE(skyraid_offset_w)
@ -240,6 +229,7 @@ static MACHINE_DRIVER_START( skyraid )
MDRV_CPU_ADD("maincpu", M6502, 12096000 / 12)
MDRV_CPU_PROGRAM_MAP(skyraid_map)
MDRV_CPU_VBLANK_INT("screen", irq0_line_hold)
MDRV_WATCHDOG_VBLANK_INIT(4)
/* video hardware */
MDRV_SCREEN_ADD("screen", RASTER)
@ -258,6 +248,11 @@ static MACHINE_DRIVER_START( skyraid )
MDRV_VIDEO_UPDATE(skyraid)
/* sound hardware */
MDRV_SPEAKER_STANDARD_MONO("mono")
MDRV_SOUND_ADD("discrete", DISCRETE, 96000)
MDRV_SOUND_CONFIG_DISCRETE(skyraid)
MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
MACHINE_DRIVER_END
@ -291,4 +286,4 @@ ROM_START( skyraid )
ROM_END
GAME( 1978, skyraid, 0, skyraid, skyraid, 0, ORIENTATION_FLIP_Y, "Atari", "Sky Raider", GAME_NO_SOUND | GAME_IMPERFECT_COLORS )
GAME( 1978, skyraid, 0, skyraid, skyraid, 0, ORIENTATION_FLIP_Y, "Atari", "Sky Raider", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_COLORS )

View File

@ -0,0 +1,8 @@
#include "sound/discrete.h"
/*----------- defined in audio/norautp.c -----------*/
DISCRETE_SOUND_EXTERN( skyraid );
extern WRITE8_DEVICE_HANDLER( skyraid_sound_w );

View File

@ -430,7 +430,7 @@ $(MAMEOBJ)/atari.a: \
$(DRIVERS)/shuuz.o $(VIDEO)/shuuz.o \
$(DRIVERS)/skullxbo.o $(VIDEO)/skullxbo.o \
$(DRIVERS)/skydiver.o $(AUDIO)/skydiver.o $(VIDEO)/skydiver.o \
$(DRIVERS)/skyraid.o $(VIDEO)/skyraid.o \
$(DRIVERS)/skyraid.o $(AUDIO)/skyraid.o $(VIDEO)/skyraid.o \
$(DRIVERS)/sprint2.o $(AUDIO)/sprint2.o $(VIDEO)/sprint2.o \
$(DRIVERS)/sprint4.o $(VIDEO)/sprint4.o $(AUDIO)/sprint4.o \
$(DRIVERS)/sprint8.o $(VIDEO)/sprint8.o \