2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
12 #define EVENT_COUNTER 0
15 void Z80CTC::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"));
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;
36 counter[ch].req_intr = false;
37 counter[ch].in_service = false;
38 counter[ch].vector = ch << 1;
43 void Z80CTC::write_io8(uint32_t addr, uint32_t data)
46 if(counter[ch].latch) {
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;
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;
71 if(!(data & 0x80) && counter[ch].req_intr) {
72 counter[ch].req_intr = false;
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;
86 uint32_t Z80CTC::read_io8(uint32_t addr)
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;
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);
105 } else if(counter[ch].sysclock_id != -1) {
106 int passed = get_passed_clock(counter[ch].prev);
108 //#ifdef Z80CTC_CLOCKS
109 if(_E_Z80CTC_CLOCKS) {
110 input = (uint32_t)(passed * __Z80CTC_CLOCKS / cpu_clocks);
116 if(counter[ch].input <= input) {
117 input = counter[ch].input - 1;
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);
129 return counter[ch].count & 0xff;
132 void Z80CTC::event_callback(int event_id, int err)
134 int ch = event_id & 3;
136 input_sysclock(ch, counter[ch].input);
137 counter[ch].sysclock_id = -1;
139 input_clock(ch, counter[ch].input);
140 counter[ch].clock_id = -1;
142 update_event(ch, err);
145 void Z80CTC::write_signal(int id, uint32_t data, uint32_t mask)
154 // more correct implements...
155 bool next = ((data & mask) != 0);
156 if(counter[ch].prev_in != next) {
157 if(counter[ch].slope == next) {
161 counter[ch].prev_in = next;
166 void Z80CTC::input_clock(int ch, int clock)
168 if(!(counter[ch].control & 0x40)) {
169 // now timer mode, start timer and quit !!!
170 counter[ch].start = true;
173 if(counter[ch].freeze) {
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;
185 write_signals(&counter[ch].outputs, 0xffffffff);
186 write_signals(&counter[ch].outputs, 0);
190 void Z80CTC::input_sysclock(int ch, int clock)
192 if(counter[ch].control & 0x40) {
193 // now counter mode, quit !!!
196 if(!counter[ch].start || counter[ch].freeze) {
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;
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;
211 write_signals(&counter[ch].outputs, 0xffffffff);
212 write_signals(&counter[ch].outputs, 0);
216 void Z80CTC::update_event(int ch, int err)
218 if(counter[ch].control & 0x40) {
220 if(counter[ch].sysclock_id != -1) {
221 cancel_event(this, counter[ch].sysclock_id);
223 counter[ch].sysclock_id = -1;
225 if(counter[ch].freeze) {
226 if(counter[ch].clock_id != -1) {
227 cancel_event(this, counter[ch].clock_id);
229 counter[ch].clock_id = -1;
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);
240 if(counter[ch].clock_id != -1) {
241 cancel_event(this, counter[ch].clock_id);
243 counter[ch].clock_id = -1;
245 if(!counter[ch].start || counter[ch].freeze) {
246 if(counter[ch].sysclock_id != -1) {
247 cancel_event(this, counter[ch].sysclock_id);
249 counter[ch].sysclock_id = -1;
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;
259 counter[ch].period = counter[ch].input + err;
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);
268 void Z80CTC::set_intr_iei(bool val)
276 #define set_intr_oei(val) { \
280 d_child->set_intr_iei(oei); \
285 void Z80CTC::update_intr()
290 if((next = iei) == true) {
291 for(int ch = 0; ch < 4; ch++) {
292 if(counter[ch].in_service) {
301 if((next = iei) == true) {
303 for(int ch = 0; ch < 4; ch++) {
304 if(counter[ch].in_service) {
307 if(counter[ch].req_intr) {
314 d_cpu->set_intr_line(next, true, intr_bit);
318 uint32_t Z80CTC::get_intr_ack()
321 for(int ch = 0; ch < 4; ch++) {
322 if(counter[ch].in_service) {
323 // invalid interrupt status
325 } else if(counter[ch].req_intr) {
326 counter[ch].req_intr = false;
327 counter[ch].in_service = true;
329 return counter[ch].vector;
333 return d_child->get_intr_ack();
338 void Z80CTC::notify_intr_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; // ???
350 d_child->notify_intr_reti();
354 #define STATE_VERSION 1
356 bool Z80CTC::process_state(FILEIO* state_fio, bool loading)
358 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
361 if(!state_fio->StateCheckInt32(this_device_id)) {
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);
386 state_fio->StateValue(cpu_clocks);
387 state_fio->StateValue(iei);
388 state_fio->StateValue(oei);
389 state_fio->StateValue(intr_bit);