OSDN Git Service

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