1 /*
2 Copyright (C) 2017 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 // CONFIGURABLE LOGIC CELL (CLC)
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 "gpsim_time.h"
36 #include "clc.h"
37 #include "nco.h"
38 #include "cwg.h"
39 #include "stimuli.h"
40 #include "trace.h"
41
42 // Report state changes on incoming INx pins
43 class INxSignalSink: public SignalSink
44 {
45 public:
INxSignalSink(CLC_BASE * _clc,int _index)46 INxSignalSink(CLC_BASE * _clc, int _index)
47 : m_clc(_clc), index(_index)
48 {
49 }
50
setSinkState(char new3State)51 virtual void setSinkState(char new3State)
52 {
53 m_clc->setState(new3State, index);
54 }
release()55 virtual void release()
56 {
57 delete this;
58 }
59
60 private:
61 CLC_BASE * m_clc;
62 int index;
63 };
64
65
66 class CLCSigSource: public SignalControl
67 {
68 public:
CLCSigSource(CLC_BASE * _clc,PinModule * _pin)69 CLCSigSource(CLC_BASE * _clc, PinModule * _pin)
70 : m_clc(_clc), m_pin(_pin), m_state('?')
71 {
72 assert(m_clc);
73 }
~CLCSigSource()74 virtual ~CLCSigSource()
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_clc->releasePinSource(m_pin);
89 }
90
91 private:
92 CLC_BASE *m_clc;
93 PinModule *m_pin;
94 char m_state;
95 };
96
97
put(unsigned int new_value)98 void CLCxCON::put(unsigned int new_value)
99 {
100 new_value &= write_mask;
101 new_value |= (value.get() & ~write_mask);
102 unsigned int diff = new_value ^ value.get();
103 trace.raw(write_trace.get() | value.get());
104 value.put(new_value);
105
106 if (!diff)
107 {
108 return;
109 }
110
111 m_clc->update_clccon(diff);
112 }
113
114
put(unsigned int new_value)115 void CLCxPOL::put(unsigned int new_value)
116 {
117 new_value &= write_mask;
118 unsigned int diff = new_value ^ value.get();
119 trace.raw(write_trace.get() | value.get());
120 value.put(new_value);
121
122 if (!diff)
123 {
124 return;
125 }
126
127 m_clc->compute_gates();
128 }
129
130
131 // used when CLC has 4 data select registers (CLCxSEL0-3)
132 // reg_number in range 0-3 to indicate which register
CLCxSELx(CLC_4SEL * _clc,Processor * pCpu,const char * pName,const char * pDesc,unsigned int _reg_number)133 CLCxSELx::CLCxSELx(CLC_4SEL * _clc, Processor * pCpu, const char *pName,
134 const char *pDesc, unsigned int _reg_number)
135 : sfr_register(pCpu, pName, pDesc), m_clc(_clc), write_mask(0x1f),
136 reg_number(_reg_number)
137 {
138 }
put(unsigned int new_value)139 void CLCxSELx::put(unsigned int new_value)
140 {
141 new_value &= write_mask;
142 trace.raw(write_trace.get() | value.get());
143 unsigned int diff = new_value ^ value.get();
144 value.put(new_value);
145
146 if(diff)
147 {
148 switch(reg_number)
149 {
150 case 0:
151 m_clc->D1S(new_value);
152 break;
153
154 case 1:
155 m_clc->D2S(new_value);
156 break;
157
158 case 2:
159 m_clc->D3S(new_value);
160 break;
161
162 case 3:
163 m_clc->D4S(new_value);
164 break;
165 }
166
167 if (m_clc->CLCenabled())
168 {
169 m_clc->config_inputs(true);
170 }
171 }
172 }
173
CLCxSEL0(CLC * _clc,Processor * pCpu,const char * pName,const char * pDesc)174 CLCxSEL0::CLCxSEL0(CLC * _clc, Processor * pCpu, const char *pName,
175 const char *pDesc)
176 : sfr_register(pCpu, pName, pDesc), m_clc(_clc), write_mask(0x77)
177 {
178 }
179
180
put(unsigned int new_value)181 void CLCxSEL0::put(unsigned int new_value)
182 {
183 new_value &= write_mask;
184 trace.raw(write_trace.get() | value.get());
185 unsigned int diff = new_value ^ value.get();
186 value.put(new_value);
187
188 if (diff & 0xf)
189 {
190 m_clc->D1S(new_value & 0xf);
191 }
192
193 if (diff & 0xf0)
194 {
195 m_clc->D2S((new_value & 0xf0) >> 4);
196 }
197
198 if (diff && m_clc->CLCenabled())
199 {
200 m_clc->config_inputs(true);
201 }
202 }
203
204
CLCxSEL1(CLC * _clc,Processor * pCpu,const char * pName,const char * pDesc)205 CLCxSEL1::CLCxSEL1(CLC * _clc, Processor * pCpu, const char *pName,
206 const char *pDesc)
207 : sfr_register(pCpu, pName, pDesc), m_clc(_clc), write_mask(0x77)
208 {
209 }
210
211
put(unsigned int new_value)212 void CLCxSEL1::put(unsigned int new_value)
213 {
214 new_value &= write_mask;
215 trace.raw(write_trace.get() | value.get());
216 unsigned int diff = new_value ^ value.get();
217 value.put(new_value);
218
219 if (diff & 0xf)
220 {
221 m_clc->D3S(new_value & 0xf);
222 }
223
224 if (diff & 0xf0)
225 {
226 m_clc->D4S((new_value & 0xf0) >> 4);
227 }
228
229 if (diff && m_clc->CLCenabled())
230 {
231 m_clc->config_inputs(true);
232 }
233 }
234
235
put(unsigned int new_value)236 void CLCxGLS0::put(unsigned int new_value)
237 {
238 unsigned int diff = new_value ^ value.get();
239 trace.raw(write_trace.get() | value.get());
240 value.put(new_value);
241
242 if (!diff)
243 {
244 return;
245 }
246
247 if (m_clc->CLCenabled())
248 {
249 m_clc->config_inputs(true);
250 }
251
252 m_clc->compute_gates();
253 }
254
255
put(unsigned int new_value)256 void CLCxGLS1::put(unsigned int new_value)
257 {
258 unsigned int diff = new_value ^ value.get();
259 trace.raw(write_trace.get() | value.get());
260 value.put(new_value);
261
262 if (!diff)
263 {
264 return;
265 }
266
267 if (m_clc->CLCenabled())
268 {
269 m_clc->config_inputs(true);
270 }
271
272 m_clc->compute_gates();
273 }
274
275
put(unsigned int new_value)276 void CLCxGLS2::put(unsigned int new_value)
277 {
278 unsigned int diff = new_value ^ value.get();
279 trace.raw(write_trace.get() | value.get());
280 value.put(new_value);
281
282 if (!diff)
283 {
284 return;
285 }
286
287 if (m_clc->CLCenabled())
288 {
289 m_clc->config_inputs(true);
290 }
291
292 m_clc->compute_gates();
293 }
294
295
put(unsigned int new_value)296 void CLCxGLS3::put(unsigned int new_value)
297 {
298 unsigned int diff = new_value ^ value.get();
299 trace.raw(write_trace.get() | value.get());
300 value.put(new_value);
301
302 if (!diff)
303 {
304 return;
305 }
306
307 if (m_clc->CLCenabled())
308 {
309 m_clc->config_inputs(true);
310 }
311
312 m_clc->compute_gates();
313 }
314
315
316 // CLCx calls to set it's LCx_OUT bit, result shared with
317 // all CLCx instances.
set_bit(bool bit_val,unsigned int pos)318 void CLCDATA::set_bit(bool bit_val, unsigned int pos)
319 {
320 Dprintf(("set_bit LC%u_OUT %d\n", pos + 1, bit_val));
321
322 if (bit_val)
323 {
324 value.put(value.get() | (1 << pos));
325
326 }
327 else
328 {
329 value.put(value.get() & ~(1 << pos));
330 }
331
332 for (int i = 0; i < 4; i++)
333 {
334 if (m_clc[i])
335 {
336 m_clc[i]->lcxupdate(bit_val, pos);
337 }
338 }
339 }
340
341
342 // used where all CLC instances use same input pins
setIOpin(PinModule * pin,int data)343 void CLCDATA::setIOpin(PinModule *pin, int data)
344 {
345 for(int i=0; i<4; i++)
346 {
347 if (m_clc[i])
348 m_clc[i]->setIOpin(pin,data);
349 }
350 }
CLC(Processor * cpu,unsigned int _index,CLCDATA * _clcdata)351 CLC::CLC(Processor * cpu, unsigned int _index, CLCDATA * _clcdata):
352 CLC_BASE(cpu, _index, _clcdata),
353 clcxsel0(this, cpu, "clcxsel0", "Multiplexer Data 1 and 2 Select Register"),
354 clcxsel1(this, cpu, "clcxsel1", "Multiplexer Data 3 and 4 Select Register")
355 {
356 }
357
358
CLC_BASE(Processor * cpu,unsigned int _index,CLCDATA * _clcdata)359 CLC_BASE::CLC_BASE(Processor * cpu, unsigned int _index, CLCDATA * _clcdata):
360 index(_index),
361 clcxcon(this, cpu, "clcxcon", "Configurable Logic Cell Control Register"),
362 clcxpol(this, cpu, "clcxpol", "Configurable Logic Cell Signal Polarity"),
363 clcxgls0(this, cpu, "clcxgls0", "Gate 1 Logic Select Register"),
364 clcxgls1(this, cpu, "clcxgls1", "Gate 2 Logic Select Register"),
365 clcxgls2(this, cpu, "clcxgls2", "Gate 3 Logic Select Register"),
366 clcxgls3(this, cpu, "clcxgls3", "Gate 4 Logic Select Register"),
367 clcdata(_clcdata)
368 {
369 for (int i = 0; i < 4; i++)
370 {
371 CMxOUT_level[i] = false;
372 pwmx_level[i] = false;
373 lcxdT[i] = false;
374 lcxg[i] = false;
375 dxs_data_length[i] = 0;
376 dxs_data[i] = nullptr;
377 INxsink[i] = nullptr;
378 INxactive[i] = 0;
379 INxstate[i] = false;
380 }
381
382 std::fill_n(DxS_data, 4, UNUSED);
383 std::fill_n(pinCLCxIN, 4, nullptr);
384 }
385
386
~CLC_BASE()387 CLC_BASE::~CLC_BASE()
388 {
389 delete CLCxsrc;
390 }
391
392
393 /*
394 ** Set the DxS input selection table
395 ** input - table 1-4
396 ** length - number of entries in the data array
397 ** data - array of data_in enums
398 */
set_dxs_data(int input,int length,data_in * data)399 void CLC_BASE::set_dxs_data(int input, int length, data_in *data)
400 {
401 assert(input && input < 5);
402
403 dxs_data_length[input-1] = length;
404 dxs_data[input-1] = data;
405 #ifdef DEBUG
406 Dprintf(("CLC_BASE::set_dxs_data CLC%u table %d\n", index+1, input));
407 for(int i=0; i<length; i++)
408 printf("%d, ", dxs_data[input-1][i]);
409 printf("\n");
410 #endif
411 }
412
setIOpin(PinModule * pin,int data)413 void CLC_BASE::setIOpin(PinModule *pin, int data)
414 {
415 Dprintf(("CLC_BASE::setIOpin CLC%u pin=%s data=%d\n", index+1, pin?pin->getPin().name().c_str():"NULL", data));
416 if (data == CLCout_PIN)
417 {
418 if (!pin)
419 oeCLCx(false);
420 else
421 setCLCxPin(pin);
422 }
423 else if (data >= CLCin0_PIN && data <= CLCin3_PIN)
424 {
425 int i = data - CLCin0_PIN;
426 if (pin != pinCLCxIN[i])
427 {
428 if (CLCenabled())
429 {
430 if (pinCLCxIN[i])
431 enableINxpin(i, false);
432 pinCLCxIN[i] = pin;
433 enableINxpin(i, true);
434 }
435 else
436 {
437 pinCLCxIN[i] = pin;
438 }
439 }
440 }
441 else
442 {
443 fprintf(stderr, "CLC_BASE::setIOpin data=%d not supported\n", data);
444 }
445 }
446
447
448 // Handle output pin multiplexing
setCLCxPin(PinModule * alt_pin)449 void CLC_BASE::setCLCxPin(PinModule * alt_pin)
450 {
451
452 if (alt_pin != pinCLCx)
453 {
454 oeCLCx(false);
455 pinCLCx = alt_pin;
456 oeCLCx(true);
457 }
458 }
459
460
461
462
463 // Handle T0 overflow notification
t0_overflow()464 void CLC_BASE::t0_overflow()
465 {
466 bool gate_change = false;
467
468 for (int i = 0; i < 4; i++)
469 {
470 if (DxS_data[i] == T0_OVER)
471 {
472 lcxdT[i] = true;
473 gate_change = true;
474 }
475 }
476
477 if (gate_change)
478 {
479 Dprintf(("CLC%u t0_overflow() enable=%d\n", index + 1,
480 CLCenabled()));
481 compute_gates();
482
483 for (int i = 0; i < 4; i++)
484 {
485 if (DxS_data[i] == T0_OVER)
486 {
487 lcxdT[i] = false;
488 }
489 }
490
491 compute_gates();
492 }
493 }
494
495
496 // Handle T1 overflow notification
t1_overflow()497 void CLC_BASE::t1_overflow()
498 {
499 bool gate_change = false;
500
501 for (int i = 0; i < 4; i++)
502 {
503 if (DxS_data[i] == T1_OVER)
504 {
505 lcxdT[i] = true;
506 gate_change = true;
507 }
508 }
509
510 if (gate_change)
511 {
512 Dprintf(("CLC%u t1_overflow() enable=%d\n", index + 1,
513 CLCenabled()));
514 compute_gates();
515
516 for (int i = 0; i < 4; i++)
517 {
518 if (DxS_data[i] == T1_OVER)
519 {
520 lcxdT[i] = false;
521 }
522 }
523
524 compute_gates();
525 }
526 }
527
528
529 // Handle T[246] match notification
530 // If an input gate using a t[246] match, toggle input gate
t2_match(char tmr_number)531 void CLC_BASE::t2_match(char tmr_number)
532 {
533 bool gate_change = false;
534
535 for (int i = 0; i < 4; i++)
536 {
537 if (
538 (DxS_data[i] == T2_MATCH && tmr_number == '2') ||
539 (DxS_data[i] == T4_MATCH && tmr_number == '4') ||
540 (DxS_data[i] == T6_MATCH && tmr_number == '6')
541 )
542 {
543 lcxdT[i] = true;
544 gate_change = true;
545 }
546 }
547
548 if (gate_change)
549 {
550 Dprintf(("CLC%u t2_match(%c) enable=%d\n", index + 1, tmr_number, CLCenabled()));
551 compute_gates();
552
553 for (int i = 0; i < 4; i++)
554 {
555 if (
556 (DxS_data[i] == T2_MATCH && tmr_number == '2') ||
557 (DxS_data[i] == T4_MATCH && tmr_number == '4') ||
558 (DxS_data[i] == T6_MATCH && tmr_number == '6')
559 )
560 {
561 lcxdT[i] = false;
562 }
563 }
564
565 compute_gates();
566 }
567 }
568
569
570 // Handle updates for frc or lfintosc
osc_out(bool level,int kind)571 void CLC_BASE::osc_out(bool level, int kind)
572 {
573 bool gate_change = false;
574
575 for (int i = 0; i < 4; i++)
576 {
577 if (DxS_data[i] == kind && lcxdT[i] != level)
578 {
579 lcxdT[i] = level;
580 gate_change = true;
581 }
582 }
583
584 if (gate_change)
585 {
586 Dprintf(("CLC%u osc_out() kind=%d level=%d enable=%d\n", index + 1,
587 kind, level, CLCenabled()));
588 compute_gates();
589 }
590 }
591
592
593 // Handle updates for NCO module
NCO_out(bool level)594 void CLC_BASE::NCO_out(bool level)
595 {
596 if (NCO_level != level)
597 {
598 bool gate_change = false;
599 NCO_level = level;
600
601 for (int i = 0; i < 4; i++)
602 {
603 if (DxS_data[i] == NCOx)
604 {
605 lcxdT[i] = level;
606 gate_change = true;
607 }
608 }
609
610 if (gate_change)
611 {
612 Dprintf(("CLC%u NCO_out() level=%d enable=%d\n", index + 1,
613 level, CLCenabled()));
614 compute_gates();
615 }
616 }
617 }
618
619 // Handle updates for ZCD module
ZCDx_out(bool level)620 void CLC_BASE::ZCDx_out(bool level)
621 {
622 if (ZCD_level != level)
623 {
624 bool gate_change = false;
625 ZCD_level = level;
626
627 for (int i = 0; i < 4; i++)
628 {
629 if (DxS_data[i] == ZCD_OUT)
630 {
631 lcxdT[i] = level;
632 gate_change = true;
633 }
634 }
635
636 if (gate_change)
637 {
638 Dprintf(("CLC%u ZCD_out() level=%d enable=%d\n", index + 1,
639 level, CLCenabled()));
640 compute_gates();
641 }
642 }
643 }
644
645
646 // Handle updates from comparator module
CxOUT_sync(bool level,int cm)647 void CLC_BASE::CxOUT_sync(bool level, int cm)
648 {
649 if (CMxOUT_level[cm] != level)
650 {
651 bool gate_change = false;
652 CMxOUT_level[cm] = level;
653
654 for (int i = 0; i < 4; i++)
655 {
656 if ((DxS_data[i] == C1OUT && cm == 0) ||
657 (DxS_data[i] == C2OUT && cm == 1))
658 {
659 lcxdT[i] = level;
660 gate_change = true;
661 }
662 }
663
664 if (gate_change)
665 {
666 Dprintf(("CLC%u C%dOUT_sync() level=%d enable=%d\n", index + 1,
667 cm + 1, level, CLCenabled()));
668 compute_gates();
669 }
670 }
671 }
672
673
674 // Handle updates from pwm module
out_pwm(bool level,int id)675 void CLC_BASE::out_pwm(bool level, int id)
676 {
677 Dprintf(("CLC%u out_pwm() pwm%d level=%d enable=%d\n", index + 1, id + 1,
678 level, CLCenabled()));
679
680 if (pwmx_level[id] != level)
681 {
682 bool gate_change = false;
683 pwmx_level[id] = level;
684
685 for (int i = 0; i < 4; i++)
686 {
687 if ((DxS_data[i] == PWM1 && id == 0) ||
688 (DxS_data[i] == PWM2 && id == 1) ||
689 (DxS_data[i] == PWM3 && id == 2) ||
690 (DxS_data[i] == PWM4 && id == 3))
691 {
692 lcxdT[i] = level;
693 gate_change = true;
694 }
695 }
696
697 if (gate_change)
698 {
699 Dprintf(("CLC%u out_pwm() pwm%d level=%d enable=%d\n",
700 index + 1, id + 1, level, CLCenabled()));
701 compute_gates();
702 }
703 }
704 }
705
706
707 // notification on CLCxIN[12]
setState(char new3State,int id)708 void CLC_BASE::setState(char new3State, int id)
709 {
710 bool state = (new3State == '1' || new3State == 'W');
711
712 if (state != INxstate[id])
713 {
714 bool gate_change = false;
715 INxstate[id] = state;
716
717 for (int i = 0; i < 4; i++)
718 {
719 if ((DxS_data[i] == CLCxIN0 && id == 0) ||
720 (DxS_data[i] == CLCxIN1 && id == 1))
721 {
722 lcxdT[i] = state;
723 gate_change = true;
724 }
725 }
726
727 if (gate_change)
728 {
729 Dprintf(("CLC%u setState() IN%d level=%d enable=%d\n",
730 index + 1, id, state, CLCenabled()));
731 compute_gates();
732 }
733 }
734 }
735
736
737 // Enable/Disable input pin i
enableINxpin(int i,bool on)738 void CLC_BASE::enableINxpin(int i, bool on)
739 {
740 if (on)
741 {
742 if (!INxactive[i])
743 {
744 char name[7] = "LCyINx";
745
746 if (!INxgui[i].length())
747 {
748 INxgui[i] = pinCLCxIN[i]->getPin().GUIname();
749 }
750
751 name[2] = '0' + index;
752 name[5] = '0' + i;
753 pinCLCxIN[i]->getPin().newGUIname(name);
754
755 if (!INxsink[i])
756 {
757 INxsink[i] = new INxSignalSink(this, i);
758 }
759
760 pinCLCxIN[i]->addSink(INxsink[i]);
761 setState(pinCLCxIN[i]->getPin().getState() ? '1' : '0', i);
762 }
763
764 INxactive[i]++;
765
766 }
767 else if (!--INxactive[i])
768 {
769 if (INxgui[i].length())
770 {
771 pinCLCxIN[i]->getPin().newGUIname(INxgui[i].c_str());
772
773 }
774 else
775 pinCLCxIN[i]->getPin().newGUIname(pinCLCxIN[i]->getPin().
776 name().c_str());
777
778 if (INxsink[i])
779 {
780 pinCLCxIN[i]->removeSink(INxsink[i]);
781 }
782 }
783 }
784
785
786 // Enable/disable output pin
oeCLCx(bool on)787 void CLC_BASE::oeCLCx(bool on)
788 {
789 if (on)
790 {
791 if (!srcCLCxactive)
792 {
793 char name[] = "CLCx";
794 name[3] = '1' + index;
795 CLCxgui = pinCLCx->getPin().GUIname();
796 pinCLCx->getPin().newGUIname(name);
797
798 if (!CLCxsrc)
799 {
800 CLCxsrc = new CLCSigSource(this, pinCLCx);
801 }
802
803 pinCLCx->setSource(CLCxsrc);
804 srcCLCxactive = true;
805 CLCxsrc->setState((clcxcon.value.get() & LCxOE) ? '1' : '0');
806 pinCLCx->updatePinModule();
807 }
808
809 }
810 else if (srcCLCxactive)
811 {
812 if (CLCxgui.length())
813 {
814 pinCLCx->getPin().newGUIname(CLCxgui.c_str());
815
816 }
817 else
818 pinCLCx->getPin().newGUIname(pinCLCx->getPin().name().
819 c_str());
820
821 pinCLCx->setSource(0);
822 delete CLCxsrc;
823 CLCxsrc = nullptr;
824 srcCLCxactive = false;
825 pinCLCx->updatePinModule();
826 }
827 }
828
829
830 // Update the output value of each of the 4 Data Gates
831 // taking into account both input and output polarity
compute_gates()832 void CLC_BASE::compute_gates()
833 {
834 unsigned int glsx[] =
835 {
836 clcxgls0.value.get(), clcxgls1.value.get(),
837 clcxgls2.value.get(), clcxgls3.value.get()
838 };
839 int mask;
840 unsigned int pol = clcxpol.value.get();
841
842 for (int j = 0; j < 4; j++)
843 {
844 bool gate_out = false;
845 mask = 1;
846
847 for (int i = 0; i < 4; i++)
848 {
849 if (glsx[j] & mask)
850 {
851 gate_out = !lcxdT[i];
852 }
853
854 mask <<= 1;
855
856 if (glsx[j] & mask)
857 {
858 gate_out = lcxdT[i];
859 }
860
861 mask <<= 1;
862 }
863
864 gate_out = (pol & (1 << j)) ? !gate_out : gate_out;
865 lcxg[j] = gate_out;
866 }
867
868 if (CLCenabled())
869 {
870 Dprintf(("CLC_BASE::compute_gates CLC%u lcxdT = {%d %d %d %d} lcxg={%d %d %d %d}\n", index + 1, lcxdT[0], lcxdT[1], lcxdT[2], lcxdT[3], lcxg[0], lcxg[1], lcxg[2], lcxg[3]));
871 }
872
873 cell_function();
874 }
875
876
877 // Select and execute cell functions
cell_function()878 void CLC_BASE::cell_function()
879 {
880 bool out = false;
881 unsigned int con = clcxcon.value.get();
882 unsigned int pol = clcxpol.value.get();
883
884 switch (con & 0x7)
885 {
886 case 0: // AND-OR
887 out = (lcxg[0] && lcxg[1]) || (lcxg[2] && lcxg[3]);
888 break;
889
890 case 1: // OR-XOR
891 out = (lcxg[0] || lcxg[1]) ^ (lcxg[2] || lcxg[3]);
892 break;
893
894 case 2: // 4 input AND
895 out = lcxg[0] && lcxg[1] && lcxg[2] && lcxg[3];
896 break;
897
898 case 3:
899 out = cell_sr_latch();
900 break;
901
902 case 4:
903 out = cell_1_in_flipflop();
904 break;
905
906 case 5:
907 out = cell_2_in_flipflop();
908 break;
909
910 case 6:
911 out = JKflipflop();
912 break;
913
914 case 7:
915 out = transparent_D_latch();
916 break;
917 }
918
919 if (pol & LCxPOL)
920 {
921 out = !out;
922 }
923
924 if (CLCenabled())
925 {
926 outputCLC(out);
927 }
928 }
929
930
931 // Send output to required consumers
outputCLC(bool out)932 void CLC_BASE::outputCLC(bool out)
933 {
934 unsigned int con = clcxcon.value.get();
935 bool old_out = con & LCxOUT;
936 Dprintf(("outputCLC CLC%u out=%d old_out=%d clcdata=0x%x\n", index, out,
937 old_out, clcdata->value.get()));
938
939 if (out)
940 {
941 con |= LCxOUT;
942
943 }
944 else
945 {
946 con &= ~LCxOUT;
947 }
948
949 clcxcon.value.put(con);
950 assert(m_Interrupt);
951 Dprintf(("CLC_BASE::outputCLC CLC%u old_out %d out %d int 0x%x \n", index + 1,
952 old_out, out, con & LCxINTP));
953
954 if (!old_out && out && (con & LCxINTP)) //Positive edge interrupt
955 {
956 m_Interrupt->Trigger();
957 }
958
959 if (old_out && !out && (con & LCxINTN)) //Negative edge interrupt
960 {
961 m_Interrupt->Trigger();
962 }
963
964 assert(clcdata);
965 clcdata->set_bit(out, index);
966
967 // send output to other modules
968 if (p_nco)
969 p_nco->link_nco(out, index);
970
971 if (p_cog)
972 p_cog->out_clc(out, index);
973
974 if (CLCenabled())
975 {
976 CLCxsrc->setState(out ? '1' : '0');
977 pinCLCx->updatePinModule();
978 }
979 }
980
981
cell_sr_latch()982 bool CLC_BASE::cell_sr_latch()
983 {
984 bool set = lcxg[0] || lcxg[1];
985 bool reset = lcxg[2] || lcxg[3];
986
987 if (set)
988 {
989 Doutput = true;
990
991 }
992 else if (reset)
993 {
994 Doutput = false;
995 }
996
997 return Doutput;
998 }
999
1000
cell_1_in_flipflop()1001 bool CLC_BASE::cell_1_in_flipflop()
1002 {
1003 bool set = lcxg[3];
1004 bool reset = lcxg[2];
1005 bool clock = lcxg[0];
1006 bool D = lcxg[1];
1007
1008 if (set)
1009 {
1010 Doutput = true;
1011
1012 }
1013 else if (reset)
1014 {
1015 Doutput = false;
1016
1017 }
1018 else if (!Dclock && clock)
1019 {
1020 Doutput = D;
1021 }
1022
1023 Dclock = clock;
1024 return Doutput;
1025 }
1026
1027
cell_2_in_flipflop()1028 bool CLC_BASE::cell_2_in_flipflop()
1029 {
1030 bool reset = lcxg[2];
1031 bool clock = lcxg[0];
1032 bool D = lcxg[1] || lcxg[3];
1033
1034 if (reset)
1035 {
1036 Doutput = false;
1037
1038 }
1039 else if (!Dclock && clock)
1040 {
1041 Doutput = D;
1042 }
1043
1044 Dclock = clock;
1045 return Doutput;
1046 }
1047
1048
JKflipflop()1049 bool CLC_BASE::JKflipflop()
1050 {
1051 bool J = lcxg[1];
1052 bool K = lcxg[3];
1053 bool reset = lcxg[2];
1054 bool clock = lcxg[0];
1055
1056 if (reset)
1057 {
1058 Doutput = false;
1059
1060 }
1061 else if (!Dclock && clock) // Clock + edge
1062 {
1063 if (J && K) // Toggle output
1064 {
1065 Doutput = !Doutput;
1066
1067 }
1068 else if (J && !K) // Set output
1069 {
1070 Doutput = true;
1071
1072 }
1073 else if (!J && K) // clear output
1074 {
1075 Doutput = false;
1076
1077 }
1078 else if (!J && !K) // no change
1079 {
1080 ;
1081 }
1082 }
1083
1084 Dclock = clock;
1085 return Doutput;
1086 }
1087
1088
transparent_D_latch()1089 bool CLC_BASE::transparent_D_latch()
1090 {
1091 bool reset = lcxg[0];
1092 bool D = lcxg[1];
1093 bool LE = lcxg[2];
1094 bool set = lcxg[3];
1095
1096 if (set)
1097 {
1098 Doutput = true;
1099
1100 }
1101 else if (reset)
1102 {
1103 Doutput = false;
1104
1105 }
1106 else if (!LE)
1107 {
1108 Doutput = D;
1109 }
1110
1111 return Doutput;
1112 }
1113
1114
releasePinSource(PinModule * pin)1115 void CLC_BASE::releasePinSource(PinModule * pin)
1116 {
1117 if (pin == pinCLCx)
1118 {
1119 srcCLCxactive = false;
1120 }
1121 }
1122
1123
1124 // Called from clcdata, process LCx_OUT updates where x = pos
lcxupdate(bool bit_val,unsigned int pos)1125 void CLC_BASE::lcxupdate(bool bit_val, unsigned int pos)
1126 {
1127 bool update = false;
1128
1129 for (int i = 0; i < 4; i++)
1130 {
1131 if ((lcxdT[i] != bit_val) &&
1132 ((DxS_data[i] == LC1 && pos == 0) ||
1133 (DxS_data[i] == LC2 && pos == 1) ||
1134 (DxS_data[i] == LC3 && pos == 2) ||
1135 (DxS_data[i] == LC4 && pos == 3)))
1136 {
1137 update = true;
1138 lcxdT[i] = bit_val;
1139 }
1140 }
1141
1142 if (update)
1143 {
1144 if (CLCenabled())
1145 Dprintf(("CLC%u lcxupdate LC%u_OUT=%d\n", index + 1, pos + 1,
1146 bit_val));
1147
1148 compute_gates();
1149 }
1150 }
1151
1152
1153 // CLCCON register has changed
update_clccon(unsigned int diff)1154 void CLC_BASE::update_clccon(unsigned int diff)
1155 {
1156 unsigned int val = clcxcon.value.get();
1157
1158 if (diff & LCxOE)
1159 {
1160 if ((val & (LCxOE | LCxEN)) == (LCxOE | LCxEN))
1161 {
1162 oeCLCx(true);
1163 }
1164
1165 if ((val & (LCxOE | LCxEN)) == (LCxEN))
1166 {
1167 oeCLCx(false);
1168 }
1169 }
1170
1171 if (diff & LCxEN) // clc off or on
1172 {
1173 if (val & LCxEN) // CLC on
1174 {
1175 config_inputs(true);
1176
1177 }
1178 else // CLC off
1179 {
1180 config_inputs(false);
1181 oeCLCx(false);
1182 }
1183 }
1184 }
1185
1186
1187 // Initialize inputs as required, called when CLC is enabled or disabled
1188 // or changes in clcxselx clcxglsx while clc enabled
config_inputs(bool on)1189 void CLC_BASE::config_inputs(bool on)
1190 {
1191 unsigned int active_gates = clcxgls0.value.get() |
1192 clcxgls1.value.get() | clcxgls2.value.get() | clcxgls3.value.get();
1193 Dprintf(("config_inputs CLC%u on=%d active_gates=0x%x\n", index + 1, on,
1194 active_gates));
1195 bool haveIN[4] = {false, false, false, false};
1196 bool haveFRC = false;
1197 bool haveLFINTOSC = false;
1198 bool haveHFINTOSC = false;
1199 int mask = 3;
1200
1201 for (int i = 0; i < 4; i++)
1202 {
1203 if (active_gates & mask) // data input used
1204 {
1205 if (DxS_data[i] == CLCxIN0) { haveIN[0] = true; }
1206 else if (DxS_data[i] == CLCxIN1) { haveIN[1] = true; }
1207 else if (DxS_data[i] == CLCxIN2) { haveIN[2] = true; }
1208 else if (DxS_data[i] == CLCxIN3) { haveIN[3] = true; }
1209 else if (DxS_data[i] == FRC_IN) { haveFRC = true; }
1210 else if (DxS_data[i] == LFINTOSC) { haveLFINTOSC = true; }
1211 else if (DxS_data[i] == HFINTOSC) { haveHFINTOSC = true; }
1212 }
1213
1214 mask <<= 2;
1215 }
1216
1217 // If on==true and inactive, turn on
1218 // if on==false and active. turn off
1219
1220
1221 for (int i = 0; i<4; i++)
1222 {
1223 if (haveIN[i] && (INxactive[i] ^ on))
1224 {
1225 Dprintf(("config_inputs CLC%u IN%d on=%d\n", index + 1, i, on));
1226 enableINxpin(i, on);
1227
1228 }
1229 else if (!haveIN[i] && INxactive[i])
1230 {
1231 Dprintf(("config_inputs CLC%u IN%d OFF on=%d\n", index + 1, i, on));
1232 enableINxpin(i, false);
1233 }
1234 }
1235
1236
1237 if (haveFRC && (FRCactive ^ on))
1238 {
1239 Dprintf(("config_inputs CLC%u FRC FRCactive=%d on=%d\n", index + 1,
1240 FRCactive, on));
1241 FRCactive = on;
1242 frc->start_osc_sim(on);
1243
1244 }
1245 else if (!haveFRC && FRCactive)
1246 {
1247 Dprintf(("config_inputs CLC%u FRC OFF on=%d\n", index + 1, on));
1248 FRCactive = false;
1249 frc->start_osc_sim(false);
1250 }
1251
1252 if (haveLFINTOSC && (LFINTOSCactive ^ on))
1253 {
1254 Dprintf(("config_inputs CLC%u LFINTOSC LFINTOSCactive=%d on=%d\n",
1255 index + 1, LFINTOSCactive, on));
1256 LFINTOSCactive = on;
1257 lfintosc->start_osc_sim(on);
1258
1259 }
1260 else if (!haveLFINTOSC && LFINTOSCactive)
1261 {
1262 Dprintf(("config_inputs CLC%u LFINTOSC OFF on=%d\n", index + 1,
1263 on));
1264 LFINTOSCactive = false;
1265 lfintosc->start_osc_sim(false);
1266 }
1267
1268 if (haveHFINTOSC && (HFINTOSCactive ^ on))
1269 {
1270 Dprintf(("config_inputs CLC%u HFINTOSC HFINTOSCactive=%d on=%d\n",
1271 index + 1, HFINTOSCactive, on));
1272 HFINTOSCactive = on;
1273 hfintosc->start_osc_sim(on);
1274
1275 }
1276 else if (!haveHFINTOSC && HFINTOSCactive)
1277 {
1278 Dprintf(("config_inputs CLC%u HFINTOSC OFF on=%d\n", index + 1,
1279 on));
1280 HFINTOSCactive = false;
1281 hfintosc->start_osc_sim(false);
1282 }
1283
1284 if (on)
1285 {
1286 compute_gates();
1287 }
1288 }
1289
1290
CLC_4SEL(Processor * cpu,unsigned int _index,CLCDATA * _clcdata)1291 CLC_4SEL::CLC_4SEL(Processor * cpu, unsigned int _index, CLCDATA * _clcdata)
1292 : CLC_BASE(cpu, _index, _clcdata),
1293 clcxsel0(this, cpu, "clcxsel0", "Multiplexer Data 1 Select Register", 0),
1294 clcxsel1(this, cpu, "clcxsel1", "Multiplexer Data 2 Select Register", 1),
1295 clcxsel2(this, cpu, "clcxsel2", "Multiplexer Data 3 Select Register", 2),
1296 clcxsel3(this, cpu, "clcxsel3", "Multiplexer Data 4 Select Register", 3)
1297 {
1298 }
1299
1300
1301
1302
1303 // OSC_SIM simulates clock inputs for CLC.
1304 // If the requested frequency > FOSC/4, OSC_SIM will generate pulses at
1305 // a frequency of FOSC/4.
1306 // If the requested frequency is not a whole fraction of FOSC/4, the
1307 // simulated clock will have jitter to approximate the requested frequency.
1308 // The duty cycle of the simulated frequency will only be 50% when
1309 // the requested frequency is a whole fraction of FOSC/8.
OSC_SIM(double _freq,int _data_in)1310 OSC_SIM::OSC_SIM(double _freq, int _data_in)
1311 : frequency(_freq), data_in(_data_in)
1312 {
1313 for (int i = 0; i < 4; i++)
1314 {
1315 m_clc[i] = nullptr;
1316 }
1317 }
1318
1319
start_osc_sim(bool on)1320 void OSC_SIM::start_osc_sim(bool on)
1321 {
1322 if (on)
1323 {
1324 Dprintf(("OSC_SIM::start_osc_sim freq=%.0f kHz active %d\n",
1325 frequency / 1000.0, active));
1326
1327 if (!active)
1328 {
1329 int cycles = get_cycles().instruction_cps() / frequency + 0.5;
1330
1331 if (cycles < 2)
1332 {
1333 fprintf(stderr,
1334 "OSC_SIM %.1f kHz not simulated at current CPU frequency\n",
1335 frequency / 1000.0);
1336 fprintf(stderr, "Using pulses at %.1f kHz\n",
1337 get_cycles().instruction_cps() / 1000.0);
1338 cycles = 1;
1339 }
1340
1341 adjust_cycles =
1342 frequency - get_cycles().instruction_cps() / cycles;
1343 next_cycle = cycles / 2;
1344 level = true;
1345
1346 for (int i = 0; i < 4; i++)
1347 {
1348 if (m_clc[i])
1349 {
1350 m_clc[i]->osc_out(level, data_in);
1351 }
1352 }
1353
1354 if (future_cycle)
1355 {
1356 get_cycles().clear_break(this);
1357 }
1358
1359 future_cycle = get_cycles().get() + cycles - next_cycle;
1360 get_cycles().set_break(future_cycle, this);
1361 Dprintf(("OSC_SIM::start_osc_sim cycles=%d adj_cycles=%" PRINTF_GINT64_MODIFIER "d freq=%.1f kHz inst_cps=%e\n", cycles, adjust_cycles, frequency / 1000.0, get_cycles().instruction_cps()));
1362 }
1363
1364 active++;
1365
1366 }
1367 else if (--active == 0)
1368 {
1369 Dprintf(("OSC_SIM::start_osc_sim stop freq=%.0f\n",
1370 frequency / 1000.0));
1371
1372 if (future_cycle)
1373 {
1374 get_cycles().clear_break(this);
1375 future_cycle = 0;
1376 }
1377 }
1378 }
1379
1380
callback()1381 void OSC_SIM::callback()
1382 {
1383 for (int i = 0; i < 4; i++)
1384 {
1385 if (m_clc[i])
1386 {
1387 m_clc[i]->osc_out(!level, data_in);
1388 }
1389 }
1390
1391 if (!next_cycle && level) // Sending a pulse
1392 {
1393 for (int i = 0; i < 4; i++)
1394 {
1395 if (m_clc[i])
1396 {
1397 m_clc[i]->osc_out(level, data_in);
1398 }
1399 }
1400 }
1401
1402 if (next_cycle)
1403 {
1404 future_cycle = get_cycles().get() + next_cycle;
1405 next_cycle = 0;
1406 level = false;
1407
1408 }
1409 else
1410 {
1411 adjust_cycles += frequency;
1412 int cycles = get_cycles().instruction_cps() / adjust_cycles + 0.5;
1413
1414 if (cycles < 2)
1415 {
1416 cycles = 1;
1417 adjust_cycles = 0;
1418
1419 }
1420 else
1421 {
1422 adjust_cycles -= get_cycles().instruction_cps() / cycles;
1423 }
1424
1425 next_cycle = cycles / 2;
1426 level = true;
1427 future_cycle = get_cycles().get() + cycles - next_cycle;
1428 }
1429
1430 get_cycles().set_break(future_cycle, this);
1431 }
1432