1 // license:BSD-3-Clause
2 // copyright-holders:Couriersud
3 /*****************************************************************************
4
5 resnet.cpp
6
7 Compute weights for resistors networks.
8
9 ******************************************************************************
10
11 Function can evaluate from one to three networks at a time.
12
13 The output weights can either be scaled with automatically calculated scaler
14 or scaled with a 'scaler' provided on entry.
15
16 On entry
17 --------
18
19 'minval','maxval' specify the range of output signals (sum of weights).
20 'scaler' if negative, function will calculate proper scaler,
21 otherwise it will use the one provided here.
22 'count_x' is the number of resistors in this network
23 'resistances_x' is the pointer to a table containing the resistances
24 'weights_x' is the pointer to a table to be filled with the weights
25 (it can contain negative values if 'minval' is below zero).
26 'pulldown_x' is the resistance of a pulldown resistor (0 means there's no pulldown resistor)
27 'pullup_x' is the resistance of a pullup resistor (0 means there's no pullup resistor)
28
29
30 Return value
31 ------------
32
33 The value of the scaler that was used for fitting the output within the expected range.
34 Note that if you provide your own scaler on entry it will be returned here.
35
36
37 All resistances are expected in Ohms.
38
39
40 Hint
41 ----
42
43 If there is no need to calculate all three networks at a time, just specify '0'
44 for the 'count_x' for unused network(s).
45
46 *****************************************************************************/
47
48
49 #include "emu.h"
50 #include "resnet.h"
51
52 #define VERBOSE 0
53
54
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)55 double compute_resistor_weights(
56 int minval, int maxval, double scaler,
57 int count_1, const int * resistances_1, double * weights_1, int pulldown_1, int pullup_1,
58 int count_2, const int * resistances_2, double * weights_2, int pulldown_2, int pullup_2,
59 int count_3, const int * resistances_3, double * weights_3, int pulldown_3, int pullup_3 )
60 {
61 int networks_no;
62
63 int rescount[MAX_NETS]; /* number of resistors in each of the nets */
64 double r[MAX_NETS][MAX_RES_PER_NET]; /* resistances */
65 double w[MAX_NETS][MAX_RES_PER_NET]; /* calulated weights */
66 double ws[MAX_NETS][MAX_RES_PER_NET]; /* calulated, scaled weights */
67 int r_pd[MAX_NETS]; /* pulldown resistances */
68 int r_pu[MAX_NETS]; /* pullup resistances */
69
70 double max_out[MAX_NETS];
71 double * out[MAX_NETS];
72
73 int i,j,n;
74 double scale;
75 double max;
76
77 /* parse input parameters */
78
79 networks_no = 0;
80 for (n = 0; n < MAX_NETS; n++)
81 {
82 int count, pd, pu;
83 const int * resistances;
84 double * weights;
85
86 switch(n){
87 case 0:
88 count = count_1;
89 resistances = resistances_1;
90 weights = weights_1;
91 pd = pulldown_1;
92 pu = pullup_1;
93 break;
94 case 1:
95 count = count_2;
96 resistances = resistances_2;
97 weights = weights_2;
98 pd = pulldown_2;
99 pu = pullup_2;
100 break;
101 case 2:
102 default:
103 count = count_3;
104 resistances = resistances_3;
105 weights = weights_3;
106 pd = pulldown_3;
107 pu = pullup_3;
108 break;
109 }
110
111 /* parameters validity check */
112 if (count > MAX_RES_PER_NET)
113 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);
114
115
116 if (count > 0)
117 {
118 rescount[networks_no] = count;
119 for (i=0; i < count; i++)
120 {
121 r[networks_no][i] = 1.0 * resistances[i];
122 }
123 out[networks_no] = weights;
124 r_pd[networks_no] = pd;
125 r_pu[networks_no] = pu;
126 networks_no++;
127 }
128 }
129 if (networks_no < 1)
130 fatalerror("compute_resistor_weights(): no input data\n");
131
132 /* calculate outputs for all given networks */
133 for( i = 0; i < networks_no; i++ )
134 {
135 double R0, R1, Vout, dst;
136
137 /* of n resistors */
138 for(n = 0; n < rescount[i]; n++)
139 {
140 R0 = ( r_pd[i] == 0 ) ? 1.0/1e12 : 1.0/r_pd[i];
141 R1 = ( r_pu[i] == 0 ) ? 1.0/1e12 : 1.0/r_pu[i];
142
143 for( j = 0; j < rescount[i]; j++ )
144 {
145 if( j==n ) /* only one resistance in the network connected to Vcc */
146 {
147 if (r[i][j] != 0.0)
148 R1 += 1.0/r[i][j];
149 }
150 else
151 if (r[i][j] != 0.0)
152 R0 += 1.0/r[i][j];
153 }
154
155 /* now determine the voltage */
156 R0 = 1.0/R0;
157 R1 = 1.0/R1;
158 Vout = (maxval - minval) * R0 / (R1 + R0) + minval;
159
160 /* and convert it to a destination value */
161 dst = (Vout < minval) ? minval : (Vout > maxval) ? maxval : Vout;
162
163 w[i][n] = dst;
164 }
165 }
166
167 /* calculate maximum outputs for all given networks */
168 j = 0;
169 max = 0.0;
170 for( i = 0; i < networks_no; i++ )
171 {
172 double sum = 0.0;
173
174 /* of n resistors */
175 for( n = 0; n < rescount[i]; n++ )
176 sum += w[i][n]; /* maximum output, ie when each resistance is connected to Vcc */
177
178 max_out[i] = sum;
179 if (max < sum)
180 {
181 max = sum;
182 j = i;
183 }
184 }
185
186
187 if (scaler < 0.0) /* use autoscale ? */
188 /* calculate the output scaler according to the network with the greatest output */
189 scale = ((double)maxval) / max_out[j];
190 else /* use scaler provided on entry */
191 scale = scaler;
192
193 /* calculate scaled output and fill the output table(s)*/
194 for(i = 0; i < networks_no;i++)
195 {
196 for (n = 0; n < rescount[i]; n++)
197 {
198 ws[i][n] = w[i][n]*scale; /* scale the result */
199 (out[i])[n] = ws[i][n]; /* fill the output table */
200 }
201 }
202
203 /* debug code */
204 if (VERBOSE)
205 {
206 osd_printf_info("compute_resistor_weights(): scaler = %15.10f\n",scale);
207 osd_printf_info("min val :%i max val:%i Total number of networks :%i\n", minval, maxval, networks_no );
208
209 for(i = 0; i < networks_no;i++)
210 {
211 double sum = 0.0;
212
213 osd_printf_info(" Network no.%i=> resistances: %i", i, rescount[i] );
214 if (r_pu[i] != 0)
215 osd_printf_info(", pullup resistor: %i Ohms",r_pu[i]);
216 if (r_pd[i] != 0)
217 osd_printf_info(", pulldown resistor: %i Ohms",r_pd[i]);
218 osd_printf_info("\n maximum output of this network:%10.5f (scaled to %15.10f)\n", max_out[i], max_out[i]*scale );
219 for (n = 0; n < rescount[i]; n++)
220 {
221 osd_printf_info(" res %2i:%9.1f Ohms weight=%10.5f (scaled = %15.10f)\n", n, r[i][n], w[i][n], ws[i][n] );
222 sum += ws[i][n];
223 }
224 osd_printf_info(" sum of scaled weights = %15.10f\n", sum );
225 }
226 }
227 /* debug end */
228
229 return (scale);
230
231 }
232
233
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)234 double compute_resistor_net_outputs(
235 int minval, int maxval, double scaler,
236 int count_1, const int * resistances_1, double * outputs_1, int pulldown_1, int pullup_1,
237 int count_2, const int * resistances_2, double * outputs_2, int pulldown_2, int pullup_2,
238 int count_3, const int * resistances_3, double * outputs_3, int pulldown_3, int pullup_3 )
239 {
240 int networks_no;
241
242 int rescount[MAX_NETS]; /* number of resistors in each of the nets */
243 double r[MAX_NETS][MAX_RES_PER_NET]; /* resistances */
244 int r_pd[MAX_NETS]; /* pulldown resistances */
245 int r_pu[MAX_NETS]; /* pullup resistances */
246
247 double max_out[MAX_NETS];
248 double min_out[MAX_NETS];
249 double * out[MAX_NETS];
250
251 int i,j,n;
252 double scale;
253 double min;
254 double max;
255
256 /* parse input parameters */
257
258 std::vector<double> o((1<<MAX_RES_PER_NET) * MAX_NETS);
259 std::vector<double> os((1<<MAX_RES_PER_NET) * MAX_NETS);
260
261 networks_no = 0;
262 for (n = 0; n < MAX_NETS; n++)
263 {
264 int count, pd, pu;
265 const int * resistances;
266 double * weights;
267
268 switch(n){
269 case 0:
270 count = count_1;
271 resistances = resistances_1;
272 weights = outputs_1;
273 pd = pulldown_1;
274 pu = pullup_1;
275 break;
276 case 1:
277 count = count_2;
278 resistances = resistances_2;
279 weights = outputs_2;
280 pd = pulldown_2;
281 pu = pullup_2;
282 break;
283 case 2:
284 default:
285 count = count_3;
286 resistances = resistances_3;
287 weights = outputs_3;
288 pd = pulldown_3;
289 pu = pullup_3;
290 break;
291 }
292
293 /* parameters validity check */
294 if (count > MAX_RES_PER_NET)
295 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);
296
297 if (count > 0)
298 {
299 rescount[networks_no] = count;
300 for (i=0; i < count; i++)
301 {
302 r[networks_no][i] = 1.0 * resistances[i];
303 }
304 out[networks_no] = weights;
305 r_pd[networks_no] = pd;
306 r_pu[networks_no] = pu;
307 networks_no++;
308 }
309 }
310
311 if (networks_no<1)
312 fatalerror("compute_resistor_net_outputs(): no input data\n");
313
314 /* calculate outputs for all given networks */
315 for( i = 0; i < networks_no; i++ )
316 {
317 double R0, R1, Vout, dst;
318
319 /* of n resistors, generating 1<<n possible outputs */
320 for(n = 0; n < (1<<rescount[i]); n++)
321 {
322 R0 = ( r_pd[i] == 0 ) ? 1.0/1e12 : 1.0/r_pd[i];
323 R1 = ( r_pu[i] == 0 ) ? 1.0/1e12 : 1.0/r_pu[i];
324
325 for( j = 0; j < rescount[i]; j++ )
326 {
327 if( (n & (1<<j)) == 0 )/* only when this resistance in the network connected to GND */
328 if (r[i][j] != 0.0)
329 R0 += 1.0/r[i][j];
330 }
331
332 /* now determine the voltage */
333 R0 = 1.0/R0;
334 R1 = 1.0/R1;
335 Vout = (maxval - minval) * R0 / (R1 + R0) + minval;
336
337 /* and convert it to a destination value */
338 dst = (Vout < minval) ? minval : (Vout > maxval) ? maxval : Vout;
339
340 o[i*(1<<MAX_RES_PER_NET)+n] = dst;
341 }
342 }
343
344 /* calculate minimum outputs for all given networks */
345 min = maxval;
346 max = minval;
347 for( i = 0; i < networks_no; i++ )
348 {
349 double val;
350 double max_tmp = minval;
351 double min_tmp = maxval;
352
353 for (n = 0; n < (1<<rescount[i]); n++)
354 {
355 if (min_tmp > o[i*(1<<MAX_RES_PER_NET)+n])
356 min_tmp = o[i*(1<<MAX_RES_PER_NET)+n];
357 if (max_tmp < o[i*(1<<MAX_RES_PER_NET)+n])
358 max_tmp = o[i*(1<<MAX_RES_PER_NET)+n];
359 }
360
361 max_out[i] = max_tmp; /* maximum output */
362 min_out[i] = min_tmp; /* minimum output */
363
364 val = min_out[i]; /* minimum output of this network */
365 if (min > val)
366 {
367 min = val;
368 }
369 val = max_out[i]; /* maximum output of this network */
370 if (max < val)
371 {
372 max = val;
373 }
374 }
375
376
377 if (scaler < 0.0) /* use autoscale ? */
378 /* calculate the output scaler according to the network with the smallest output */
379 scale = ((double)maxval) / (max-min);
380 else /* use scaler provided on entry */
381 scale = scaler;
382
383 /* calculate scaled output and fill the output table(s) */
384 for(i = 0; i < networks_no; i++)
385 {
386 for (n = 0; n < (1<<rescount[i]); n++)
387 {
388 os[i*(1<<MAX_RES_PER_NET)+n] = (o[i*(1<<MAX_RES_PER_NET)+n] - min) * scale; /* scale the result */
389 (out[i])[n] = os[i*(1<<MAX_RES_PER_NET)+n]; /* fill the output table */
390 }
391 }
392
393 /* debug code */
394 if (VERBOSE)
395 {
396 osd_printf_info("compute_resistor_net_outputs(): scaler = %15.10f\n",scale);
397 osd_printf_info("min val :%i max val:%i Total number of networks :%i\n", minval, maxval, networks_no );
398
399 for(i = 0; i < networks_no;i++)
400 {
401 osd_printf_info(" Network no.%i=> resistances: %i", i, rescount[i] );
402 if (r_pu[i] != 0)
403 osd_printf_info(", pullup resistor: %i Ohms",r_pu[i]);
404 if (r_pd[i] != 0)
405 osd_printf_info(", pulldown resistor: %i Ohms",r_pd[i]);
406 osd_printf_info("\n maximum output of this network:%10.5f", max_out[i] );
407 osd_printf_info("\n minimum output of this network:%10.5f\n", min_out[i] );
408 for (n = 0; n < rescount[i]; n++)
409 {
410 osd_printf_info(" res %2i:%9.1f Ohms\n", n, r[i][n]);
411 }
412 for (n = 0; n < (1<<rescount[i]); n++)
413 {
414 osd_printf_info(" 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] );
415 }
416 }
417 }
418 /* debug end */
419
420 return (scale);
421
422 }
423
424 /*****************************************************************************
425
426 New Interface
427
428 *****************************************************************************/
429
430
431 /* Datasheets give a maximum of 0.4V to 0.5V
432 * However in the circuit simulated here this will only
433 * occur if (rBias + rOutn) = 50 Ohm, rBias exists.
434 * This is highly unlikely. With the resistor values used
435 * in such circuits VOL is likely to be around 50mV.
436 */
437
438 #define TTL_VOL (0.05)
439
440
441 /* Likely, datasheets give a typical value of 3.4V to 3.6V
442 * for VOH. Modelling the TTL circuit however backs a value
443 * of 4V for typical currents involved in resistor networks.
444 */
445
446 #define TTL_VOH (4.0)
447
compute_res_net(int inputs,int channel,const res_net_info & di)448 int compute_res_net(int inputs, int channel, const res_net_info &di)
449 {
450 double rTotal=0.0;
451 double v = 0;
452 int i;
453
454 double vBias = di.rgb[channel].vBias;
455 double vOH = di.vOH;
456 double vOL = di.vOL;
457 double minout = di.rgb[channel].minout;
458 double cut = di.rgb[channel].cut;
459 double vcc = di.vcc;
460 double ttlHRes = 0;
461 double rGnd = di.rgb[channel].rGnd;
462 u8 OpenCol = di.OpenCol;
463
464 /* Global options */
465
466 switch (di.options & RES_NET_AMP_MASK)
467 {
468 case RES_NET_AMP_USE_GLOBAL:
469 /* just ignore */
470 break;
471 case RES_NET_AMP_NONE:
472 minout = 0.0;
473 cut = 0.0;
474 break;
475 case RES_NET_AMP_DARLINGTON:
476 minout = 0.9;
477 cut = 0.0;
478 break;
479 case RES_NET_AMP_EMITTER:
480 minout = 0.0;
481 cut = 0.7;
482 break;
483 case RES_NET_AMP_CUSTOM:
484 /* Fall through */
485 break;
486 default:
487 fatalerror("compute_res_net: Unknown amplifier type\n");
488 }
489
490 switch (di.options & RES_NET_VCC_MASK)
491 {
492 case RES_NET_VCC_5V:
493 vcc = 5.0;
494 break;
495 case RES_NET_VCC_CUSTOM:
496 /* Fall through */
497 break;
498 default:
499 fatalerror("compute_res_net: Unknown vcc type\n");
500 }
501
502 switch (di.options & RES_NET_VBIAS_MASK)
503 {
504 case RES_NET_VBIAS_USE_GLOBAL:
505 /* just ignore */
506 break;
507 case RES_NET_VBIAS_5V:
508 vBias = 5.0;
509 break;
510 case RES_NET_VBIAS_TTL:
511 vBias = TTL_VOH;
512 break;
513 case RES_NET_VBIAS_CUSTOM:
514 /* Fall through */
515 break;
516 default:
517 fatalerror("compute_res_net: Unknown vcc type\n");
518 }
519
520 switch (di.options & RES_NET_VIN_MASK)
521 {
522 case RES_NET_VIN_OPEN_COL:
523 OpenCol = 1;
524 vOL = TTL_VOL;
525 break;
526 case RES_NET_VIN_VCC:
527 vOL = 0.0;
528 vOH = vcc;
529 OpenCol = 0;
530 break;
531 case RES_NET_VIN_TTL_OUT:
532 vOL = TTL_VOL;
533 vOH = TTL_VOH;
534 /* rough estimation from 82s129 (7052) datasheet and from various sources
535 * 1.4k / 30
536 */
537 ttlHRes = 50;
538 OpenCol = 0;
539 break;
540 case RES_NET_VIN_CUSTOM:
541 /* Fall through */
542 break;
543 default:
544 fatalerror("compute_res_net: Unknown vin type\n");
545 }
546
547 /* Per channel options */
548
549 switch (di.rgb[channel].options & RES_NET_AMP_MASK)
550 {
551 case RES_NET_AMP_USE_GLOBAL:
552 /* use global defaults */
553 break;
554 case RES_NET_AMP_NONE:
555 minout = 0.0;
556 cut = 0.0;
557 break;
558 case RES_NET_AMP_DARLINGTON:
559 minout = 0.7;
560 cut = 0.0;
561 break;
562 case RES_NET_AMP_EMITTER:
563 minout = 0.0;
564 cut = 0.7;
565 break;
566 case RES_NET_AMP_CUSTOM:
567 /* Fall through */
568 break;
569 default:
570 fatalerror("compute_res_net: Unknown amplifier type\n");
571 }
572
573 switch (di.rgb[channel].options & RES_NET_VBIAS_MASK)
574 {
575 case RES_NET_VBIAS_USE_GLOBAL:
576 /* use global defaults */
577 break;
578 case RES_NET_VBIAS_5V:
579 vBias = 5.0;
580 break;
581 case RES_NET_VBIAS_TTL:
582 vBias = TTL_VOH;
583 break;
584 case RES_NET_VBIAS_CUSTOM:
585 /* Fall through */
586 break;
587 default:
588 fatalerror("compute_res_net: Unknown vcc type\n");
589 }
590
591 /* Input impedances */
592
593 switch (di.options & RES_NET_MONITOR_MASK)
594 {
595 case RES_NET_MONITOR_INVERT:
596 case RES_NET_MONITOR_SANYO_EZV20:
597 /* Nothing */
598 break;
599 case RES_NET_MONITOR_ELECTROHOME_G07:
600 if (rGnd != 0.0)
601 rGnd = rGnd * 5600 / (rGnd + 5600);
602 else
603 rGnd = 5600;
604 break;
605 }
606
607 /* compute here - pass a / low inputs */
608
609 for (i=0; i<di.rgb[channel].num; i++)
610 {
611 int level = ((inputs >> i) & 1);
612 if (di.rgb[channel].R[i] != 0.0 && !level)
613 {
614 // There is no difference in the calculation of the "low" input
615 // (transistor conducting to ground) between TTL output and
616 // open collector output. This is documented explicitly in the
617 // code below (no difference if / else.
618 if (OpenCol)
619 {
620 rTotal += 1.0 / di.rgb[channel].R[i];
621 v += vOL / di.rgb[channel].R[i];
622 }
623 else
624 {
625 rTotal += 1.0 / di.rgb[channel].R[i];
626 v += vOL / di.rgb[channel].R[i];
627 }
628 }
629 }
630
631 /* Mix in rbias and rgnd */
632 if ( di.rgb[channel].rBias != 0.0 )
633 {
634 rTotal += 1.0 / di.rgb[channel].rBias;
635 v += vBias / di.rgb[channel].rBias;
636 }
637 if (rGnd != 0.0)
638 rTotal += 1.0 / rGnd;
639
640 /* if the resulting voltage after application of all low inputs is
641 * greater than vOH, treat high inputs as open collector/high impedance
642 * There will be now current into/from the TTL gate
643 */
644
645 if ( (di.options & RES_NET_VIN_MASK)==RES_NET_VIN_TTL_OUT)
646 {
647 if (v / rTotal > vOH)
648 OpenCol = 1;
649 }
650
651 /* Second pass - high inputs */
652
653 for (i=0; i<di.rgb[channel].num; i++)
654 {
655 int level = ((inputs >> i) & 1);
656 if (di.rgb[channel].R[i] != 0.0 && level)
657 {
658 if (OpenCol)
659 {
660 rTotal += 0;
661 v += 0;
662 }
663 else
664 {
665 rTotal += 1.0 / (di.rgb[channel].R[i] + ttlHRes);
666 v += vOH / (di.rgb[channel].R[i] + ttlHRes);
667 }
668 }
669 }
670
671 rTotal = 1.0 / rTotal;
672 v *= rTotal;
673 v = std::max(minout, v - cut);
674
675 switch (di.options & RES_NET_MONITOR_MASK)
676 {
677 case RES_NET_MONITOR_INVERT:
678 v = vcc - v;
679 break;
680 case RES_NET_MONITOR_SANYO_EZV20:
681 v = vcc - v;
682 v = std::max(double(0), v-0.7);
683 v = std::min(v, vcc - 2 * 0.7);
684 v = v / (vcc-1.4);
685 v = v * vcc;
686 break;
687 case RES_NET_MONITOR_ELECTROHOME_G07:
688 /* Nothing */
689 break;
690 }
691
692 return (int) (v * 255 / vcc + 0.4);
693 }
694
compute_res_net_all(std::vector<rgb_t> & rgb,const u8 * prom,const res_net_decode_info & rdi,const res_net_info & di)695 void compute_res_net_all(std::vector<rgb_t> &rgb, const u8 *prom, const res_net_decode_info &rdi, const res_net_info &di)
696 {
697 u8 r,g,b;
698 int i,j,k;
699
700 rgb.resize(rdi.end - rdi.start + 1);
701 for (i=rdi.start; i<=rdi.end; i++)
702 {
703 u8 t[3] = {0,0,0};
704 int s;
705 for (j=0;j<rdi.numcomp;j++)
706 for (k=0; k<3; k++)
707 {
708 s = rdi.shift[3*j+k];
709 if (s>0)
710 t[k] = t[k] | ( (prom[i+rdi.offset[3*j+k]]>>s) & rdi.mask[3*j+k]);
711 else
712 t[k] = t[k] | ( (prom[i+rdi.offset[3*j+k]]<<(0-s)) & rdi.mask[3*j+k]);
713 }
714 r = compute_res_net(t[0], RES_NET_CHAN_RED, di);
715 g = compute_res_net(t[1], RES_NET_CHAN_GREEN, di);
716 b = compute_res_net(t[2], RES_NET_CHAN_BLUE, di);
717 rgb[i-rdi.start] = rgb_t(r,g,b);
718 }
719 }
720