2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
12 #define EVENT_COUNTER 0
17 for(int ch = 0; ch < 4; ch++) {
18 counter[ch].count = counter[ch].constant = 256;
19 counter[ch].clocks = 0;
20 counter[ch].control = 0;
21 counter[ch].slope = false;
22 counter[ch].prescaler = 256;
23 counter[ch].freeze = counter[ch].start = counter[ch].latch = false;
24 counter[ch].clock_id = counter[ch].sysclock_id = -1;
25 counter[ch].first_constant = true;
27 counter[ch].req_intr = false;
28 counter[ch].in_service = false;
29 counter[ch].vector = ch << 1;
34 void Z80CTC::write_io8(uint32_t addr, uint32_t data)
37 if(counter[ch].latch) {
39 counter[ch].constant = data ? data : 256;
40 counter[ch].latch = false;
41 if(counter[ch].freeze || counter[ch].first_constant) {
42 counter[ch].count = counter[ch].constant;
43 counter[ch].clocks = 0;
44 counter[ch].freeze = false;
45 counter[ch].first_constant = false;
51 counter[ch].prescaler = (data & 0x20) ? 256 : 16;
52 counter[ch].latch = ((data & 4) != 0);
53 counter[ch].freeze = ((data & 2) != 0);
54 counter[ch].start = (counter[ch].freq || !(data & 8));
55 counter[ch].control = data;
56 counter[ch].slope = ((data & 0x10) != 0);
57 if(!(data & 0x80) && counter[ch].req_intr) {
58 counter[ch].req_intr = false;
64 counter[0].vector = (data & 0xf8) | 0;
65 counter[1].vector = (data & 0xf8) | 2;
66 counter[2].vector = (data & 0xf8) | 4;
67 counter[3].vector = (data & 0xf8) | 6;
72 uint32_t Z80CTC::read_io8(uint32_t addr)
76 if(counter[ch].clock_id != -1) {
77 int passed = get_passed_clock(counter[ch].prev);
78 uint32_t input = (uint32_t)(counter[ch].freq * passed / cpu_clocks);
79 if(counter[ch].input <= input) {
80 input = counter[ch].input - 1;
83 input_clock(ch, input);
84 // cancel and re-register event
85 cancel_event(this, counter[ch].clock_id);
86 counter[ch].input -= input;
87 counter[ch].period -= passed;
88 counter[ch].prev = get_current_clock();
89 register_event_by_clock(this, EVENT_COUNTER + ch, counter[ch].period, false, &counter[ch].clock_id);
91 } else if(counter[ch].sysclock_id != -1) {
92 int passed = get_passed_clock(counter[ch].prev);
94 uint32_t input = (uint32_t)(passed * Z80CTC_CLOCKS / cpu_clocks);
96 uint32_t input = passed;
98 if(counter[ch].input <= input) {
99 input = counter[ch].input - 1;
102 input_sysclock(ch, input);
103 // cancel and re-register event
104 cancel_event(this, counter[ch].sysclock_id);
105 counter[ch].input -= passed;
106 counter[ch].period -= passed;
107 counter[ch].prev = get_current_clock();
108 register_event_by_clock(this, EVENT_TIMER + ch, counter[ch].period, false, &counter[ch].sysclock_id);
111 return counter[ch].count & 0xff;
114 void Z80CTC::event_callback(int event_id, int err)
116 int ch = event_id & 3;
118 input_sysclock(ch, counter[ch].input);
119 counter[ch].sysclock_id = -1;
121 input_clock(ch, counter[ch].input);
122 counter[ch].clock_id = -1;
124 update_event(ch, err);
127 void Z80CTC::write_signal(int id, uint32_t data, uint32_t mask)
136 // more correct implements...
137 bool next = ((data & mask) != 0);
138 if(counter[ch].prev_in != next) {
139 if(counter[ch].slope == next) {
143 counter[ch].prev_in = next;
148 void Z80CTC::input_clock(int ch, int clock)
150 if(!(counter[ch].control & 0x40)) {
151 // now timer mode, start timer and quit !!!
152 counter[ch].start = true;
155 if(counter[ch].freeze) {
160 counter[ch].count -= clock;
161 while(counter[ch].count <= 0) {
162 counter[ch].count += counter[ch].constant;
163 if(counter[ch].control & 0x80) {
164 counter[ch].req_intr = true;
167 write_signals(&counter[ch].outputs, 0xffffffff);
168 write_signals(&counter[ch].outputs, 0);
172 void Z80CTC::input_sysclock(int ch, int clock)
174 if(counter[ch].control & 0x40) {
175 // now counter mode, quit !!!
178 if(!counter[ch].start || counter[ch].freeze) {
181 counter[ch].clocks += clock;
182 int input = counter[ch].clocks >> (counter[ch].prescaler == 256 ? 8 : 4);
183 counter[ch].clocks &= counter[ch].prescaler - 1;
186 counter[ch].count -= input;
187 while(counter[ch].count <= 0) {
188 counter[ch].count += counter[ch].constant;
189 if(counter[ch].control & 0x80) {
190 counter[ch].req_intr = true;
193 write_signals(&counter[ch].outputs, 0xffffffff);
194 write_signals(&counter[ch].outputs, 0);
198 void Z80CTC::update_event(int ch, int err)
200 if(counter[ch].control & 0x40) {
202 if(counter[ch].sysclock_id != -1) {
203 cancel_event(this, counter[ch].sysclock_id);
205 counter[ch].sysclock_id = -1;
207 if(counter[ch].freeze) {
208 if(counter[ch].clock_id != -1) {
209 cancel_event(this, counter[ch].clock_id);
211 counter[ch].clock_id = -1;
214 if(counter[ch].clock_id == -1 && counter[ch].freq) {
215 counter[ch].input = counter[ch].count;
216 counter[ch].period = (uint32_t)(cpu_clocks * counter[ch].input / counter[ch].freq) + err;
217 counter[ch].prev = get_current_clock() + err;
218 register_event_by_clock(this, EVENT_COUNTER + ch, counter[ch].period, false, &counter[ch].clock_id);
222 if(counter[ch].clock_id != -1) {
223 cancel_event(this, counter[ch].clock_id);
225 counter[ch].clock_id = -1;
227 if(!counter[ch].start || counter[ch].freeze) {
228 if(counter[ch].sysclock_id != -1) {
229 cancel_event(this, counter[ch].sysclock_id);
231 counter[ch].sysclock_id = -1;
234 if(counter[ch].sysclock_id == -1) {
235 counter[ch].input = counter[ch].count * counter[ch].prescaler - counter[ch].clocks;
237 counter[ch].period = (uint32_t)(counter[ch].input * cpu_clocks / Z80CTC_CLOCKS) + err;
239 counter[ch].period = counter[ch].input + err;
241 counter[ch].prev = get_current_clock() + err;
242 register_event_by_clock(this, EVENT_TIMER + ch, counter[ch].period, false, &counter[ch].sysclock_id);
247 void Z80CTC::set_intr_iei(bool val)
255 #define set_intr_oei(val) { \
259 d_child->set_intr_iei(oei); \
264 void Z80CTC::update_intr()
269 if((next = iei) == true) {
270 for(int ch = 0; ch < 4; ch++) {
271 if(counter[ch].in_service) {
280 if((next = iei) == true) {
282 for(int ch = 0; ch < 4; ch++) {
283 if(counter[ch].in_service) {
286 if(counter[ch].req_intr) {
293 d_cpu->set_intr_line(next, true, intr_bit);
297 uint32_t Z80CTC::get_intr_ack()
300 for(int ch = 0; ch < 4; ch++) {
301 if(counter[ch].in_service) {
302 // invalid interrupt status
304 } else if(counter[ch].req_intr) {
305 counter[ch].req_intr = false;
306 counter[ch].in_service = true;
308 return counter[ch].vector;
312 return d_child->get_intr_ack();
317 void Z80CTC::notify_intr_reti()
320 for(int ch = 0; ch < 4; ch++) {
321 if(counter[ch].in_service) {
322 counter[ch].in_service = false;
323 counter[ch].req_intr = false; // ???
329 d_child->notify_intr_reti();
333 #define STATE_VERSION 1
335 void Z80CTC::save_state(FILEIO* state_fio)
337 state_fio->FputUint32(STATE_VERSION);
338 state_fio->FputInt32(this_device_id);
340 for(int i = 0; i < 4; i++) {
341 state_fio->FputUint8(counter[i].control);
342 state_fio->FputBool(counter[i].slope);
343 state_fio->FputUint16(counter[i].count);
344 state_fio->FputUint16(counter[i].constant);
345 state_fio->FputUint8(counter[i].vector);
346 state_fio->FputInt32(counter[i].clocks);
347 state_fio->FputInt32(counter[i].prescaler);
348 state_fio->FputBool(counter[i].freeze);
349 state_fio->FputBool(counter[i].start);
350 state_fio->FputBool(counter[i].latch);
351 state_fio->FputBool(counter[i].prev_in);
352 state_fio->FputBool(counter[i].first_constant);
353 state_fio->FputUint64(counter[i].freq);
354 state_fio->FputInt32(counter[i].clock_id);
355 state_fio->FputInt32(counter[i].sysclock_id);
356 state_fio->FputUint32(counter[i].input);
357 state_fio->FputUint32(counter[i].period);
358 state_fio->FputUint32(counter[i].prev);
359 state_fio->FputBool(counter[i].req_intr);
360 state_fio->FputBool(counter[i].in_service);
362 state_fio->FputUint64(cpu_clocks);
363 state_fio->FputBool(iei);
364 state_fio->FputBool(oei);
365 state_fio->FputUint32(intr_bit);
368 bool Z80CTC::load_state(FILEIO* state_fio)
370 if(state_fio->FgetUint32() != STATE_VERSION) {
373 if(state_fio->FgetInt32() != this_device_id) {
376 for(int i = 0; i < 4; i++) {
377 counter[i].control = state_fio->FgetUint8();
378 counter[i].slope = state_fio->FgetBool();
379 counter[i].count = state_fio->FgetUint16();
380 counter[i].constant = state_fio->FgetUint16();
381 counter[i].vector = state_fio->FgetUint8();
382 counter[i].clocks = state_fio->FgetInt32();
383 counter[i].prescaler = state_fio->FgetInt32();
384 counter[i].freeze = state_fio->FgetBool();
385 counter[i].start = state_fio->FgetBool();
386 counter[i].latch = state_fio->FgetBool();
387 counter[i].prev_in = state_fio->FgetBool();
388 counter[i].first_constant = state_fio->FgetBool();
389 counter[i].freq = state_fio->FgetUint64();
390 counter[i].clock_id = state_fio->FgetInt32();
391 counter[i].sysclock_id = state_fio->FgetInt32();
392 counter[i].input = state_fio->FgetUint32();
393 counter[i].period = state_fio->FgetUint32();
394 counter[i].prev = state_fio->FgetUint32();
395 counter[i].req_intr = state_fio->FgetBool();
396 counter[i].in_service = state_fio->FgetBool();
398 cpu_clocks = state_fio->FgetUint64();
399 iei = state_fio->FgetBool();
400 oei = state_fio->FgetBool();
401 intr_bit = state_fio->FgetUint32();