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