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