OSDN Git Service

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