1 /*
2    Copyright (C) 2015	Roy R Rankin
3 
4 This file is part of the libgpsim library of gpsim
5 
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10 
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Lesser General Public License for more details.
15 
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, see
18 <http://www.gnu.org/licenses/lgpl-2.1.html>.
19 */
20 
21 #include "../config.h"
22 #include "14bit-processors.h"
23 #include "14bit-registers.h"
24 #include "a2d_v2.h"
25 
26 
27 #include "ctmu.h"
28 
29 //#define DEBUG
30 #if defined(DEBUG)
31 #include "../config.h"
32 #define Dprintf(arg) {printf("%s:%d ",__FILE__,__LINE__); printf arg; }
33 #else
34 #define Dprintf(arg) {}
35 #endif
36 
37 
CTMUCONH(Processor * pCpu,const char * pName,const char * pDesc,CTMU * _ctmu)38     CTMUCONH::CTMUCONH(Processor *pCpu, const char *pName,
39 		const char *pDesc, CTMU *_ctmu)
40 	: sfr_register(pCpu,pName,pDesc),
41 	ctmu(_ctmu)
42     {
43 	ctmu->ctmuconh = this;
44     }
45 
46 
put(unsigned int new_value)47     void CTMUCONH::put(unsigned int new_value)
48     {
49 	unsigned int diff = value.get() ^ new_value;
50 	trace.raw(write_trace.get() | value.get());
51 	value.put(new_value);
52 	if (diff & CTMUEN)	// on or off
53 	{
54 	    if (new_value & CTMUEN)	// enable CTMU
55 		ctmu->enable(new_value);
56 	    else
57 		ctmu->disable();	// disable CTMU
58 	}
59 	if ((diff & TGEN) || (diff & CTMUEN))	// Pulse generation
60         {
61 	   if ((new_value & TGEN) && (new_value & CTMUEN))
62 		ctmu->tgen_on();
63 	   else
64 		ctmu->tgen_off();
65 	}
66 	if (diff & IDISSEN)
67 	    ctmu->idissen(new_value & IDISSEN);
68     }
69 
CTMUCONL(Processor * pCpu,const char * pName,const char * pDesc,CTMU * _ctmu)70     CTMUCONL::CTMUCONL(Processor *pCpu, const char *pName,
71 		const char *pDesc, CTMU *_ctmu)
72 	: sfr_register(pCpu,pName,pDesc),
73 	ctmu(_ctmu)
74     {
75 	ctmu->ctmuconl = this;
76     }
77 
78 
put(unsigned int new_value)79     void CTMUCONL::put(unsigned int new_value)
80     {
81 	unsigned int diff = value.get() ^ new_value;
82 	trace.raw(write_trace.get() | value.get());
83 	value.put(new_value);
84 	if (diff)
85 	    ctmu->stat_change();
86     }
87 
CTMUICON(Processor * pCpu,const char * pName,const char * pDesc,CTMU * _ctmu)88     CTMUICON::CTMUICON(Processor *pCpu, const char *pName,
89 		const char *pDesc, CTMU *_ctmu)
90 	: sfr_register(pCpu,pName,pDesc),
91 	ctmu(_ctmu)
92     {
93 	ctmu->ctmuicon = this;
94     }
95 
put(unsigned int new_value)96     void CTMUICON::put(unsigned int new_value)
97     {
98 	unsigned int diff = value.get() ^ new_value;
99         int adj= ((new_value & 0xfc) >>2);
100         double I;
101 	trace.raw(write_trace.get() | value.get());
102 	value.put(new_value);
103 
104 	if (!diff) return;
105 
106 	if (new_value & ITRIM5)
107 	{
108 	    adj -= 0x40;
109         }
110 	switch(new_value & (IRNG0|IRNG1))
111 	{
112 	case 0: 	// Current off
113 	    I = 0.;
114 	    break;
115 
116 	case 1:			// Base current
117 	    I = 0.55e-6;	// 0.55 uA
118     	    break;
119 
120 	case 2:			// 10x Range
121 	    I = 5.5e-6;		//5.5 uA
122 	    break;
123 
124 	case 3:			// 100x Range
125 	    I = 55e-6;		// 55 uA
126 	}
127 	// AN1250 page 4 says adjustment steps 2%, no value found in 18f26k22
128 	//	spec sheet
129 	I += I * adj * 0.02;
130 
131 	ctmu->new_current(I);
132 }
133 
134 
135 class CTMU_SignalSink : public SignalSink
136 {
137 public:
CTMU_SignalSink(CTMU * _ctmu)138   CTMU_SignalSink(CTMU *_ctmu)
139     : m_state(false), m_ctmu(_ctmu)
140   {
141     assert(_ctmu);
142   }
143 
setSinkState(char new3State)144   virtual void setSinkState(char new3State)
145   {
146 	m_state = ((new3State == '0') | (new3State == 'w'))?false:true;
147 	m_ctmu->new_edge();
148   }
release()149   virtual void release() { delete this; }
get_state()150   bool get_state() { return m_state;}
151 private:
152   bool m_state;
153   CTMU *m_ctmu;
154 };
155 
156 
CTMU(Processor * pCpu)157 CTMU::CTMU(Processor *pCpu)
158   : cpu(pCpu)
159 {
160 }
161 
enable(unsigned int value)162 void CTMU::enable(unsigned int value)
163 {
164     if (!ctmu_cted1_sink)
165     {
166 	ctmu_cted1_sink = new CTMU_SignalSink(this);
167 	ctmu_cted2_sink = new CTMU_SignalSink(this);
168     }
169     m_cted1->addSink(ctmu_cted1_sink);
170     m_cted2->addSink(ctmu_cted2_sink);
171 
172     idissen(value & CTMUCONH::IDISSEN);
173     stat_change();
174 }
175 
176 
disable()177 void CTMU::disable()
178 {
179     current_off();
180     if (ctmu_cted1_sink)
181     {
182 	m_cted1->removeSink(ctmu_cted1_sink);
183 	m_cted2->removeSink(ctmu_cted2_sink);
184 	delete ctmu_cted1_sink; ctmu_cted1_sink = 0;
185 	delete ctmu_cted2_sink; ctmu_cted2_sink = 0;
186     }
187 }
current_off()188 void CTMU::current_off()
189 {
190 	ctmu_stim->set_Vth(cpu->get_Vdd());
191 	ctmu_stim->set_Zth(1e12);
192 	ctmu_stim->updateNode();
193 }
new_current(double I)194 void CTMU::new_current(double I)
195 {
196     current = I;
197     if (I)
198         resistance = Vsrc / I;
199     else
200 	resistance = 1e12;
201 }
202 
stat_change()203 void CTMU::stat_change()
204 {
205     unsigned int value = ctmuconl->value.get();
206     bool edg1 = value & CTMUCONL::EDG1STAT;
207     bool edg2 = value & CTMUCONL::EDG2STAT;
208 
209     // Don't do anything is CTMU not enables
210     if (! (ctmuconh->value.get() & CTMUCONH::CTMUEN))
211 	return;
212 
213     /* either edg1 or edg2 set, but not both */
214     if(edg1 ^ edg2)
215     {
216 	ctmu_stim->set_Vth(Vsrc);
217 	ctmu_stim->set_Zth(resistance);
218 	ctmu_stim->updateNode();
219 	if (ctmuconh->value.get() & CTMUCONH::TGEN)
220 	    ctpls_source->putState('1');
221     }
222     else
223     {
224 	current_off();
225 	if (ctmuconh->value.get() & CTMUCONH::TGEN)
226 	    ctpls_source->putState('0');
227 	if (ctmuconh->value.get() & CTMUCONH::CTTRIG)
228 	{
229 	    adcon1->ctmu_trigger();
230 	}
231     }
232 
233 }
234 #define EDG1_SEL(x) ((x) & (CTMUCONL::EDG1SEL0 | CTMUCONL::EDG1SEL1))
235 #define EDG2_SEL(x) ((x) & (CTMUCONL::EDG2SEL0 | CTMUCONL::EDG2SEL1))
new_edge()236 void CTMU::new_edge()
237 {
238    unsigned int value = ctmuconl->value.get();
239    bool state1 = ctmu_cted1_sink->get_state();
240    bool state2 = ctmu_cted2_sink->get_state();
241 
242 
243    // return if edges are blocked
244    if (!(ctmuconh->value.get() & CTMUCONH::EDGEN))
245    {
246        cted1_state = state1;
247        cted2_state = state2;
248        return;
249    }
250    if (state1 != cted1_state)	// state change on cted1
251    {
252 	//using CTED1
253 	if (EDG1_SEL(value) == (CTMUCONL::EDG1SEL0 | CTMUCONL::EDG1SEL1))
254 	{
255 	    // positive edge active
256 	    if (value & CTMUCONL::EDG1POL)
257 	    {
258 		if (state1)
259 		    value |= CTMUCONL::EDG1STAT;
260 	    }
261 	    // negative edge
262 	    else
263 	    {
264 		if (!state1)
265 		    value |= CTMUCONL::EDG1STAT;
266 	    }
267 	    ctmuconl->put(value);
268 
269 	}
270 	//using CTED1
271 	if (EDG2_SEL(value) == (CTMUCONL::EDG2SEL0 | CTMUCONL::EDG2SEL1))
272 	{
273 	    // positive edge active
274 	    if (value & CTMUCONL::EDG2POL)
275 	    {
276 		if (state1)
277 		    value |= CTMUCONL::EDG2STAT;
278 	    }
279 	    // negative edge
280 	    else
281 	    {
282 		if (!state1)
283 		    value |= CTMUCONL::EDG2STAT;
284 	    }
285 	    ctmuconl->put(value);
286 
287 	}
288 	cted1_state = state1;
289    }
290    if (state2 != cted2_state)	// state change on cted2
291    {
292 	//using CTED2
293 	if (EDG1_SEL(value) == (CTMUCONL::EDG1SEL1))
294 	{
295 	    // positive edge active
296 	    if (value & CTMUCONL::EDG1POL)
297 	    {
298 		if (state2)
299 		    value |= CTMUCONL::EDG1STAT;
300 	    }
301 	    // negative edge
302 	    else
303 	    {
304 		if (!state2)
305 		    value |= CTMUCONL::EDG1STAT;
306 	    }
307 	    ctmuconl->put(value);
308 
309 	}
310 	//using CTED2
311 	if (EDG2_SEL(value) == (CTMUCONL::EDG2SEL1))
312 	{
313 	    // positive edge active
314 	    if (value & CTMUCONL::EDG2POL)
315 	    {
316 		if (state2)
317 		    value |= CTMUCONL::EDG2STAT;
318 	    }
319 	    // negative edge
320 	    else
321 	    {
322 		if (!state2)
323 		    value |= CTMUCONL::EDG2STAT;
324 	    }
325 	    ctmuconl->put(value);
326 
327 	}
328 	cted2_state = state2;
329    }
330 }
331 
332 //Status from comparator module for C2
syncC2out(bool high)333 void CTMU::syncC2out(bool high)
334 {
335     if ((ctmuconh->value.get() & CTMUCONH::TGEN) && high)
336     {
337         unsigned int value = ctmuconl->value.get();
338 	value |= CTMUCONL::EDG2STAT;
339 	ctmuconl->put(value);
340     }
341 
342 }
343 
tgen_on()344 void CTMU::tgen_on()
345 {
346     cm2con1->set_ctmu_stim(ctmu_stim, this);
347     m_ctpls->getPin().newGUIname("ctpls");
348     if (!ctpls_source)
349 	ctpls_source = new PeripheralSignalSource(m_ctpls);
350     m_ctpls->setSource(ctpls_source);
351 }
352 
tgen_off()353 void CTMU::tgen_off()
354 {
355     cm2con1->set_ctmu_stim(0, 0);
356     m_ctpls->getPin().newGUIname(m_ctpls->getPin().name().c_str());
357     if (ctpls_source)
358         m_ctpls->setSource(0);
359 }
360 
361 
idissen(bool ground)362 void CTMU::idissen(bool ground)
363 {
364     // Don't do anything is CTMU not enables
365     if (! (ctmuconh->value.get() & CTMUCONH::CTMUEN))
366 	return;
367 
368     if (ground)
369     {
370 	ctmu_stim->set_Vth(0.);
371 	ctmu_stim->set_Zth(300.0);
372 	ctmu_stim->updateNode();
373 
374     }
375     else
376     {
377 	stat_change();
378     }
379 }
380 
381