diff --git a/.gitattributes b/.gitattributes index 637168a7ed2..4f431b67875 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1270,6 +1270,7 @@ src/mame/audio/cclimber.c svneol=native#text/plain src/mame/audio/cinemat.c svneol=native#text/plain src/mame/audio/circus.c svneol=native#text/plain src/mame/audio/cliffhgr.c svneol=native#text/plain +src/mame/audio/copsnrob.c svneol=native#text/plain src/mame/audio/cps3.c svneol=native#text/plain src/mame/audio/crbaloon.c svneol=native#text/plain src/mame/audio/cyberbal.c svneol=native#text/plain @@ -3279,7 +3280,6 @@ src/mame/machine/cdicdic.h svneol=native#text/plain src/mame/machine/cdislave.c svneol=native#text/plain src/mame/machine/cdislave.h svneol=native#text/plain src/mame/machine/chaknpop.c svneol=native#text/plain -src/mame/machine/copsnrob.c svneol=native#text/plain src/mame/machine/cps2crpt.c svneol=native#text/plain src/mame/machine/cubocd32.c svneol=native#text/plain src/mame/machine/cx4data.c svneol=native#text/plain diff --git a/src/emu/sound/disc_dev.c b/src/emu/sound/disc_dev.c index ba1cfb5f8b1..786883593a7 100644 --- a/src/emu/sound/disc_dev.c +++ b/src/emu/sound/disc_dev.c @@ -56,7 +56,6 @@ struct dsd_555_mstbl_context int trig_is_logic; int trig_discharges_cap; int output_type; - int output_is_ac; double ac_shift; /* DC shift needed to make waveform ac */ int flip_flop; /* 555 flip/flop output state */ int has_rc_nodes; @@ -483,14 +482,15 @@ DISCRETE_STEP(dsd_555_mstbl) DISCRETE_DECLARE_INFO(discrete_555_desc) double v_cap; /* Current voltage on capacitor, before dt */ - double v_cap_next = 0; /* Voltage on capacitor, after dt */ - double x_time = 0; /* time since change happened */ + double x_time = 0; /* time since change happened */ double dt, exponent; + double out = 0; int trigger = 0; int trigger_type; - int update_exponent = 0; + int update_exponent = context->has_rc_nodes; + int flip_flop; - if(DSD_555_MSTBL__RESET) + if(UNEXPECTED(DSD_555_MSTBL__RESET)) { /* We are in RESET */ node->output[0] = 0; @@ -499,102 +499,115 @@ DISCRETE_STEP(dsd_555_mstbl) return; } - trigger_type = info->options; dt = node->info->sample_time; + flip_flop = context->flip_flop; + trigger_type = info->options; + v_cap = context->cap_voltage; switch (trigger_type & DSD_555_TRIGGER_TYPE_MASK) { case DISC_555_TRIGGER_IS_LOGIC: - trigger = (int)!DSD_555_MSTBL__TRIGGER; + trigger = ((int)DSD_555_MSTBL__TRIGGER) ? 0 : 1; + if (UNEXPECTED(trigger)) + x_time = 1.0 - DSD_555_MSTBL__TRIGGER; break; case DISC_555_TRIGGER_IS_VOLTAGE: trigger = (int)(DSD_555_MSTBL__TRIGGER < context->trigger); break; case DISC_555_TRIGGER_IS_COUNT: trigger = (int)DSD_555_MSTBL__TRIGGER; - if (trigger && !context->flip_flop) - { + if (UNEXPECTED(trigger)) x_time = DSD_555_MSTBL__TRIGGER - trigger; - if (x_time != 0) - { - /* adjust sample to after trigger */ - x_time = (1.0 - x_time); - update_exponent = 1; - dt = x_time * node->info->sample_time; - } - } break; } + if (UNEXPECTED(trigger && !flip_flop && x_time != 0)) + { + /* adjust sample to after trigger */ + update_exponent = 1; + dt *= x_time; + } + x_time = 0; + if ((trigger_type & DISC_555_TRIGGER_DISCHARGES_CAP) && trigger) context->cap_voltage = 0; /* Wait for trigger */ - if (!context->flip_flop && trigger) - context->flip_flop = 1; - - if (context->flip_flop) + if (UNEXPECTED(!flip_flop && trigger)) { - v_cap = context->cap_voltage; + flip_flop = 1; + context->flip_flop = 1; + } + if (flip_flop) + { /* Sometimes a switching network is used to setup the capacitance. * These may select 'no' capacitor, causing oscillation to stop. */ - if (DSD_555_MSTBL__C == 0) + if (UNEXPECTED(DSD_555_MSTBL__C == 0)) { - context->flip_flop = 0; - /* The voltage goes high because the cap circuit is open. */ - v_cap_next = info->v_pos; - v_cap = info->v_pos; + /* The trigger voltage goes high because the cap circuit is open. + * and the cap discharges */ + v_cap = info->v_pos; /* needed for cap output type */ context->cap_voltage = 0; + + if (!trigger) + { + flip_flop = 0; + context->flip_flop = 0; + } } else { /* Charging */ - update_exponent |= context->has_rc_nodes; - if (update_exponent) + double v_diff = context->v_charge - v_cap; + + if (UNEXPECTED(update_exponent)) exponent = RC_CHARGE_EXP_DT(DSD_555_MSTBL__R * DSD_555_MSTBL__C, dt); else exponent = context->exp_charge; - v_cap_next = v_cap + ((info->v_pos - v_cap) * exponent); + v_cap += v_diff * exponent; /* Has it charged past upper limit? */ /* If trigger is still enabled, then we keep charging, * regardless of threshold. */ - if ((v_cap_next >= context->threshold) && !trigger) + if (UNEXPECTED((v_cap >= context->threshold) && !trigger)) { - dt = DSD_555_MSTBL__R * DSD_555_MSTBL__C * log(1.0 / (1.0 - ((v_cap_next - context->threshold) / (context->v_charge - v_cap)))); - x_time = dt / node->info->sample_time; - v_cap_next = 0; - v_cap = context->threshold; + dt = DSD_555_MSTBL__R * DSD_555_MSTBL__C * log(1.0 / (1.0 - ((v_cap - context->threshold) / v_diff))); + x_time = 1.0 - dt / node->info->sample_time; + v_cap = 0; + flip_flop = 0; context->flip_flop = 0; } + context->cap_voltage = v_cap; } - - context->cap_voltage = v_cap_next; } - switch (info->options & DISC_555_OUT_MASK) + switch (context->output_type) { case DISC_555_OUT_SQW: - node->output[0] = context->flip_flop * context->v_out_high; - /* Fake it to AC if needed */ - if (context->output_is_ac) - node->output[0] -= context->v_out_high / 2.0; + out = flip_flop * context->v_out_high - context->ac_shift; break; case DISC_555_OUT_CAP: - node->output[0] = v_cap_next; - /* Fake it to AC if needed */ - if (context->output_is_ac) - node->output[0] -= context->threshold * 3.0 /4.0; + if (x_time > 0) + out = v_cap * x_time; + else + out = v_cap; + + out -= context->ac_shift; break; case DISC_555_OUT_ENERGY: - if (x_time == 0) x_time = 1.0; - node->output[0] = context->v_out_high * (context->flip_flop ? x_time : (1.0 - x_time)); - if (context->output_is_ac) - node->output[0] -= context->v_out_high / 2.0; + if (x_time > 0) + out = context->v_out_high * x_time; + else if (flip_flop) + out = context->v_out_high; + else + out = 0; + + out -= context->ac_shift; break; } + node->output[0] = out; } DISCRETE_RESET(dsd_555_mstbl) @@ -617,9 +630,16 @@ DISCRETE_RESET(dsd_555_mstbl) context->threshold = info->v_pos * 2.0 / 3.0; context->trigger = info->v_pos / 3.0; - context->output_is_ac = info->options & DISC_555_OUT_AC; - /* Calculate DC shift needed to make squarewave waveform AC */ - context->ac_shift = context->output_is_ac ? -context->v_out_high / 2.0 : 0; + /* Calculate DC shift needed to make waveform AC */ + if (info->options & DISC_555_OUT_AC) + { + if (context->output_type == DISC_555_OUT_CAP) + context->ac_shift = context->threshold * 3.0 /4.0; + else + context->ac_shift = context->v_out_high / 2.0; + } + else + context->ac_shift = 0; context->trig_is_logic = (info->options & DISC_555_TRIGGER_IS_VOLTAGE) ? 0: 1; context->trig_discharges_cap = (info->options & DISC_555_TRIGGER_DISCHARGES_CAP) ? 1: 0; @@ -1870,6 +1890,5 @@ DISCRETE_RESET(dsd_ls624) else context->has_freq_in_cap = 0; - node->output[0] = 0; } diff --git a/src/emu/sound/disc_mth.c b/src/emu/sound/disc_mth.c index c8ddc1b8484..e029a95507c 100644 --- a/src/emu/sound/disc_mth.c +++ b/src/emu/sound/disc_mth.c @@ -65,10 +65,10 @@ struct dst_bits_decode_context struct dst_dac_r1_context { - double i_bias; /* current of the bias circuit */ - double exponent; /* smoothing curve */ - double r_total; /* all resistors in parallel */ - int last_data; + double exponent; + double last_v; + double v_step[256]; + int has_c_filter; }; struct dst_diode_mix_context @@ -250,7 +250,8 @@ DISCRETE_RESET(dst_comp_adder) DISCRETE_DECLARE_INFO(discrete_comp_adder_table) int i, bit; - int length = 1 << info->length; + int bit_length = info->length; + int length = 1 << bit_length; assert(length <= 256); @@ -261,18 +262,21 @@ DISCRETE_RESET(dst_comp_adder) { case DISC_COMP_P_CAPACITOR: context->total[i] = info->cDefault; - for(bit = 0; bit < info->length; bit++) + for(bit = 0; bit < bit_length; bit++) { - if (i & (1 << bit)) context->total[i] += info->c[bit]; + if (i & (1 << bit)) + context->total[i] += info->c[bit]; } break; case DISC_COMP_P_RESISTOR: context->total[i] = (info->cDefault != 0) ? 1.0 / info->cDefault : 0; - for(bit = 0; bit < info->length; bit++) + for(bit = 0; bit < bit_length; bit++) { - if ((i & (1 << bit)) && (info->c[bit] != 0)) context->total[i] += 1.0 / info->c[bit]; + if ((i & (1 << bit)) && (info->c[bit] != 0)) + context->total[i] += 1.0 / info->c[bit]; } - if (context->total[i] != 0) context->total[i] = 1.0 / context->total[i]; + if (context->total[i] != 0) + context->total[i] = 1.0 / context->total[i]; break; } } @@ -310,6 +314,7 @@ DISCRETE_STEP(dst_clamp) * also passed discrete_dac_r1_ladder structure * * Mar 2004, D Renaud. + * Nov 2010, D Renaud. - optimized for speed ************************************************************************/ #define DST_DAC_R1__DATA DISCRETE_INPUT(0) #define DST_DAC_R1__VON DISCRETE_INPUT(1) @@ -317,49 +322,33 @@ DISCRETE_STEP(dst_clamp) DISCRETE_STEP(dst_dac_r1) { DISCRETE_DECLARE_CONTEXT(dst_dac_r1) - DISCRETE_DECLARE_INFO(discrete_dac_r1_ladder) - int bit, bit_val, data; - double v, i_bit, i_total, x_time, von; + int data = (int)DST_DAC_R1__DATA; + double v = context->v_step[data]; + double x_time = DST_DAC_R1__DATA - data; + double last_v = context->last_v; - i_total = context->i_bias; + context->last_v = v; - data = (int)DST_DAC_R1__DATA; - x_time = DST_DAC_R1__DATA - data; - - von = DST_DAC_R1__VON; - for (bit=0; bit < info->ladderLength; bit++) - { - /* Add up currents of ON circuits per Millman. */ - - /* ignore if no resistor present */ - if (info->r[bit] != 0) - { - i_bit = von / info->r[bit]; - bit_val = (data >> bit) & 0x01; - - if ((x_time != 0.0) && (bit_val != ((context->last_data >> bit) & 0x01))) - { - /* there is x_time and a change in bit, - * so anti-alias the current */ - i_bit *= bit_val ? x_time : 1.0 - x_time; - } - else - { - /* there is no x_time or a change in bit, - * so 0 the current if the bit value is 0 */ - if (bit_val == 0) - i_bit = 0; - } - i_total += i_bit; - } - } - - v = i_total * context->r_total; - context->last_data = data; + if (x_time > 0) + v = x_time * (v - last_v) + last_v; /* Filter if needed, else just output voltage */ - node->output[0] = info->cFilter ? node->output[0] + ((v - node->output[0]) * context->exponent) : v; + if (context->has_c_filter) + { + double out = node->output[0]; + double v_diff = v - out; + /* optimization - if charged close enough to voltage */ + if (fabs(v_diff) < 0.000001) + node->output[0] = v; + else + { + out += v_diff * context->exponent; + node->output[0] = out; + } + } + else + node->output[0] = v; } DISCRETE_RESET(dst_dac_r1) @@ -368,24 +357,31 @@ DISCRETE_RESET(dst_dac_r1) DISCRETE_DECLARE_INFO(discrete_dac_r1_ladder) int bit; + int ladderLength = info->ladderLength; + int total_steps = 1 << ladderLength; + double r_total = 0; + double i_bias; + double v_on = DST_DAC_R1__VON; + + context->last_v = 0; /* Calculate the Millman current of the bias circuit */ if (info->rBias) - context->i_bias = info->vBias / info->rBias; + i_bias = info->vBias / info->rBias; else - context->i_bias = 0; + i_bias = 0; /* * We will do a small amount of error checking. * But if you are an idiot and pass a bad ladder table * then you deserve a crash. */ - if (info->ladderLength < 2) + if (ladderLength < 2 && info->rBias == 0 && info->rGnd == 0) { /* You need at least 2 resistors for a ladder */ discrete_log(node->info, "dst_dac_r1_reset - Ladder length too small"); } - if (info->ladderLength > DISC_LADDER_MAXRES ) + if (ladderLength > DISC_LADDER_MAXRES ) { discrete_log(node->info, "dst_dac_r1_reset - Ladder length exceeds DISC_LADDER_MAXRES"); } @@ -395,22 +391,48 @@ DISCRETE_RESET(dst_dac_r1) * This is the combined resistance of the voltage sources. * This is used for the charging curve. */ - context->r_total = 0; - for(bit = 0; bit < info->ladderLength; bit++) + for(bit = 0; bit < ladderLength; bit++) { if (info->r[bit] != 0) - context->r_total += 1.0 / info->r[bit]; + r_total += 1.0 / info->r[bit]; } - if (info->rBias) context->r_total += 1.0 / info->rBias; - if (info->rGnd) context->r_total += 1.0 / info->rGnd; - context->r_total = 1.0 / context->r_total; + if (info->rBias) r_total += 1.0 / info->rBias; + if (info->rGnd) r_total += 1.0 / info->rGnd; + r_total = 1.0 / r_total; node->output[0] = 0; - if (info->cFilter) + if (info->cFilter > 0) { - /* Setup filter constants */ - context->exponent = RC_CHARGE_EXP(context->r_total * info->cFilter); + context->has_c_filter = 1; + /* Setup filter constant */ + context->exponent = RC_CHARGE_EXP(r_total * info->cFilter); + } + else + context->has_c_filter = 0; + + /* pre-calculate all possible values to speed up step routine */ + for(int i = 0; i < total_steps; i++) + { + double i_total = i_bias; + for (bit = 0; bit < ladderLength; bit++) + { + /* Add up currents of ON circuits per Millman. */ + + /* ignore if no resistor present */ + if (EXPECTED(info->r[bit] != 0)) + { + double i_bit; + int bit_val = (i >> bit) & 0x01; + + if (bit_val != 0) + i_bit = v_on / info->r[bit]; + else + i_bit = 0; + i_total += i_bit; + } + } + context->v_step[i] = i_total * r_total; } } diff --git a/src/emu/sound/discrete.c b/src/emu/sound/discrete.c index 8a4d7a5a54d..7e2a282a16d 100644 --- a/src/emu/sound/discrete.c +++ b/src/emu/sound/discrete.c @@ -306,7 +306,7 @@ static const discrete_module module_list[] = /* from disc_dev.c */ /* generic modules */ - { DST_CUSTOM ,"DST_CUSTOM" , 1 ,0 ,NULL ,NULL ,NULL ,NULL }, + { DST_CUSTOM ,"DST_CUSTOM" , 8 ,0 ,NULL ,NULL ,NULL ,NULL }, /* Component specific modules */ { DSD_555_ASTBL ,"DSD_555_ASTBL" , 1 ,sizeof(struct dsd_555_astbl_context) ,dsd_555_astbl_reset ,dsd_555_astbl_step ,NULL ,NULL }, { DSD_555_MSTBL ,"DSD_555_MSTBL" , 1 ,sizeof(struct dsd_555_mstbl_context) ,dsd_555_mstbl_reset ,dsd_555_mstbl_step ,NULL ,NULL }, @@ -1035,7 +1035,7 @@ static void find_input_nodes(const discrete_info *info) if (!node_ref) fatalerror("discrete_start - NODE_%02d referenced a non existent node NODE_%02d", NODE_BLOCKINDEX(node), NODE_INDEX(inputnode)); - if (NODE_CHILD_NODE_NUM(inputnode) >= node_ref->module->num_output) + if ((NODE_CHILD_NODE_NUM(inputnode) >= node_ref->module->num_output) && (node_ref->module->type != DST_CUSTOM)) fatalerror("discrete_start - NODE_%02d referenced non existent output %d on node NODE_%02d", NODE_BLOCKINDEX(node), NODE_CHILD_NODE_NUM(inputnode), NODE_INDEX(inputnode)); node->input[inputnum] = &(node_ref->output[NODE_CHILD_NODE_NUM(inputnode)]); /* Link referenced node out to input */ diff --git a/src/emu/sound/discrete.h b/src/emu/sound/discrete.h index ac4c6af84c3..5848a91a150 100644 --- a/src/emu/sound/discrete.h +++ b/src/emu/sound/discrete.h @@ -1866,7 +1866,7 @@ * * DISCRETE_DAC_R1(name of node, * data node (static value is useless), - * vData node or static value (voltage when a bit is on ), + * vData static value (voltage when a bit is on ), * address of discrete_dac_r1_ladder structure) * * discrete_dac_r1_ladder = {ladderLength, r{}, vBias, rBias, rGnd, cFilter} @@ -4517,7 +4517,7 @@ enum #define DISCRETE_TRANSFORM5(NODE,INP0,INP1,INP2,INP3,INP4,FUNCT) { NODE, DST_TRANSFORM , 5, { INP0,INP1,INP2,INP3,INP4 }, { INP0,INP1,INP2,INP3,INP4 }, FUNCT, "DISCRETE_TRANSFORM5" }, /* Component specific */ #define DISCRETE_COMP_ADDER(NODE,DATA,TABLE) { NODE, DST_COMP_ADDER , 1, { DATA }, { DATA }, TABLE, "DISCRETE_COMP_ADDER" }, -#define DISCRETE_DAC_R1(NODE,DATA,VDATA,LADDER) { NODE, DST_DAC_R1 , 2, { DATA,VDATA }, { DATA,VDATA }, LADDER, "DISCRETE_DAC_R1" }, +#define DISCRETE_DAC_R1(NODE,DATA,VDATA,LADDER) { NODE, DST_DAC_R1 , 2, { DATA,NODE_NC }, { DATA,VDATA }, LADDER, "DISCRETE_DAC_R1" }, #define DISCRETE_DIODE_MIXER2(NODE,IN0,IN1,TABLE) { NODE, DST_DIODE_MIX , 3, { IN0,IN1 }, { IN0,IN1 }, TABLE, "DISCRETE_DIODE_MIXER2" }, #define DISCRETE_DIODE_MIXER3(NODE,IN0,IN1,IN2,TABLE) { NODE, DST_DIODE_MIX , 4, { IN0,IN1,IN2 }, { IN0,IN1,IN2 }, TABLE, "DISCRETE_DIODE_MIXER3" }, #define DISCRETE_DIODE_MIXER4(NODE,IN0,IN1,IN2,IN3,TABLE) { NODE, DST_DIODE_MIX , 5, { IN0,IN1,IN2,IN3 }, { IN0,IN1,IN2,IN3 }, TABLE, "DISCRETE_DIODE_MIXER4" }, diff --git a/src/mame/audio/copsnrob.c b/src/mame/audio/copsnrob.c new file mode 100644 index 00000000000..85f3f968c71 --- /dev/null +++ b/src/mame/audio/copsnrob.c @@ -0,0 +1,665 @@ +/************************************************************************ + * copsnrob Sound System Analog emulation + * Nov 2010, Derrick Renaud + ************************************************************************/ +#include "emu.h" +#include "includes/copsnrob.h" +#include "sound/discrete.h" + + +/* Discrete Sound Input Nodes */ +#define COPSNROB_MOTOR0_INV NODE_01 +#define COPSNROB_MOTOR1_INV NODE_02 +#define COPSNROB_MOTOR2_INV NODE_03 +#define COPSNROB_MOTOR3_INV NODE_04 +#define COPSNROB_ZINGS_INV NODE_05 +#define COPSNROB_FIRES_INV NODE_06 +#define COPSNROB_CRASH_INV NODE_07 +#define COPSNROB_SCREECH_INV NODE_08 +#define COPSNROB_AUDIO_ENABLE NODE_09 + +/* Discrete Sound Output Nodes */ +#define COPSNROB_MOTOR0_SND NODE_11 +#define COPSNROB_MOTOR1_SND NODE_12 +#define COPSNROB_MOTOR2_SND NODE_13 +#define COPSNROB_MOTOR3_SND NODE_14 +#define COPSNROB_FZ_SND NODE_15 +#define COPSNROB_CRASH_SND NODE_16 +#define COPSNROB_SCREECH_SND NODE_17 +#define COPSNROB_NOISE_1 NODE_18 +#define COPSNROB_NOISE_2 NODE_18_01 + +/* Parts List - Resistors */ +#define COPSNROB_R16 RES_K(10) +#define COPSNROB_R18 RES_K(100) +#define COPSNROB_R19 RES_K(100) +#define COPSNROB_R20 RES_K(100) +#define COPSNROB_R21 RES_K(47) +#define COPSNROB_R25 RES_K(47) +#define COPSNROB_R26 RES_K(150) +#define COPSNROB_R27 RES_K(22) +#define COPSNROB_R28 RES_K(18) +#define COPSNROB_R33 RES_K(10) +#define COPSNROB_R35 RES_K(10) +#define COPSNROB_R36 RES_K(15) +#define COPSNROB_R37 RES_K(4.7) +#define COPSNROB_R38 RES_K(15) +#define COPSNROB_R39 RES_K(10) +#define COPSNROB_R41 RES_K(33) +#define COPSNROB_R42 RES_K(33) +#define COPSNROB_R47 RES_K(10) +#define COPSNROB_R48 RES_K(1) +#define COPSNROB_R49 RES_K(47) +#define COPSNROB_R50 RES_K(47) +#define COPSNROB_R53 RES_K(47) +#define COPSNROB_R54 RES_K(22) +#define COPSNROB_R55 RES_K(47) +#define COPSNROB_R56 RES_K(470) +#define COPSNROB_R57 RES_K(820) +#define COPSNROB_R58 RES_K(68) +#define COPSNROB_R59 RES_K(1) +#define COPSNROB_R64 RES_K(47) +#define COPSNROB_R65 RES_K(4.7) +#define COPSNROB_R66 RES_K(1.5) +#define COPSNROB_R69 RES_K(330) +#define COPSNROB_R70 RES_K(330) +#define COPSNROB_R71 RES_K(100) +#define COPSNROB_R72 RES_K(100) +#define COPSNROB_R73 RES_K(47) +#define COPSNROB_R74 RES_K(1) +#define COPSNROB_R75 RES_K(1) +#define COPSNROB_R76 RES_K(12) +#define COPSNROB_R77 RES_K(33) +#define COPSNROB_R78 RES_K(100) +#define COPSNROB_R79 RES_K(2.2) +#define COPSNROB_R80 RES_K(1) +#define COPSNROB_R81 RES_K(8.2) +#define COPSNROB_R82 RES_K(3.9) +#define COPSNROB_R83 RES_K(27) +#define COPSNROB_R84 RES_K(15) +#define COPSNROB_R85 (330) +#define COPSNROB_R86 RES_K(330) +#define COPSNROB_R87 (820) +#define COPSNROB_R88 RES_K(1) +#define COPSNROB_R89 RES_K(1) +#define COPSNROB_R92 RES_K(100) +#define COPSNROB_R93 RES_K(100) +#define COPSNROB_R94 RES_K(10) + +/* Parts List - Capacitors */ +#define COPSNROB_C3 CAP_U(100) +#define COPSNROB_C12 CAP_U(0.1) +#define COPSNROB_C13 CAP_U(0.1) +#define COPSNROB_C17 CAP_U(0.001) +#define COPSNROB_C19 CAP_U(10) +#define COPSNROB_C20 CAP_U(0.01) +#define COPSNROB_C23 CAP_U(0.1) +#define COPSNROB_C24 CAP_U(0.22) +#define COPSNROB_C28 CAP_U(1) +#define COPSNROB_C30 CAP_U(0.01) +#define COPSNROB_C31 CAP_U(0.1) +#define COPSNROB_C32 CAP_U(5) +#define COPSNROB_C33 CAP_U(10) +#define COPSNROB_C36 CAP_U(100) +#define COPSNROB_C39 CAP_U(0.1) +#define COPSNROB_C37 CAP_U(0.1) +#define COPSNROB_C40 CAP_U(0.1) +#define COPSNROB_C41 CAP_U(0.03) +#define COPSNROB_C42 CAP_U(0.047) +#define COPSNROB_C43 CAP_U(0.047) +#define COPSNROB_C55 CAP_U(0.1) +#define COPSNROB_C58 CAP_U(0.1) +#define COPSNROB_C59 CAP_U(0.1) + +/* Timing values */ +#define COPSNROB_2V (15750/2/2) /* has to be verified */ + + +static const discrete_555_desc copsnrob_motor23_555_1 = +{ + DISC_555_OUT_SQW, + 5, DEFAULT_555_VALUES +}; + +static const discrete_555_desc copsnrob_motor23_555_2 = +{ + DISC_555_OUT_ENERGY | DISC_555_TRIGGER_IS_LOGIC, + 5, DEFAULT_555_VALUES +}; + +static const discrete_op_amp_filt_info copsnrob_motor23_filter = +{ + COPSNROB_R28, 0, COPSNROB_R87, 0, COPSNROB_R86, /* r1, r2, r3, r4, rF */ + COPSNROB_C42, COPSNROB_C43, 0, /* c1, c2, c3 */ + 5.0 * RES_VOLTAGE_DIVIDER(COPSNROB_R88, COPSNROB_R89), 5, 0 /* vRef, vP, vN */ +}; + +static const discrete_dac_r1_ladder copsnrob_crash_dac = +{ + 4, /* ladderLength */ + {COPSNROB_R81, COPSNROB_R82, COPSNROB_R79, COPSNROB_R80}, + 0, 0, 0, COPSNROB_C58 /* vBias, rBias, rGnd, cFilter */ +}; + +static const discrete_mixer_desc copsnrob_final_mixer01 = +{ + DISC_MIXER_IS_RESISTOR, + {COPSNROB_R21, COPSNROB_R25, COPSNROB_R33, COPSNROB_R70, COPSNROB_R71}, + {0}, {0}, 0, COPSNROB_R35, 0, COPSNROB_C59, /* r_node{}, c{}, rI, rF, cF, cAmp */ + 0, 1 /* vRef, gain */ +}; + +static const discrete_mixer_desc copsnrob_final_mixer23 = +{ + DISC_MIXER_IS_RESISTOR, + {COPSNROB_R93, COPSNROB_R92, COPSNROB_R72, COPSNROB_R69, COPSNROB_R16}, + {0}, {0}, 0, COPSNROB_R94, 0, COPSNROB_C55, /* r_node{}, c{}, rI, rF, cF, cAmp */ + 0, 1 /* vRef, gain */ +}; + +static const discrete_dac_r1_ladder copsnrob_motor23_cv_dac = +{ + 1, /* ladderLength */ + {COPSNROB_R65}, + 5, RES_K(5), RES_K(10), COPSNROB_C36 /* vBias; rBias; rGnd; cFilter */ +}; + +#define COPSNROB_MOTOR01_BASE_NODE NODE_20 +#define COPSNROB_MOTOR23_BASE_NODE NODE_30 +#define COPSNROB_NODE(_base, _num, _offset) NODE_RELATIVE(_base, _num * 100 + _offset) +#define COPSNROB_MOTOR01_NODE(_num, _offset) COPSNROB_NODE(COPSNROB_MOTOR01_BASE_NODE, _num, _offset) +#define COPSNROB_MOTOR23_NODE(_num, _offset) COPSNROB_NODE(COPSNROB_MOTOR23_BASE_NODE, _num, _offset) + + +/************************************************ + * MOTOR2/3 Definition Start + ************************************************/ +#define COPSNROB_MOTOR23(_output, _input, _num) \ + /* simulate the RC connected to the 555 CV pin with a DAC */ \ + DISCRETE_DAC_R1(COPSNROB_MOTOR23_NODE(_num, 1), \ + _input, 4.2, &copsnrob_motor23_cv_dac) /* DATA; VDATA - TTL with light load */ \ + DISCRETE_555_ASTABLE_CV(COPSNROB_MOTOR23_NODE(_num, 2), /* IC J2, pin 5 */ \ + 1, /* RESET */ \ + COPSNROB_R64, COPSNROB_R42, COPSNROB_C24, \ + COPSNROB_MOTOR23_NODE(_num, 1), /* CTRLV - IC J2, pin 3 */ \ + &copsnrob_motor23_555_1) \ + /* R27 and C17 can be ignored, we will just trigger on the logic */ \ + DISCRETE_555_MSTABLE(COPSNROB_MOTOR23_NODE(_num, 3), /* IC J3, pin 9 */ \ + 1, /* RESET */ \ + COPSNROB_MOTOR23_NODE(_num, 2), /* IC J3, pin 8 */ \ + COPSNROB_R41, COPSNROB_C23, \ + &copsnrob_motor23_555_2) \ + DISCRETE_OP_AMP_FILTER(_output, /* IC L4, pin 7 */ \ + 1, /* ENAB */ \ + COPSNROB_MOTOR23_NODE(_num, 3), 0, /* INP0; INP1 */ \ + DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &copsnrob_motor23_filter) +/************************************************ + * MOTOR2/3 Definition End + ************************************************/ + + +/************************************************ + * CUSTOM_NOISE Definition Start + * - output is energy + ************************************************/ +#define COPSNROB_CUSTOM_NOISE__FREQ DISCRETE_INPUT(0) + +struct copsnrob_custom_noise_context +{ + int flip_flop; + int noise1_had_xtime; + int noise2_had_xtime; + UINT8 high_byte; + UINT8 low_byte; + double t_used; + double t1; +}; + +#define COPSNROB_CUSTOM_NOISE_HIGH 4.2 + +DISCRETE_STEP(copsnrob_custom_noise) +{ + DISCRETE_DECLARE_CONTEXT(copsnrob_custom_noise) + + double t_used = context->t_used; + double t1 = context->t1; + double x_time = 0; + UINT8 low_byte = context->low_byte; + UINT8 high_byte = context->high_byte; + UINT8 xnor_out; /* IC F2, pin 2 */ + int last_noise1_bit = (low_byte >> 4) & 0x01; + int last_noise2_bit = (low_byte >> 5) & 0x01; + + t_used += node->info->sample_time; + + /* This clock will never run faster then the sample rate, + * so we do not bother to check. + */ + if (t_used > t1) + { + /* calculate the overshoot time */ + t_used -= t1; + context->flip_flop ^= 1; + /* clocks on low to high */ + if (context->flip_flop) + { + int new_noise_bit; + + /* shift */ + xnor_out = (((low_byte >> 6) & 0x01) ^ (high_byte & 0x01)) ^ 0x01; + low_byte = (low_byte << 1) | ((high_byte >> 7) & 0x01); + high_byte = (high_byte << 1) | xnor_out; + if (high_byte == 0xff) /* IC H1, pin 8 */ + high_byte = 0; + context->low_byte = low_byte; + context->high_byte = high_byte; + + /* Convert last switch time to a ratio */ + x_time = t_used / node->info->sample_time; + /* use x_time if bit changed */ + new_noise_bit = (low_byte >> 4) & 0x01; + if (last_noise1_bit != new_noise_bit) + { + node->output[0] = COPSNROB_CUSTOM_NOISE_HIGH * (new_noise_bit ? x_time : (1.0 - x_time)); + context->noise1_had_xtime = 1; + } + new_noise_bit = (low_byte >> 5) & 0x01; + if (last_noise2_bit != new_noise_bit) + { + node->output[1] = COPSNROB_CUSTOM_NOISE_HIGH * (new_noise_bit ? x_time : (1.0 - x_time)); + context->noise2_had_xtime = 1; + } + } + } + else + { + /* see if we need to move from x_time state to full state */ + if (context->noise1_had_xtime) + { + node->output[0] = COPSNROB_CUSTOM_NOISE_HIGH * last_noise1_bit; + context->noise1_had_xtime = 0; + } + if (context->noise2_had_xtime) + { + node->output[1] = COPSNROB_CUSTOM_NOISE_HIGH * last_noise2_bit; + context->noise2_had_xtime = 0; + } + } + + context->t_used = t_used; +} + +DISCRETE_RESET(copsnrob_custom_noise) +{ + DISCRETE_DECLARE_CONTEXT(copsnrob_custom_noise) + + context->t1 = 0.5 / COPSNROB_CUSTOM_NOISE__FREQ ; + context->flip_flop = 0; + context->low_byte = 0; + context->high_byte = 0; + context->t_used = 0; + context->noise1_had_xtime = 0; + context->noise2_had_xtime = 0; +} + +static const discrete_custom_info copsnrob_custom_noise = +{ + DISCRETE_CUSTOM_MODULE( copsnrob_custom_noise, struct copsnrob_custom_noise_context), + NULL +}; +/************************************************ + * CUSTOM_NOISE Definition End + ************************************************/ + + +#if (0) +/************************************************ + * CUSTOM_ZINGS_555_MONOSTABLE Definition Start + * - output is energy + ************************************************/ +#define COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__TRIG DISCRETE_INPUT(0) +#define COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__R DISCRETE_INPUT(1) +#define COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__C DISCRETE_INPUT(2) + +struct copsnrob_zings_555_monostable_context +{ + double rc; + double exponent; + double v_cap; + int flip_flop; +}; + +DISCRETE_STEP(copsnrob_zings_555_monostable) +{ + DISCRETE_DECLARE_CONTEXT(copsnrob_zings_555_monostable) + + const double v_threshold = 5.0 * 2 / 3; + const double v_out_high = 5.0 - 0.5; /* light load */ + + /* int ff_reset = (COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__TRIG > v_threshold ? 1 : 0; */ + int ff_set = COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__TRIG < (5.0 / 3) ? 1 : 0; + int flip_flop = context->flip_flop; + double v_cap = context->v_cap; + double x_time = 0; + + /* From testing a real IC */ + /* Trigger going low overides everything. It forces the FF/Output high. + * If Threshold is high, the output will still go high as long as trigger is low. + * The output will then go low when trigger rises above it's 1/3VCC value. + * If threshold is below it's 2/3VCC value, the output will remain high. + */ + if (ff_set) + { + flip_flop = 1; + context->flip_flop = flip_flop; + } + + if (flip_flop) + { + double v_diff = v_out_high - v_cap; + + /* charge */ + v_cap += v_diff * context->exponent; + /* no state change if trigger is low */ + if (!ff_set && (v_cap > v_threshold)) + { + double rc = context->rc; + + flip_flop = 0; + context->flip_flop = flip_flop; + /* calculate overshoot */ + x_time = rc * log(1.0 / (1.0 - ((v_cap - v_threshold) / v_diff))); + /* discharge the overshoot */ + v_cap = v_threshold; + v_cap -= v_cap * RC_CHARGE_EXP_DT(rc, x_time); + x_time /= node->info->sample_time; + } + } + else + { + /* Optimization - already discharged */ + if (v_cap == 0) + return; + /* discharge */ + v_cap -= v_cap * context->exponent; + /* Optimization - close enough to 0 to be 0 */ + if (v_cap < 0.0001) + v_cap = 0; + } + context->v_cap = v_cap; + + if (x_time > 0) + node->output[0] = v_out_high * x_time; + else if (flip_flop) + node->output[0] = v_out_high; + else + node->output[0] = 0; +} + +DISCRETE_RESET(copsnrob_zings_555_monostable) +{ + DISCRETE_DECLARE_CONTEXT(copsnrob_zings_555_monostable) + + context->rc = COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__R * COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__C; + context->exponent = RC_CHARGE_EXP(context->rc); + context->v_cap = 0; + context->flip_flop = 0; + node->output[0] = 0; +} + +static const discrete_custom_info copsnrob_zings_555_monostable = +{ + DISCRETE_CUSTOM_MODULE( copsnrob_zings_555_monostable, struct copsnrob_zings_555_monostable_context), + NULL +}; +/************************************************ + * CUSTOM_ZINGS_555_MONOSTABLE Definition End + ************************************************/ + + +/************************************************ + * CUSTOM_ZINGS_555_ASTABLE Definition Start + * - output is energy + ************************************************/ +#define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__RESET DISCRETE_INPUT(0) +#define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__R1 DISCRETE_INPUT(1) +#define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__R2 DISCRETE_INPUT(2) +#define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__C1 DISCRETE_INPUT(3) +#define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__C2 DISCRETE_INPUT(4) + +struct copsnrob_zings_555_astable_context +{ + double r1c1; + double r2c2; + double exponent1; + double exponent2; + double v_cap1; + double v_cap2; + int flip_flop; +}; + +DISCRETE_STEP(copsnrob_zings_555_astable) +{ + DISCRETE_DECLARE_CONTEXT(copsnrob_zings_555_astable) + + int reset_active = COPSNROB_CUSTOM_ZINGS_555_ASTABLE__RESET < 0.7; + int flip_flop = context->flip_flop; + double v_cap1 = context->v_cap1; + double v_cap2 = context->v_cap2; + double x_time = 0; + + if (reset_active) + { + if (flip_flop) + { + flip_flop = 0; + context->flip_flop = 0; + } + /* Optimization - only discharge if needed */ + if (v_cap1 != 0) + { + /* discharge */ + v_cap1 -= v_cap1 * context->exponent; + /* Optimization - close enough to 0 to be 0 */ + if (v_cap1 < 0.0001) + v_cap1 = 0; + } + } + else + { + /* this oscillator will never create a frequency greater then 1/2 the sample rate, + * so we won't worry about missing samples */ + if (flip_flop) + { + /* The reset voltage also charges the CV cap */ + double v_diff1 = COPSNROB_CUSTOM_ZINGS_555_ASTABLE__RESET - v_cap1; + + /* charge */ + v_cap1 += v_diff1 * context->exponent1; + + if (v_cap1 > v_threshold) + { + double r1c1 = context->r1c1; + + flip_flop = 0; + context->flip_flop = flip_flop; + /* calculate overshoot */ + x_time = r1c1 * log(1.0 / (1.0 - ((v_cap1 - v_threshold) / v_diff1))); + /* discharge the overshoot */ + v_cap1 = v_threshold; + v_cap1 -= v_cap1 * RC_CHARGE_EXP_DT(r1c1, x_time); + x_time /= node->info->sample_time; + } + } + + } + +} + +DISCRETE_RESET(copsnrob_zings_555_astable) +{ + DISCRETE_DECLARE_CONTEXT(copsnrob_zings_555_astable) + + context->r1c1 = COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__R1 * COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__C1; + context->r2c2 = COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__R2 * COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__C2; + context->exponent1 = RC_CHARGE_EXP(context->r1c1); + context->exponent2 = RC_CHARGE_EXP(context->r2c2); + context->v_cap1 = 0; + context->v_cap2 = 0; + context->flip_flop = 0; + node->output[0] = 0; +} + +static const discrete_custom_info copsnrob_zings_555_astable = +{ + DISCRETE_CUSTOM_MODULE( copsnrob_zings_555_astable, struct copsnrob_zings_555_astable_context), + NULL +}; +/************************************************ + * CUSTOM_ZINGS_555_ASTABLE Definition End + ************************************************/ +#endif + + +DISCRETE_SOUND_START(copsnrob) + + /************************************************ + * Input register mapping + ************************************************/ + DISCRETE_INPUTX_LOGIC(COPSNROB_MOTOR0_INV, 3.8, 0, 0) /* TTL at high load */ + DISCRETE_INPUTX_LOGIC(COPSNROB_MOTOR1_INV, 3.8, 0, 0) /* TTL at high load */ + DISCRETE_INPUT_LOGIC(COPSNROB_MOTOR2_INV) + DISCRETE_INPUT_LOGIC(COPSNROB_MOTOR3_INV) + DISCRETE_INPUT_LOGIC(COPSNROB_ZINGS_INV) + DISCRETE_INPUT_LOGIC(COPSNROB_FIRES_INV) + DISCRETE_INPUT_NOT(COPSNROB_CRASH_INV) /* inverted for counter use */ + DISCRETE_INPUT_LOGIC(COPSNROB_SCREECH_INV) + DISCRETE_INPUT_NOT(COPSNROB_AUDIO_ENABLE) /* IC A1, pins 2 & 12 */ + + /************************************************ + * MOTOR0/1 + ************************************************/ + DISCRETE_CONSTANT(COPSNROB_MOTOR0_SND, 0) + DISCRETE_CONSTANT(COPSNROB_MOTOR1_SND, 0) + + /************************************************ + * MOTOR2/3 + ************************************************/ + COPSNROB_MOTOR23(COPSNROB_MOTOR2_SND, COPSNROB_MOTOR2_INV, 0) + COPSNROB_MOTOR23(COPSNROB_MOTOR3_SND, COPSNROB_MOTOR3_INV, 1) + + /************************************************ + * CRASH + ************************************************/ + DISCRETE_CUSTOM1(COPSNROB_NOISE_1, /* IC J2, pin 10 */ + COPSNROB_2V, /* CLK */ + &copsnrob_custom_noise) + /* COPSNROB_NOISE_2 derived from sub out of above custom module - IC J2, pin 11 */ + /* We use the measured 555 timer frequency (IC M3) for speed */ + DISCRETE_COUNTER(NODE_40, /* IC L2 */ + NODE_41, /* ENAB - IC L2, pin 14 */ + COPSNROB_CRASH_INV, /* RESET - IC L2, pin 11 */ + 92, /* IC L2, pin 4 - freq measured */ + 0, 15, DISC_COUNT_DOWN, 15, DISC_CLK_IS_FREQ) /* MIN; MAX; DIR; INIT0; CLKTYPE */ + DISCRETE_TRANSFORM2(NODE_41, /* IC M2, pin 3 - goes high at count 0 */ + NODE_40, 0, "01=!") /* -we will invert it for use by the counter module */ + DISCRETE_SWITCH(NODE_42, /* IC L3 */ + 1, COPSNROB_NOISE_2, 0, NODE_40) /* ENAB; SWITCH; INP0; INP1 */ + DISCRETE_DAC_R1(COPSNROB_CRASH_SND, + NODE_42, 3.8, /* DATA; VDATA */ + &copsnrob_crash_dac) +//DISCRETE_WAVLOG2(COPSNROB_NOISE_1, 1000, COPSNROB_NOISE_2, 1000) +//DISCRETE_WAVLOG2(NODE_42, 1000, COPSNROB_CRASH_SND, 1000) + + /************************************************ + * SCREECH + ************************************************/ + DISCRETE_CONSTANT(COPSNROB_SCREECH_SND, 0) + + /************************************************ + * FZ (Fires, Zings) + ************************************************/ +#if (0) + DISCRETE_CUSTOM2(NODE_60, /* IC D3, pin 5 */ + COPSNROB_R38, COPSNROB_C19, + &copsnrob_zings_555_monostable) + DISCRETE_CUSTOM4(NODE_60, /* IC D3, pin 8 & 12 */ + COPSNROB_R36, COPSNROB_R37, + COPSNROB_C3, COPSNROB_C13, + &copsnrob_zings_555_astable) + +#else + DISCRETE_CONSTANT(COPSNROB_FZ_SND, 0) +#endif + + /************************************************ + * MIXER + ************************************************/ + DISCRETE_MIXER5(NODE_90, /* IC B3, pin 3 */ + COPSNROB_AUDIO_ENABLE, /* ENAB */ + COPSNROB_MOTOR1_SND, COPSNROB_MOTOR0_SND, COPSNROB_FZ_SND, COPSNROB_SCREECH_SND, COPSNROB_CRASH_SND, + &copsnrob_final_mixer01) + DISCRETE_MIXER5(NODE_91, /* IC P3, pin 3 */ + COPSNROB_AUDIO_ENABLE, /* ENAB */ + COPSNROB_MOTOR3_SND, COPSNROB_MOTOR2_SND, COPSNROB_CRASH_SND, COPSNROB_SCREECH_SND, COPSNROB_FZ_SND, + &copsnrob_final_mixer23) + DISCRETE_OUTPUT(NODE_90, 32767.0*3.5) + DISCRETE_OUTPUT(NODE_91, 32767.0*3.5) +DISCRETE_SOUND_END + + +WRITE8_HANDLER( copsnrob_misc_w ) +{ + device_t *device = space->machine->device("discrete"); + copsnrob_state *state = space->machine->driver_data(); + UINT8 latched_data = state->ic_h3_data; + UINT8 special_data = data & 0x01; + + /* ignore if no change */ + if (((latched_data >> offset) & 0x01) == special_data) + return; + + if (special_data) + latched_data |= 1 << offset; + else + latched_data &= ~(1 << offset); + + switch (offset) + { + case 0x00: + discrete_sound_w(device, COPSNROB_MOTOR3_INV, special_data); + break; + + case 0x01: + discrete_sound_w(device, COPSNROB_MOTOR2_INV, special_data); + break; + + case 0x02: + discrete_sound_w(device, COPSNROB_MOTOR1_INV, special_data); + break; + + case 0x03: + discrete_sound_w(device, COPSNROB_MOTOR0_INV, special_data); + break; + + case 0x04: + discrete_sound_w(device, COPSNROB_SCREECH_INV, special_data); + break; + + case 0x05: + discrete_sound_w(device, COPSNROB_CRASH_INV, special_data); + break; + + case 0x06: + /* One Start */ + set_led_status(space->machine, 0, !special_data); + break; + + case 0x07: + discrete_sound_w(device, COPSNROB_AUDIO_ENABLE, special_data); + break; + + } + + state->ic_h3_data = latched_data; +} diff --git a/src/mame/drivers/copsnrob.c b/src/mame/drivers/copsnrob.c index cda26eb2a2a..2a32119acf1 100644 --- a/src/mame/drivers/copsnrob.c +++ b/src/mame/drivers/copsnrob.c @@ -38,8 +38,7 @@ I/O Write: - 0500-0503 Direction of the cars - 0504-0507 (sounds/enable) - 0506: LED 1 + 0500-0507 (sounds/enable) - 0506: LED 1 0600 Beer Truck Y 0700-07ff Beer Truck Sync Area 0800-08ff Bullets RAM @@ -76,26 +75,22 @@ static PALETTE_INIT( copsnrob ) /************************************* * - * LEDs + * I/O * *************************************/ static READ8_HANDLER( copsnrob_misc_r ) { - copsnrob_state *state = space->machine->driver_data(); - return state->misc | (input_port_read(space->machine, "IN0") & 0x80); + return input_port_read(space->machine, "IN0") & 0x80; } -static WRITE8_HANDLER( copsnrob_misc_w ) +static WRITE8_HANDLER( copsnrob_misc2_w ) { copsnrob_state *state = space->machine->driver_data(); + state->misc = data & 0x7f; - set_led_status(space->machine, 1, ~data & 0x40); -} - -static WRITE8_HANDLER( copsnrob_led_w ) -{ - set_led_status(space->machine, 0, ~data & 0x01); + /* Multi Player Start */ + set_led_status(space->machine, 1, !((data >> 6) & 0x01)); } @@ -109,9 +104,7 @@ static WRITE8_HANDLER( copsnrob_led_w ) static ADDRESS_MAP_START( main_map, ADDRESS_SPACE_PROGRAM, 8 ) ADDRESS_MAP_GLOBAL_MASK(0x1fff) AM_RANGE(0x0000, 0x01ff) AM_RAM - AM_RANGE(0x0500, 0x0503) AM_WRITEONLY -// AM_RANGE(0x0504, 0x0507) AM_WRITENOP // ??? - AM_RANGE(0x0506, 0x0506) AM_WRITE(copsnrob_led_w) + AM_RANGE(0x0500, 0x0507) AM_WRITE(copsnrob_misc_w) AM_RANGE(0x0600, 0x0600) AM_WRITEONLY AM_BASE_MEMBER(copsnrob_state, trucky) AM_RANGE(0x0700, 0x07ff) AM_WRITEONLY AM_BASE_MEMBER(copsnrob_state, truckram) AM_RANGE(0x0800, 0x08ff) AM_RAM AM_BASE_MEMBER(copsnrob_state, bulletsram) @@ -122,8 +115,11 @@ static ADDRESS_MAP_START( main_map, ADDRESS_SPACE_PROGRAM, 8 ) // AM_RANGE(0x1000, 0x1003) AM_WRITENOP // AM_RANGE(0x1000, 0x1000) AM_READ_PORT("IN0") AM_RANGE(0x1000, 0x1000) AM_READ(copsnrob_misc_r) - AM_RANGE(0x1000, 0x1000) AM_WRITE(copsnrob_misc_w) - AM_RANGE(0x1002, 0x100e) AM_READ(copsnrob_gun_position_r) + AM_RANGE(0x1000, 0x1000) AM_WRITE(copsnrob_misc2_w) + AM_RANGE(0x1002, 0x1002) AM_READ_PORT("CTRL1") + AM_RANGE(0x1006, 0x1006) AM_READ_PORT("CTRL2") + AM_RANGE(0x100a, 0x100a) AM_READ_PORT("CTRL3") + AM_RANGE(0x100e, 0x100e) AM_READ_PORT("CTRL4") AM_RANGE(0x1012, 0x1012) AM_READ_PORT("DSW") AM_RANGE(0x1016, 0x1016) AM_READ_PORT("IN1") AM_RANGE(0x101a, 0x101a) AM_READ_PORT("IN2") @@ -138,6 +134,8 @@ ADDRESS_MAP_END * *************************************/ +static const int gun_table[] = {0x3f, 0x5f, 0x6f, 0x77, 0x7b, 0x7d, 0x7e}; + static INPUT_PORTS_START( copsnrob ) PORT_START("IN0") PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_VBLANK ) @@ -166,25 +164,20 @@ static INPUT_PORTS_START( copsnrob ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(2) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_PLAYER(1) - /* These input ports are fake */ - PORT_START("FAKE0") - PORT_BIT( 0x01, IP_ACTIVE_HIGH,IPT_JOYSTICK_UP ) PORT_4WAY PORT_PLAYER(1) - PORT_BIT( 0x02, IP_ACTIVE_HIGH,IPT_JOYSTICK_DOWN ) PORT_4WAY PORT_PLAYER(1) + PORT_START("CTRL1") + PORT_BIT( 0x7f, 0x03, IPT_POSITIONAL_V ) PORT_POSITIONS(7) PORT_REMAP_TABLE(gun_table) PORT_SENSITIVITY(15) PORT_KEYDELTA(1) PORT_CENTERDELTA(0) PORT_PLAYER(1) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) - PORT_START("FAKE1") - PORT_BIT( 0x01, IP_ACTIVE_HIGH,IPT_JOYSTICK_UP ) PORT_4WAY PORT_PLAYER(2) - PORT_BIT( 0x02, IP_ACTIVE_HIGH,IPT_JOYSTICK_DOWN ) PORT_4WAY PORT_PLAYER(2) + PORT_START("CTRL2") + PORT_BIT( 0x7f, 0x03, IPT_POSITIONAL_V ) PORT_POSITIONS(7) PORT_REMAP_TABLE(gun_table) PORT_SENSITIVITY(15) PORT_KEYDELTA(1) PORT_CENTERDELTA(0) PORT_PLAYER(2) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) - PORT_START("FAKE2") - PORT_BIT( 0x01, IP_ACTIVE_HIGH,IPT_JOYSTICK_UP ) PORT_4WAY PORT_PLAYER(3) - PORT_BIT( 0x02, IP_ACTIVE_HIGH,IPT_JOYSTICK_DOWN ) PORT_4WAY PORT_PLAYER(3) + PORT_START("CTRL3") + PORT_BIT( 0x7f, 0x03, IPT_POSITIONAL_V ) PORT_POSITIONS(7) PORT_REMAP_TABLE(gun_table) PORT_SENSITIVITY(15) PORT_KEYDELTA(1) PORT_CENTERDELTA(0) PORT_PLAYER(3) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3) - PORT_START("FAKE3") - PORT_BIT( 0x01, IP_ACTIVE_HIGH,IPT_JOYSTICK_UP ) PORT_4WAY PORT_PLAYER(4) - PORT_BIT( 0x02, IP_ACTIVE_HIGH,IPT_JOYSTICK_DOWN ) PORT_4WAY PORT_PLAYER(4) + PORT_START("CTRL4") + PORT_BIT( 0x7f, 0x03, IPT_POSITIONAL_V ) PORT_POSITIONS(7) PORT_REMAP_TABLE(gun_table) PORT_SENSITIVITY(15) PORT_KEYDELTA(1) PORT_CENTERDELTA(0) PORT_PLAYER(4) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(4) INPUT_PORTS_END @@ -260,6 +253,7 @@ static MACHINE_START( copsnrob ) { copsnrob_state *state = machine->driver_data(); + state_save_register_global(machine, state->ic_h3_data); state_save_register_global(machine, state->misc); } @@ -267,6 +261,7 @@ static MACHINE_RESET( copsnrob ) { copsnrob_state *state = machine->driver_data(); + state->ic_h3_data = 0; state->misc = 0; } @@ -293,6 +288,14 @@ static MACHINE_CONFIG_START( copsnrob, copsnrob_state ) MDRV_PALETTE_INIT(copsnrob) MDRV_VIDEO_UPDATE(copsnrob) + + /* sound hardware */ + MDRV_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + + MDRV_SOUND_ADD("discrete", DISCRETE, 0) + MDRV_SOUND_CONFIG_DISCRETE(copsnrob) + MDRV_SOUND_ROUTE(0, "lspeaker", 1.0) + MDRV_SOUND_ROUTE(1, "rspeaker", 1.0) MACHINE_CONFIG_END @@ -341,4 +344,4 @@ ROM_END * *************************************/ -GAMEL( 1976, copsnrob, 0, copsnrob, copsnrob, 0, ROT0, "Atari", "Cops'n Robbers", GAME_NO_SOUND | GAME_SUPPORTS_SAVE, layout_copsnrob ) +GAMEL( 1976, copsnrob, 0, copsnrob, copsnrob, 0, ROT0, "Atari", "Cops'n Robbers", GAME_IMPERFECT_SOUND | GAME_SUPPORTS_SAVE, layout_copsnrob ) diff --git a/src/mame/includes/copsnrob.h b/src/mame/includes/copsnrob.h index 929027c9c0f..965fb899cbe 100644 --- a/src/mame/includes/copsnrob.h +++ b/src/mame/includes/copsnrob.h @@ -4,6 +4,9 @@ *************************************************************************/ +#include "sound/discrete.h" + + class copsnrob_state : public driver_device { public: @@ -21,6 +24,7 @@ public: /* misc */ UINT8 misc; + UINT8 ic_h3_data; }; @@ -32,3 +36,9 @@ READ8_HANDLER( copsnrob_gun_position_r ); /*----------- defined in video/copsnrob.c -----------*/ VIDEO_UPDATE( copsnrob ); + + +/*----------- defined in audio/copsnrob.c -----------*/ + +DISCRETE_SOUND_EXTERN( copsnrob ); +WRITE8_HANDLER( copsnrob_misc_w ); diff --git a/src/mame/machine/copsnrob.c b/src/mame/machine/copsnrob.c deleted file mode 100644 index 578929498f5..00000000000 --- a/src/mame/machine/copsnrob.c +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - - Atari Cops'n Robbers hardware - -***************************************************************************/ - -#include "emu.h" -#include "includes/copsnrob.h" - -static const int gun_mask[] = {0x7e, 0x7d, 0x7b, 0x77, 0x6f, 0x5f, 0x3f}; - -// The gun control is a 7 position switch. I'm doing the following to -// emulate it: -// -// I read out the current gun position via the sprite image locations, -// and then decrement/increment it if the up/down keys are pressed. - -READ8_HANDLER( copsnrob_gun_position_r ) -{ - copsnrob_state *state = space->machine->driver_data(); - int keys, current_car_image, current_gun_pos = 0; - - // Determine which player we need - switch (offset) - { - default: - case 0x00: - current_car_image = state->carimage[0]; - keys = input_port_read(space->machine, "FAKE0"); - break; - case 0x04: - current_car_image = state->carimage[1]; - keys = input_port_read(space->machine, "FAKE1"); - break; - case 0x08: - current_car_image = state->carimage[2]; - keys = input_port_read(space->machine, "FAKE2"); - break; - case 0x0c: - current_car_image = state->carimage[3]; - keys = input_port_read(space->machine, "FAKE3"); - break; - } - - if (current_car_image < 7) - { - current_gun_pos = 6 - current_car_image; - } - else if (current_car_image < 14) - { - current_gun_pos = 13 - current_car_image; - } - - // Gun up - if ((keys & 0x01) && (current_gun_pos != 6)) current_gun_pos++; - - // Gun down - if ((keys & 0x02) && (current_gun_pos != 0)) current_gun_pos--; - - return (keys & 0x80) | gun_mask[current_gun_pos]; -} diff --git a/src/mame/mame.mak b/src/mame/mame.mak index 57fc0a63e9b..8f0d6b3fa7f 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -411,7 +411,7 @@ $(MAMEOBJ)/atari.a: \ $(DRIVERS)/cloud9.o $(VIDEO)/cloud9.o \ $(DRIVERS)/cmmb.o \ $(DRIVERS)/cojag.o $(AUDIO)/jaguar.o $(VIDEO)/jaguar.o \ - $(DRIVERS)/copsnrob.o $(MACHINE)/copsnrob.o $(VIDEO)/copsnrob.o \ + $(DRIVERS)/copsnrob.o $(AUDIO)/copsnrob.o $(VIDEO)/copsnrob.o \ $(DRIVERS)/cyberbal.o $(AUDIO)/cyberbal.o $(VIDEO)/cyberbal.o \ $(DRIVERS)/destroyr.o \ $(DRIVERS)/dragrace.o $(AUDIO)/dragrace.o $(VIDEO)/dragrace.o \