2
Copyright( C) 2008,2015 Roy R Rankin
3
Copyright( C) 2006 T. Scott Dattalo
5
This file is part of the libgpsim library of gpsim
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.
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.
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>.
23
#include "pic-processor.h"
28
static PinModule InvalidAnInput;
33
#define Dprintf(arg) {printf("%s:%d ",__FILE__,__LINE__); printf arg; }
35
#define Dprintf(arg) {}
39
ADCON0_V2::ADCON0_V2(Processor *pCpu, const char *pName)
40
: SfrReg(pCpu, pName),
41
adres(0), adresl(0), adcon1(0), adcon2(0), intcon(0), pir1v2(0),
42
ad_state(AD_IDLE), channel_mask(15),
48
void ADCON0_V2::setA2DBits( uint nBits ) // Set resolution of A2D converter
50
m_A2DScale =( 1<<nBits) - 1;
54
void ADCON0_V2::start_conversion(void)
56
uint64_t fc = cpu->currentCycle();
58
Dprintf(("starting A/D conversion\n"));
60
if(!(value.get() & ADON) )
66
// Get the A/D Conversion Clock Select bits
68
// This switch case will get the ADCS bits and set the Tad, or The A/D
69
// converter clock period. Tad is the number of the oscillator periods
70
// rather instruction cycle periods.
72
Tad = adcon2->get_tad();
73
Tacq = adcon2->get_nacq();
75
if( Tad == 0 ) // RC time source
79
Tad =( m_RCtime*cpu->get_frequency());
80
Tad = Tad < 2 ? 2 : Tad;
85
if( Tacq == 0) fc += 1; // if Tacq is 0, go to acqusition on next clock cycle
87
else fc +=( Tacq * Tad ) / cpu->get_ClockPerInstr();
89
if( ad_state != AD_IDLE )
91
// The A/D converter is either 'converting' or 'acquiring'
92
// in either case, there is callback break that needs to be moved.
95
cpu->reassign_break( future_cycle, fc, this );
97
else cpu->setBreakAbs( fc, this );
100
ad_state = AD_ACQUIRING;
103
void ADCON0_V2::stop_conversion(void)
108
void ADCON0_V2::put( uint new_value )
110
uint old_value = value.get();
111
// SET: Reflect it first!
112
value.put(new_value);
114
if( new_value & ADON ) // The A/D converter is being turned on( or maybe left on)
117
/*if( ctmu_stim) // deal with ctmu stimulus for channel change or ON/OFF
119
if( (old_value ^ new_value) &( ADON|CHS0|CHS1|CHS2|CHS3))
121
if ( new_value & ADON) attach_ctmu_stim();// A/D is on
122
else if(!(new_value & ADON)) detach_ctmu_stim();// A/D is off
125
if((new_value & ~old_value) & GO) // The 'GO' bit is being turned on, which is request to initiate and A/D conversion
128
else stop_conversion();
131
/*void ADCON0_V2::set_ctmu_stim( stimulus *_ctmu_stim )
133
ctmu_stim = _ctmu_stim;
134
if( value.get() & ADON ) attach_ctmu_stim();
137
void ADCON0_V2::put_conversion(void)
139
double dRefSep = m_dSampledVrefHi - m_dSampledVrefLo;
140
double dNormalizedVoltage;
142
dNormalizedVoltage =( dRefSep>0.0) ?
143
( m_dSampledVoltage - m_dSampledVrefLo)/dRefSep : 0.0;
144
dNormalizedVoltage = dNormalizedVoltage>1.0 ? 1.0 : dNormalizedVoltage;
146
uint converted =( uint)(m_A2DScale*dNormalizedVoltage + 0.5);
148
if(adresl) // non-null for more than 8 bit conversion
150
if( adcon2->value.get() & ADCON2_V2::ADFM )
152
adresl->put( converted & 0xff );
153
adres->put( (converted >> 8) & 0x3 );
157
adresl->put( (converted << 6) & 0xc0);
158
adres->put( (converted >> 2) & 0xff);
161
else adres->put((converted ) & 0xff);
164
// ADCON0_V2 callback is called when the cycle counter hits the break point that
165
// was set in ADCON0_V2::put.
167
void ADCON0_V2::callback(void)
171
switch(ad_state) // The a/d converter is simulated with a state machine.
177
channel =( value.get() >> 2) & channel_mask;
179
m_dSampledVoltage = adcon1->getChannelVoltage( channel );
180
m_dSampledVrefHi = adcon1->getVrefHi();
181
m_dSampledVrefLo = adcon1->getVrefLo();
183
future_cycle = cpu->currentCycle() +( (m_nBits+1)*Tad )/cpu->get_ClockPerInstr();
184
cpu->setBreakAbs( future_cycle, this );
185
ad_state = AD_CONVERTING;
191
value.put(value.get() &( ~GO)); // Clear the GO/!DONE flag.
197
//------------------------------------------------------
199
void ADCON0_V2::set_interrupt(void)
202
intcon->peripheral_interrupt();
206
void ADCON0_V2::detach_ctmu_stim()
210
if( active_stim >=0 && ctmu_stim )
212
PinModule *pm=adcon1->get_A2Dpin( active_stim );
213
if( pm && pm->getPin().snode && ctmu_stim)
215
pm->getPin().snode->detach_stimulus(ctmu_stim);
216
pm->getPin().snode->update();
221
/* Move ctmu_stim onto currently selected A/D channel input pin.
222
if channel has not changed, just return.
223
Stimulus can only be attached if pin is connected to a node.
225
void ADCON0_V2::attach_ctmu_stim()
227
int channel =( value.get() >> 2) & channel_mask;
228
if ( active_stim == channel ) return;
229
else if( active_stim >= 0 ) detach_ctmu_stim();
231
PinModule *pm=adcon1->get_A2Dpin(channel);
235
/*if( !(pm->getPin().snode) )
237
printf("Warning ADCON0_V2::attach_ctmu_stim %s has no node attached CTMU will not work properly\n", pm->getPin().name_str.c_str());
241
pm->getPin().snode->attach_stimulus(ctmu_stim);
242
pm->getPin().snode->update();
243
active_stim = channel;
249
//------------------------------------------------------
252
ADCON1_V2::ADCON1_V2(Processor *pCpu, const char *pName)
253
: SfrReg(pCpu, pName ),
254
m_AnalogPins(0), m_nAnalogChannels(0),
255
mValidCfgBits(0), mCfgBitShift(0), m_vrefHiChan(-1),
256
m_vrefLoChan(-1), mIoMask(0), m_adcon0(0)
258
for( int i=0; i<(int)cMaxConfigurations; i++)
259
setChannelConfiguration(i, 0);
261
ADCON1_V2::~ADCON1_V2()
263
delete [] m_AnalogPins;
266
void ADCON1_V2::put( uint new_value )
268
uint new_mask = get_adc_configmask(new_value);
269
uint diff = mIoMask ^ new_mask;
271
Dprintf( ( "ADCON1_V2::put( %02X ) - new_mask %02X\n", new_value, new_mask ));
275
for(uint i = 0; i < m_nAnalogChannels; i++)
277
if( (diff &( 1 << i)) && m_AnalogPins[i] != &InvalidAnInput)
279
if( new_mask &( 1<<i))
281
snprintf(newname, sizeof(newname), "an%u", i);
282
m_AnalogPins[i]->AnalogReq(this, true, newname);
286
m_AnalogPins[i]->AnalogReq(this, false, "?" /*m_AnalogPins[i]->getPin().name_str.c_str()*/);
291
value.put(new_value);
295
* If A2D uses PCFG, call for each PCFG value( cfg 0 to 15) with
296
* each set bit of bitMask indicating port is an analog port
297
*( either A2D input port or Vref). Processors which use an A2D
298
* method that uses ANSEL register will not call this.
300
* As an example, for the following Port Configuration Control bit:
301
* PCFG AN7 AN6 AN5 AN4 AN3 AN2 AN1 AN0
302
* ---- ---- ----- ----- ----- ----- ----- ----- -----
303
* 1100 D D D A Vref+ Vref- A A
305
* then call setChannelConfiguration with cfg = 12 , bitMask = 0x1f
307
void ADCON1_V2::setChannelConfiguration( uint cfg, uint bitMask )
309
if( cfg < cMaxConfigurations) m_configuration_bits[cfg] = bitMask;
313
* Performs same function as setChannelConfiguration, but defines
314
* all entiries in configuration table in one call.
317
void ADCON1_V2::setChanTable(
318
uint m0, uint m1, uint m2, uint m3,
319
uint m4, uint m5, uint m6, uint m7,
320
uint m8, uint m9, uint m10, uint m11,
321
uint m12, uint m13, uint m14, uint m15)
323
m_configuration_bits[0] = m0;
324
m_configuration_bits[1] = m1;
325
m_configuration_bits[2] = m2;
326
m_configuration_bits[3] = m3;
327
m_configuration_bits[4] = m4;
328
m_configuration_bits[5] = m5;
329
m_configuration_bits[6] = m6;
330
m_configuration_bits[7] = m7;
331
m_configuration_bits[8] = m8;
332
m_configuration_bits[9] = m9;
333
m_configuration_bits[10] = m10;
334
m_configuration_bits[11] = m11;
335
m_configuration_bits[12] = m12;
336
m_configuration_bits[13] = m13;
337
m_configuration_bits[14] = m14;
338
m_configuration_bits[15] = m15;
341
void ADCON1_V2::setNumberOfChannels( uint nChannels ) // Number of A2D channels processor supports
343
PinModule** save = NULL;
345
if( !nChannels || nChannels <= m_nAnalogChannels) return;
347
if( m_nAnalogChannels && nChannels > m_nAnalogChannels )
350
m_AnalogPins = new PinModule *[nChannels];
352
for( uint i=0; i<nChannels; i++ )
354
if( i < m_nAnalogChannels )
356
if( save) m_AnalogPins[i] = save[i];
358
else m_AnalogPins[i] = &InvalidAnInput;
360
if( save) delete save;
362
m_nAnalogChannels = nChannels;
366
* Configure use of adcon1 register
367
* The register is first anded with mask and then shifted
368
* right shift bits. The result being either PCFG or VCFG
369
* depending on the type of a2d being used.
371
void ADCON1_V2::setValidCfgBits(uint mask, uint shift)
373
mValidCfgBits = mask;
374
mCfgBitShift = shift;
378
* get_adc_configmask() is called with the value of the adcon1 register
380
* if the configuration bit mask is less than 16, the confiiguration bit table
381
* is used to determine if the channel is an analog port.
383
* Otherwise, each bit in the adcon1 register indicates that the port is
384
* digital(1) or analog(0) aka the 18f1220.
387
uint ADCON1_V2::get_adc_configmask(uint reg)
390
if( mValidCfgBits <= 0xf) // use config bit table
392
return( m_configuration_bits[ (reg>>mCfgBitShift) & mValidCfgBits ] );
394
else // register directly gives Analog ports( 18f1220)
396
return( ~(reg >> mCfgBitShift) & mValidCfgBits);
401
* Associate a processor I/O pin with an A2D channel
403
void ADCON1_V2::setIOPin(uint channel, PinModule *newPin)
406
if( channel < m_nAnalogChannels &&
407
m_AnalogPins[channel] == &InvalidAnInput && newPin!=0) {
408
m_AnalogPins[channel] = newPin;
412
printf("WARNING %s channel %u, cannot set IOpin\n",__FUNCTION__, channel);
413
if( m_AnalogPins[channel] != &InvalidAnInput)
414
printf("Pin Already assigned\n");
415
else if( channel > m_nAnalogChannels)
416
printf("channel %u >= number of channels %u\n", channel, m_nAnalogChannels);
421
//------------------------------------------------------
422
PinModule *ADCON1_V2::get_A2Dpin(uint channel)
424
if( ( 1<<channel) & get_adc_configmask(value.data) )
426
PinModule *pm = m_AnalogPins[channel];
427
if( pm != &InvalidAnInput)
429
cout << "ADCON1_V2::getChannelVoltage channel " << channel <<
435
//------------------------------------------------------
436
double ADCON1_V2::getChannelVoltage( uint channel )
440
if( channel <= m_nAnalogChannels )
442
PinModule* pm = get_A2Dpin( channel );
445
////if( pm->getPin().snode) pm->getPin().snode->update();
446
voltage = pm->getPin().get_nodeVoltage();
450
cout << "ADCON1_V2::getChannelVoltage channel " << channel << " not a valid pin\n";
454
else cout << "ADCON1_V2::getChannelVoltage channel " << channel << " > m_nAnalogChannels " << m_nAnalogChannels << "\n";
459
double ADCON1_V2::getVrefHi()
461
assert(m_vrefHiChan >= 0); // m_vrefHiChan has not been set
462
if( ( m_adcon0 &&( m_adcon0->value.data & ADCON0_V2::VCFG0)) ||
463
( !m_adcon0 &&( value.data & VCFG0))) // Use Vref+
464
return(getChannelVoltage(m_vrefHiChan));
466
return cpu->get_Vdd();
469
double ADCON1_V2::getVrefLo()
471
assert(m_vrefLoChan >= 0); // m_vrefLoChan has not been set
472
if( ( m_adcon0 &&( m_adcon0->value.data & ADCON0_V2::VCFG1)) ||
473
( !m_adcon0 &&( value.data & VCFG1))) // Use Vref-
474
return getChannelVoltage(m_vrefLoChan);
479
//------------------------------------------------------
482
ADCON2_V2::ADCON2_V2(Processor *pCpu, const char *pName )
483
: SfrReg(pCpu, pName )
487
char ADCON2_V2::get_nacq()
489
static char acq_tab[8] = { 0, 2, 4, 6, 8, 12, 16, 20};
490
return(acq_tab[((value.get() &( ACQT2 | ACQT1 | ACQT0)) >> 3) ]);
493
char ADCON2_V2::get_tad()
495
static char adcs_tab[8] = { 2, 8, 32, 0, 4, 16, 64, 0};
496
return(adcs_tab[(value.get() &( ADCS2 | ADCS1 | ADCS0)) ]);
499
bool ADCON2_V2::get_adfm()
501
return((value.get() & ADFM) == ADFM);
504
ADCON1_2B::ADCON1_2B(Processor *pCpu, const char *pName ) :
505
ADCON1_V2(pCpu, pName ), Vctmu(0.0), Vdac(0.0), Vfvr_buf2(0)
509
//------------------------------------------------------
510
PinModule *ADCON1_2B::get_A2Dpin(uint channel)
512
if(channel <= m_nAnalogChannels)
514
PinModule *pm = m_AnalogPins[channel];
515
if( pm != &InvalidAnInput)
517
cout << "ADCON1_V2::getChannelVoltage channel " << channel << " not analog\n";
521
double ADCON1_2B::getChannelVoltage(uint channel)
525
if( channel <= m_nAnalogChannels )
527
PinModule *pm = get_A2Dpin(channel);
528
if( pm ) voltage = pm->getPin().get_nodeVoltage();
531
cout << "ADCON1_2B::getChannelVoltage channel " << channel << " not valid for A2D\n";
534
else if( channel == CTMU) voltage = Vctmu;
535
else if( channel == DAC) voltage = Vdac;
536
else if( channel == FVR_BUF2) voltage = Vfvr_buf2;
537
else cout << "ADCON1_2B::getChannelVoltage channel " << channel << " not valid for A2D\n";
541
double ADCON1_2B::getVrefHi()
543
assert(m_vrefHiChan >= 0); // m_vrefHiChan has not been set
545
switch( value.data &( PVCFG1 | PVCFG0))
548
case( PVCFG1 | PVCFG0 ): // reserved use Vdd
549
return cpu->get_Vdd();
552
case PVCFG0: // use external pin Vref+
553
return(getChannelVoltage(m_vrefHiChan));
556
case PVCFG1: // use FVR buf2
562
double ADCON1_2B::getVrefLo()
564
assert(m_vrefLoChan >= 0); // m_vrefLoChan has not been set
566
// external pin Vref- ?
567
if( (value.data &( NVCFG1 | NVCFG0)) == NVCFG1)
568
return getChannelVoltage(m_vrefLoChan);
573
void ADCON1_2B::put(uint new_value)
575
value.put(new_value);
578
// Special trigger from ctmu module
579
void ADCON1_2B::ctmu_trigger()
581
if( value.data & TRIGSEL) // special trigger from CTMU active?
584
uint value = m_adcon0->value.data;
585
if( (value & ADCON0_V2::ADON))
587
value |= ADCON0_V2::GO;
588
m_adcon0->put(value);
592
// Special trigger from cpp module
593
void ADCON1_2B::ccp_trigger()
595
if( !(value.data & TRIGSEL)) // special trigger from ccp active?
597
uint value = m_adcon0->value.data;
598
if( (value & ADCON0_V2::ADON))
600
value |= ADCON0_V2::GO;
601
m_adcon0->put(value);
606
ANSEL_2B::ANSEL_2B(Processor *pCpu, const char *pName )
607
: SfrReg(pCpu, pName ), mask(0)
609
for(int i=0; i<8; i++)
611
analog_channel[i] = -1;
612
m_AnalogPins[i] = &InvalidAnInput;
616
void ANSEL_2B::put(uint new_value)
618
put_value(new_value);
621
void ANSEL_2B::put_value( uint new_value )
625
uint diff = value.get() ^ new_value;
627
value.put(new_value);
629
for(int i = 0; i < 8; i++)
631
if( ((1<<i) & diff) &&( m_AnalogPins[i] != &InvalidAnInput))
633
if( new_value &( 1<<i))
635
snprintf( newname, sizeof(newname), "an%d", analog_channel[i] );
636
m_AnalogPins[i]->AnalogReq(this, true, newname);
640
m_AnalogPins[i]->AnalogReq( this, false, "?" /*m_AnalogPins[i]->getPin().name_str.c_str()*/);
645
void ANSEL_2B::setIOPin( uint channel, PinModule* port, ADCON1_2B* adcon1 )
648
uint pin = port->getPinNumber();
649
m_AnalogPins[pin] = port;
650
analog_channel[pin] = channel;
651
adcon1->setIOPin(channel, port);
654
if( (1<<pin) & value.get() )
656
snprintf(newname, sizeof(newname), "an%u", channel);
657
m_AnalogPins[pin]->AnalogReq(this, true, newname);
660
ANSEL_2A::ANSEL_2A(Processor *pCpu, const char *pName )
661
: ANSEL_2B(pCpu, pName )
664
void ANSEL_2A::setIOPin(uint channel, PinModule *port, ADCON1_2B *adcon1)
667
uint bit = channel & 7;
668
m_AnalogPins[bit] = port;
669
analog_channel[bit] = channel;
670
adcon1->setIOPin(channel, port);
673
if( (1<<bit) & value.get())
675
snprintf(newname, sizeof(newname), "an%u", channel);
676
m_AnalogPins[bit]->AnalogReq(this, true, newname);
680
//--------------------------------------------------
681
// member functions for the FVRCON_V2 class
682
// with one set of gains and FVRST set after delay
683
//--------------------------------------------------
685
FVRCON_V2::FVRCON_V2(Processor *pCpu, const char *pName, uint bitMask)
686
: SfrReg(pCpu, pName ), future_cycle(0),
687
adcon1(0), daccon0(0), cmModule(0), cpscon0(0)
689
mask_writable = bitMask;
692
void FVRCON_V2::put(uint new_value)
694
uint masked_value =( new_value & mask_writable);
695
put_value(masked_value);
698
void FVRCON_V2::put_value(uint new_value)
700
uint diff = value.get() ^ new_value;
704
if( diff & FVREN ) new_value &= ~FVRRDY; // Clear FVRRDY regardless of ON or OFF
705
if( new_value & FVREN ) // Enable ON?
707
future_cycle = cpu->currentCycle() + 25e-6 /cpu->seconds_per_cycle();
708
cpu->setBreakAbs( future_cycle, this );
710
else if( future_cycle )
712
cpu->clear_break(this);
716
value.put( new_value );
717
compute_FVR( new_value );
722
// Set FVRRDY bit after timeout
723
void FVRCON_V2::callback()
726
put_value(value.get() | FVRRDY);
731
double FVRCON_V2::compute_FVR(uint fvrcon)
735
if( fvrcon & FVRRDY )
737
switch(fvrcon &( FVRS0 | FVRS1))
739
case 0: // output is off
743
case FVRS0: // Gain = 1
747
case FVRS1: // Gain = 2
751
case( FVRS0|FVRS1): // Gain = 4
756
if( ret > cpu->get_Vdd() )
758
cerr << "warning FVRCON FVRAD("<< ret <<") > Vdd(" <<cpu->get_Vdd() << ")\n";
761
for( uint i=0; i<daccon0_list.size(); i++)
763
daccon0_list[i]->set_FVR_CDA_volt(ret);
765
if( adcon1 ) adcon1->setVoltRef( ret );
766
if( cmModule ) cmModule->set_FVR_volt( ret );
767
if( cpscon0 ) cpscon0->set_FVR_volt( ret );
771
void DACCON0_V2::compute_dac(uint value)
773
double Vhigh = get_Vhigh(value);
777
if( value & DACEN ) // DAC is enabled
779
Dprintf(("DACCON0_V2::compute_dac Vhigh %.2f daccon1_reg %x\n", Vhigh, daccon1_reg));
780
Vout =(Vhigh-Vlow)*daccon1_reg/bit_resolution - Vlow;
782
else if( value & DACLPS) Vout = Vhigh;
785
set_dacoutpin(value & DACOE, 0, Vout);
787
if( adcon1 ) adcon1->update_dac( Vout );
788
if( cmModule ) cmModule->set_DAC_volt( Vout );
789
if( cpscon0 ) cpscon0->set_DAC_volt( Vout );
792
double DACCON0_V2::get_Vhigh(uint value)
794
uint mode =( value &( DACPSS0|DACPSS1)) >> 2;
798
return cpu->get_Vdd();
800
case 1: // Vref+ pin, get is from A2D setup
802
return(adcon1->getChannelVoltage(adcon1->getVrefHiChan()));
803
cerr << "ERROR DACCON0 DACPSS=01b adcon1 not set\n";
806
case 2: // Fixed Voltage Reference
809
case 3: // Reserved value
810
cerr << "ERROR DACCON0 DACPSS=11b is reserved value\n";
813
return 0.; // cant get here