OSDN Git Service

[VM][COMMON_VM] Include IO:: class to common_vm.
[csp-qt/common_source_project-fm7.git] / source / src / vm / z80ctc.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.08.18 -
6
7         [ Z80CTC ]
8 */
9
10 #include "z80ctc.h"
11
12 #define EVENT_COUNTER   0
13 #define EVENT_TIMER     4
14
15 void Z80CTC::initialize()
16 {
17         DEVICE::initialize();
18         _E_Z80CTC_CLOCKS = osd->check_feature(_T("Z80CTC_CLOCKS"));
19         if(_E_Z80CTC_CLOCKS) {
20                 __Z80CTC_CLOCKS = osd->get_feature_double_value(_T("Z80CTC_CLOCKS"));
21         }
22 }
23
24 void Z80CTC::reset()
25 {
26         for(int ch = 0; ch < 4; ch++) {
27                 counter[ch].count = counter[ch].constant = 256;
28                 counter[ch].clocks = 0;
29                 counter[ch].control = 0;
30                 counter[ch].slope = false;
31                 counter[ch].prescaler = 256;
32                 counter[ch].freeze = counter[ch].start = counter[ch].latch = false;
33                 counter[ch].clock_id = counter[ch].sysclock_id = -1;
34                 counter[ch].first_constant = true;
35                 // interrupt
36                 counter[ch].req_intr = false;
37                 counter[ch].in_service = false;
38                 counter[ch].vector = ch << 1;
39         }
40         iei = oei = true;
41 }
42
43 void Z80CTC::write_io8(uint32_t addr, uint32_t data)
44 {
45         int ch = addr & 3;
46         if(counter[ch].latch) {
47                 // time constant
48                 counter[ch].constant = data ? data : 256;
49                 counter[ch].latch = false;
50                 if(counter[ch].freeze || counter[ch].first_constant) {
51                         counter[ch].count = counter[ch].constant;
52                         counter[ch].clocks = 0;
53                         counter[ch].freeze = false;
54                         counter[ch].first_constant = false;
55                         update_event(ch, 0);
56                 }
57         } else {
58                 if(data & 1) {
59                         // control word
60                         counter[ch].prescaler = (data & 0x20) ? 256 : 16;
61                         counter[ch].latch = ((data & 0x04) != 0);
62                         counter[ch].freeze = ((data & 0x02) != 0);
63                         counter[ch].start = (counter[ch].freq || !(data & 0x08));
64                         counter[ch].control = data;
65                         counter[ch].slope = ((data & 0x10) != 0);
66                         if((data & 0x02) && (counter[ch].req_intr || counter[ch].in_service)) {
67                                 counter[ch].req_intr = false;
68                                 counter[ch].in_service = false;
69                                 update_intr();
70                         }
71                         if(!(data & 0x80) && counter[ch].req_intr) {
72                                 counter[ch].req_intr = false;
73                                 update_intr();
74                         }
75                         update_event(ch, 0);
76                 } else if(ch == 0) {
77                         // vector
78                         counter[0].vector = (data & 0xf8) | 0;
79                         counter[1].vector = (data & 0xf8) | 2;
80                         counter[2].vector = (data & 0xf8) | 4;
81                         counter[3].vector = (data & 0xf8) | 6;
82                 }
83         }
84 }
85
86 uint32_t Z80CTC::read_io8(uint32_t addr)
87 {
88         int ch = addr & 3;
89         // update counter
90         if(counter[ch].clock_id != -1) {
91                 int passed = get_passed_clock(counter[ch].prev);
92                 uint32_t input = (uint32_t)(counter[ch].freq * passed / cpu_clocks);
93                 if(counter[ch].input <= input) {
94                         input = counter[ch].input - 1;
95                 }
96                 if(input > 0) {
97                         input_clock(ch, input);
98                         // cancel and re-register event
99                         cancel_event(this, counter[ch].clock_id);
100                         counter[ch].input -= input;
101                         counter[ch].period -= passed;
102                         counter[ch].prev = get_current_clock();
103                         register_event_by_clock(this, EVENT_COUNTER + ch, counter[ch].period, false, &counter[ch].clock_id);
104                 }
105         } else if(counter[ch].sysclock_id != -1) {
106                 int passed = get_passed_clock(counter[ch].prev);
107                 uint32_t input;
108 //#ifdef Z80CTC_CLOCKS
109                 if(_E_Z80CTC_CLOCKS) {
110                         input = (uint32_t)(passed * __Z80CTC_CLOCKS / cpu_clocks);
111                 } else {                
112 //#else
113                         input = passed;
114                 }
115 //#endif
116                 if(counter[ch].input <= input) {
117                         input = counter[ch].input - 1;
118                 }
119                 if(input > 0) {
120                         input_sysclock(ch, input);
121                         // cancel and re-register event
122                         cancel_event(this, counter[ch].sysclock_id);
123                         counter[ch].input -= passed;
124                         counter[ch].period -= passed;
125                         counter[ch].prev = get_current_clock();
126                         register_event_by_clock(this, EVENT_TIMER + ch, counter[ch].period, false, &counter[ch].sysclock_id);
127                 }
128         }
129         return counter[ch].count & 0xff;
130 }
131
132 void Z80CTC::event_callback(int event_id, int err)
133 {
134         int ch = event_id & 3;
135         if(event_id & 4) {
136                 input_sysclock(ch, counter[ch].input);
137                 counter[ch].sysclock_id = -1;
138         } else {
139                 input_clock(ch, counter[ch].input);
140                 counter[ch].clock_id = -1;
141         }
142         update_event(ch, err);
143 }
144
145 void Z80CTC::write_signal(int id, uint32_t data, uint32_t mask)
146 {
147         int ch = id & 3;
148 #if 1
149         if(data & mask) {
150                 input_clock(ch, 1);
151                 update_event(ch, 0);
152         }
153 #else
154         // more correct implements...
155         bool next = ((data & mask) != 0);
156         if(counter[ch].prev_in != next) {
157                 if(counter[ch].slope == next) {
158                         input_clock(ch, 1);
159                         update_event(ch, 0);
160                 }
161                 counter[ch].prev_in = next;
162         }
163 #endif
164 }
165
166 void Z80CTC::input_clock(int ch, int clock)
167 {
168         if(!(counter[ch].control & 0x40)) {
169                 // now timer mode, start timer and quit !!!
170                 counter[ch].start = true;
171                 return;
172         }
173         if(counter[ch].freeze) {
174                 return;
175         }
176         
177         // update counter
178         counter[ch].count -= clock;
179         while(counter[ch].count <= 0) {
180                 counter[ch].count += counter[ch].constant;
181                 if(counter[ch].control & 0x80) {
182                         counter[ch].req_intr = true;
183                         update_intr();
184                 }
185                 write_signals(&counter[ch].outputs, 0xffffffff);
186                 write_signals(&counter[ch].outputs, 0);
187         }
188 }
189
190 void Z80CTC::input_sysclock(int ch, int clock)
191 {
192         if(counter[ch].control & 0x40) {
193                 // now counter mode, quit !!!
194                 return;
195         }
196         if(!counter[ch].start || counter[ch].freeze) {
197                 return;
198         }
199         counter[ch].clocks += clock;
200         int input = counter[ch].clocks >> (counter[ch].prescaler == 256 ? 8 : 4);
201         counter[ch].clocks &= counter[ch].prescaler - 1;
202         
203         // update counter
204         counter[ch].count -= input;
205         while(counter[ch].count <= 0) {
206                 counter[ch].count += counter[ch].constant;
207                 if(counter[ch].control & 0x80) {
208                         counter[ch].req_intr = true;
209                         update_intr();
210                 }
211                 write_signals(&counter[ch].outputs, 0xffffffff);
212                 write_signals(&counter[ch].outputs, 0);
213         }
214 }
215
216 void Z80CTC::update_event(int ch, int err)
217 {
218         if(counter[ch].control & 0x40) {
219                 // counter mode
220                 if(counter[ch].sysclock_id != -1) {
221                         cancel_event(this, counter[ch].sysclock_id);
222                 }
223                 counter[ch].sysclock_id = -1;
224                 
225                 if(counter[ch].freeze) {
226                         if(counter[ch].clock_id != -1) {
227                                 cancel_event(this, counter[ch].clock_id);
228                         }
229                         counter[ch].clock_id = -1;
230                         return;
231                 }
232                 if(counter[ch].clock_id == -1 && counter[ch].freq) {
233                         counter[ch].input = counter[ch].count;
234                         counter[ch].period = (uint32_t)(cpu_clocks * counter[ch].input / counter[ch].freq) + err;
235                         counter[ch].prev = get_current_clock() + err;
236                         register_event_by_clock(this, EVENT_COUNTER + ch, counter[ch].period, false, &counter[ch].clock_id);
237                 }
238         } else {
239                 // timer mode
240                 if(counter[ch].clock_id != -1) {
241                         cancel_event(this, counter[ch].clock_id);
242                 }
243                 counter[ch].clock_id = -1;
244                 
245                 if(!counter[ch].start || counter[ch].freeze) {
246                         if(counter[ch].sysclock_id != -1) {
247                                 cancel_event(this, counter[ch].sysclock_id);
248                         }
249                         counter[ch].sysclock_id = -1;
250                         return;
251                 }
252                 if(counter[ch].sysclock_id == -1) {
253                         counter[ch].input = counter[ch].count * counter[ch].prescaler - counter[ch].clocks;
254 //#ifdef Z80CTC_CLOCKS
255                         if(_E_Z80CTC_CLOCKS) {
256                                 counter[ch].period = (uint32_t)(counter[ch].input * cpu_clocks / __Z80CTC_CLOCKS) + err;
257                         } else {
258 //#else
259                                 counter[ch].period = counter[ch].input + err;
260                         }
261 //#endif
262                         counter[ch].prev = get_current_clock() + err;
263                         register_event_by_clock(this, EVENT_TIMER + ch, counter[ch].period, false, &counter[ch].sysclock_id);
264                 }
265         }
266 }
267
268 void Z80CTC::set_intr_iei(bool val)
269 {
270         if(iei != val) {
271                 iei = val;
272                 update_intr();
273         }
274 }
275
276 #define set_intr_oei(val) { \
277         if(oei != val) { \
278                 oei = val; \
279                 if(d_child) { \
280                         d_child->set_intr_iei(oei); \
281                 } \
282         } \
283 }
284
285 void Z80CTC::update_intr()
286 {
287         bool next;
288         
289         // set oei signal
290         if((next = iei) == true) {
291                 for(int ch = 0; ch < 4; ch++) {
292                         if(counter[ch].in_service) {
293                                 next = false;
294                                 break;
295                         }
296                 }
297         }
298         set_intr_oei(next);
299         
300         // set int signal
301         if((next = iei) == true) {
302                 next = false;
303                 for(int ch = 0; ch < 4; ch++) {
304                         if(counter[ch].in_service) {
305                                 break;
306                         }
307                         if(counter[ch].req_intr) {
308                                 next = true;
309                                 break;
310                         }
311                 }
312         }
313         if(d_cpu) {
314                 d_cpu->set_intr_line(next, true, intr_bit);
315         }
316 }
317
318 uint32_t Z80CTC::get_intr_ack()
319 {
320         // ack (M1=IORQ=L)
321         for(int ch = 0; ch < 4; ch++) {
322                 if(counter[ch].in_service) {
323                         // invalid interrupt status
324                         return 0xff;
325                 } else if(counter[ch].req_intr) {
326                         counter[ch].req_intr = false;
327                         counter[ch].in_service = true;
328                         update_intr();
329                         return counter[ch].vector;
330                 }
331         }
332         if(d_child) {
333                 return d_child->get_intr_ack();
334         }
335         return 0xff;
336 }
337
338 void Z80CTC::notify_intr_reti()
339 {
340         // detect RETI
341         for(int ch = 0; ch < 4; ch++) {
342                 if(counter[ch].in_service) {
343                         counter[ch].in_service = false;
344                         counter[ch].req_intr = false; // ???
345                         update_intr();
346                         return;
347                 }
348         }
349         if(d_child) {
350                 d_child->notify_intr_reti();
351         }
352 }
353
354 #define STATE_VERSION   1
355
356 bool Z80CTC::process_state(FILEIO* state_fio, bool loading)
357 {
358         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
359                 return false;
360         }
361         if(!state_fio->StateCheckInt32(this_device_id)) {
362                 return false;
363         }
364         for(int i = 0; i < 4; i++) {
365                 state_fio->StateValue(counter[i].control);
366                 state_fio->StateValue(counter[i].slope);
367                 state_fio->StateValue(counter[i].count);
368                 state_fio->StateValue(counter[i].constant);
369                 state_fio->StateValue(counter[i].vector);
370                 state_fio->StateValue(counter[i].clocks);
371                 state_fio->StateValue(counter[i].prescaler);
372                 state_fio->StateValue(counter[i].freeze);
373                 state_fio->StateValue(counter[i].start);
374                 state_fio->StateValue(counter[i].latch);
375                 state_fio->StateValue(counter[i].prev_in);
376                 state_fio->StateValue(counter[i].first_constant);
377                 state_fio->StateValue(counter[i].freq);
378                 state_fio->StateValue(counter[i].clock_id);
379                 state_fio->StateValue(counter[i].sysclock_id);
380                 state_fio->StateValue(counter[i].input);
381                 state_fio->StateValue(counter[i].period);
382                 state_fio->StateValue(counter[i].prev);
383                 state_fio->StateValue(counter[i].req_intr);
384                 state_fio->StateValue(counter[i].in_service);
385         }
386         state_fio->StateValue(cpu_clocks);
387         state_fio->StateValue(iei);
388         state_fio->StateValue(oei);
389         state_fio->StateValue(intr_bit);
390         return true;
391 }