1 /*
2    Copyright (C) 1998-2003 Scott Dattalo
3                  2003 Mike Durian
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 
22 #ifndef SRC_INTCON_H_
23 #define SRC_INTCON_H_
24 
25 #include <vector>
26 
27 #include "gpsim_classes.h"
28 #include "registers.h"
29 #include "pic-ioports.h"
30 
31 class IOCxF;
32 class PicPortGRegister;
33 class Processor;
34 class PIR_SET;
35 class RCON;
36 
37 //---------------------------------------------------------
38 // INTCON - Interrupt control register
39 
40 class INTCON : public sfr_register
41 {
42 public:
43     unsigned int interrupt_trace = 0;
44     bool in_interrupt = false;
45 
46     enum
47     {
48         RBIF = 1 << 0,
49         INTF = 1 << 1,
50         T0IF = 1 << 2,
51         RBIE = 1 << 3,
52         INTE = 1 << 4,
53         T0IE = 1 << 5,
54         XXIE = 1 << 6,  // Processor dependent
55         PEIE = 1 << 6,
56         GIE  = 1 << 7
57     };
58 
59     INTCON(Processor *pCpu, const char *pName, const char *pDesc);
set_gie()60     virtual void set_gie() { put(value.get() | GIE); }
61 
clear_gie()62     virtual void clear_gie() { put(value.get() & ~GIE); }
63 
64     void set_T0IF();
65 
66     /*
67     // Bit 6 of intcon depends on the processor that's being simulated,
68     // This generic function will get called whenever interrupt flag upon
69     // which bit 6 enables becomes true. (e.g. for the c84, this
70     // routine is called when EEIF goes high.)
71     */
72     virtual void peripheral_interrupt(bool hi_pri = false);
73 
74     virtual void set_rbif(bool b);
75 
set_intf(bool b)76     inline void set_intf(bool b)
77     {
78         bool current = (value.get() & INTF) == INTF;
79 
80         if (b && !current)
81         {
82             put(value.get() | INTF);
83         }
84 
85         if (!b && current)
86         {
87             put(value.get() & ~INTF);
88         }
89     }
90 
set_t0if()91     inline void set_t0if() { put(value.get() | T0IF); }
92 
set_rbie()93     inline void set_rbie() { put(value.get() | RBIE); }
94 
set_inte()95     inline void set_inte() { put(value.get() | INTE); }
96 
set_t0ie()97     inline void set_t0ie() { put(value.get() | T0IE); }
98 
set_portGReg(PicPortGRegister * _portGReg)99     void set_portGReg(PicPortGRegister *_portGReg) { portGReg = _portGReg; }
100     virtual int check_peripheral_interrupt() = 0;
101     virtual void put(unsigned int new_value);
102     virtual void put_value(unsigned int new_value);
aocxf_val(IOCxF *,unsigned int)103     virtual void aocxf_val(IOCxF *, unsigned int /* val */ ) {}
104 
105     PicPortGRegister *portGReg = nullptr;
106 };
107 
108 
109 //---------------------------------------------------------
110 class INTCON2 :  public sfr_register
111 {
112 public:
113     INTCON2(Processor *pCpu, const char *pName, const char *pDesc);
114 
115     virtual void put_value(unsigned int new_value);
116     virtual void put(unsigned int new_value);
117 
118     virtual bool assignBitSink(unsigned int bitPosition, BitSink *);
119     virtual bool releaseBitSink(unsigned int bitPosition, BitSink *);
120 
121     enum
122     {
123         RBIP    = 1 << 0,
124         INT3IP  = 1 << 1,
125         TMR0IP  = 1 << 2,
126         INTEDG3 = 1 << 3,
127         INTEDG2 = 1 << 4,
128         INTEDG1 = 1 << 5,
129         INTEDG0 = 1 << 6,
130         RBPU    = 1 << 7
131     };
132 
133 private:
134     BitSink *m_bsRBPU = nullptr;
135 };
136 
137 
138 class INTCON3 :  public sfr_register
139 {
140 public:
141     INTCON3(Processor *pCpu, const char *pName, const char *pDesc);
142 
143     virtual void put_value(unsigned int new_value);
144     virtual void put(unsigned int new_value);
145 
set_int1f(bool b)146     inline void set_int1f(bool b)
147     {
148         bool current = (value.get() & INT1IF) == INT1IF;
149 
150         if (b && !current)
151         {
152             put(value.get() | INT1IF);
153         }
154 
155         if (!b && current)
156         {
157             put(value.get() & ~INT1IF);
158         }
159     }
set_int2f(bool b)160     inline void set_int2f(bool b)
161     {
162         bool current = (value.get() & INT2IF) == INT2IF;
163 
164         if (b && !current)
165         {
166             put(value.get() | INT2IF);
167         }
168 
169         if (!b && current)
170         {
171             put(value.get() & ~INT2IF);
172         }
173     }
set_int3f(bool b)174     inline void set_int3f(bool b)
175     {
176         bool current = (value.get() & INT3IF) == INT3IF;
177 
178         if (b && !current)
179         {
180             put(value.get() | INT3IF);
181         }
182 
183         if (!b && current)
184         {
185             put(value.get() & ~INT3IF);
186         }
187     }
set_int1e()188     inline void set_int1e() { put(value.get() | INT1IE); }
set_int2e()189     inline void set_int2e() { put(value.get() | INT2IE); }
set_int3e()190     inline void set_int3e() { put(value.get() | INT3IE); }
191     enum
192     {
193         INT1IF  = 1 << 0,
194         INT2IF  = 1 << 1,
195         INT3IF  = 1 << 2,
196         INT1IE  = 1 << 3,
197         INT2IE  = 1 << 4,
198         INT3IE  = 1 << 5,
199         INT1IP  = 1 << 6,
200         INT2IP  = 1 << 7
201     };
202 };
203 
204 
205 // A 14-bit intcon with pir registers
206 class INTCON_14_PIR : public INTCON
207 {
208 public:
209     INTCON_14_PIR(Processor *pCpu, const char *pName, const char *pDesc);
210 
211     virtual void put(unsigned int new_value);
212     virtual void put_value(unsigned int new_value);
set_pir_set(PIR_SET * p)213     inline void set_pir_set(PIR_SET *p) { pir_set = p; }
214 
215     virtual int check_peripheral_interrupt();
216     virtual void set_rbif(bool b);
set_gie()217     virtual void set_gie() { put_value(value.get() | GIE); }
clear_gie()218     virtual void clear_gie() { put_value(value.get() & ~GIE); }
219     virtual void aocxf_val(IOCxF *, unsigned int val);
220     virtual void reset(RESET_TYPE r);
221 
222     enum
223     {
224         IOCIF = 1 << 0,
225         INTF  = 1 << 1,
226         T0IF  = 1 << 2,
227         IOCIE = 1 << 3,
228         INTE  = 1 << 4,
229         T0IE  = 1 << 5,
230         PEIE  = 1 << 6,
231         GIE   = 1 << 7
232     };
233 
234     //private:
235     PIR_SET *pir_set = nullptr;
236     unsigned int write_mask;    // Bits that instructions can modify
237     struct aocxf
238     {
239         struct IOCxF *ptr_iocxf;
240         unsigned int val;
241     };
242     std::vector<aocxf> aocxf_list;
243 };
244 
245 
246 
247 //---------------------------------------------------------
248 // INTCON_16 - Interrupt control register for the 16-bit core
249 
250 class INTCON_16 : public INTCON
251 {
252 public:
253     INTCON_16(Processor *pCpu, const char *pName, const char *pDesc);
254 
255     enum
256     {
257         GIEH = GIE,
258         GIEL = XXIE,
259         TMR0IE = T0IE,
260         INT0IE = INTE,
261         TMR0IF = T0IF,
262         INT0IF = INTF
263     };
264 #define INTERRUPT_VECTOR_LO       (0x18 >> 1)
265 #define INTERRUPT_VECTOR_HI       (0x08 >> 1)
266 
set_rcon(RCON * r)267     inline void set_rcon(RCON *r) { rcon = r; }
set_intcon2(INTCON2 * ic)268     inline void set_intcon2(INTCON2 *ic) { intcon2 = ic; }
set_pir_set(PIR_SET * p)269     inline void set_pir_set(PIR_SET *p) { pir_set = p; }
270 
271     virtual void put(unsigned int new_value);
272     virtual void put_value(unsigned int new_value);
273 
274     virtual void peripheral_interrupt(bool hi_pri = false);
275     virtual void general_interrupt(bool hi_pri = false);
276 
277     void clear_gies();
278     void set_gies();
279     virtual int check_peripheral_interrupt();
get_interrupt_vector()280     unsigned int get_interrupt_vector()
281     {
282         return interrupt_vector;
283     }
isHighPriorityInterrupt()284     bool isHighPriorityInterrupt()
285     {
286         return (interrupt_vector == INTERRUPT_VECTOR_HI);
287     }
set_interrupt_vector(unsigned int new_int_vect)288     void set_interrupt_vector(unsigned int new_int_vect)
289     {
290         interrupt_vector = new_int_vect;
291     }
292 
293 private:
294     unsigned int interrupt_vector = 0;        // Starting address of the interrupt
295     RCON *rcon = nullptr;
296     INTCON2 *intcon2 = nullptr;
297     PIR_SET *pir_set = nullptr;
298 };
299 
300 
301 #endif /* INTCON_H */
302