1 /*
2 Copyright (C) 1998 Scott Dattalo
3 Copyright (C) 2009 Roy R. Rankin
4
5 This file is part of the libgpsim library of gpsim
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, see
19 <http://www.gnu.org/licenses/lgpl-2.1.html>.
20 */
21
22 #include <assert.h>
23 #include <stdio.h>
24 #include <iostream>
25
26 #include "pic-processor.h"
27 #include "pic-ioports.h"
28 #include "intcon.h"
29 #include "psp.h"
30 #include "trace.h"
31 #include "ui.h"
32
33 //#define DEBUG
34 #if defined(DEBUG)
35 #define Dprintf(arg) {printf("%s:%d ",__FILE__,__LINE__); printf arg; }
36 #else
37 #define Dprintf(arg) {}
38 #endif
39
40 //-------------------------------------------------------------------
41 //
42 // ioports.cc
43 //
44 // The ioport infrastructure for gpsim is provided here. The class
45 // taxonomy for the IOPORT class is:
46 //
47 // file_register
48 // |-> sfr_register
49 // |-> IOPORT
50 // |-> PORTA
51 // |-> PORTB
52 // |-> PORTC
53 // |-> PORTD
54 // |-> PORTE
55 // |-> PORTF
56 //
57 // Each I/O port has an associated array of I/O pins which provide an
58 // interface to the virtual external world of the stimuli.
59 //
60 //-------------------------------------------------------------------
61
62 class PicSignalSource : public SignalControl
63 {
64 public:
PicSignalSource(PortRegister * _reg,unsigned int bitPosition)65 PicSignalSource(PortRegister *_reg, unsigned int bitPosition)
66 : m_register(_reg), m_bitMask(1 << bitPosition)
67 {
68 }
getState()69 char getState()
70 {
71
72 char r = m_register ? (((m_register->getDriving() & m_bitMask) != 0) ? '1' : '0') : 'Z';
73
74 Dprintf(("PicSignalSource::getState() %s bitmask:0x%x state:%c\n",
75 (m_register?m_register->name().c_str():"NULL"),
76 m_bitMask,r));
77
78 return r;
79 }
release()80 void release()
81 {
82 delete this;
83 }
84 private:
85 PortRegister *m_register;
86 unsigned int m_bitMask;
87 };
88
89
90
91 //------------------------------------------------------------------------
92
PicPortRegister(Processor * pCpu,const char * pName,const char * pDesc,unsigned int numIopins,unsigned int enableMask)93 PicPortRegister::PicPortRegister(Processor *pCpu, const char *pName, const char *pDesc,
94 /*const char *port_name,*/
95 unsigned int numIopins,
96 unsigned int enableMask)
97 : PortRegister(pCpu, pName, pDesc,numIopins, false), m_tris(0)
98 {
99 setEnableMask(enableMask);
100 }
101
102 class PicSignalControl : public SignalControl
103 {
104 public:
PicSignalControl(PicTrisRegister * _reg,unsigned int bitPosition)105 PicSignalControl(PicTrisRegister *_reg, unsigned int bitPosition)
106 : m_register(_reg), m_bitMask(1 << bitPosition)
107 {
108 }
~PicSignalControl()109 virtual ~PicSignalControl()
110 {
111 }
112
getState()113 virtual char getState()
114 {
115 return m_register ? m_register->get3StateBit(m_bitMask) : '?';
116 }
release()117 virtual void release()
118 {
119 delete this;
120 }
121 private:
122 PicTrisRegister *m_register;
123 unsigned int m_bitMask;
124 };
125
setTris(PicTrisRegister * new_tris)126 void PicPortRegister::setTris(PicTrisRegister *new_tris)
127 {
128 if (!m_tris)
129 m_tris = new_tris;
130
131 unsigned int mask = getEnableMask();
132 for (unsigned int i = 0, m = 1; i < mNumIopins; i++, m <<= 1)
133 {
134 if (mask & m)
135 operator[](i).setDefaultControl(new PicSignalControl(m_tris, i));
136 }
137 }
138 //------------------------------------------------------------------------
139
PicTrisRegister(Processor * pCpu,const char * pName,const char * pDesc,PicPortRegister * _port,bool bIgnoreWDTResets,unsigned int enableMask)140 PicTrisRegister::PicTrisRegister(Processor *pCpu, const char *pName, const char *pDesc,
141 /*const char *tris_name,*/
142 PicPortRegister *_port,
143 bool bIgnoreWDTResets,
144 unsigned int enableMask)
145 : sfr_register(pCpu, pName, pDesc),
146 m_port(_port),
147 m_EnableMask(enableMask),
148 m_bIgnoreWDTResets(bIgnoreWDTResets)
149 {
150 if (m_port)
151 m_port->setTris(this);
152 }
153
put(unsigned int new_value)154 void PicTrisRegister::put(unsigned int new_value)
155 {
156 trace.raw(write_trace.get() | value.data);
157 value.put((value.get() & ~m_EnableMask) | (new_value & m_EnableMask));
158
159 if (m_port)
160 m_port->updatePort();
161 }
162
put_value(unsigned int new_value)163 void PicTrisRegister::put_value(unsigned int new_value)
164 {
165 value.put(new_value & m_EnableMask);
166
167 if (m_port)
168 m_port->updatePort();
169 }
170
get()171 unsigned int PicTrisRegister::get()
172 {
173 trace.raw(read_trace.get() | value.data);
174 return value.data;
175 }
176
setEnableMask(unsigned int enableMask)177 void PicTrisRegister::setEnableMask(unsigned int enableMask)
178 {
179 m_EnableMask = enableMask;
180 }
181
get3StateBit(unsigned int bitMask)182 char PicTrisRegister::get3StateBit(unsigned int bitMask)
183 {
184 RegisterValue rv = getRV_notrace();
185 unsigned int enabled = bitMask & m_EnableMask;
186 if (!enabled)
187 return '1';
188
189 return (rv.init & enabled) ? '?' : ((rv.data & enabled) ? '1': '0');
190 }
191
reset(RESET_TYPE r)192 void PicTrisRegister::reset(RESET_TYPE r)
193 {
194 if (!(m_bIgnoreWDTResets && r == WDT_RESET))
195 putRV(por_value);
196 }
197
198
199 //------------------------------------------------------------------------
200
PicPSP_TrisRegister(Processor * pCpu,const char * pName,const char * pDesc,PicPortRegister * _port,bool bIgnoreWDTResets)201 PicPSP_TrisRegister::PicPSP_TrisRegister(Processor *pCpu, const char *pName, const char *pDesc,
202 /*const char *tris_name, */
203 PicPortRegister *_port, bool bIgnoreWDTResets)
204 : PicTrisRegister(pCpu, pName, pDesc, _port, bIgnoreWDTResets)
205 {
206 }
207 // If not in PSPMODE, OBF and IBF are always clear
208 // When in PSPMODE, OBF and IBF can only be cleared by reading and writing
209 // to the PSP parallel port and are set by bus transfers.
210 //
put(unsigned int new_value)211 void PicPSP_TrisRegister::put(unsigned int new_value)
212 {
213 unsigned int mask = (PSP::OBF | PSP::IBF);
214 unsigned int fixed;
215
216 trace.raw(write_trace.get() | value.data);
217 if (! (new_value & PSP::PSPMODE))
218 fixed = 0;
219 else
220 fixed = value.data & mask;
221
222 value.data = (new_value & ~mask) | fixed;
223 if (m_port)
224 m_port->updatePort();
225 }
226
227 // used by gpsim to change register value
put_value(unsigned int new_value)228 void PicPSP_TrisRegister::put_value(unsigned int new_value)
229 {
230 trace.raw(write_trace.get() | value.data);
231
232 value.data = new_value;
233 if (m_port)
234 m_port->updatePort();
235 }
236
get()237 unsigned int PicPSP_TrisRegister::get()
238 {
239 return value.data;
240 }
241
242
243 //------------------------------------------------------------------------
244
PicPortBRegister(Processor * pCpu,const char * pName,const char * pDesc,INTCON * pIntcon,unsigned int numIopins,unsigned int enableMask,INTCON2 * pIntcon2,INTCON3 * pIntcon3)245 PicPortBRegister::PicPortBRegister(Processor *pCpu, const char *pName, const char *pDesc,
246 INTCON *pIntcon,
247 unsigned int numIopins,
248 unsigned int enableMask,
249 INTCON2 *pIntcon2,
250 INTCON3 *pIntcon3)
251 : PicPortRegister(pCpu, pName, pDesc, numIopins, enableMask),
252 intf_bit(9),
253 cpu(pCpu),
254 m_bRBPU(false),
255 m_bIntEdge(true),
256 m_bsRBPU(0),
257 m_pIntcon(pIntcon),
258 m_pIntcon2(pIntcon2),
259 m_pIntcon3(pIntcon3)
260 {
261 assert(m_pIntcon);
262 }
263
~PicPortBRegister()264 PicPortBRegister::~PicPortBRegister()
265 {
266 delete m_bsRBPU;
267 }
268
269 //------------------------------------------------------------------------
270
put(unsigned int new_value)271 void PicPortBRegister::put(unsigned int new_value)
272 {
273 trace.raw(write_trace.get() | value.data);
274
275
276 // unsigned int diff = mEnableMask & (new_value ^ value.data);
277 drivingValue = new_value & mEnableMask;
278 value.data = drivingValue;
279 // If no stimuli are connected to the Port pins, then the driving
280 // value and the driven value are the same. If there are external
281 // stimuli (or perhaps internal peripherals) overdriving or overriding
282 // this port, then the call to updatePort() will update 'drivenValue'
283 // to its proper value.
284 updatePort();
285 lastDrivenValue = rvDrivenValue;
286
287 }
288
get()289 unsigned int PicPortBRegister::get()
290 {
291 lastDrivenValue = rvDrivenValue;
292 return mOutputMask & rvDrivenValue.data;
293 }
294
295 //------------------------------------------------------------------------
296 // setbit
297 // FIXME - a sink should be created for the intf and rbif functions.
298
setbit(unsigned int bit_number,char new3State)299 void PicPortBRegister::setbit(unsigned int bit_number, char new3State)
300 {
301 Dprintf(("PicPortBRegister::setbit() bit=%u,val=%c bIntEdge=%d\n",
302 bit_number, new3State, m_bIntEdge));
303
304 // interrupt bit 0 on specified edge
305 bool bNewValue = new3State == '1' || new3State == 'W';
306 lastDrivenValue = rvDrivenValue;
307 setINTif(bit_number, bNewValue);
308 PortRegister::setbit(bit_number, new3State);
309
310
311 // interrupt and exit sleep level change top 4 bits on input
312 unsigned int bitMask = (1 << bit_number) & 0xF0;
313
314 if ((lastDrivenValue.data ^ rvDrivenValue.data) & m_tris->get_value() & bitMask)
315 {
316
317 if ((m_pIntcon->get() & (INTCON::GIE | INTCON::RBIE)) == INTCON::RBIE)
318 cpu_pic->exit_sleep();
319 m_pIntcon->set_rbif(true);
320 }
321 }
322
setINTif(unsigned int bit_number,bool bNewValue)323 void PicPortBRegister::setINTif(unsigned int bit_number, bool bNewValue)
324 {
325 // lastDrivenValue = rvDrivenValue;
326 bool OldValue = (lastDrivenValue.data&(1 << bit_number)) ;
327 bool level;
328
329 if (OldValue == bNewValue) return;
330 if (m_pIntcon3)
331 {
332 int intcon = m_pIntcon->value.get();
333 int intcon2 = m_pIntcon2->value.get();
334 int intcon3 = m_pIntcon3->value.get();
335 switch (bit_number)
336 {
337 case 0:
338 level = intcon2 & INTCON2::INTEDG0;
339 if ((OldValue != bNewValue) && (bNewValue == level))
340 {
341 m_pIntcon->set_intf(true);
342 if ( (intcon & INTCON::INTE))
343 {
344 cpu_pic->exit_sleep();
345 ((INTCON_16 *)m_pIntcon)->general_interrupt(true);
346 }
347 }
348 return;
349 break;
350
351 case 1:
352 level = intcon2 & INTCON2::INTEDG1;
353 if ((OldValue != bNewValue) && (bNewValue == level))
354 {
355 m_pIntcon3->set_int1f(true);
356 if ((intcon3 & INTCON3::INT1IE))
357 {
358 cpu_pic->exit_sleep();
359 ((INTCON_16 *)m_pIntcon)->general_interrupt(intcon3 & INTCON3::INT1IP);
360 }
361 }
362 return;
363 break;
364
365 case 2:
366 level = intcon2 & INTCON2::INTEDG2;
367 if ((OldValue != bNewValue) && (bNewValue == level))
368 {
369 m_pIntcon3->set_int2f(true);
370 if ((intcon3 & INTCON3::INT2IE))
371 {
372 cpu_pic->exit_sleep();
373 ((INTCON_16 *)m_pIntcon)->general_interrupt(intcon3 & INTCON3::INT2IP);
374 }
375 }
376 return;
377 break;
378
379 case 3:
380 if (intf_bit != 3) return;
381 level = intcon2 & INTCON2::INTEDG3;
382 if ((OldValue != bNewValue) && (bNewValue == level))
383 {
384 m_pIntcon3->set_int3f(true);
385 if ((intcon3 & INTCON3::INT3IE))
386 {
387 cpu_pic->exit_sleep();
388 ((INTCON_16 *)m_pIntcon)->general_interrupt(intcon2 & INTCON2::INT3IP);
389 }
390 }
391 return;
392 break;
393 }
394 }
395 else
396 {
397 if (bit_number == intf_bit)
398 {
399 if ((OldValue != m_bIntEdge) && (bNewValue == m_bIntEdge))
400 {
401 if ((m_pIntcon->get() & INTCON::INTE))
402 {
403 cpu_pic->exit_sleep();
404 }
405 m_pIntcon->set_intf(true);
406 }
407 }
408 }
409 }
410 class RBPUBitSink : public BitSink
411 {
412 PicPortBRegister *m_pPortB;
413 public:
RBPUBitSink(PicPortBRegister * pPortB)414 explicit RBPUBitSink(PicPortBRegister *pPortB)
415 : m_pPortB(pPortB)
416 {}
417
setSink(bool b)418 void setSink(bool b)
419 {
420 if (m_pPortB)
421 m_pPortB->setRBPU(b);
422 }
423 };
424
assignRBPUSink(unsigned int bitPos,sfr_register * pSFR)425 void PicPortBRegister::assignRBPUSink(unsigned int bitPos, sfr_register *pSFR)
426 {
427 if (pSFR && !m_bsRBPU)
428 {
429 m_bsRBPU = new RBPUBitSink(this);
430 if (!pSFR->assignBitSink(bitPos, m_bsRBPU))
431 {
432 delete m_bsRBPU;
433 m_bsRBPU = 0;
434 }
435 }
436 }
437
setRBPU(bool bNewRBPU)438 void PicPortBRegister::setRBPU(bool bNewRBPU)
439 {
440 m_bRBPU = !bNewRBPU;
441
442 Dprintf(("PicPortBRegister::setRBPU() =%d\n", (m_bRBPU ? 1 : 0)));
443
444 unsigned int mask = getEnableMask();
445 for (unsigned int i = 0, m = 1; mask; i++, m <<= 1)
446 {
447 if (mask & m)
448 {
449 mask ^= m;
450 operator[](i).getPin().update_pullup(m_bRBPU ? '1' : '0', true);
451 }
452 }
453 }
454
setIntEdge(bool bNewIntEdge)455 void PicPortBRegister::setIntEdge(bool bNewIntEdge)
456 {
457 m_bIntEdge = bNewIntEdge;
458 }
459
PicPortGRegister(Processor * pCpu,const char * pName,const char * pDesc,INTCON * pIntcon,IOC * pIoc,unsigned int numIopins,unsigned int enableMask,INTCON2 * pIntcon2,INTCON3 * pIntcon3)460 PicPortGRegister::PicPortGRegister(Processor *pCpu, const char *pName,
461 const char *pDesc,
462 INTCON *pIntcon, IOC *pIoc,
463 unsigned int numIopins, unsigned int enableMask,
464 INTCON2 *pIntcon2,
465 INTCON3 *pIntcon3)
466 : PicPortBRegister(pCpu, pName, pDesc, pIntcon, numIopins, enableMask),
467 m_pIntcon(pIntcon), m_pIoc(pIoc)
468 {
469 m_pIntcon->set_portGReg(this);
470 m_pIntcon2=pIntcon2;
471 m_pIntcon3=pIntcon3;
472 }
473
474 // set_rbif involves RBIF,RBIE in INTCON which are the same bits as GPIF,GPIE
setIOCif()475 void PicPortGRegister::setIOCif()
476 {
477 // interrupt and exit sleep for level change on bits where IOC set
478 int bitMask = m_pIoc->get_value();
479
480
481 if ( (lastDrivenValue.data ^ rvDrivenValue.data) & m_tris->get_value() & bitMask )
482 {
483 cpu_pic->exit_sleep();
484 m_pIntcon->set_rbif(true);
485 }
486 }
487
setbit(unsigned int bit_number,char new3State)488 void PicPortGRegister::setbit(unsigned int bit_number, char new3State)
489 {
490 bool bNewValue = new3State == '1' || new3State == 'W';
491
492 lastDrivenValue = rvDrivenValue;
493 PortRegister::setbit(bit_number, new3State);
494
495 setINTif(bit_number, bNewValue);
496 setIOCif();
497 // interrupt and exit sleep for level change on bits where IOC set
498 int bitMask = m_pIoc->get_value() & (1 << bit_number);
499
500 if (verbose)
501 printf("PicPortGRegister::setbit() bit=%u,val=%c IOC_bit=%x\n", bit_number, new3State, bitMask);
502 }
503
504
setbit(unsigned int bit_number,char new3State)505 void PicPortIOCRegister::setbit(unsigned int bit_number, char new3State)
506 {
507 bool bNewValue = new3State == '1' || new3State == 'W';
508 int lastDrivenValue = rvDrivenValue.data & (1 << bit_number);
509 setINTif(bit_number, bNewValue);
510 PortRegister::setbit(bit_number, new3State);
511 int newDrivenValue = rvDrivenValue.data & (1 << bit_number);
512
513 if (verbose)
514 {
515 printf("PicPortIOCRegister::setbit() bit=%u,val=%c IOC_+=%x IOC_-=%x\n",
516 bit_number, new3State, m_Iocap->get_value() & (1 << bit_number),
517 m_Iocan->get_value() & (1 << bit_number));
518 }
519
520 if (newDrivenValue > lastDrivenValue)
521 {
522 // positive edge
523 if (m_tris->get_value() & (m_Iocap->get_value() & (1 << bit_number)))
524 {
525 cpu_pic->exit_sleep();
526 m_pIntcon->set_rbif(true);
527 if (m_Iocaf)
528 m_Iocaf->put(m_Iocaf->get_value() | (1 << bit_number));
529 }
530 }
531 else if (newDrivenValue < lastDrivenValue)
532 {
533 // negative edge
534 if (m_tris->get_value() & (m_Iocan->get_value() & (1 << bit_number)))
535 {
536 cpu_pic->exit_sleep();
537 m_pIntcon->set_rbif(true);
538 if (m_Iocaf)
539 m_Iocaf->put(m_Iocaf->get_value() | (1 << bit_number));
540 }
541 }
542 }
543
PicPSP_PortRegister(Processor * pCpu,const char * pName,const char * pDesc,unsigned int numIopins,unsigned int enableMask)544 PicPSP_PortRegister::PicPSP_PortRegister(Processor *pCpu, const char *pName, const char *pDesc,
545 /*const char *port_name,*/
546 unsigned int numIopins,
547 unsigned int enableMask)
548 : PortRegister(pCpu, pName, pDesc,numIopins, false), m_tris(0), m_psp(0)
549 {
550 setEnableMask(enableMask);
551 }
552
put(unsigned int new_value)553 void PicPSP_PortRegister::put(unsigned int new_value)
554 {
555 trace.raw(write_trace.get() | value.data);
556 unsigned int diff = mEnableMask & (new_value ^ value.data);
557
558 if (m_psp && m_psp->pspmode())
559 {
560 m_psp->psp_put(new_value);
561 }
562 else if (diff)
563 {
564 drivingValue = new_value & mEnableMask;
565 value.data = drivingValue;
566 // If no stimuli are connected to the Port pins, then the driving
567 // value and the driven value are the same. If there are external
568 // stimuli (or perhaps internal peripherals) overdriving or overriding
569 // this port, then the call to updatePort() will update 'drivenValue'
570 // to its proper value.
571 updatePort();
572 }
573 }
574
get()575 unsigned int PicPSP_PortRegister::get()
576 {
577 if (m_psp && m_psp->pspmode())
578 return(m_psp->psp_get());
579
580 return rvDrivenValue.data;
581 }
582
583
setTris(PicTrisRegister * new_tris)584 void PicPSP_PortRegister::setTris(PicTrisRegister *new_tris)
585 {
586 if (!m_tris)
587 m_tris = new_tris;
588
589 unsigned int mask = getEnableMask();
590 for (unsigned int i = 0, m = 1; i < mNumIopins; i++, m <<= 1)
591 {
592 if (mask & m)
593 operator[](i).setDefaultControl(new PicSignalControl(m_tris, i));
594 }
595 }
596
597 //------------------------------------------------------------------------
598 // Latch Register
599
PicLatchRegister(Processor * pCpu,const char * pName,const char * pDesc,PortRegister * _port,unsigned int enableMask)600 PicLatchRegister::PicLatchRegister(Processor *pCpu, const char *pName, const char *pDesc,
601 /*const char *_name, */
602 PortRegister *_port,
603 unsigned int enableMask)
604 : sfr_register(pCpu, pName, pDesc),
605 m_port(_port), m_EnableMask(enableMask)
606 {
607 }
608
put(unsigned int new_value)609 void PicLatchRegister::put(unsigned int new_value)
610 {
611 trace.raw(write_trace.get() | value.data);
612 value.data = new_value & m_EnableMask;
613 m_port->put_value(value.data);
614 }
615
put_value(unsigned int new_value)616 void PicLatchRegister::put_value(unsigned int new_value)
617 {
618 value.data = new_value & m_EnableMask;
619 m_port->put_value(value.data);
620 }
621
get()622 unsigned int PicLatchRegister::get()
623 {
624 value.data = m_port->getDriving();
625 trace.raw(read_trace.get() | value.data);
626 trace.raw(read_trace.geti() | value.init);
627
628 return value.data;
629 }
630
setbit(unsigned int,char)631 void PicLatchRegister::setbit(unsigned int, char)
632 {
633 printf("PicLatchRegister::setbit() -- shouldn't be called\n");
634 }
635
setEnableMask(unsigned int nEnableMask)636 void PicLatchRegister::setEnableMask(unsigned int nEnableMask)
637 {
638 m_EnableMask = nEnableMask;
639 }
640
641