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