1 /*
2  *  KCemu -- The emulator for the KC85 homecomputer series and much more.
3  *  Copyright (C) 1997-2010 Torsten Paul
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <iostream>
21 #include <iomanip>
22 
23 #include "kc/system.h"
24 
25 #include "kc/kc.h"
26 #include "ui/ui.h"
27 #include "kc/ctc.h"
28 #include "kc/tape.h"
29 
30 #include "libdbg/dbg.h"
31 
32 using namespace std;
33 
CTC(const char * name)34 CTC::CTC(const char *name) : InterfaceCircuit(name), Callback(name)
35 {
36   _irq_valid[0] = 0;
37   _irq_valid[1] = 1;
38   _irq_valid[2] = 2;
39   _irq_valid[3] = 3;
40   _cb_list[0] = NULL;
41   _cb_list[1] = NULL;
42   _cb_list[2] = NULL;
43   _cb_list[3] = NULL;
44 
45   reset(true);
46 }
47 
~CTC(void)48 CTC::~CTC(void)
49 {
50 }
51 
52 void
reti(void)53 CTC::reti(void)
54 {
55   int a, b;
56 
57   b = 0;
58   for (a = 0;a < 4;a++)
59     {
60       if (_irq_active[a])
61 	{
62 	  b++;
63 	  _irq_active[a] = 0;
64 	}
65     }
66 
67   if (b > 1)
68     DBG(2, form("KCemu/CTC/reti",
69 		"CTC::reti(): more than one irq active!!!"));
70 
71   if (b == 0)
72     return;
73 
74   DBG(2, form("KCemu/CTC/reti",
75 	      "CTC::reti(): active: %d %d %d %d - pending: %d %d %d %d\n",
76 	      _irq_active[0],
77 	      _irq_active[1],
78 	      _irq_active[2],
79 	      _irq_active[3],
80 	      _irq_pending[0],
81 	      _irq_pending[1],
82 	      _irq_pending[2],
83 	      _irq_pending[3]));
84 
85   for (a = 0;a < 4;a++)
86     {
87       if (_irq_pending[a])
88 	{
89 	  DBG(2, form("KCemu/CTC/reti",
90 		      "CTC::reti(): trigger_irq(): channel = %d\n",
91 		      a));
92 	  try_trigger_irq(a);
93 	  break;
94 	}
95     }
96 }
97 
98 void
irqreq(void)99 CTC::irqreq(void)
100 {
101 }
102 
103 word_t
irqack(void)104 CTC::irqack(void)
105 {
106   return IRQ_NOT_ACK;
107 }
108 
109 void
reset(bool power_on)110 CTC::reset(bool power_on)
111 {
112   int a;
113 
114   _irq_vector = 0;
115   for (a = 0;a < 4;a++)
116     {
117       _control[a]     = 0x23;
118       _value[a]       = 0;
119       _restart[a]     = 0;
120       _timer_value[a] = 0;
121       _irq_active[a]  = 0;
122       _irq_pending[a] = 0;
123       _irq_valid[a]   += 4;
124     }
125 }
126 
127 void
trigger(byte_t channel)128 CTC::trigger(byte_t channel)
129 {
130   byte_t c = channel & 3;
131 
132   if ((_control[c] & MODE) != MODE_COUNTER)
133     return;
134 
135   _value[c]--;
136   if (_value[c] > 0)
137     return;
138 
139   _value[c] = _timer_value[c];
140   try_trigger_irq(c);
141 }
142 
143 void
handle_counter_mode(int channel)144 CTC::handle_counter_mode(int channel)
145 {
146   long cv;
147 
148   switch (channel)
149     {
150     case 0: cv = counter_value_0(); break;
151     case 1: cv = counter_value_1(); break;
152     case 2: cv = counter_value_2(); break;
153     case 3: cv = counter_value_3(); break;
154     }
155 
156   if (cv == 0)
157     return;
158 
159   cv *= _timer_value[channel]; // mapping from 0 to 256 is done in c_out()
160 
161   run_cb_tc(channel, _timer_value[channel]);
162 
163   _irq_valid[channel] += 4;
164   add_callback(cv, this, (void *)((long)_irq_valid[channel]));
165 }
166 
167 void
try_trigger_irq(int channel)168 CTC::try_trigger_irq(int channel)
169 {
170   if ((_control[channel] & IRQ) == IRQ_DISABLED)
171     {
172       _irq_pending[channel] = 0;
173       return;
174     }
175 
176   _irq_pending[channel] = 1;
177   trigger_irq(channel);
178 }
179 
180 void
callback(void * data)181 CTC::callback(void *data)
182 {
183   bool cont;
184   long val = (long)data;
185   byte_t c = val & 3;
186 
187   if (_irq_valid[c] != val)
188     return;
189 
190   DBG(2, form("KCemu/CTC/reti",
191 	      "CTC::callback(): active: %d %d %d %d - pending: %d %d %d %d\n",
192 	      _irq_active[0],
193 	      _irq_active[1],
194 	      _irq_active[2],
195 	      _irq_active[3],
196 	      _irq_pending[0],
197 	      _irq_pending[1],
198 	      _irq_pending[2],
199 	      _irq_pending[3]));
200 
201   switch (c)
202     {
203     case 0:
204       DBG(2, form("KCemu/CTC/irq/0",
205 		  "CTC::callback() : irq channel 0\n"));
206       cont = irq_0();
207       break;
208     case 1:
209       DBG(2, form("KCemu/CTC/irq/1",
210 		  "CTC::callback() : irq channel 1\n"));
211       cont = irq_1();
212       break;
213     case 2:
214       DBG(2, form("KCemu/CTC/irq/2",
215 		  "CTC::callback() : irq channel 2\n"));
216       cont = irq_2();
217       break;
218     case 3:
219       DBG(2, form("KCemu/CTC/irq/3",
220 		  "CTC::callback() : irq channel 3\n"));
221       cont = irq_3();
222       break;
223     }
224 
225   /*
226    *  COUNTER mode (clock source comes from the CLK pin)
227    */
228   if ((_control[c] & MODE) == MODE_COUNTER)
229     {
230       handle_counter_mode(c);
231       return;
232     }
233 
234   if ((_control[c] & IRQ) == IRQ_ENABLED)
235     {
236       DBG(2, form("KCemu/CTC/callback",
237 		  "CTC::callback(): trigger_irq(): _irq_pending = %d\n",
238 		  _irq_pending[c]));
239       try_trigger_irq(c);
240     }
241 
242   add_callback(_timer_value[c], this, (void *)((long)val));
243 }
244 
245 byte_t
c_in(byte_t c)246 CTC::c_in(byte_t c)
247 {
248   word_t val;
249   unsigned long long diff = 0;
250 
251   if (_timer_value[c] == 0)
252     {
253       return 0;
254     }
255 
256   if ((_control[c] & MODE) == MODE_COUNTER)
257     {
258       diff = 0;
259     }
260   else
261     {
262       if ((_control[c] & RESET) == RESET_ACTIVE)
263         {
264           diff = 0;
265         }
266       else
267         {
268           diff = get_counter() - _counter[c];
269         }
270     }
271 
272   if ((_control[c] & PRESCALER) == PRESCALER_16)
273     {
274       diff /= 16;
275       val = ((_value[c] / 16) - diff) & 0xff;
276     }
277   else
278     {
279       diff /= 256;
280       val = ((_value[c] / 256) - diff) & 0xff;
281     }
282 
283   _counter[c] = get_counter();
284 
285   return val;
286 }
287 
288 void
c_out(byte_t channel,byte_t val)289 CTC::c_out(byte_t channel, byte_t val)
290 {
291   if ((_control[channel] & CONSTANT) == CONSTANT_LOAD)
292     {
293       _control[channel] &= ~(CONSTANT | RESET);
294       run_cb_start(channel);
295 
296       if ((_control[channel] & MODE) == MODE_TIMER)
297 	{
298 	  if ((_control[channel] & PRESCALER) == PRESCALER_16)
299 	    {
300 	      _timer_value[channel] = val << 4; /* div 16 */
301 	      if (_timer_value[channel] == 0)
302 		_timer_value[channel] = 4096;
303 	    }
304 	  else
305 	    {
306 	      _timer_value[channel] = val << 8; /* div 256 */
307 	      /*
308 	       *  well, this should be 65536 but this would need a dword
309 	       *  for _timer_value
310 	       */
311 	      if (_timer_value[channel] == 0)
312 		_timer_value[channel] = 65535;
313 	    }
314 	}
315       else
316 	{
317 	  /*
318 	   *  COUNTER MODE has no prescaler
319 	   */
320 	  _timer_value[channel] = val;
321 	}
322 
323       _counter[channel] = get_counter();
324       _value[channel] = _timer_value[channel];
325       run_cb_tc(channel, _timer_value[channel]);
326 
327       if ((_control[channel] & MODE) == MODE_COUNTER)
328 	{
329 	  handle_counter_mode(channel);
330 	  return;
331         }
332 
333       _irq_valid[channel] += 4;
334       /*
335        *  Added a fixed offset for callback timing added for the poly880
336        *  emulation. Without offset the CTC caused NMI is triggered
337        *  one opcode too early.
338        *
339        *  FIXME: check timing
340        */
341       add_callback(_timer_value[channel] + 4, this, (void *)((long)_irq_valid[channel]));
342       return;
343     }
344 
345   if ((val & CONTROL) == CONTROL_VECTOR)
346     {
347       if (channel != 0) return;
348       _irq_vector = val & ~ 7;
349       return;
350     }
351 
352   if ((val & RESET) == RESET_ACTIVE)
353     {
354       _value[channel] = _timer_value[channel];
355       _irq_valid[channel] += 4;
356       if ((_control[channel] & RESET) != RESET_ACTIVE)
357 	run_cb_stop(channel);
358     }
359 
360   _control[channel] = val;
361 }
362 
363 void
register_callback(int channel,CTCCallbackInterface * cbi)364 CTC::register_callback(int channel, CTCCallbackInterface *cbi)
365 {
366   int c = channel & 3;
367 
368   if (_cb_list[c] == NULL)
369     {
370       _cb_list[c] = new cb_list_t();
371     }
372 
373   _cb_list[c]->push_back(cbi);
374 }
375 
run_cb_start(int channel)376 void CTC::run_cb_start(int channel)
377 {
378   if (_cb_list[channel] == NULL)
379     return;
380 
381   for (iterator it = _cb_list[channel]->begin();it != _cb_list[channel]->end();it++)
382     (*it)->ctc_callback_start(channel);
383 }
384 
run_cb_stop(int channel)385 void CTC::run_cb_stop(int channel)
386 {
387   if (_cb_list[channel] == NULL)
388     return;
389 
390   for (iterator it = _cb_list[channel]->begin();it != _cb_list[channel]->end();it++)
391     (*it)->ctc_callback_stop(channel);
392 }
393 
run_cb_tc(int channel,long tc)394 void CTC::run_cb_tc(int channel, long tc)
395 {
396   if (_cb_list[channel] == NULL)
397     return;
398 
399   for (iterator it = _cb_list[channel]->begin();it != _cb_list[channel]->end();it++)
400     (*it)->ctc_callback_TC(channel, tc);
401 }
402 
403 void
info(void)404 CTC::info(void)
405 {
406     cout << "  CTC:" << endl;
407     cout << "  ----                   channel 0     channel 1     "
408 	 << "channel 2     channel 3" << endl;
409     cout << "\tirq vector:      "
410 	 << hex << setfill('0') << setw(2) << (int)(_irq_vector)
411 	 << "h           "
412 	 << hex << setfill('0') << setw(2) << (int)(_irq_vector | 0x02)
413 	 << "h           "
414 	 << hex << setfill('0') << setw(2) << (int)(_irq_vector | 0x04)
415 	 << "h           "
416 	 << hex << setfill('0') << setw(2) << (int)(_irq_vector | 0x06)
417 	 << "h" << endl;
418     cout << "\tirq enabled:     "
419 	 << ((_control[0] & IRQ)?"yes":"no ")
420 	 << "           "
421 	 << ((_control[1] & IRQ)?"yes":"no ")
422 	 << "           "
423 	 << ((_control[2] & IRQ)?"yes":"no ")
424 	 << "           "
425 	 << ((_control[3] & IRQ)?"yes":"no ") << endl;
426     cout << "\tcounter mode:    "
427 	 << ((_control[0] & MODE)?"counter":"timer  ")
428 	 << "       "
429 	 << ((_control[1] & MODE)?"counter":"timer  ")
430 	 << "       "
431 	 << ((_control[2] & MODE)?"counter":"timer  ")
432 	 << "       "
433 	 << ((_control[3] & MODE)?"counter":"timer") << endl;
434     cout << "\tclock divider:   "
435 	 << ((_control[0] & PRESCALER)?"256":"16 ")
436 	 << "           "
437 	 << ((_control[1] & PRESCALER)?"256":"16 ")
438 	 << "           "
439 	 << ((_control[2] & PRESCALER)?"256":"16 ")
440 	 << "           "
441 	 << ((_control[3] & PRESCALER)?"256":"16 ") << endl;
442     cout << "\twait for tv:     "
443 	 << ((_control[0] & CONSTANT)?"yes":"no ")
444 	 << "           "
445 	 << ((_control[1] & CONSTANT)?"yes":"no ")
446 	 << "           "
447 	 << ((_control[2] & CONSTANT)?"yes":"no ")
448 	 << "           "
449 	 << ((_control[3] & CONSTANT)?"yes":"no ") << endl;
450     cout << "\treset:           "
451 	 << ((_control[0] & RESET)?"yes":"no ")
452 	 << "           "
453 	 << ((_control[1] & RESET)?"yes":"no ")
454 	 << "           "
455 	 << ((_control[2] & RESET)?"yes":"no ")
456 	 << "           "
457 	 << ((_control[3] & RESET)?"yes":"no ") << endl;
458     cout << "\ttimer value:     "
459 	 << hex << setfill('0') << setw(2) << (int)_timer_value[0]
460 	 << "h           "
461 	 << hex << setfill('0') << setw(2) << (int)_timer_value[1]
462 	 << "h           "
463 	 << hex << setfill('0') << setw(2) << (int)_timer_value[2]
464 	 << "h           "
465 	 << hex << setfill('0') << setw(2) << (int)_timer_value[3]
466 	 << "h" << endl;
467     cout << "\tvalue:           "
468 	 << hex << setfill('0') << setw(2) << (int)_value[0]
469 	 << "h           "
470 	 << hex << setfill('0') << setw(2) << (int)_value[1]
471 	 << "h           "
472 	 << hex << setfill('0') << setw(2) << (int)_value[2]
473 	 << "h           "
474 	 << hex << setfill('0') << setw(2) << (int)_value[3]
475 	 << "h" << endl << endl;
476 }
477