summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/video/resnet.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/video/resnet.c')
-rw-r--r--trunk/src/emu/video/resnet.c725
1 files changed, 725 insertions, 0 deletions
diff --git a/trunk/src/emu/video/resnet.c b/trunk/src/emu/video/resnet.c
new file mode 100644
index 00000000000..35d98e376ba
--- /dev/null
+++ b/trunk/src/emu/video/resnet.c
@@ -0,0 +1,725 @@
+/*****************************************************************************
+
+ resnet.c
+
+ Compute weights for resistors networks.
+
+ Copyright Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+******************************************************************************
+
+ Function can evaluate from one to three networks at a time.
+
+ The output weights can either be scaled with automatically calculated scaler
+ or scaled with a 'scaler' provided on entry.
+
+ On entry
+ --------
+
+ 'minval','maxval' specify the range of output signals (sum of weights).
+ 'scaler' if negative, function will calculate proper scaler,
+ otherwise it will use the one provided here.
+ 'count_x' is the number of resistors in this network
+ 'resistances_x' is the pointer to a table containing the resistances
+ 'weights_x' is the pointer to a table to be filled with the weights
+ (it can contain negative values if 'minval' is below zero).
+ 'pulldown_x' is the resistance of a pulldown resistor (0 means there's no pulldown resistor)
+ 'pullup_x' is the resistance of a pullup resistor (0 means there's no pullup resistor)
+
+
+ Return value
+ ------------
+
+ The value of the scaler that was used for fitting the output within the expected range.
+ Note that if you provide your own scaler on entry it will be returned here.
+
+
+ All resistances are expected in Ohms.
+
+
+ Hint
+ ----
+
+ If there is no need to calculate all three networks at a time, just specify '0'
+ for the 'count_x' for unused network(s).
+
+*****************************************************************************/
+
+
+#include "emu.h"
+#include "resnet.h"
+
+#define VERBOSE 0
+
+
+double compute_resistor_weights(
+ int minval, int maxval, double scaler,
+ int count_1, const int * resistances_1, double * weights_1, int pulldown_1, int pullup_1,
+ int count_2, const int * resistances_2, double * weights_2, int pulldown_2, int pullup_2,
+ int count_3, const int * resistances_3, double * weights_3, int pulldown_3, int pullup_3 )
+{
+
+ int networks_no;
+
+ int rescount[MAX_NETS]; /* number of resistors in each of the nets */
+ double r[MAX_NETS][MAX_RES_PER_NET]; /* resistances */
+ double w[MAX_NETS][MAX_RES_PER_NET]; /* calulated weights */
+ double ws[MAX_NETS][MAX_RES_PER_NET]; /* calulated, scaled weights */
+ int r_pd[MAX_NETS]; /* pulldown resistances */
+ int r_pu[MAX_NETS]; /* pullup resistances */
+
+ double max_out[MAX_NETS];
+ double * out[MAX_NETS];
+
+ int i,j,n;
+ double scale;
+ double max;
+
+ /* parse input parameters */
+
+ networks_no = 0;
+ for (n = 0; n < MAX_NETS; n++)
+ {
+ int count, pd, pu;
+ const int * resistances;
+ double * weights;
+
+ switch(n){
+ case 0:
+ count = count_1;
+ resistances = resistances_1;
+ weights = weights_1;
+ pd = pulldown_1;
+ pu = pullup_1;
+ break;
+ case 1:
+ count = count_2;
+ resistances = resistances_2;
+ weights = weights_2;
+ pd = pulldown_2;
+ pu = pullup_2;
+ break;
+ case 2:
+ default:
+ count = count_3;
+ resistances = resistances_3;
+ weights = weights_3;
+ pd = pulldown_3;
+ pu = pullup_3;
+ break;
+ }
+
+ /* parameters validity check */
+ if (count > MAX_RES_PER_NET)
+ fatalerror("compute_resistor_weights(): too many resistors in net #%i. The maximum allowed is %i, the number requested was: %i\n",n, MAX_RES_PER_NET, count);
+
+
+ if (count > 0)
+ {
+ rescount[networks_no] = count;
+ for (i=0; i < count; i++)
+ {
+ r[networks_no][i] = 1.0 * resistances[i];
+ }
+ out[networks_no] = weights;
+ r_pd[networks_no] = pd;
+ r_pu[networks_no] = pu;
+ networks_no++;
+ }
+ }
+ if (networks_no < 1)
+ fatalerror("compute_resistor_weights(): no input data\n");
+
+ /* calculate outputs for all given networks */
+ for( i = 0; i < networks_no; i++ )
+ {
+ double R0, R1, Vout, dst;
+
+ /* of n resistors */
+ for(n = 0; n < rescount[i]; n++)
+ {
+ R0 = ( r_pd[i] == 0 ) ? 1.0/1e12 : 1.0/r_pd[i];
+ R1 = ( r_pu[i] == 0 ) ? 1.0/1e12 : 1.0/r_pu[i];
+
+ for( j = 0; j < rescount[i]; j++ )
+ {
+ if( j==n ) /* only one resistance in the network connected to Vcc */
+ {
+ if (r[i][j] != 0.0)
+ R1 += 1.0/r[i][j];
+ }
+ else
+ if (r[i][j] != 0.0)
+ R0 += 1.0/r[i][j];
+ }
+
+ /* now determine the voltage */
+ R0 = 1.0/R0;
+ R1 = 1.0/R1;
+ Vout = (maxval - minval) * R0 / (R1 + R0) + minval;
+
+ /* and convert it to a destination value */
+ dst = (Vout < minval) ? minval : (Vout > maxval) ? maxval : Vout;
+
+ w[i][n] = dst;
+ }
+ }
+
+ /* calculate maximum outputs for all given networks */
+ j = 0;
+ max = 0.0;
+ for( i = 0; i < networks_no; i++ )
+ {
+ double sum = 0.0;
+
+ /* of n resistors */
+ for( n = 0; n < rescount[i]; n++ )
+ sum += w[i][n]; /* maximum output, ie when each resistance is connected to Vcc */
+
+ max_out[i] = sum;
+ if (max < sum)
+ {
+ max = sum;
+ j = i;
+ }
+ }
+
+
+ if (scaler < 0.0) /* use autoscale ? */
+ /* calculate the output scaler according to the network with the greatest output */
+ scale = ((double)maxval) / max_out[j];
+ else /* use scaler provided on entry */
+ scale = scaler;
+
+ /* calculate scaled output and fill the output table(s)*/
+ for(i = 0; i < networks_no;i++)
+ {
+ for (n = 0; n < rescount[i]; n++)
+ {
+ ws[i][n] = w[i][n]*scale; /* scale the result */
+ (out[i])[n] = ws[i][n]; /* fill the output table */
+ }
+ }
+
+/* debug code */
+if (VERBOSE)
+{
+ logerror("compute_resistor_weights(): scaler = %15.10f\n",scale);
+ logerror("min val :%i max val:%i Total number of networks :%i\n", minval, maxval, networks_no );
+
+ for(i = 0; i < networks_no;i++)
+ {
+ double sum = 0.0;
+
+ logerror(" Network no.%i=> resistances: %i", i, rescount[i] );
+ if (r_pu[i] != 0)
+ logerror(", pullup resistor: %i Ohms",r_pu[i]);
+ if (r_pd[i] != 0)
+ logerror(", pulldown resistor: %i Ohms",r_pd[i]);
+ logerror("\n maximum output of this network:%10.5f (scaled to %15.10f)\n", max_out[i], max_out[i]*scale );
+ for (n = 0; n < rescount[i]; n++)
+ {
+ logerror(" res %2i:%9.1f Ohms weight=%10.5f (scaled = %15.10f)\n", n, r[i][n], w[i][n], ws[i][n] );
+ sum += ws[i][n];
+ }
+ logerror(" sum of scaled weights = %15.10f\n", sum );
+ }
+}
+/* debug end */
+
+ return (scale);
+
+}
+
+
+double compute_resistor_net_outputs(
+ int minval, int maxval, double scaler,
+ int count_1, const int * resistances_1, double * outputs_1, int pulldown_1, int pullup_1,
+ int count_2, const int * resistances_2, double * outputs_2, int pulldown_2, int pullup_2,
+ int count_3, const int * resistances_3, double * outputs_3, int pulldown_3, int pullup_3 )
+{
+
+ int networks_no;
+
+ int rescount[MAX_NETS]; /* number of resistors in each of the nets */
+ double r[MAX_NETS][MAX_RES_PER_NET]; /* resistances */
+ double *o; /* calulated outputs */
+ double *os; /* calulated, scaled outputss */
+ int r_pd[MAX_NETS]; /* pulldown resistances */
+ int r_pu[MAX_NETS]; /* pullup resistances */
+
+ double max_out[MAX_NETS];
+ double min_out[MAX_NETS];
+ double * out[MAX_NETS];
+
+ int i,j,n;
+ double scale;
+ double min;
+ double max;
+
+ /* parse input parameters */
+
+ o = global_alloc_array(double, (1<<MAX_RES_PER_NET) * MAX_NETS);
+ os = global_alloc_array(double, (1<<MAX_RES_PER_NET) * MAX_NETS);
+
+ networks_no = 0;
+ for (n = 0; n < MAX_NETS; n++)
+ {
+ int count, pd, pu;
+ const int * resistances;
+ double * weights;
+
+ switch(n){
+ case 0:
+ count = count_1;
+ resistances = resistances_1;
+ weights = outputs_1;
+ pd = pulldown_1;
+ pu = pullup_1;
+ break;
+ case 1:
+ count = count_2;
+ resistances = resistances_2;
+ weights = outputs_2;
+ pd = pulldown_2;
+ pu = pullup_2;
+ break;
+ case 2:
+ default:
+ count = count_3;
+ resistances = resistances_3;
+ weights = outputs_3;
+ pd = pulldown_3;
+ pu = pullup_3;
+ break;
+ }
+
+ /* parameters validity check */
+ if (count > MAX_RES_PER_NET)
+ fatalerror("compute_resistor_net_outputs(): too many resistors in net #%i. The maximum allowed is %i, the number requested was: %i\n",n, MAX_RES_PER_NET, count);
+
+ if (count > 0)
+ {
+ rescount[networks_no] = count;
+ for (i=0; i < count; i++)
+ {
+ r[networks_no][i] = 1.0 * resistances[i];
+ }
+ out[networks_no] = weights;
+ r_pd[networks_no] = pd;
+ r_pu[networks_no] = pu;
+ networks_no++;
+ }
+ }
+
+ if (networks_no<1)
+ fatalerror("compute_resistor_net_outputs(): no input data\n");
+
+ /* calculate outputs for all given networks */
+ for( i = 0; i < networks_no; i++ )
+ {
+ double R0, R1, Vout, dst;
+
+ /* of n resistors, generating 1<<n possible outputs */
+ for(n = 0; n < (1<<rescount[i]); n++)
+ {
+ R0 = ( r_pd[i] == 0 ) ? 1.0/1e12 : 1.0/r_pd[i];
+ R1 = ( r_pu[i] == 0 ) ? 1.0/1e12 : 1.0/r_pu[i];
+
+ for( j = 0; j < rescount[i]; j++ )
+ {
+ if( (n & (1<<j)) == 0 )/* only when this resistance in the network connected to GND */
+ if (r[i][j] != 0.0)
+ R0 += 1.0/r[i][j];
+ }
+
+ /* now determine the voltage */
+ R0 = 1.0/R0;
+ R1 = 1.0/R1;
+ Vout = (maxval - minval) * R0 / (R1 + R0) + minval;
+
+ /* and convert it to a destination value */
+ dst = (Vout < minval) ? minval : (Vout > maxval) ? maxval : Vout;
+
+ o[i*(1<<MAX_RES_PER_NET)+n] = dst;
+ }
+ }
+
+ /* calculate minimum outputs for all given networks */
+ j = 0;
+ min = maxval;
+ max = minval;
+ for( i = 0; i < networks_no; i++ )
+ {
+ double val = 0.0;
+ double max_tmp = minval;
+ double min_tmp = maxval;
+
+ for (n = 0; n < (1<<rescount[i]); n++)
+ {
+ if (min_tmp > o[i*(1<<MAX_RES_PER_NET)+n])
+ min_tmp = o[i*(1<<MAX_RES_PER_NET)+n];
+ if (max_tmp < o[i*(1<<MAX_RES_PER_NET)+n])
+ max_tmp = o[i*(1<<MAX_RES_PER_NET)+n];
+ }
+
+ max_out[i] = max_tmp; /* maximum output */
+ min_out[i] = min_tmp; /* minimum output */
+
+ val = min_out[i]; /* minimum output of this network */
+ if (min > val)
+ {
+ min = val;
+ }
+ val = max_out[i]; /* maximum output of this network */
+ if (max < val)
+ {
+ max = val;
+ }
+ }
+
+
+ if (scaler < 0.0) /* use autoscale ? */
+ /* calculate the output scaler according to the network with the smallest output */
+ scale = ((double)maxval) / (max-min);
+ else /* use scaler provided on entry */
+ scale = scaler;
+
+ /* calculate scaled output and fill the output table(s) */
+ for(i = 0; i < networks_no; i++)
+ {
+ for (n = 0; n < (1<<rescount[i]); n++)
+ {
+ os[i*(1<<MAX_RES_PER_NET)+n] = (o[i*(1<<MAX_RES_PER_NET)+n] - min) * scale; /* scale the result */
+ (out[i])[n] = os[i*(1<<MAX_RES_PER_NET)+n]; /* fill the output table */
+ }
+ }
+
+/* debug code */
+if (VERBOSE)
+{
+ logerror("compute_resistor_net_outputs(): scaler = %15.10f\n",scale);
+ logerror("min val :%i max val:%i Total number of networks :%i\n", minval, maxval, networks_no );
+
+ for(i = 0; i < networks_no;i++)
+ {
+ logerror(" Network no.%i=> resistances: %i", i, rescount[i] );
+ if (r_pu[i] != 0)
+ logerror(", pullup resistor: %i Ohms",r_pu[i]);
+ if (r_pd[i] != 0)
+ logerror(", pulldown resistor: %i Ohms",r_pd[i]);
+ logerror("\n maximum output of this network:%10.5f", max_out[i] );
+ logerror("\n minimum output of this network:%10.5f\n", min_out[i] );
+ for (n = 0; n < rescount[i]; n++)
+ {
+ logerror(" res %2i:%9.1f Ohms\n", n, r[i][n]);
+ }
+ for (n = 0; n < (1<<rescount[i]); n++)
+ {
+ logerror(" combination %2i out=%10.5f (scaled = %15.10f)\n", n, o[i*(1<<MAX_RES_PER_NET)+n], os[i*(1<<MAX_RES_PER_NET)+n] );
+ }
+ }
+}
+/* debug end */
+
+ global_free(o);
+ global_free(os);
+ return (scale);
+
+}
+
+/*****************************************************************************
+
+ New Interface
+
+*****************************************************************************/
+
+
+/* Datasheets give a maximum of 0.4V to 0.5V
+ * However in the circuit simulated here this will only
+ * occur if (rBias + rOutn) = 50 Ohm, rBias exists.
+ * This is highly unlikely. With the resistor values used
+ * in such circuits VOL is likely to be around 50mV.
+ */
+
+#define TTL_VOL (0.05)
+
+
+/* Likely, datasheets give a typical value of 3.4V to 3.6V
+ * for VOH. Modelling the TTL circuit however backs a value
+ * of 4V for typical currents involved in resistor networks.
+ */
+
+#define TTL_VOH (4.0)
+
+int compute_res_net(int inputs, int channel, const res_net_info *di)
+{
+ double rTotal=0.0;
+ double v = 0;
+ int i;
+
+ double vBias = di->rgb[channel].vBias;
+ double vOH = di->vOH;
+ double vOL = di->vOL;
+ double minout = di->rgb[channel].minout;
+ double cut = di->rgb[channel].cut;
+ double vcc = di->vcc;
+ double ttlHRes = 0;
+ double rGnd = di->rgb[channel].rGnd;
+ UINT8 OpenCol = di->OpenCol;
+
+ /* Global options */
+
+ switch (di->options & RES_NET_AMP_MASK)
+ {
+ case RES_NET_AMP_USE_GLOBAL:
+ /* just ignore */
+ break;
+ case RES_NET_AMP_NONE:
+ minout = 0.0;
+ cut = 0.0;
+ break;
+ case RES_NET_AMP_DARLINGTON:
+ minout = 0.9;
+ cut = 0.0;
+ break;
+ case RES_NET_AMP_EMITTER:
+ minout = 0.0;
+ cut = 0.7;
+ break;
+ case RES_NET_AMP_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown amplifier type");
+ }
+
+ switch (di->options & RES_NET_VCC_MASK)
+ {
+ case RES_NET_VCC_5V:
+ vcc = 5.0;
+ break;
+ case RES_NET_VCC_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown vcc type");
+ }
+
+ switch (di->options & RES_NET_VBIAS_MASK)
+ {
+ case RES_NET_VBIAS_USE_GLOBAL:
+ /* just ignore */
+ break;
+ case RES_NET_VBIAS_5V:
+ vBias = 5.0;
+ break;
+ case RES_NET_VBIAS_TTL:
+ vBias = TTL_VOH;
+ break;
+ case RES_NET_VBIAS_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown vcc type");
+ }
+
+ switch (di->options & RES_NET_VIN_MASK)
+ {
+ case RES_NET_VIN_OPEN_COL:
+ OpenCol = 1;
+ vOL = TTL_VOL;
+ break;
+ case RES_NET_VIN_VCC:
+ vOL = 0.0;
+ vOH = vcc;
+ OpenCol = 0;
+ break;
+ case RES_NET_VIN_TTL_OUT:
+ vOL = TTL_VOL;
+ vOH = TTL_VOH;
+ /* rough estimation from 82s129 (7052) datasheet and from various sources
+ * 1.4k / 30
+ */
+ ttlHRes = 50;
+ OpenCol = 0;
+ break;
+ case RES_NET_VIN_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown vin type");
+ }
+
+ /* Per channel options */
+
+ switch (di->rgb[channel].options & RES_NET_AMP_MASK)
+ {
+ case RES_NET_AMP_USE_GLOBAL:
+ /* use global defaults */
+ break;
+ case RES_NET_AMP_NONE:
+ minout = 0.0;
+ cut = 0.0;
+ break;
+ case RES_NET_AMP_DARLINGTON:
+ minout = 0.7;
+ cut = 0.0;
+ break;
+ case RES_NET_AMP_EMITTER:
+ minout = 0.0;
+ cut = 0.7;
+ break;
+ case RES_NET_AMP_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown amplifier type");
+ }
+
+ switch (di->rgb[channel].options & RES_NET_VBIAS_MASK)
+ {
+ case RES_NET_VBIAS_USE_GLOBAL:
+ /* use global defaults */
+ break;
+ case RES_NET_VBIAS_5V:
+ vBias = 5.0;
+ break;
+ case RES_NET_VBIAS_TTL:
+ vBias = TTL_VOH;
+ break;
+ case RES_NET_VBIAS_CUSTOM:
+ /* Fall through */
+ break;
+ default:
+ fatalerror("compute_res_net: Unknown vcc type");
+ }
+
+ /* Input impedances */
+
+ switch (di->options & RES_NET_MONITOR_MASK)
+ {
+ case RES_NET_MONITOR_INVERT:
+ case RES_NET_MONITOR_SANYO_EZV20:
+ /* Nothing */
+ break;
+ case RES_NET_MONITOR_ELECTROHOME_G07:
+ if (rGnd != 0.0)
+ rGnd = rGnd * 5600 / (rGnd + 5600);
+ else
+ rGnd = 5600;
+ break;
+ }
+
+ /* compute here - pass a / low inputs */
+
+ for (i=0; i<di->rgb[channel].num; i++)
+ {
+ int level = ((inputs >> i) & 1);
+ if (di->rgb[channel].R[i] != 0.0 && !level)
+ {
+ if (OpenCol)
+ {
+ rTotal += 1.0 / di->rgb[channel].R[i];
+ v += vOL / di->rgb[channel].R[i];
+ }
+ else
+ {
+ rTotal += 1.0 / di->rgb[channel].R[i];
+ v += vOL / di->rgb[channel].R[i];
+ }
+ }
+ }
+
+ /* Mix in rbias and rgnd */
+ if ( di->rgb[channel].rBias != 0.0 )
+ {
+ rTotal += 1.0 / di->rgb[channel].rBias;
+ v += vBias / di->rgb[channel].rBias;
+ }
+ if (rGnd != 0.0)
+ rTotal += 1.0 / rGnd;
+
+ /* if the resulting voltage after application of all low inputs is
+ * greater than vOH, treat high inputs as open collector/high impedance
+ * There will be now current into/from the TTL gate
+ */
+
+ if ( (di->options & RES_NET_VIN_MASK)==RES_NET_VIN_TTL_OUT)
+ {
+ if (v / rTotal > vOH)
+ OpenCol = 1;
+ }
+
+ /* Second pass - high inputs */
+
+ for (i=0; i<di->rgb[channel].num; i++)
+ {
+ int level = ((inputs >> i) & 1);
+ if (di->rgb[channel].R[i] != 0.0 && level)
+ {
+ if (OpenCol)
+ {
+ rTotal += 0;
+ v += 0;
+ }
+ else
+ {
+ rTotal += 1.0 / (di->rgb[channel].R[i] + ttlHRes);
+ v += vOH / (di->rgb[channel].R[i] + ttlHRes);
+ }
+ }
+ }
+
+ rTotal = 1.0 / rTotal;
+ v *= rTotal;
+ v = MAX(minout, v - cut);
+
+ switch (di->options & RES_NET_MONITOR_MASK)
+ {
+ case RES_NET_MONITOR_INVERT:
+ v = vcc - v;
+ break;
+ case RES_NET_MONITOR_SANYO_EZV20:
+ v = vcc - v;
+ v = MAX(0, v-0.7);
+ v = MIN(v, vcc - 2 * 0.7);
+ v = v / (vcc-1.4);
+ v = v * vcc;
+ break;
+ case RES_NET_MONITOR_ELECTROHOME_G07:
+ /* Nothing */
+ break;
+ }
+
+ return (int) (v * 255 / vcc + 0.4);
+}
+
+rgb_t *compute_res_net_all(running_machine &machine, const UINT8 *prom, const res_net_decode_info *rdi, const res_net_info *di)
+{
+ UINT8 r,g,b;
+ int i,j,k;
+ rgb_t *rgb;
+
+ rgb = auto_alloc_array(machine, rgb_t, rdi->end - rdi->start + 1);
+ for (i=rdi->start; i<=rdi->end; i++)
+ {
+ UINT8 t[3] = {0,0,0};
+ int s;
+ for (j=0;j<rdi->numcomp;j++)
+ for (k=0; k<3; k++)
+ {
+ s = rdi->shift[3*j+k];
+ if (s>0)
+ t[k] = t[k] | ( (prom[i+rdi->offset[3*j+k]]>>s) & rdi->mask[3*j+k]);
+ else
+ t[k] = t[k] | ( (prom[i+rdi->offset[3*j+k]]<<(0-s)) & rdi->mask[3*j+k]);
+ }
+ r = compute_res_net(t[0], RES_NET_CHAN_RED, di);
+ g = compute_res_net(t[1], RES_NET_CHAN_GREEN, di);
+ b = compute_res_net(t[2], RES_NET_CHAN_BLUE, di);
+ rgb[i-rdi->start] = MAKE_RGB(r,g,b);
+ }
+ return rgb;
+}