1 /*
2 Copyright (C) 2017,2018 Roy R. Rankin
3 This file is part of the libgpsim library of gpsim
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, see
17 <http://www.gnu.org/licenses/lgpl-2.1.html>.
18 */
19
20 // NUMERICALLY CONTROLLED OSCILLATOR (NCO) MODULE
21
22
23 //#define DEBUG
24 #if defined(DEBUG)
25 #include "../config.h"
26 #define Dprintf(arg) {printf("%s:%d ",__FILE__,__LINE__); printf arg; }
27 #else
28 #define Dprintf(arg) {}
29 #endif
30
31 #include <assert.h>
32 #include <stdio.h>
33
34 #include "pic-processor.h"
35 #include "nco.h"
36 #include "clc.h"
37 #include "cwg.h"
38 #include "gpsim_interface.h"
39 #include "pir.h"
40 #include "processor.h"
41 #include "stimuli.h"
42 #include "trace.h"
43
44 class NCO_Interface: public Interface
45 {
46 public:
NCO_Interface(NCO * _nco)47 explicit NCO_Interface(NCO * _nco)
48 : Interface((gpointer *) _nco), nco(_nco)
49 {
50 }
51
SimulationHasStopped(gpointer)52 virtual void SimulationHasStopped(gpointer /* object */)
53 {
54 nco->current_value();
55 }
Update(gpointer object)56 virtual void Update(gpointer object)
57 {
58 SimulationHasStopped(object);
59 }
60
61 private:
62 NCO * nco;
63 };
64
65
66 class NCOSigSource: public SignalControl
67 {
68 public:
NCOSigSource(NCO * _nco,PinModule * _pin)69 NCOSigSource(NCO * _nco, PinModule * _pin)
70 : m_nco(_nco), m_state('?'), m_pin(_pin)
71 {
72 assert(m_nco);
73 }
~NCOSigSource()74 virtual ~ NCOSigSource()
75 {
76 }
77
setState(char _state)78 void setState(char _state)
79 {
80 m_state = _state;
81 }
getState()82 virtual char getState()
83 {
84 return m_state;
85 }
release()86 virtual void release()
87 {
88 m_nco->releasePinSource(m_pin);
89 }
90
91 private:
92 NCO * m_nco;
93 char m_state;
94 PinModule *m_pin;
95 };
96
97
98 // Report state changes on incoming CLK pin
99 class ncoCLKSignalSink: public SignalSink
100 {
101 public:
ncoCLKSignalSink(NCO * _nco)102 explicit ncoCLKSignalSink(NCO * _nco)
103 : m_nco(_nco)
104 {
105 }
106
setSinkState(char new3State)107 virtual void setSinkState(char new3State)
108 {
109 m_nco->setState(new3State);
110 }
release()111 virtual void release()
112 {
113 delete this;
114 }
115
116 private:
117 NCO * m_nco;
118 };
119
120
NCO(Processor * pCpu)121 NCO::NCO(Processor * pCpu):
122 nco1con(this, pCpu, "nco1con", "NCOx Control Register"),
123 nco1clk(this, pCpu, "nco1clk", "NCOx Input Clock Control Register"),
124 nco1acch(this, pCpu, "nco1acch", "NCOx Accumulator Register-High Byte"),
125 nco1accl(this, pCpu, "nco1accl", "NCOx Accumulator Register-Low Byte"),
126 nco1accu(this, pCpu, "nco1accu", "NCOx Accumulator Register-Upper Byte"),
127 nco1inch(this, pCpu, "nco1inch", "NCOx Increment Register-High Byte"),
128 nco1incl(this, pCpu, "nco1incl", "NCOx Increment Register-Low Byte"),
129 cpu(pCpu), inc(1)
130 {
131 acc_hold[0] = acc_hold[1] = acc_hold[2] = 0;
132
133 for (int i = 0; i < 4; i++)
134 {
135 m_clc[i] = nullptr;
136 }
137 }
138
139
~NCO()140 NCO::~NCO()
141 {
142 delete NCO1src;
143 delete nco_interface;
144 }
145
146
147 // Process change in nconcon register
update_ncocon(unsigned int diff)148 void NCO::update_ncocon(unsigned int diff)
149 {
150 unsigned int value = nco1con.value.get();
151 Dprintf(("NCO::update_ncocon diff=0x%x value=0x%x\n", diff, value));
152
153 if ((diff & NxEN) && (value & NxEN)) //NCO turning on
154 {
155 Dprintf(("NCO::update_ncocon ON nco1con=0x%x nco1clk=0x%x\n", value,
156 nco1clk.value.get()));
157 pulseWidth = 0;
158
159 if (!nco_interface)
160 {
161 nco_interface = new NCO_Interface(this);
162 get_interface().prepend_interface(nco_interface);
163 }
164
165 if (value & NxOE)
166 {
167 oeNCO1(true);
168 }
169
170 // force clock to current state
171 update_ncoclk(NxCLKS_mask);
172
173 }
174 else if ((diff & NxEN) && !(value & NxEN)) //NCO turning off
175 {
176 Dprintf(("NCO::update_ncocon OFF nco1con=0x%x nco1clk=0x%x acc=0x%x\n", value,
177 nco1clk.value.get(), acc));
178 pulseWidth = 0;
179 oeNCO1(false);
180 current_value();
181
182 if (future_cycle)
183 {
184 get_cycles().clear_break(future_cycle);
185 future_cycle = 0;
186 }
187
188 if (acc >= (1 << 20))
189 {
190 acc -= (1 << 20);
191 }
192
193 }
194 else if (value & NxEN) // currently running
195 {
196 if ((diff & NxOE))
197 {
198 oeNCO1(value & NxOE);
199 }
200
201 if (diff & NxPOL)
202 {
203 outputNCO1(value & NxOUT);
204 }
205 }
206 }
207
208
209 /* this does a manual update of the accumulator register
210 and is used when the LCx_out or NCO1CLK are used as the
211 clock source
212 */
NCOincrement()213 void NCO::NCOincrement()
214 {
215 // Load nco1inc on second + clock edge
216 if (inc_load && !--inc_load)
217 {
218 set_inc_buf();
219 Dprintf(("NCO::NCOincrement() loading inc with 0x%x\n", inc));
220 }
221
222 // Turn off output if pulsewidth goes to zero
223 if (pulseWidth && !--pulseWidth)
224 {
225 nco1con.value.put(nco1con.value.get() & ~NxOUT);
226 outputNCO1(false);
227 }
228
229 // Overflow was on last edge
230 if (NCOoverflow)
231 {
232 unsigned int value = nco1con.value.get();
233
234 if (!(value & NxPFM)) // Fixed duty cycle
235 {
236 value = (value & NxOUT) ? value & ~NxOUT : value | NxOUT;
237
238 }
239 else
240 {
241 pulseWidth = 1 << ((nco1clk.value.get() & NxPW_mask) >> 5);
242 value = value | NxOUT;
243 }
244
245 nco1con.value.put(value);
246 NCOoverflow = false;
247 outputNCO1(value & NxOUT);
248 Dprintf(("m_NCOif=%p pir=%p\n", m_NCOif, pir));
249
250 if (m_NCOif)
251 {
252 m_NCOif->Trigger();
253
254 }
255 else if (pir)
256 {
257 pir->set_nco1if();
258
259 }
260 else
261 {
262 fprintf(stderr, "NCO interrupt method not configured\n");
263 }
264 }
265
266 acc += inc;
267 Dprintf(("NCO::NCOincrement() acc=0x%x inc=0x%x\n", acc, inc));
268
269 if (acc >= (1 << 20)) // overflow
270 {
271 Dprintf(("NCO::NCOincrement() acc overflow acc=0x%x\n", acc));
272 acc -= (1 << 20);
273 NCOoverflow = true;
274 }
275 }
276
277
callback()278 void NCO::callback()
279 {
280 current_value();
281 future_cycle = 0;
282 unsigned int value = nco1con.value.get();
283
284 if (acc >= (1 << 20))
285 {
286 acc -= (1 << 20);
287 unsigned int value = nco1con.value.get();
288
289 if (!(value & NxPFM)) // Fixed duty cycle
290 {
291 value = (value & NxOUT) ? value & ~NxOUT : value | NxOUT;
292 Dprintf(("call simulate_clock\n"));
293 simulate_clock(true);
294
295 }
296 else
297 {
298 unsigned int cps = cpu->get_ClockCycles_per_Instruction();
299 pulseWidth = 1 << ((nco1clk.value.get() & NxPW_mask) >> 5);
300 Dprintf(("NCO::callback raw pulseWidth=%u ", pulseWidth));
301 value = value | NxOUT;
302
303 if (clock_src() == HFINTOSC)
304 {
305 pulseWidth *= cpu->get_frequency() / (16e6);
306 }
307
308 int rem = pulseWidth % cps;
309 pulseWidth /= cps;
310
311 if (!pulseWidth || rem)
312 {
313 pulseWidth++;
314 }
315
316 Dprintf(("pulseWidth=%u rem = %d value=0x%x\n", pulseWidth, rem,
317 value));
318 last_cycle = get_cycles().get();
319 future_cycle = last_cycle + pulseWidth;
320 get_cycles().set_break(future_cycle, this);
321 }
322
323 nco1con.value.put(value);
324 outputNCO1(value & NxOUT);
325 Dprintf(("m_NCOif=%p pir=%p\n", m_NCOif, pir));
326
327 if (m_NCOif)
328 {
329 m_NCOif->Trigger();
330
331 }
332 else if (pir)
333 {
334 pir->set_nco1if();
335
336 }
337 else
338 {
339 fprintf(stderr, "NCO interrupt method not configured\n");
340 }
341
342 }
343 else if (pulseWidth)
344 {
345 value &= ~NxOUT;
346 nco1con.value.put(value);
347 outputNCO1(value & NxOUT);
348 Dprintf(("call simulate_clock\n"));
349 simulate_clock(true);
350
351 }
352 else
353 {
354 Dprintf(("call simulate_clock\n"));
355 simulate_clock(true);
356 }
357 }
358
359
360 // Use callback to simulate NCO driven by internal clock
simulate_clock(bool on)361 void NCO::simulate_clock(bool on)
362 {
363 Dprintf(("on=%d inc=%u clock=%s\n", on, inc, clock_src() ? "Fosc" : "HFINTOSC"));
364
365 if (on && inc)
366 {
367 gint64 delta;
368 unsigned int cps = cpu->get_ClockCycles_per_Instruction();
369 unsigned int rem = 0;
370
371 if (future_cycle)
372 {
373 current_value();
374 get_cycles().clear_break(future_cycle);
375 }
376
377 delta = ((1 << 20) - acc) / inc;
378
379 if (delta <= 0)
380 {
381 delta = 1;
382
383 }
384 else
385 {
386 rem = ((1 << 20) - acc) % inc;
387 }
388
389 if (rem)
390 {
391 delta++;
392 }
393
394 if (clock_src() == HFINTOSC)
395 {
396 delta *= cpu->get_frequency() / (16e6);
397 Dprintf(("delta=%" PRINTF_GINT64_MODIFIER "d cpu=%.3fMHz HFINTOC=%.3fMHz\n", delta, cpu->get_frequency() / 1e6, 16e6 / 1e6));
398 }
399
400 rem = delta % cps; // if rem != 0 timing is approximate
401 delta /= cps;
402
403 if ((delta <= 0) || rem > 0)
404 {
405 delta++;
406 }
407
408 Dprintf(("NCO::simulate_clock clock=%.2e acc=0x%x delta = %"
409 PRINTF_GINT64_MODIFIER "d rem=%u\n",
410 (clock_src() == HFINTOSC) ? 16e6 : cpu->get_frequency(),
411 acc, delta, rem));
412 last_cycle = get_cycles().get();
413 future_cycle = last_cycle + delta;
414 get_cycles().set_break(future_cycle, this);
415
416 }
417 else // clock off
418 {
419 current_value();
420
421 if (future_cycle)
422 {
423 current_value();
424 get_cycles().clear_break(future_cycle);
425 future_cycle = 0;
426 }
427 }
428 }
429
430
431 // Set output value for output pin
outputNCO1(bool level)432 void NCO::outputNCO1(bool level)
433 {
434 level = (nco1con.value.get() & NxPOL) ? !level : level;
435 Dprintf(("NCO::outputNCO1 level=%d\n", level));
436
437 for (int i = 0; i < 4; i++)
438 {
439 if (m_clc[i])
440 {
441 m_clc[i]->NCO_out(level);
442 }
443 }
444
445 if (m_cwg)
446 {
447 m_cwg->out_NCO(level);
448 }
449
450 if (NCO1src)
451 {
452 NCO1src->setState(level ? '1' : '0');
453 pinNCO1->updatePinModule();
454 }
455 }
456
457
458 // Enable/disable output pin
oeNCO1(bool on)459 void NCO::oeNCO1(bool on)
460 {
461 if (on)
462 {
463 if (!srcNCO1active)
464 {
465 NCO1gui = pinNCO1->getPin().GUIname();
466 pinNCO1->getPin().newGUIname("NCO1");
467
468 if (!NCO1src)
469 {
470 NCO1src = new NCOSigSource(this, pinNCO1);
471 }
472
473 pinNCO1->setSource(NCO1src);
474 srcNCO1active = true;
475 NCO1src->setState((nco1con.value.get() & NxOUT) ? '1' : '0');
476 pinNCO1->updatePinModule();
477 }
478
479 }
480 else if (srcNCO1active)
481 {
482 if (NCO1gui.length())
483 {
484 pinNCO1->getPin().newGUIname(NCO1gui.c_str());
485
486 }
487 else
488 {
489 pinNCO1->getPin().newGUIname(pinNCO1->getPin().name().c_str());
490 }
491
492 pinNCO1->setSource(0);
493 srcNCO1active = false;
494 pinNCO1->updatePinModule();
495 }
496 }
497
498
enableCLKpin(bool on)499 void NCO::enableCLKpin(bool on)
500 {
501 if (on)
502 {
503 CLKgui = pinNCOclk->getPin().GUIname();
504 pinNCOclk->getPin().newGUIname("NCLK");
505
506 if (!CLKsink)
507 {
508 CLKsink = new ncoCLKSignalSink(this);
509 }
510
511 pinNCOclk->addSink(CLKsink);
512 CLKstate = pinNCOclk->getPin().getState();
513
514 }
515 else
516 {
517 if (CLKgui.length())
518 {
519 pinNCOclk->getPin().newGUIname(CLKgui.c_str());
520
521 }
522 else
523 pinNCOclk->getPin().newGUIname(pinNCOclk->getPin().name().
524 c_str());
525
526 if (CLKsink)
527 {
528 pinNCOclk->removeSink(CLKsink);
529 }
530 }
531 }
532
533
534 // new value for NCO1CLK register
update_ncoclk(unsigned int diff)535 void NCO::update_ncoclk(unsigned int diff)
536 {
537 Dprintf(("nco1con=0x%x diff=0x%x\n", nco1con.value.get(), diff));
538
539 if ((nco1con.value.get() & NxEN) && (diff & NxCLKS_mask))
540 {
541 enableCLKpin(false);
542
543 if (future_cycle)
544 {
545 simulate_clock(false);
546 }
547
548 Dprintf(("clk=%d\n", clock_src()));
549
550 switch (clock_src())
551 {
552 case HFINTOSC:
553 simulate_clock(true);
554 break;
555
556 case FOSC:
557 simulate_clock(true); //FIXME FOSC different HFINTOSC
558 break;
559
560 case LC1_OUT:
561 break;
562
563 case NCO1CLK:
564 enableCLKpin(true);
565 break;
566 }
567 }
568 }
569
570
571 // return pseudo clock codes (this for 16f1503)
clock_src()572 int NCO::clock_src()
573 {
574 switch (nco1clk.value.get() & NxCLKS_mask)
575 {
576 case 0: //HFINTOSC
577 return HFINTOSC;
578 break;
579
580 case 1: //FOSC
581 return FOSC;
582 break;
583
584 case 2: // LC1_OUT
585 return LC1_OUT;
586 break;
587
588 case 3: // NCO1CLK pin
589 return NCO1CLK;
590 break;
591 }
592
593 return -1;
594 }
595
596
setIOpins(PinModule * pIN,PinModule * pOUT)597 void NCO::setIOpins(PinModule * pIN, PinModule * pOUT)
598 {
599 pinNCOclk = pIN;
600 pinNCO1 = pOUT;
601 }
602
603
setIOpin(PinModule * pin,int data)604 void NCO::setIOpin(PinModule *pin, int data)
605 {
606 if (data == NCOout_PIN)
607 {
608 setNCOxPin(pin);
609
610 }
611 else
612 {
613 fprintf(stderr, "NCO::setIOpin unexpected data=%d\n", data);
614 }
615 }
616
617
618 // remap NCO1 pin, called from APFCON
setNCOxPin(PinModule * pNCOx)619 void NCO::setNCOxPin(PinModule * pNCOx)
620 {
621 if (pNCOx == pinNCO1)
622 {
623 return;
624 }
625
626 if (srcNCO1active) // old pin active disconnect
627 {
628 oeNCO1(false);
629
630 if (NCO1src)
631 {
632 delete NCO1src;
633 }
634
635 NCO1src = 0;
636 }
637
638 pinNCO1 = pNCOx;
639
640 if (nco1con.value.get() & NxOE)
641 {
642 oeNCO1(true);
643 }
644 }
645
646
647 // link from Configurable Logic Cell
link_nco(bool level,char)648 void NCO::link_nco(bool level, char /* index */)
649 {
650 // Active?
651 if (clock_src() == LC1_OUT)
652 {
653 Dprintf(("NCO::link_nco level=%d index=%d edge=%d\n", level, index,
654 (bool)(level & !CLKstate)));
655
656 if (level & !CLKstate) // new edge
657 {
658 NCOincrement();
659 }
660
661 CLKstate = level;
662 }
663 }
664
665
666 // Save acc buffer into accx registers,
667 // but if clock is simulated, first compute value of acc buffer.
current_value()668 void NCO::current_value()
669 {
670 if (future_cycle && (get_cycles().get() - last_cycle))
671 {
672 unsigned int cps = cpu->get_ClockCycles_per_Instruction();
673 guint32 delta_acc = (get_cycles().get() - last_cycle) * inc * cps;
674
675 if (clock_src() == HFINTOSC)
676 {
677 delta_acc *= 16e6 / cpu->get_frequency();
678 }
679
680 acc += delta_acc;
681 last_cycle = get_cycles().get();
682 }
683
684 nco1accu.value.put((acc >> 16) & 0x0f);
685 nco1acch.value.put((acc >> 8) & 0xff);
686 nco1accl.value.put(acc & 0xff);
687 }
688
689
690 // transfer accx registers to acc buffer
set_acc_buf()691 void NCO::set_acc_buf()
692 {
693 acc = ((acc_hold[2] & 0x0f) << 16) | (acc_hold[1] << 8) | acc_hold[0];
694 NCOoverflow = false;
695
696 if ((clock_src() == FOSC || clock_src() == HFINTOSC) &&
697 (nco1con.value.get() & NxEN))
698 {
699 set_inc_buf();
700 Dprintf(("call simulate_clock\n"));
701 simulate_clock(true);
702 }
703 }
704
705
706 /*
707 Documentation indicates the increment buffer is loaded
708 on second rising edge of the source clock;
709 */
newINCL()710 void NCO::newINCL()
711 {
712 Dprintf(("newINCL clock=%d\n", clock_src()));
713
714 // If NCO is not enables, inc buffer loaded immediately
715 if (!(nco1con.value.get() & NxEN))
716 {
717 set_inc_buf();
718 }
719
720 // If simulating clock, load will be too early or late,
721 // so do it now (to simplify code)
722 else if (clock_src() == FOSC || clock_src() == HFINTOSC)
723 {
724 current_value();
725 set_inc_buf();
726 Dprintf(("call simulate_clock\n"));
727 simulate_clock(true);
728
729 }
730 else
731 {
732 inc_load = 2;
733 }
734 }
735
736
737 // load inc buffer from registers
set_inc_buf()738 void NCO::set_inc_buf()
739 {
740 inc = (nco1inch.value.get() << 8) | nco1incl.value.get();
741 Dprintf(("NCO::set_inc_buf inc=0x%x\n", inc));
742 }
743
744
745 // process input from clock pin
setState(char new3State)746 void NCO::setState(char new3State)
747 {
748 if (clock_src() == NCO1CLK)
749 {
750 if (new3State == '1' && !CLKstate) //new edge
751 {
752 CLKstate = true;
753 NCOincrement();
754
755 }
756 else if (new3State == '0' && CLKstate)
757 {
758 CLKstate = false;
759 }
760 }
761 }
762
763
sleep(bool on)764 void NCO::sleep(bool on)
765 {
766 if (clock_src() == FOSC)
767 {
768 // pause FOSC on sleep, restart on wakeup
769 simulate_clock(!on);
770 }
771 }
772
773
releasePinSource(PinModule * pin)774 void NCO::releasePinSource(PinModule * pin)
775 {
776 if (pin)
777 {
778 if (pin == pinNCO1)
779 {
780 srcNCO1active = false;
781 }
782 }
783 }
784
785
NCOxCON(NCO * pt,Processor * pCpu,const char * pName,const char * pDesc)786 NCOxCON::NCOxCON(NCO * pt, Processor * pCpu, const char *pName,
787 const char *pDesc)
788 : sfr_register(pCpu, pName, pDesc), con_mask(0xd1), pt_nco(pt)
789 {
790 }
791
792
put(unsigned int new_value)793 void NCOxCON::put(unsigned int new_value)
794 {
795 new_value &= con_mask;
796 unsigned int diff = new_value ^ value.get();
797
798 if (!diff)
799 {
800 return;
801 }
802
803 trace.raw(write_trace.get() | value.get());
804 value.put(new_value);
805 pt_nco->update_ncocon(diff);
806 }
807
808
809 // make sure acc reset after con
reset(RESET_TYPE r)810 void NCOxCON::reset(RESET_TYPE r)
811 {
812 putRV(por_value);
813 pt_nco->nco1accu.reset(r);
814 pt_nco->nco1acch.reset(r);
815 pt_nco->nco1accl.reset(r);
816 }
817
818
NCOxCLK(NCO * pt,Processor * pCpu,const char * pName,const char * pDesc)819 NCOxCLK::NCOxCLK(NCO * pt, Processor * pCpu, const char *pName,
820 const char *pDesc)
821 : sfr_register(pCpu, pName, pDesc), clk_mask(0xe3), pt_nco(pt)
822 {
823 }
824
825
put(unsigned int new_value)826 void NCOxCLK::put(unsigned int new_value)
827 {
828 new_value &= clk_mask;
829 unsigned int diff = new_value ^ value.get();
830
831 if (!diff)
832 {
833 return;
834 }
835
836 trace.raw(write_trace.get() | value.get());
837 value.put(new_value);
838 pt_nco->update_ncoclk(diff);
839 }
840
841
NCOxACCH(NCO * pt,Processor * pCpu,const char * pName,const char * pDesc)842 NCOxACCH::NCOxACCH(NCO * pt, Processor * pCpu, const char *pName,
843 const char *pDesc)
844 : sfr_register(pCpu, pName, pDesc), pt_nco(pt)
845 {
846 }
847
848
put(unsigned int new_value)849 void NCOxACCH::put(unsigned int new_value)
850 {
851 unsigned int diff = new_value ^ value.get();
852 pt_nco->set_hold_acc(new_value, 1);
853 pt_nco->set_accFlag(true);
854
855 if (!diff)
856 {
857 return;
858 }
859
860 trace.raw(write_trace.get() | value.get());
861 value.put(new_value);
862 }
863
864
NCOxACCL(NCO * pt,Processor * pCpu,const char * pName,const char * pDesc)865 NCOxACCL::NCOxACCL(NCO * pt, Processor * pCpu, const char *pName,
866 const char *pDesc)
867 : sfr_register(pCpu, pName, pDesc), pt_nco(pt)
868 {
869 }
870
871
put(unsigned int new_value)872 void NCOxACCL::put(unsigned int new_value)
873 {
874 unsigned int diff = new_value ^ value.get();
875 pt_nco->set_hold_acc(new_value, 0);
876 pt_nco->set_accFlag(true);
877
878 if (diff)
879 {
880 trace.raw(write_trace.get() | value.get());
881 value.put(new_value);
882 }
883
884 if (pt_nco->get_accFlag())
885 {
886 pt_nco->set_acc_buf();
887 pt_nco->set_accFlag(false);
888 }
889 }
890
891
NCOxACCU(NCO * pt,Processor * pCpu,const char * pName,const char * pDesc)892 NCOxACCU::NCOxACCU(NCO * pt, Processor * pCpu, const char *pName,
893 const char *pDesc)
894 : sfr_register(pCpu, pName, pDesc), pt_nco(pt)
895 {
896 }
897
898
put(unsigned int new_value)899 void NCOxACCU::put(unsigned int new_value)
900 {
901 unsigned int diff = new_value ^ value.get();
902 pt_nco->set_hold_acc(new_value, 2);
903 pt_nco->set_accFlag(true);
904
905 if (!diff)
906 {
907 return;
908 }
909
910 trace.raw(write_trace.get() | value.get());
911 value.put(new_value);
912 }
913
914
NCOxINCH(NCO * pt,Processor * pCpu,const char * pName,const char * pDesc)915 NCOxINCH::NCOxINCH(NCO * pt, Processor * pCpu, const char *pName,
916 const char *pDesc)
917 : sfr_register(pCpu, pName, pDesc), pt_nco(pt)
918 {
919 }
920
921
put(unsigned int new_value)922 void NCOxINCH::put(unsigned int new_value)
923 {
924 unsigned int diff = new_value ^ value.get();
925
926 if (!diff)
927 {
928 return;
929 }
930
931 trace.raw(write_trace.get() | value.get());
932 value.put(new_value);
933 }
934
935
NCOxINCL(NCO * pt,Processor * pCpu,const char * pName,const char * pDesc)936 NCOxINCL::NCOxINCL(NCO * pt, Processor * pCpu, const char *pName,
937 const char *pDesc)
938 : sfr_register(pCpu, pName, pDesc), pt_nco(pt)
939 {
940 }
941
942
put(unsigned int new_value)943 void NCOxINCL::put(unsigned int new_value)
944 {
945 trace.raw(write_trace.get() | value.get());
946 value.put(new_value);
947 pt_nco->newINCL();
948 }
949
950
NCO2(Processor * pCpu)951 NCO2::NCO2(Processor * pCpu)
952 : NCO(pCpu)
953 {
954 }
955
956
957 // return pseudo clock codes (this for 10f320)
clock_src()958 int NCO2::clock_src()
959 {
960 switch (nco1clk.value.get() & NxCLKS_mask)
961 {
962 case 2: //HFINTOSC
963 return HFINTOSC;
964 break;
965
966 case 1: //FOSC
967 return FOSC;
968 break;
969
970 case 3: // LC1_OUT
971 return LC1_OUT;
972 break;
973
974 case 0: // NCO1CLK pin
975 return NCO1CLK;
976 break;
977 }
978
979 return -1;
980 }
981