1 /*
2 Copyright (C) 2006 T. Scott Dattalo
3 Copyright (C) 2009, 2013, 2017 Roy R. Rankin
4
5 This file is part of the libgpsim library of gpsim
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, see
19 <http://www.gnu.org/licenses/lgpl-2.1.html>.
20 */
21
22 #include <assert.h>
23 #include <stdio.h>
24 #include <string>
25
26 #include "a2dconverter.h"
27
28 #include "14bit-processors.h"
29 #include "14bit-registers.h"
30 #include "comparator.h"
31 #include "intcon.h"
32 #include "ioports.h"
33 #include "pir.h"
34 #include "processor.h"
35 #include "trace.h"
36 #include "ui.h"
37
38 #define p_cpu ((Processor *)cpu)
39
40 static PinModule AnInvalidAnalogInput;
41
42 //#define DEBUG
43 #if defined(DEBUG)
44 #include "../config.h"
45 #define Dprintf(arg) {printf("%s:%d ",__FILE__,__LINE__); printf arg; }
46 #else
47 #define Dprintf(arg) {}
48 #endif
49
50 //------------------------------------------------------
51 // ADRES
52 //
53 /*
54 void ADRES::put(int new_value)
55 {
56
57 trace.raw(write_trace.get() | value.get());
58
59 if(new_value > 255)
60 value.put(255);
61 else if (new_value < 0)
62 value.put(0);
63 else
64 value.put(new_value);
65 }
66
67 */
68 //------------------------------------------------------
69 // ADCON0
70 //
ADCON0(Processor * pCpu,const char * pName,const char * pDesc)71 ADCON0::ADCON0(Processor *pCpu, const char *pName, const char *pDesc)
72 : sfr_register(pCpu, pName, pDesc),
73 ad_state(AD_IDLE),
74 channel_mask(7), channel_shift(3), GO_bit(GO)
75 {
76 }
77
78
79 /*
80 * Link PIC register for High Byte A/D result
81 */
setAdres(sfr_register * new_adres)82 void ADCON0::setAdres(sfr_register *new_adres)
83 {
84 adres = new_adres;
85 }
86
87
88 /*
89 * Link PIC register for Low Byte A/D result
90 */
setAdresLow(sfr_register * new_adresl)91 void ADCON0::setAdresLow(sfr_register *new_adresl)
92 {
93 adresl = new_adresl;
94 }
95
96
97 /*
98 * Link PIC register for ADCON1
99 */
setAdcon1(ADCON1 * new_adcon1)100 void ADCON0::setAdcon1(ADCON1 *new_adcon1)
101 {
102 adcon1 = new_adcon1;
103 }
104
105
106 /*
107 * Link PIC register for INTCON
108 */
setIntcon(INTCON * new_intcon)109 void ADCON0::setIntcon(INTCON *new_intcon)
110 {
111 intcon = new_intcon;
112 }
113
114
115 /*
116 * Link PIC register for PIR
117 * If set ADIF in PIR otherwise ADIF in ADCON0
118 */
setPir(PIR * pPir)119 void ADCON0::setPir(PIR *pPir)
120 {
121 m_pPir = pPir;
122 }
123
124
125 /*
126 * Set resolution of A2D converter
127 */
setA2DBits(unsigned int nBits)128 void ADCON0::setA2DBits(unsigned int nBits)
129 {
130 m_A2DScale = (1 << nBits) - 1;
131 m_nBits = nBits;
132 }
133
134
start_conversion()135 void ADCON0::start_conversion()
136 {
137 Dprintf(("starting A/D conversion at 0x%" PRINTF_GINT64_MODIFIER "x\n", get_cycles().get()));
138
139 if (!(value.get() & ADON))
140 {
141 Dprintf((" A/D converter is disabled\n"));
142 stop_conversion();
143 return;
144 }
145
146 put(value.get() | GO_bit);
147 guint64 fc = get_cycles().get() + (2 * Tad) /
148 p_cpu->get_ClockCycles_per_Instruction();
149 Dprintf(("ad_state %u fc %" PRINTF_GINT64_MODIFIER "x now %" PRINTF_GINT64_MODIFIER "x\n", ad_state, fc, get_cycles().get()))
150
151 if (ad_state != AD_IDLE)
152 {
153 // The A/D converter is either 'converting' or 'acquiring'
154 // in either case, there is callback break that needs to be moved.
155 stop_conversion();
156 get_cycles().reassign_break(future_cycle, fc, this);
157
158 }
159 else
160 {
161 get_cycles().set_break(fc, this);
162 }
163
164 future_cycle = fc;
165 ad_state = AD_ACQUIRING;
166 }
167
168
stop_conversion()169 void ADCON0::stop_conversion()
170 {
171 Dprintf(("stopping A/D conversion\n"));
172 ad_state = AD_IDLE;
173 }
174
175
set_Tad(unsigned int new_value)176 void ADCON0::set_Tad(unsigned int new_value)
177 {
178 // Get the A/D Conversion Clock Select bits
179 //
180 // This switch case will get the ADCS bits and set the Tad, or The A/D
181 // converter clock period. Tad is the number of the oscillator periods
182 // rather instruction cycle periods. ADCS2 only exists on some processors,
183 // but should be 0 where it is not used.
184 switch (new_value & (ADCS0 | ADCS1))
185 {
186 case 0:
187 Tad = (adcon1->value.get() & ADCON1::ADCS2) ? 4 : 2;
188 break;
189
190 case ADCS0:
191 Tad = (adcon1->value.get() & ADCON1::ADCS2) ? 16 : 8;
192 break;
193
194 case ADCS1:
195 Tad = (adcon1->value.get() & ADCON1::ADCS2) ? 64 : 32;
196 break;
197
198 case (ADCS0|ADCS1): // typical 4 usec, convert to osc cycles
199 if (cpu)
200 {
201 Tad = (unsigned int)(4.e-6 * p_cpu->get_frequency());
202 Tad = Tad < 2 ? 2 : Tad;
203
204 }
205 else
206 {
207 Tad = 6;
208 }
209
210 break;
211 }
212 }
213
214
put(unsigned int new_value)215 void ADCON0::put(unsigned int new_value)
216 {
217 trace.raw(write_trace.get() | value.get());
218 set_Tad(new_value);
219 unsigned int old_value = value.get();
220 // SET: Reflect it first!
221 value.put(new_value);
222
223 if (new_value & ADON)
224 {
225 // The A/D converter is being turned on (or maybe left on)
226 if ((new_value & ~old_value) & GO_bit)
227 {
228 if (verbose)
229 {
230 printf("starting A2D conversion\n");
231 }
232
233 Dprintf(("starting A2D conversion\n"));
234 // The 'GO' bit is being turned on, which is request to initiate
235 // and A/D conversion
236 start_conversion();
237 }
238
239 }
240 else
241 {
242 stop_conversion();
243 }
244 }
245
246
put_conversion()247 void ADCON0::put_conversion()
248 {
249 double dRefSep = m_dSampledVrefHi - m_dSampledVrefLo;
250 double dNormalizedVoltage;
251 dNormalizedVoltage = (dRefSep > 0.0) ?
252 (m_dSampledVoltage - m_dSampledVrefLo) / dRefSep : 0.0;
253 dNormalizedVoltage = dNormalizedVoltage > 1.0 ? 1.0 : dNormalizedVoltage;
254 unsigned int converted = (unsigned int)(m_A2DScale * dNormalizedVoltage + 0.5);
255 Dprintf(("put_conversion: Vrefhi:%.4f Vreflo:%.4f conversion:%u normV:%f\n",
256 m_dSampledVrefHi, m_dSampledVrefLo, converted, dNormalizedVoltage));
257
258 if (verbose)
259 {
260 printf("result=0x%02x\n", converted);
261 }
262
263 Dprintf(("%u-bit result 0x%x ADFM %d\n", m_nBits, converted, get_ADFM()));
264
265 if (adresl) // non-null for more than 8 bit conversion
266 {
267 if (get_ADFM())
268 {
269 adresl->put(converted & 0xff);
270 adres->put((converted >> 8) & 0x3);
271
272 }
273 else
274 {
275 adresl->put((converted << 6) & 0xc0);
276 adres->put((converted >> 2) & 0xff);
277 }
278
279 }
280 else
281 {
282 adres->put((converted) & 0xff);
283 }
284 }
285
286
287 // ADCON0 callback is called when the cycle counter hits the break point that
288 // was set in ADCON0::put.
289
callback()290 void ADCON0::callback()
291 {
292 int channel;
293 Dprintf((" ADCON0 Callback: 0x%" PRINTF_GINT64_MODIFIER "x ad_state=0x%x\n", get_cycles().get(), ad_state));
294
295 //
296 // The a/d converter is simulated with a state machine.
297 //
298
299 switch (ad_state)
300 {
301 case AD_IDLE:
302 Dprintf(("ignoring ad callback since ad_state is idle\n"));
303 break;
304
305 case AD_ACQUIRING:
306 channel = (value.get() >> channel_shift) & channel_mask;
307 m_dSampledVoltage = getChannelVoltage(channel);
308 m_dSampledVrefHi = getVrefHi();
309 m_dSampledVrefLo = getVrefLo();
310 Dprintf(("Acquiring channel:%d V=%g reflo=%g refhi=%g\n",
311 channel, m_dSampledVoltage, m_dSampledVrefLo, m_dSampledVrefHi));
312 future_cycle = get_cycles().get() + (m_nBits * Tad) / p_cpu->get_ClockCycles_per_Instruction();
313 get_cycles().set_break(future_cycle, this);
314
315 if (verbose)
316 printf("A/D %u bits channel:%d Vin=%.4f Refhi=%.4f Reflo=%.4f ", m_nBits,
317 channel, m_dSampledVoltage, m_dSampledVrefHi, m_dSampledVrefLo);
318
319 ad_state = AD_CONVERTING;
320 break;
321
322 case AD_CONVERTING:
323 put_conversion();
324 // Clear the GO/!DONE flag.
325 value.put(value.get() & (~GO_bit));
326 set_interrupt();
327 ad_state = AD_IDLE;
328 }
329 }
330
331
332 //------------------------------------------------------
333 // If the ADIF bit is in the PIR1 register, call setPir()
334 // in the ADC setup. Otherwise, ADIF is assumed to be in
335 // the ADCON0 register
336 //
337 // Chips like 10f220 do not have interupt and intcon is not defined.
338 // Thus no interrupt needs be generated
339 //
set_interrupt()340 void ADCON0::set_interrupt()
341 {
342 if (m_pPir)
343 {
344 m_pPir->set_adif();
345
346 }
347 else if (intcon)
348 {
349 value.put(value.get() | ADIF);
350 intcon->peripheral_interrupt();
351 }
352 }
353
354
getVrefHi()355 double ADCON0_91X::getVrefHi()
356 {
357 if (value.get() & VCFG0)
358 {
359 return getChannelVoltage(Vrefhi_position);
360
361 }
362 else
363 {
364 return ((Processor *)cpu)->get_Vdd();
365 }
366 }
367
368
getVrefLo()369 double ADCON0_91X::getVrefLo()
370 {
371 if (value.get() & VCFG1)
372 {
373 return getChannelVoltage(Vreflo_position);
374
375 }
376 else
377 {
378 return 0.0;
379 }
380 }
381
382
383 //------------------------------------------------------
384 // ADCON0
385 //
ADCON0_DIF(Processor * pCpu,const char * pName,const char * pDesc)386 ADCON0_DIF::ADCON0_DIF(Processor *pCpu, const char *pName, const char *pDesc)
387 : ADCON0(pCpu, pName, pDesc), adcon2(nullptr)
388 {
389 }
390
391
put(unsigned int new_value)392 void ADCON0_DIF::put(unsigned int new_value)
393 {
394 trace.raw(write_trace.get() | value.get());
395
396 if (new_value & ADRMD) // 10 Bit
397 {
398 setA2DBits(10);
399
400 }
401 else
402 {
403 setA2DBits(12);
404 }
405
406 set_Tad(new_value);
407 unsigned int old_value = value.get();
408 // SET: Reflect it first!
409 value.put(new_value);
410
411 if (new_value & ADON)
412 {
413 // The A/D converter is being turned on (or maybe left on)
414 if ((new_value & ~old_value) & GO_bit)
415 {
416 if (verbose)
417 {
418 printf("starting A2D conversion\n");
419 }
420
421 Dprintf(("starting A2D conversion\n"));
422 // The 'GO' bit is being turned on, which is request to initiate
423 // and A/D conversion
424 start_conversion();
425 }
426
427 }
428 else
429 {
430 stop_conversion();
431 }
432 }
433
434
put_conversion(void)435 void ADCON0_DIF::put_conversion(void)
436 {
437 int channel = adcon2->value.get() & 0x0f;
438 double dRefSep = m_dSampledVrefHi - m_dSampledVrefLo;
439 double dNormalizedVoltage;
440 double m_dSampledVLo;
441
442 if (channel == 0x0e) // shift AN21 to adcon0 channel
443 {
444 channel = 0x15;
445 }
446
447 if (channel == 0x0f) // use ADNREF for V-
448 {
449 m_dSampledVLo = getVrefLo();
450
451 }
452 else
453 {
454 m_dSampledVLo = getChannelVoltage(channel);
455 }
456
457 dNormalizedVoltage = (m_dSampledVoltage - m_dSampledVLo) / dRefSep;
458 dNormalizedVoltage = dNormalizedVoltage > 1.0 ? 1.0 : dNormalizedVoltage;
459 int converted = (int)(m_A2DScale * dNormalizedVoltage + 0.5);
460 Dprintf(("put_conversion: V+:%g V-:%g Vrefhi:%g Vreflo:%g conversion:%d normV:%g\n",
461 m_dSampledVoltage, m_dSampledVLo,
462 m_dSampledVrefHi, m_dSampledVrefLo, converted, dNormalizedVoltage));
463
464 if (verbose)
465 {
466 printf("result=0x%02x\n", converted);
467 }
468
469 Dprintf(("%u-bit result 0x%x ADFM %d\n", m_nBits, converted, get_ADFM()));
470
471 if (!get_ADFM()) // signed
472 {
473 int sign = 0;
474
475 if (converted < 0)
476 {
477 sign = 1;
478 converted = -converted;
479 }
480
481 converted = ((converted << (16 - m_nBits)) % 0xffff) | sign;
482 }
483
484 adresl->put(converted & 0xff);
485 adres->put((converted >> 8) & 0xff);
486 }
487
488
ADCON1_16F(Processor * pCpu,const char * pName,const char * pDesc)489 ADCON1_16F::ADCON1_16F(Processor *pCpu, const char *pName, const char *pDesc)
490 : ADCON1(pCpu, pName, pDesc), FVR_chan(99)
491 {
492 valid_bits = 0x70;
493 }
494
495
put_value(unsigned int new_value)496 void ADCON1_16F::put_value(unsigned int new_value)
497 {
498 unsigned int masked_value = new_value & valid_bits;
499 unsigned int Tad = 6;
500 setADCnames();
501
502 switch (masked_value & (ADCS0 | ADCS1))
503 {
504 case 0:
505 Tad = (new_value & ADCS2) ? 4 : 2;
506 break;
507
508 case ADCS0:
509 Tad = (new_value & ADCS2) ? 16 : 8;
510 break;
511
512 case ADCS1:
513 Tad = (new_value & ADCS2) ? 64 : 32;
514 break;
515
516 case (ADCS0|ADCS1): // typical 4 usec, convert to osc cycles
517 if (cpu)
518 {
519 Tad = (unsigned int)(4.e-6 * p_cpu->get_frequency());
520 Tad = Tad < 2 ? 2 : Tad;
521
522 }
523 else
524 {
525 Tad = 6;
526 }
527
528 break;
529 }
530
531 adcon0->set_Tad(Tad);
532
533 if (ADFM & valid_bits)
534 {
535 adfm = ADFM & masked_value;
536 }
537
538 //RRR FIXME handle ADPREF
539 value.put(new_value & valid_bits);
540 }
541
542
getVrefLo()543 double ADCON1_16F::getVrefLo()
544 {
545 if (ADNREF & value.get())
546 {
547 if (Vreflo_position[cfg_index] < m_nAnalogChannels)
548 {
549 return getChannelVoltage(Vreflo_position[cfg_index]);
550 }
551
552 std::cerr << "WARNING Vreflo pin not configured\n";
553 return -1.0;
554 }
555
556 return 0.0; //Vss
557 }
558
559
getVrefHi()560 double ADCON1_16F::getVrefHi()
561 {
562 if (ADPREF0 & valid_bits)
563 {
564 unsigned int mode = value.get() & (ADPREF1 | ADPREF0);
565
566 switch (mode)
567 {
568 case 0:
569 return ((Processor *)cpu)->get_Vdd();
570
571 case 1:
572 std::cerr << "WARNING reserved value for ADPREF\n";
573 return -1.0;
574
575 case 2:
576 if (Vrefhi_position[cfg_index] < m_nAnalogChannels)
577 {
578 return getChannelVoltage(Vrefhi_position[cfg_index]);
579 }
580
581 std::cerr << "WARNING Vrefhi pin not configured\n";
582 return -1.0;
583
584 case 3:
585 if (FVR_chan < m_nAnalogChannels)
586 {
587 return getChannelVoltage(FVR_chan);
588 }
589
590 std::cerr << "WARNING FVR_chan not set\n";
591 return -1.0;
592 };
593 }
594
595 if (Vrefhi_position[cfg_index] < m_nAnalogChannels)
596 {
597 return getChannelVoltage(Vrefhi_position[cfg_index]);
598 }
599
600 return ((Processor *)cpu)->get_Vdd();
601 }
602
603
604 //------------------------------------------------------
605 // ADCON1
606 //
ADCON1(Processor * pCpu,const char * pName,const char * pDesc)607 ADCON1::ADCON1(Processor *pCpu, const char *pName, const char *pDesc)
608 : sfr_register(pCpu, pName, pDesc), valid_bits(0xff)
609 {
610 for (int i = 0; i < (int)cMaxConfigurations; i++)
611 {
612 setChannelConfiguration(i, 0);
613 setVrefLoConfiguration(i, 0xffff);
614 setVrefHiConfiguration(i, 0xffff);
615 }
616 }
617
618
~ADCON1()619 ADCON1::~ADCON1()
620 {
621 delete [] m_voltageRef;
622
623 if (m_AnalogPins)
624 {
625 if (m_ad_in_ctl)
626 {
627 for (unsigned int i = 0; i < m_nAnalogChannels; i++)
628 {
629 m_AnalogPins[i]->setControl(0);
630 }
631
632 delete m_ad_in_ctl;
633 }
634
635 delete [] m_AnalogPins;
636 }
637 }
638
639
put(unsigned int new_value)640 void ADCON1::put(unsigned int new_value)
641 {
642 unsigned int masked_value = new_value & valid_bits;
643 trace.raw(write_trace.get() | value.get());
644 put_value(masked_value);
645 }
646
647
put_value(unsigned int new_value)648 void ADCON1::put_value(unsigned int new_value)
649 {
650 unsigned int masked_value = new_value & valid_bits;
651 cfg_index = get_cfg(masked_value);
652 setADCnames();
653 adfm = masked_value & ADFM;
654 value.put(masked_value);
655 }
656
657
658 // Obtain new mIoMask and set pin names as per function
setADCnames()659 void ADCON1::setADCnames()
660 {
661 unsigned int new_mask = m_configuration_bits[cfg_index];
662 unsigned int diff = mIoMask ^ new_mask;
663 Dprintf(("ADCON1::setADCnames - cfg_index=%u new_mask %02X channels %u\n",
664 cfg_index, new_mask, m_nAnalogChannels));
665 char newname[20];
666
667 for (unsigned int i = 0; i < m_nAnalogChannels; i++)
668 {
669 if ((diff & (1 << i)) && m_AnalogPins[i] != &AnInvalidAnalogInput)
670 {
671 if (new_mask & (1 << i))
672 {
673 snprintf(newname, sizeof(newname), "an%u", i);
674 m_AnalogPins[i]->AnalogReq(this, true, newname);
675
676 }
677 else
678 {
679 m_AnalogPins[i]->AnalogReq(this, false, m_AnalogPins[i]->getPin().name().c_str());
680 }
681 }
682 }
683
684 mIoMask = new_mask;
685 }
686
687
688 /*
689 * If A2D uses PCFG, call for each PCFG value (cfg 0 to 15) with
690 * each set bit of bitMask indicating port is an analog port
691 * (either A2D input port or Vref). Processors which use an A2D
692 * method that uses ANSEL register will not call this.
693 *
694 * As an example, for the following Port Configuration Control bit:
695 * PCFG AN7 AN6 AN5 AN4 AN3 AN2 AN1 AN0
696 * ---- ---- ----- ----- ----- ----- ----- ----- -----
697 * 1100 D D D A Vref+ Vref- A A
698 *
699 * then call setChannelConfiguration with cfg = 12 , bitMask = 0x1f
700 * */
setChannelConfiguration(unsigned int cfg,unsigned int bitMask)701 void ADCON1::setChannelConfiguration(unsigned int cfg, unsigned int bitMask)
702 {
703 if (cfg < cMaxConfigurations)
704 {
705 m_configuration_bits[cfg] = bitMask;
706 }
707 }
708
709
getVrefLoChannel(unsigned int cfg)710 unsigned int ADCON1::getVrefLoChannel(unsigned int cfg)
711 {
712 if (cfg < cMaxConfigurations)
713 {
714 return Vreflo_position[cfg];
715 }
716
717 return 0xffff;
718 }
719
720
getVrefHiChannel(unsigned int cfg)721 unsigned int ADCON1::getVrefHiChannel(unsigned int cfg)
722 {
723 Dprintf(("ADCON1::getVrefHiChannel cfg=%u %u\n", cfg, Vrefhi_position[cfg]));
724
725 if (cfg < cMaxConfigurations)
726 {
727 return Vrefhi_position[cfg];
728 }
729
730 return 0xffff;
731 }
732
733
734 /*
735 * Call for each configuration mode that uses an І/O pin as Vref-
736 * to declare which port is being used for this.
737 */
setVrefLoConfiguration(unsigned int cfg,unsigned int channel)738 void ADCON1::setVrefLoConfiguration(unsigned int cfg, unsigned int channel)
739 {
740 if (cfg < cMaxConfigurations)
741 {
742 Vreflo_position[cfg] = channel;
743 }
744 }
745
746
747 /*
748 * Call for each configuration mode that uses an І/O pin as Vref+
749 * to declare which port is being used for this.
750 */
setVrefHiConfiguration(unsigned int cfg,unsigned int channel)751 void ADCON1::setVrefHiConfiguration(unsigned int cfg, unsigned int channel)
752 {
753 if (cfg < cMaxConfigurations)
754 {
755 Vrefhi_position[cfg] = channel;
756 }
757 }
758
759
760 /*
761 * Number of A2D channels processor supports
762 */
setNumberOfChannels(unsigned int nChannels)763 void ADCON1::setNumberOfChannels(unsigned int nChannels)
764 {
765 PinModule **save = nullptr; // save existing pins when nChannels increases
766
767 if (!nChannels || nChannels <= m_nAnalogChannels)
768 {
769 return; // do nothing if NChannels decreases
770 }
771
772 if (m_nAnalogChannels && nChannels > m_nAnalogChannels)
773 {
774 save = m_AnalogPins;
775 }
776
777 delete [] m_voltageRef;
778
779 m_voltageRef = new float [nChannels];
780 m_AnalogPins = new PinModule *[nChannels];
781
782 for (unsigned int i = 0; i < nChannels; i++)
783 {
784 m_voltageRef[i] = -1.0;
785
786 if (i < m_nAnalogChannels)
787 {
788 if (save)
789 {
790 m_AnalogPins[i] = save[i];
791 }
792
793 }
794 else
795 {
796 m_AnalogPins[i] = &AnInvalidAnalogInput;
797 }
798 }
799
800 delete [] save;
801
802 m_nAnalogChannels = nChannels;
803 }
804
805
806 /*
807 * Configure use of adcon1 register
808 * The register is first anded with mask and then shifted
809 * right shift bits. The result being either PCFG or VCFG
810 * depending on the type of a2d being used.
811 */
setValidCfgBits(unsigned int mask,unsigned int shift)812 void ADCON1::setValidCfgBits(unsigned int mask, unsigned int shift)
813 {
814 mValidCfgBits = mask;
815 mCfgBitShift = shift;
816 }
817
818
get_adc_configmask(unsigned int reg)819 unsigned int ADCON1::get_adc_configmask(unsigned int reg)
820 {
821 return m_configuration_bits[get_cfg(reg)];
822 }
823
824
get_cfg(unsigned int reg)825 int ADCON1::get_cfg(unsigned int reg)
826 {
827 return ((reg & mValidCfgBits) >> mCfgBitShift);
828 }
829
830
831 /*
832 * Associate a processor I/O pin with an A2D channel
833 */
setIOPin(unsigned int channel,PinModule * newPin)834 void ADCON1::setIOPin(unsigned int channel, PinModule *newPin)
835 {
836 if (channel < m_nAnalogChannels &&
837 m_AnalogPins[channel] == &AnInvalidAnalogInput && newPin != 0)
838 {
839 m_AnalogPins[channel] = newPin;
840
841 }
842 else
843 {
844 printf("%s:%d WARNING invalid channel number config for ADCON1 %u num %u\n", __FILE__, __LINE__, channel, m_nAnalogChannels);
845 }
846 }
847
848
setVoltRef(unsigned int channel,float value)849 void ADCON1::setVoltRef(unsigned int channel, float value)
850 {
851 if (channel < m_nAnalogChannels)
852 {
853 m_voltageRef[channel] = value;
854
855 }
856 else
857 {
858 printf("ADCON1::%s invalid channel number %u\n", __FUNCTION__, channel);
859 }
860 }
861
862
863 //------------------------------------------------------
getChannelVoltage(unsigned int channel)864 double ADCON1::getChannelVoltage(unsigned int channel)
865 {
866 double voltage = 0.0;
867
868 if (channel < m_nAnalogChannels)
869 {
870 if ((1 << channel) & m_configuration_bits[cfg_index])
871 {
872 PinModule *pm = m_AnalogPins[channel];
873
874 if (pm != &AnInvalidAnalogInput)
875 {
876 voltage = pm->getPin().get_nodeVoltage();
877
878 }
879 else
880 {
881 std::cerr << "ADCON1::getChannelVoltage channel " << channel <<
882 " not valid analog input\n";
883 std::cerr << "Please raise a Gpsim bug report\n";
884 }
885
886 }
887 else // use voltage reference
888 {
889 Dprintf(("ADCON1::getChannelVoltage channel=%u voltage %f\n", \
890 channel, m_voltageRef[channel]));
891 voltage = m_voltageRef[channel];
892
893 if (voltage < 0.0)
894 {
895 std::cout << "ADCON1::getChannelVoltage channel " << channel <<
896 " not a configured input\n";
897 voltage = 0.0;
898 }
899 }
900
901 }
902 else
903 {
904 std::cerr << "ADCON1::getChannelVoltage channel " << channel <<
905 " >= "
906 << m_nAnalogChannels << " (number of channels)\n";
907 std::cerr << "Please raise a Gpsim bug report\n";
908 }
909
910 return voltage;
911 }
912
913
getVrefHi()914 double ADCON1::getVrefHi()
915 {
916 if (Vrefhi_position[cfg_index] < m_nAnalogChannels)
917 {
918 return getChannelVoltage(Vrefhi_position[cfg_index]);
919 }
920
921 return ((Processor *)cpu)->get_Vdd();
922 }
923
924
getVrefLo()925 double ADCON1::getVrefLo()
926 {
927 if (Vreflo_position[cfg_index] < m_nAnalogChannels)
928 {
929 return getChannelVoltage(Vreflo_position[cfg_index]);
930 }
931
932 return 0.0;
933 }
934
935
936 // if on is true, set pin as input regardless of TRIS state
937 // else restore TRIS control
938 //
set_channel_in(unsigned int channel,bool on)939 void ADCON1::set_channel_in(unsigned int channel, bool on)
940 {
941 Dprintf(("channel=%u on=%d m_ad_in_ctl=%p\n", channel, on, m_ad_in_ctl));
942
943 if (on && (m_ad_in_ctl == nullptr))
944 {
945 m_ad_in_ctl = new AD_IN_SignalControl();
946 }
947
948 if (on)
949 {
950 m_AnalogPins[channel]->setControl(m_ad_in_ctl);
951
952 }
953 else
954 {
955 m_AnalogPins[channel]->setControl(0);
956 }
957
958 m_AnalogPins[channel]->updatePinModule();
959 }
960
961
ANSEL(Processor * pCpu,const char * pName,const char * pDesc)962 ANSEL::ANSEL(Processor *pCpu, const char *pName, const char *pDesc)
963 : sfr_register(pCpu, pName, pDesc), valid_bits(0x7f)
964 {
965 }
966
967
setAdcon1(ADCON1 * new_adcon1)968 void ANSEL::setAdcon1(ADCON1 *new_adcon1)
969 {
970 adcon1 = new_adcon1;
971 }
972
973
put(unsigned int new_value)974 void ANSEL::put(unsigned int new_value)
975 {
976 unsigned int cfgmax = adcon1->getNumberOfChannels();
977 unsigned int i;
978 unsigned int mask = (new_value & valid_bits);
979
980 if (anselh)
981 {
982 mask |= anselh->value.get() << 8;
983 }
984
985 trace.raw(write_trace.get() | value.get());
986
987 /*
988 Generate ChannelConfiguration from ansel register
989 */
990 for (i = 0; i < cfgmax; i++)
991 {
992 adcon1->setChannelConfiguration(i, mask);
993 }
994
995 value.put(new_value & valid_bits);
996 adcon1->setADCnames();
997 }
998
999
ANSEL_H(Processor * pCpu,const char * pName,const char * pDesc)1000 ANSEL_H::ANSEL_H(Processor *pCpu, const char *pName, const char *pDesc)
1001 : sfr_register(pCpu, pName, pDesc), valid_bits(0x3f)
1002 {
1003 }
1004
1005
setAdcon1(ADCON1 * new_adcon1)1006 void ANSEL_H::setAdcon1(ADCON1 *new_adcon1)
1007 {
1008 adcon1 = new_adcon1;
1009 }
1010
1011
put(unsigned int new_value)1012 void ANSEL_H::put(unsigned int new_value)
1013 {
1014 unsigned int cfgmax = adcon1->getNumberOfChannels();
1015 unsigned int i;
1016 unsigned int mask = ((new_value & valid_bits) << 8) ;
1017 trace.raw(write_trace.get() | value.get());
1018
1019 if (ansel)
1020 {
1021 mask |= ansel->value.get();
1022 }
1023
1024 /*
1025 Generate ChannelConfiguration from ansel register
1026 */
1027 for (i = 0; i < cfgmax; i++)
1028 {
1029 adcon1->setChannelConfiguration(i, mask);
1030 }
1031
1032 value.put(new_value & valid_bits);
1033 adcon1->setADCnames();
1034 }
1035
1036
ANSEL_P(Processor * pCpu,const char * pName,const char * pDesc)1037 ANSEL_P::ANSEL_P(Processor *pCpu, const char *pName, const char *pDesc)
1038 : sfr_register(pCpu, pName, pDesc), valid_bits(0x3f)
1039 {
1040 }
1041
1042
setAdcon1(ADCON1 * new_adcon1)1043 void ANSEL_P::setAdcon1(ADCON1 *new_adcon1)
1044 {
1045 adcon1 = new_adcon1;
1046 }
1047
setAnsel(ANSEL_P * new_ansel)1048 void ANSEL_P::setAnsel(ANSEL_P *new_ansel)
1049 {
1050 ansel = new_ansel;
1051 if (!ansel_list.empty())
1052 {
1053 for(auto it=ansel_list.begin(); it!=ansel_list.end(); it++)
1054 {
1055 if (*it == new_ansel)
1056 {
1057 return;
1058 }
1059 }
1060 }
1061 ansel_list.push_back(new_ansel);
1062 }
1063
1064
put(unsigned int new_value)1065 void ANSEL_P::put(unsigned int new_value)
1066 {
1067 unsigned int cfgmax = adcon1->getMaxCfg();
1068 unsigned int i;
1069 unsigned int mask;
1070 unsigned int chan = first_channel;
1071 trace.raw(write_trace.get() | value.get());
1072 new_value &= valid_bits;
1073 value.put(new_value);
1074 cfg_mask = 0;
1075
1076 for (i = 0; i < 8; i++)
1077 {
1078 if ((1 << i) & analog_pins)
1079 {
1080 if ((1 << i) & new_value)
1081 {
1082 cfg_mask |= (1 << chan);
1083 }
1084
1085 chan++;
1086 }
1087 }
1088
1089 mask = cfg_mask;
1090 for(auto it=ansel_list.begin(); it!=ansel_list.end(); it++)
1091 {
1092 mask |= (*it)->get_mask();
1093 }
1094
1095 if (!adcon1)
1096 {
1097 return;
1098 }
1099
1100 /*
1101 Generate ChannelConfiguration from ansel register
1102 */
1103 for (i = 0; i < cfgmax; i++)
1104 {
1105 adcon1->setChannelConfiguration(i, mask);
1106 }
1107
1108 adcon1->setADCnames();
1109 }
1110
1111
1112 //------------------------------------------------------
1113 // ADCON0_10
1114 //
ADCON0_10(Processor * pCpu,const char * pName,const char * pDesc)1115 ADCON0_10::ADCON0_10(Processor *pCpu, const char *pName, const char *pDesc)
1116 : ADCON0(pCpu, pName, pDesc)
1117 {
1118 GO_bit = GO; //ADCON0 and ADCON0_10 have GO flag at different bit
1119 // It should take 13 CPU instructions to complete conversion
1120 // Tad of 6 completes in 15
1121 Tad = 6;
1122 }
1123
1124
put(unsigned int new_value)1125 void ADCON0_10::put(unsigned int new_value)
1126 {
1127 unsigned int old_value = value.get();
1128 /* On first call of this function old_value has already been set to
1129 * it's default value, but we want to call set_channel_in. First
1130 * gives us a way to do this.
1131 */
1132 static bool first = true;
1133 trace.raw(write_trace.get() | value.get());
1134 Dprintf(("ADCON0_10::put new_value=0x%02x old_value=0x%02x\n", new_value, old_value));
1135
1136 if ((new_value ^ old_value) & ANS0 || first)
1137 {
1138 adcon1->set_channel_in(0, (new_value & ANS0) == ANS0);
1139 }
1140
1141 if ((new_value ^ old_value) & ANS1 || first)
1142 {
1143 adcon1->set_channel_in(1, (new_value & ANS1) == ANS1);
1144 }
1145
1146 first = false;
1147
1148 // If ADON is clear GO cannot be set
1149 if ((new_value & ADON) != ADON)
1150 {
1151 new_value &= ~GO_bit;
1152 }
1153
1154 // SET: Reflect it first!
1155 value.put(new_value);
1156
1157 if (new_value & ADON)
1158 {
1159 // The A/D converter is being turned on (or maybe left on)
1160 if ((new_value & ~old_value) & GO_bit)
1161 {
1162 if (verbose)
1163 {
1164 printf("starting A2D conversion\n");
1165 }
1166
1167 // The 'GO' bit is being turned on, which is request to initiate
1168 // and A/D conversion
1169 start_conversion();
1170 }
1171
1172 }
1173 else
1174 {
1175 stop_conversion();
1176 }
1177 }
1178
1179
1180 //------------------------------------------------------
1181 // ADCON0_12F used in 12f675. Uses ADCON1 as virtual rather than physical
1182 // register
1183 //
ADCON0_12F(Processor * pCpu,const char * pName,const char * pDesc)1184 ADCON0_12F::ADCON0_12F(Processor *pCpu, const char *pName, const char *pDesc)
1185 : ADCON0(pCpu, pName, pDesc)
1186 {
1187 GO_bit = GO; //ADCON0 and ADCON0_10 have GO flag at different bit
1188 valid_bits = 0xdf;
1189 }
1190
1191
put(unsigned int new_value)1192 void ADCON0_12F::put(unsigned int new_value)
1193 {
1194 unsigned int old_value = value.get();
1195 new_value &= valid_bits; // clear unused bits
1196 /* On first call of this function old_value has already been set to
1197 * it's default value, but we want to call set_channel_in. First
1198 * gives us a way to do this.
1199 */
1200 trace.raw(write_trace.get() | value.get());
1201 Dprintf(("ADCON0_12F::put new_value=0x%02x old_value=0x%02x\n", new_value, old_value));
1202 // tell adcon1 to use Vref
1203 adcon1->set_cfg_index((new_value & VCFG) ? 2 : 0);
1204
1205 // If ADON is clear GO cannot be set
1206 if ((new_value & ADON) != ADON)
1207 {
1208 new_value &= ~GO_bit;
1209 }
1210
1211 // SET: Reflect it first!
1212 value.put(new_value);
1213
1214 if (new_value & ADON)
1215 {
1216 // The A/D converter is being turned on (or maybe left on)
1217 if ((new_value & ~old_value) & GO_bit)
1218 {
1219 if (verbose)
1220 {
1221 printf("starting A2D conversion\n");
1222 }
1223
1224 // The 'GO' bit is being turned on, which is request to initiate
1225 // and A/D conversion
1226 start_conversion();
1227 }
1228
1229 }
1230 else
1231 {
1232 stop_conversion();
1233 }
1234 }
1235
1236
ANSEL_12F(Processor * pCpu,const char * pName,const char * pDesc)1237 ANSEL_12F::ANSEL_12F(Processor *pCpu, const char *pName, const char *pDesc)
1238 : sfr_register(pCpu, pName, pDesc)
1239 {
1240 }
1241
1242
set_tad(unsigned int new_value)1243 void ANSEL_12F::set_tad(unsigned int new_value)
1244 {
1245 unsigned int Tad = 6;
1246
1247 switch (new_value & (ADCS0 | ADCS1))
1248 {
1249 case 0:
1250 Tad = (new_value & ADCS2) ? 4 : 2;
1251 break;
1252
1253 case ADCS0:
1254 Tad = (new_value & ADCS2) ? 16 : 8;
1255 break;
1256
1257 case ADCS1:
1258 Tad = (new_value & ADCS2) ? 64 : 32;
1259 break;
1260
1261 case (ADCS0|ADCS1): // typical 4 usec, convert to osc cycles
1262 if (cpu)
1263 {
1264 Tad = (unsigned int)(4.e-6 * p_cpu->get_frequency());
1265 Tad = Tad < 2 ? 2 : Tad;
1266
1267 }
1268 else
1269 {
1270 Tad = 6;
1271 }
1272
1273 break;
1274 }
1275
1276 Dprintf(("ANSEL_12F::set_tad %x Tad=%u\n", new_value, Tad));
1277 adcon0->set_Tad(Tad);
1278 }
1279
1280
put(unsigned int new_value)1281 void ANSEL_12F::put(unsigned int new_value)
1282 {
1283 unsigned int cfgmax = adcon1->getNumberOfChannels();
1284 unsigned int i;
1285 Dprintf(("ANSEL_12F::put %x cfgmax %u\n", new_value, cfgmax));
1286 trace.raw(write_trace.get() | value.get());
1287
1288 /*
1289 Generate ChannelConfiguration from ansel register
1290 */
1291 for (i = 0; i < cfgmax; i++)
1292 {
1293 unsigned int mask = new_value & 0x0f;
1294 adcon1->setChannelConfiguration(i, mask);
1295 }
1296
1297 /*
1298 * Convert A2D conversion times and set in adcon
1299 */
1300 set_tad(new_value & (ADCS2 | ADCS1 | ADCS0));
1301 value.put(new_value & 0x7f);
1302 adcon1->setADCnames();
1303 }
1304
1305
1306 //------------------------------------------------------
1307 // ADCON0_32X used in 10f32x. Uses ADCON1 as virtual rather than physical
1308 // register
1309 //
ADCON0_32X(Processor * pCpu,const char * pName,const char * pDesc)1310 ADCON0_32X::ADCON0_32X(Processor *pCpu, const char *pName, const char *pDesc)
1311 : ADCON0(pCpu, pName, pDesc)
1312 {
1313 GO_bit = GO; //ADCON0 and ADCON0_10 have GO flag at different bit
1314 valid_bits = 0xff;
1315 }
1316
1317
put(unsigned int new_value)1318 void ADCON0_32X::put(unsigned int new_value)
1319 {
1320 unsigned int old_value = value.get();
1321 new_value &= valid_bits; // clear unused bits
1322 /* On first call of this function old_value has already been set to
1323 * it's default value, but we want to call set_channel_in. First
1324 * gives us a way to do this.
1325 */
1326 trace.raw(write_trace.get() | value.get());
1327 Dprintf(("ADCON0_32X::put new_value=0x%02x old_value=0x%02x\n", new_value, old_value));
1328 // tell adcon1 to use Vref
1329 //RRR adcon1->set_cfg_index((new_value & VCFG) ? 2: 0);
1330
1331 switch (new_value & (ADCS0 | ADCS1 | ADCS2))
1332 {
1333 case (ADCS0|ADCS1):
1334 case 0:
1335 Tad = 2;
1336 break;
1337
1338 case ADCS0:
1339 Tad = 8;
1340 break;
1341
1342 case ADCS1:
1343 Tad = 32;
1344 break;
1345 }
1346
1347 if (new_value & ADCS2)
1348 {
1349 Tad *= 2;
1350 }
1351
1352 // If ADON is clear GO cannot be set
1353 if ((new_value & ADON) != ADON)
1354 {
1355 new_value &= ~GO_bit;
1356 }
1357
1358 // SET: Reflect it first!
1359 value.put(new_value);
1360
1361 if (new_value & ADON)
1362 {
1363 // The A/D converter is being turned on (or maybe left on)
1364 if ((new_value & ~old_value) & GO_bit)
1365 {
1366 if (verbose)
1367 {
1368 printf("starting A2D conversion\n");
1369 }
1370
1371 // The 'GO' bit is being turned on, which is request to initiate
1372 // and A/D conversion
1373 start_conversion();
1374 }
1375
1376 }
1377 else
1378 {
1379 stop_conversion();
1380 }
1381 }
1382
1383
1384 // catch stimulus and set channel voltage
1385 //
a2d_stimulus(ADCON1 * arg,int chan,const char * cPname,double _Vth,double _Zth)1386 a2d_stimulus::a2d_stimulus(ADCON1 * arg, int chan, const char *cPname, double _Vth, double _Zth)
1387 : stimulus(cPname, _Vth, _Zth)
1388 {
1389 _adcon1 = arg;
1390 channel = chan;
1391 }
1392
1393
set_nodeVoltage(double v)1394 void a2d_stimulus::set_nodeVoltage(double v)
1395 {
1396 Dprintf(("nodeVoltage =%.1f\n", v));
1397 nodeVoltage = v;
1398 _adcon1->setVoltRef(channel, v);
1399 }
1400
1401
1402 //
1403 //--------------------------------------------------
1404 // member functions for the FVRCON class
1405 //--------------------------------------------------
1406 //
FVRCON(Processor * pCpu,const char * pName,const char * pDesc,unsigned int bitMask,unsigned int alwaysOne)1407 FVRCON::FVRCON(Processor *pCpu, const char *pName, const char *pDesc, unsigned int bitMask, unsigned int alwaysOne)
1408 : sfr_register(pCpu, pName, pDesc)
1409 {
1410 mask_writable = bitMask;
1411 always_one = alwaysOne;
1412 }
1413
1414
put(unsigned int new_value)1415 void FVRCON::put(unsigned int new_value)
1416 {
1417 unsigned int masked_value = (new_value & mask_writable) | always_one;
1418 trace.raw(write_trace.get() | value.get());
1419 value.put(masked_value);
1420 compute_VTemp(masked_value);
1421 compute_FVR_AD(masked_value);
1422 compute_FVR_CDA(masked_value);
1423 }
1424
1425
put_value(unsigned int new_value)1426 void FVRCON::put_value(unsigned int new_value)
1427 {
1428 unsigned int masked_value = (new_value & mask_writable) | always_one;
1429 put(masked_value);
1430 update();
1431 }
1432
1433
compute_VTemp(unsigned int fvrcon)1434 double FVRCON::compute_VTemp(unsigned int fvrcon)
1435 {
1436 double ret = -1.0;
1437
1438 if ((fvrcon & TSEN) && cpu14->m_cpu_temp)
1439 {
1440 //Transister junction threshold voltage at core temperature
1441 double Vt = 0.659 - (cpu14->m_cpu_temp->getVal() + 40.0) * 0.00132;
1442 ret = ((Processor *)cpu)->get_Vdd() - ((fvrcon & TSRNG) ? 4.0 : 2.0) * Vt;
1443
1444 if (ret < 0.0)
1445 {
1446 ret = -1.0;
1447 std::cerr << "Warning FVRCON Vdd too low for temperature range\n";
1448 }
1449 }
1450
1451 if (adcon1)
1452 {
1453 adcon1->setVoltRef(VTemp_AD_chan, ret);
1454 }
1455
1456 return ret;
1457 }
1458
1459
compute_FVR_AD(unsigned int fvrcon)1460 double FVRCON::compute_FVR_AD(unsigned int fvrcon)
1461 {
1462 double ret = -1.;
1463 unsigned int gain = (fvrcon & (ADFVR0 | ADFVR1));
1464
1465 if ((fvrcon & FVREN) && gain)
1466 {
1467 ret = 1.024 * (1 << (gain - 1));
1468 }
1469
1470 if (ret > ((Processor *)cpu)->get_Vdd())
1471 {
1472 std::cerr << "warning FVRCON FVRAD > Vdd\n";
1473 ret = -1.0;
1474 }
1475
1476 if (adcon1)
1477 {
1478 adcon1->setVoltRef(FVRAD_AD_chan, ret);
1479 }
1480
1481 return ret;
1482 }
1483
1484
compute_FVR_CDA(unsigned int fvrcon)1485 double FVRCON::compute_FVR_CDA(unsigned int fvrcon)
1486 {
1487 double ret = 0.0;
1488 unsigned int gain = (fvrcon & (CDAFVR0 | CDAFVR1)) >> 2;
1489
1490 if ((fvrcon & FVREN) && gain)
1491 {
1492 ret = 1.024 * (1 << (gain - 1));
1493 }
1494
1495 for (unsigned int i = 0; i < daccon0_list.size(); i++)
1496 {
1497 daccon0_list[i]->set_FVR_CDA_volt(ret);
1498 }
1499
1500 if (cmModule)
1501 {
1502 cmModule->set_FVR_volt(ret);
1503 }
1504
1505 if (cpscon0)
1506 {
1507 cpscon0->set_FVR_volt(ret);
1508 }
1509
1510 return ret;
1511 }
1512
1513
1514 //
1515 //--------------------------------------------------
1516 // member functions for the DAC classes
1517 //--------------------------------------------------
1518 //
DACCON0(Processor * pCpu,const char * pName,const char * pDesc,unsigned int bitMask,unsigned int bit_res)1519 DACCON0::DACCON0(Processor *pCpu, const char *pName, const char *pDesc, unsigned int bitMask, unsigned int bit_res)
1520 : sfr_register(pCpu, pName, pDesc),
1521 bit_mask(bitMask), bit_resolution(bit_res)
1522 {
1523 Pin_Active[0] = false;
1524 Pin_Active[1] = false;
1525 Vth[0] = 0.0;
1526 Vth[1] = 0.0;
1527 Zth[0] = 0.0;
1528 Zth[1] = 0.0;
1529 driving[0] = false;
1530 driving[1] = false;
1531 output_pin[0] = nullptr;
1532 output_pin[1] = nullptr;
1533 }
1534
1535
put(unsigned int new_value)1536 void DACCON0::put(unsigned int new_value)
1537 {
1538 unsigned int masked_value = (new_value & bit_mask);
1539 trace.raw(write_trace.get() | value.get());
1540 value.put(masked_value);
1541 compute_dac(masked_value);
1542 }
1543
1544
put_value(unsigned int new_value)1545 void DACCON0::put_value(unsigned int new_value)
1546 {
1547 unsigned int masked_value = (new_value & bit_mask);
1548 value.put(masked_value);
1549 compute_dac(masked_value);
1550 update();
1551 }
1552
1553
set_dcaccon1_reg(unsigned int reg)1554 void DACCON0::set_dcaccon1_reg(unsigned int reg)
1555 {
1556 daccon1_reg = reg;
1557 compute_dac(value.get());
1558 }
1559
1560
compute_dac(unsigned int value)1561 void DACCON0::compute_dac(unsigned int value)
1562 {
1563 double Vhigh = get_Vhigh(value);
1564 double Vlow = 0.0;
1565 double Vout;
1566
1567 if (value & DACEN) // DAC is enabled
1568 {
1569 // Max Vout will be 1 step below Vhigh.
1570 Vout = (Vhigh - Vlow) * daccon1_reg / bit_resolution + Vlow;
1571
1572 }
1573 else if (value & DACLPS)
1574 {
1575 Vout = Vhigh;
1576
1577 }
1578 else
1579 {
1580 Vout = Vlow;
1581 }
1582
1583 set_dacoutpin(value & DACOE, 0, Vout);
1584 set_dacoutpin(value & DACOE2, 1, Vout);
1585
1586 if (verbose)
1587 {
1588 printf("%s-%d adcon1 %p FVRCDA_AD_chan %u Vout %.2f\n", __FUNCTION__, __LINE__, adcon1, FVRCDA_AD_chan, Vout);
1589 }
1590
1591 Dprintf(("DAC DACEN %d output %.2f adcon1=%p Vhigh %.2f bit_res %u daccon1_reg %u\n", (bool)(value & DACEN), Vout, adcon1, Vhigh, bit_resolution, daccon1_reg));
1592
1593 if (adcon1)
1594 {
1595 adcon1->setVoltRef(FVRCDA_AD_chan, Vout);
1596 }
1597
1598 if (cmModule)
1599 {
1600 cmModule->set_DAC_volt(Vout);
1601 }
1602
1603 if (cpscon0)
1604 {
1605 cpscon0->set_DAC_volt(Vout);
1606 }
1607 }
1608
1609
set_dacoutpin(bool output_enabled,int chan,double Vout)1610 void DACCON0::set_dacoutpin(bool output_enabled, int chan, double Vout)
1611 {
1612 IO_bi_directional_pu *out_pin;
1613
1614 if (output_pin[chan])
1615 {
1616 out_pin = (IO_bi_directional_pu *) & (output_pin[chan]->getPin());
1617
1618 }
1619 else
1620 {
1621 return;
1622 }
1623
1624 if (output_enabled)
1625 {
1626 if (!Pin_Active[chan]) // DACOUT going to active
1627 {
1628 std::string pin_name = name().substr(0, 4);
1629
1630 if (pin_name == "dacc")
1631 {
1632 pin_name = "dacout";
1633
1634 }
1635 else if (chan == 0)
1636 {
1637 pin_name += "-1";
1638
1639 }
1640 else
1641 {
1642 pin_name += "-2";
1643 }
1644
1645 output_pin[chan]->AnalogReq(this, true, pin_name.c_str());
1646 Pin_Active[chan] = true;
1647 Vth[chan] = out_pin->get_VthIn();
1648 Zth[chan] = out_pin->get_ZthIn();
1649 driving[chan] = out_pin->getDriving();
1650 out_pin->set_ZthIn(150e3);
1651 out_pin->setDriving(false);
1652 }
1653
1654 out_pin->set_VthIn(Vout);
1655 out_pin->updateNode();
1656
1657 }
1658 else if (Pin_Active[chan]) // DACOUT leaving active
1659 {
1660 output_pin[chan]->AnalogReq(this, false, output_pin[chan]->getPin().name().c_str());
1661 Pin_Active[chan] = false;
1662 out_pin->set_VthIn(Vth[chan]);
1663 out_pin->set_ZthIn(Zth[chan]);
1664 out_pin->setDriving(driving[chan]);
1665 out_pin->updateNode();
1666 }
1667 }
1668
1669
get_Vhigh(unsigned int value)1670 double DACCON0::get_Vhigh(unsigned int value)
1671 {
1672 unsigned int mode = (value & (DACPSS0 | DACPSS1)) >> 2;
1673
1674 switch (mode)
1675 {
1676 case 0: // Vdd
1677 return ((Processor *)cpu)->get_Vdd();
1678
1679 case 1: // Vref+ pin, get is from A2D setup
1680 if (adcon1)
1681 {
1682 return (adcon1->getChannelVoltage(adcon1->getVrefHiChannel(0)));
1683 }
1684
1685 std::cerr << "ERROR DACCON0 DACPSS=01b adcon1 not set\n";
1686 return 0.0;
1687
1688 case 2: // Fixed Voltage Reference
1689 return FVR_CDA_volt;
1690
1691 case 3: // Reserved value
1692 std::cerr << "ERROR DACCON0 DACPSS=11b is reserved value\n";
1693 return 0.0;
1694 }
1695
1696 return 0.0; // cant get here
1697 }
1698
1699
DACCON1(Processor * pCpu,const char * pName,const char * pDesc,unsigned int bitMask,DACCON0 * _daccon0)1700 DACCON1::DACCON1(Processor *pCpu, const char *pName, const char *pDesc, unsigned int bitMask, DACCON0 *_daccon0)
1701 : sfr_register(pCpu, pName, pDesc),
1702 bit_mask(bitMask), daccon0(_daccon0)
1703 {
1704 }
1705
1706
put(unsigned int new_value)1707 void DACCON1::put(unsigned int new_value)
1708 {
1709 trace.raw(write_trace.get() | value.get());
1710 put_value(new_value);
1711 }
1712
1713
put_value(unsigned int new_value)1714 void DACCON1::put_value(unsigned int new_value)
1715 {
1716 unsigned int masked_value = (new_value & bit_mask);
1717 value.put(masked_value);
1718 Dprintf(("DAC daccon0=%p new_value 0x%x bit_mask 0x%x\n", daccon0, new_value, bit_mask));
1719
1720 if (daccon0)
1721 {
1722 daccon0->set_dcaccon1_reg(masked_value);
1723 }
1724
1725 update();
1726 }
1727
1728
1729 //------------------------------------------------------
1730 // ADCON2_diff for A2D with differential input ie 16f178*
1731 //
ADCON2_DIF(Processor * pCpu,const char * pName,const char * pDesc)1732 ADCON2_DIF::ADCON2_DIF(Processor *pCpu, const char *pName, const char *pDesc)
1733 : sfr_register(pCpu, pName, pDesc)
1734 {
1735 }
1736
1737
1738 #ifdef RRR
1739 //------------------------------------------------------
1740 // ADCON0
1741 //
ADCON0_32(Processor * pCpu,const char * pName,const char * pDesc)1742 ADCON0_32::ADCON0_32(Processor *pCpu, const char *pName, const char *pDesc)
1743 : ADCON0(pCpu, pName, pDesc)
1744 {
1745 }
1746
1747
put(unsigned int new_value)1748 void ADCON0_32::put(unsigned int new_value)
1749 {
1750 trace.raw(write_trace.get() | value.get());
1751 set_Tad(new_value);
1752 unsigned int old_value = value.get();
1753 // SET: Reflect it first!
1754 value.put(new_value);
1755
1756 if (new_value & ADON)
1757 {
1758 // The A/D converter is being turned on (or maybe left on)
1759 if ((new_value & ~old_value) & GO_bit)
1760 {
1761 if (verbose)
1762 {
1763 printf("starting A2D conversion\n");
1764 }
1765
1766 Dprintf(("starting A2D conversion\n"));
1767 // The 'GO' bit is being turned on, which is request to initiate
1768 // and A/D conversion
1769 start_conversion();
1770 }
1771
1772 }
1773 else
1774 {
1775 stop_conversion();
1776 }
1777 }
1778
1779
put_conversion()1780 void ADCON0_32::put_conversion()
1781 {
1782 double dRefSep = m_dSampledVrefHi - m_dSampledVrefLo;
1783 double dNormalizedVoltage;
1784 double m_dSampledVLo;
1785
1786 if (channel == 0x0e) // shift AN21 to adcon0 channel
1787 {
1788 channel = 0x15;
1789 }
1790
1791 if (channel == 0x0f) // use ADNREF for V-
1792 {
1793 m_dSampledVLo = getVrefLo();
1794
1795 }
1796 else
1797 {
1798 m_dSampledVLo = getChannelVoltage(channel);
1799 }
1800
1801 dNormalizedVoltage = (m_dSampledVoltage - m_dSampledVLo) / dRefSep;
1802 dNormalizedVoltage = dNormalizedVoltage > 1.0 ? 1.0 : dNormalizedVoltage;
1803 int converted = (int)(m_A2DScale * dNormalizedVoltage + 0.5);
1804 Dprintf(("put_conversion: V+:%g V-:%g Vrefhi:%g Vreflo:%g conversion:%d normV:%g\n",
1805 m_dSampledVoltage, m_dSampledVLo,
1806 m_dSampledVrefHi, m_dSampledVrefLo, converted, dNormalizedVoltage));
1807
1808 if (verbose)
1809 {
1810 printf("result=0x%02x\n", converted);
1811 }
1812
1813 Dprintf(("%u-bit result 0x%x ADFM %d\n", m_nBits, converted, get_ADFM()));
1814
1815 if (!get_ADFM()) // signed
1816 {
1817 int sign = 0;
1818
1819 if (converted < 0)
1820 {
1821 sign = 1;
1822 converted = -converted;
1823 }
1824
1825 converted = ((converted << (16 - m_nBits)) % 0xffff) | sign;
1826 }
1827
1828 adresl->put(converted & 0xff);
1829 adres->put((converted >> 8) & 0xff);
1830 }
1831
1832
1833 #endif //RRR
1834
1835
1836 //------------------------------------------------------
1837 // ADCON2_TRIG for A2D with start trigger ie 16f1503
1838 //
ADCON2_TRIG(Processor * pCpu,const char * pName,const char * pDesc)1839 ADCON2_TRIG::ADCON2_TRIG(Processor *pCpu, const char *pName, const char *pDesc)
1840 : sfr_register(pCpu, pName, pDesc), valid_bits(0xf0)
1841 {
1842 for (auto &a: CMxsync)
1843 {
1844 a = false;
1845 }
1846 }
1847
1848
put(unsigned int new_value)1849 void ADCON2_TRIG::put(unsigned int new_value)
1850 {
1851 new_value &= valid_bits;
1852 trace.raw(write_trace.get() | value.get());
1853 put_value(new_value);
1854 }
1855
1856
setCMxsync(unsigned int cm,bool output)1857 void ADCON2_TRIG::setCMxsync(unsigned int cm, bool output)
1858 {
1859 unsigned int select = value.get() >> 4;
1860 printf("setCMxsync() %s cm=%u output=%d\n", name().c_str(), cm, output);
1861
1862 if (select)
1863 {
1864 }
1865
1866 assert(cm < 4);
1867 CMxsync[cm] = output;
1868 }
1869
1870
t0_overflow()1871 void ADCON2_TRIG::t0_overflow()
1872 {
1873 unsigned int select = value.get() >> 4;
1874
1875 if (select == 0x02)
1876 {
1877 if (m_adcon0 && (m_adcon0->value.get() & ADCON0::ADON))
1878 {
1879 Dprintf(("trigger from timer 0\n"));
1880 m_adcon0->start_conversion();
1881 }
1882 }
1883 }
1884
1885