OSDN Git Service

[VM][STATE] Use namespace {VMNAME} to separate per VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6001 / timer.cpp
1 /*
2         NEC PC-6001 Emulator 'yaPC-6001'
3         NEC PC-6001mkII Emulator 'yaPC-6201'
4         NEC PC-6001mkIISR Emulator 'yaPC-6401'
5         NEC PC-6601 Emulator 'yaPC-6601'
6         NEC PC-6601SR Emulator 'yaPC-6801'
7
8         Author : Takeda.Toshiya
9         Date   : 2014.05.22-
10
11         [ timer ]
12 */
13
14 #include "timer.h"
15 #ifndef _PC6001
16 #include "./memory.h"
17 #endif
18
19 #define EVENT_TIMER     0
20
21 namespace PC6001 {
22
23 void TIMER::initialize()
24 {
25 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
26         memset(sr_vectors, 0, sizeof(sr_vectors));
27 #endif
28 }
29
30 void TIMER::reset()
31 {
32         IRQ = NewIRQ = 0;
33         timer_id = -1;
34         
35 #ifndef _PC6001
36         portF3 = 0x00;
37         portF4 = 0x02; //???
38         portF5 = 0x16;
39         portF7 = 0x06;
40 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
41         portFA = 0x00;
42         portFB = 0x00;
43         portF6 = 0x7f;
44 #else
45         portF6 = 0x03;
46 #endif
47 #endif
48 }
49
50 #ifndef _PC6001
51 void TIMER::write_io8(uint32_t addr, uint32_t data)
52 {
53         switch(addr & 0xff) {
54 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
55         case 0xB8:
56         case 0xB9:
57         case 0xBA:
58         case 0xBB:
59         case 0xBC:
60         case 0xBD:
61         case 0xBE:
62         case 0xBF:
63                 sr_vectors[addr & 7] = data;
64                 break;
65 #endif
66         case 0xF3:
67                 portF3 = data;
68 //              d_mem->set_portF3(data);
69                 break;
70         case 0xF4:
71                 portF4 = data;
72                 break;
73         case 0xF5:
74                 portF5 = data;
75                 break;
76         case 0xF6:
77                 portF6 = data;
78                 break;
79         case 0xF7:
80                 portF7 = data;
81                 break;
82 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
83         case 0xFA:
84                 portFA = data;
85                 break;
86         case 0xFB:
87                 portFB = data;
88                 break;
89 #endif
90         }
91 }
92
93 uint32_t TIMER::read_io8(uint32_t addr)
94 {
95         switch(addr & 0xff) {
96 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
97         case 0xB8:
98         case 0xB9:
99         case 0xBA:
100         case 0xBB:
101         case 0xBC:
102         case 0xBD:
103         case 0xBE:
104         case 0xBF:
105                 return sr_vectors[addr & 7];
106 #endif
107         case 0xF3:
108                 return portF3;
109         case 0xF4:
110                 return portF4;
111         case 0xF5:
112                 return portF5;
113         case 0xF6:
114                 return portF6;
115         case 0xF7:
116                 return portF7;
117 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
118         case 0xFA:
119                 return portFA;
120         case 0xFB:
121                 return portFB;
122 #endif
123         }
124         return 0xff;
125 }
126 #endif
127
128 void TIMER::event_callback(int event_id, int err)
129 {
130         if(event_id == EVENT_TIMER) {
131                 write_signal(SIG_TIMER_IRQ_TIMER, 1, 1);
132                 timer_id = -1;
133                 // register next event
134 #ifdef _PC6001
135                 register_event(this, EVENT_TIMER, 2000.0, false, &timer_id);
136 #else
137 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
138                 if(static_cast<VM *>(vm)->sr_mode) {
139                         register_event(this, EVENT_TIMER, 2000.0 * (portF6 + 1) / 0x80, false, &timer_id);
140                 } else
141 #endif
142                 register_event(this, EVENT_TIMER, 2000.0 * (portF6 + 1) / 4, false, &timer_id);
143 #endif
144         }
145 }
146
147 void TIMER::set_portB0(uint32_t data)
148 {
149         if(data & 1) {
150                 // stop
151                 if(timer_id != -1) {
152                         cancel_event(this, timer_id);
153                         timer_id = -1;
154                 }
155         } else {
156                 // start
157                 if(timer_id == -1) {
158 #ifdef _PC6001
159                         // first period is 1msec
160                         register_event(this, EVENT_TIMER, 1000.0, false, &timer_id);
161 #else
162 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
163                         if(static_cast<VM *>(vm)->sr_mode) {
164                                 register_event(this, EVENT_TIMER, 2000.0 * (portF6 + 1) / 0x80, false, &timer_id);
165                         } else
166 #endif
167                         register_event(this, EVENT_TIMER, 2000.0 * (portF6 + 1) / 4, false, &timer_id);
168 #endif
169                 }
170         }
171 }
172
173 void TIMER::write_signal(int id, uint32_t data, uint32_t mask)
174 {
175         if(data & mask) {
176                 IRQ |= (1 << id);
177         } else {
178                 IRQ &= ~(1 << id);
179         }
180         update_intr();
181 }
182
183 uint32_t TIMER::get_intr_ack()
184 {
185 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
186         if(static_cast<VM *>(vm)->sr_mode) {
187                 for(int i = 0, bit = 1; i < 8; i++, bit <<= 1) {
188                         if(NewIRQ & bit) {
189                                 if(portFB & bit) {
190                                         IRQ = NewIRQ = 0;
191                                         return sr_vectors[i];
192                                 }
193                                 break;
194                         }
195                 }
196         }
197 #endif
198         if(NewIRQ & 0x01) {             // Sub-CPU
199                 IRQ = NewIRQ = 0;
200 #ifndef _PC6001
201                 if(portF3 & 0x08) {
202                         return portF4;
203                 }
204 #endif
205                 return d_sub->get_intr_ack();
206         }
207 #ifndef _PC6001
208         else if(NewIRQ & 0x02) {        // Joystick
209                 IRQ = NewIRQ = 0;
210                 if(portF3 & 0x10) {
211                         return portF5;
212                 }
213                 return 0x16;
214         }
215 #endif
216         else if(NewIRQ & 0x04) {        // Timer
217                 IRQ = NewIRQ = 0;
218 #ifndef _PC6001
219                 return portF7;
220 #else
221                 return 0x06;
222 #endif
223         }
224 #ifndef _PC6001
225         else if(NewIRQ & 0x08) {        // Voice
226                 IRQ = NewIRQ = 0;
227                 return 0x20;
228         }
229         else if(NewIRQ & 0x10) {        // VRTC
230                 IRQ = NewIRQ = 0;
231                 return 0x22;
232         }
233         else if(NewIRQ & 0x20) {        // RS-232C
234                 IRQ = NewIRQ = 0;
235                 return 0x04;
236         }
237         else if(NewIRQ & 0x40) {        // Printer
238                 IRQ = NewIRQ = 0;
239 //              return 0x00;
240         }
241         else if(NewIRQ & 0x80) {        // Ext Int
242                 IRQ = NewIRQ = 0;
243 //              return 0x00;
244         }
245 #endif
246         return 0x06;    // dummy
247 }
248
249 void TIMER::notify_intr_reti()
250 {
251         update_intr();
252 }
253
254 void TIMER::update_intr()
255 {
256         NewIRQ = IRQ;
257 #ifdef _PC6001
258         NewIRQ &= 0x05; // Only Sub-CPU and Timer
259 #else
260 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
261         if(static_cast<VM *>(vm)->sr_mode) {
262                 NewIRQ &= ~portFA;
263         } else
264 #endif
265         {
266                 if(portF3 & 0x01) {
267                         NewIRQ &= ~0x01;
268                 }
269                 if(portF3 & 0x02) {
270                         NewIRQ &= ~0x02;
271                 }
272                 if(portF3 & 0x04) {
273                         NewIRQ &= ~0x04;
274                 }
275         }
276 #endif
277         if(NewIRQ) {
278                 d_cpu->write_signal(SIG_CPU_IRQ, 1, 1);
279 //      } else {
280 //              d_cpu->write_signal(SIG_CPU_IRQ, 0, 1);
281         }
282 }
283
284 #define STATE_VERSION   1
285
286 bool TIMER::process_state(FILEIO* state_fio, bool loading)
287 {
288         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
289                 return false;
290         }
291         if(!state_fio->StateCheckInt32(this_device_id)) {
292                 return false;
293         }
294         state_fio->StateUint8(IRQ);
295         state_fio->StateUint8(NewIRQ);
296         state_fio->StateInt32(timer_id);
297 #ifndef _PC6001
298 #if defined(_PC6601SR) || defined(_PC6001MK2SR)
299         state_fio->StateBuffer(sr_vectors, sizeof(sr_vectors), 1);
300         state_fio->StateUint8(portFA);
301         state_fio->StateUint8(portFB);
302 #endif
303         state_fio->StateUint8(portF3);
304         state_fio->StateUint8(portF4);
305         state_fio->StateUint8(portF5);
306         state_fio->StateUint8(portF6);
307         state_fio->StateUint8(portF7);
308 #endif
309         return true;
310 }
311
312 }
313