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 <stdio.h>
21 #include <iostream>
22 #include <iomanip>
23 
24 #include "kc/system.h"
25 
26 #include "kc/kc.h"
27 #include "kc/z80.h"
28 #include "kc/pio8.h"
29 
30 #include "libdbg/dbg.h"
31 
32 #include "kc/cb.h" // FIXME: DEBUG
33 #include "cmd/cmd.h" // FIXME: DEBUG
34 
35 #define memory ((Memory1 *)memory)
36 
37 using namespace std;
38 
39 static byte_t head0[] = { 0x00, 0x00, 0x00, 0x20, 0x26, 0x20, 0xd1 };
40 static byte_t prog0[] = {
41   0xdd, 0x21, 0x20, 0x20, 0xcd, 0x5a, 0x08, 0xfe, 0x10, 0x20, 0xf9,
42   0x76, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xae,
44   0xe3, 0x4f, 0xc2, 0xce, 0x6b
45 };
46 
47 static byte_t head1[] = { 0x01, 0x00, 0x00, 0x20, 0x2c, 0x20, 0xc0 };
48 static byte_t prog1[] = {
49   0x21, 0x26, 0x20, 0xe5, 0xdd, 0x21, 0x20, 0x20, 0xdd, 0xe3, 0x06,
50   0x32, 0xcd, 0x83, 0x08, 0x10, 0xfb, 0x18, 0xf5, 0xff, 0xff, 0xff,
51   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xae,
52   0xe3, 0x4f, 0xc2, 0xce, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
53 };
54 
55 static byte_t head2[] = { 0x02, 0x00, 0x00, 0x20, 0x1e, 0x20, 0xd4 };
56 static byte_t prog2[] = {
57   0x3e, 0xff, 0xd3, 0xf5, 0x06, 0x50, 0xcd, 0x18, 0x20, 0x10, 0xfb,
58   0x3e, 0xfd, 0xd3, 0xf5, 0x06, 0x50, 0xcd, 0x18, 0x20, 0x10, 0xfb,
59   0x18, 0xe8, 0x0e, 0xff, 0x0d, 0x20, 0xfd, 0xc9
60 };
61 
62 class TapeTest : public Callback, public CMD {
63 private:
64   int _idx;
65   int _state;
66   int _1, _2;
67   byte_t *_head;
68   byte_t *_prog;
69   byte_t _prog_len;
70 
71 public:
72   TapeTest(void);
73   virtual ~TapeTest(void);
74   void callback(void *data);
75   void execute(CMD_Args *args, CMD_Context context);
76   int send_byte(byte_t *data, int len, int state);
77 };
78 
TapeTest(void)79 TapeTest::TapeTest(void) : Callback("TapeTest"), CMD("TAPETEST")
80 {
81   register_cmd("lc80-key-f10", 0);
82   register_cmd("lc80-key-f11", 1);
83   register_cmd("lc80-key-f12", 2);
84 }
85 
~TapeTest(void)86 TapeTest::~TapeTest(void)
87 {
88 }
89 
90 void
callback(void * data)91 TapeTest::callback(void *data)
92 {
93   static int cnt;
94 
95   long i = (long)data;
96   if (i == 0)
97     {
98       pio->set_B_EXT(1, 1);
99       return;
100     }
101   else
102     {
103       pio->set_B_EXT(1, 0);
104     }
105 
106   switch (_state)
107     {
108     case 0:
109       cnt = 4000;
110       z80->addCallback(500, this, (void *)0);
111       z80->addCallback(1000, this, (void *)1);
112       //cout << "state => 1" << endl;
113       _state = 1;
114       break;
115     case 1:
116       z80->addCallback(500, this, (void *)0);
117       z80->addCallback(1000, this, (void *)1);
118       if (--cnt == 0)
119 	{
120 	  _state = 2;
121 	  //cout << "state => 2" << endl;
122 	}
123       break;
124     case 2:
125       cnt = 4000;
126       z80->addCallback(200, this, (void *)0);
127       z80->addCallback(400, this, (void *)1);
128       //cout << "state => 3" << endl;
129       _idx = 0;
130       _state = 3;
131       break;
132     case 3:
133       _state = send_byte(_head, 7, 3);
134       break;
135     case 4:
136       z80->addCallback(200, this, (void *)0);
137       z80->addCallback(400, this, (void *)1);
138       if (--cnt == 0)
139 	{
140 	  _idx = 0;
141 	  _state = 5;
142 	  cnt = 4000;
143 	  //cout << "state => 5" << endl;
144 	}
145       break;
146     case 5:
147       _state = send_byte(_prog, _prog_len, 5);
148       break;
149     case 6:
150       z80->addCallback(200, this, (void *)0);
151       z80->addCallback(400, this, (void *)1);
152       if (--cnt == 0)
153 	{
154 	  _state = 7;
155 	  //cout << "state => 7" << endl;
156 	}
157       break;
158     case 7:
159       //cout << "TAPE END" << endl;
160       break;
161     default:
162       break;
163     }
164 }
165 
166 int
send_byte(byte_t * data,int len,int state)167 TapeTest::send_byte(byte_t *data, int len, int state)
168 {
169   static int i = 0;
170 
171   if (_1 == 0)
172     {
173       if (i == 0)
174 	{
175 	  _1 = 3;
176 	  _2 = 12;
177 	}
178       else if (i == 9)
179 	{
180 	  _1 = 6;
181 	  _2 = 6;
182 	}
183       else if (data[_idx] & (1 << (i - 1)))
184 	{
185 	  _1 = 6;
186 	  _2 = 6;
187 	}
188       else
189 	{
190 	  _1 = 3;
191 	  _2 = 12;
192 	}
193     }
194 
195   if (_2 > 0)
196     {
197       _2--;
198       z80->addCallback(200, this, (void *)0);
199       z80->addCallback(400, this, (void *)1);
200     }
201   else if (_1 > 0)
202     {
203       _1--;
204       z80->addCallback(500, this, (void *)0);
205       z80->addCallback(1000, this, (void *)1);
206     }
207 
208   if (_1 == 0)
209     {
210       i++;
211       if (i > 9)
212 	{
213 	  i = 0;
214 	  _idx++;
215 	  if (_idx >= len)
216 	    return state + 1;
217 	}
218     }
219 
220   return state;
221 }
222 
223 void
execute(CMD_Args * args,CMD_Context context)224 TapeTest::execute(CMD_Args *args, CMD_Context context)
225 {
226   _idx = 0;
227   _state = 0;
228   _1 = _2 = 0;
229 
230   switch (context)
231     {
232     case 1:
233       _head = head1;
234       _prog = prog1;
235       _prog_len = sizeof(prog1);
236       break;
237     case 2:
238       _head = head2;
239       _prog = prog2;
240       _prog_len = sizeof(prog2);
241       break;
242     default:
243       _head = head0;
244       _prog = prog0;
245       _prog_len = sizeof(prog0);
246       break;
247     }
248 
249   z80->addCallback(0, this, (void *)1);
250 }
251 
252 static TapeTest *__tape_test;
253 
254 void
draw_leds(void)255 PIO8_1::draw_leds(void)
256 {
257 #if 0
258   int a;
259 
260   printf("\x1b\x5b\x48");
261 
262   // --- line 1 ---------------
263 
264   for (a = 0;a < 6;a++)
265     {
266       if (_led_value[a] & 4)
267 	printf(" --- ");
268       else
269 	printf("     ");
270     }
271   printf("        \n");
272 
273   // --- line 2 ---------------
274 
275   for (a = 0;a < 6;a++)
276     {
277       if (_led_value[a] & 2)
278 	printf("|   ");
279       else
280 	printf("    ");
281 
282       if (_led_value[a] & 1)
283 	printf("|");
284       else
285 	printf(" ");
286     }
287   printf("        \n");
288 
289   // --- line 3 ---------------
290 
291   for (a = 0;a < 6;a++)
292     {
293       if (_led_value[a] & 2)
294 	printf("|   ");
295       else
296 	printf("    ");
297 
298       if (_led_value[a] & 1)
299 	printf("|");
300       else
301 	printf(" ");
302     }
303   printf("        \n");
304 
305   // --- line 4 ---------------
306 
307   for (a = 0;a < 6;a++)
308     {
309       if (_led_value[a] & 8)
310 	printf(" --- ");
311       else
312 	printf("     ");
313     }
314   printf("        \n");
315 
316   // --- line 5 ---------------
317 
318   for (a = 0;a < 6;a++)
319     {
320       if (_led_value[a] & 64)
321 	printf("|   ");
322       else
323 	printf("    ");
324 
325       if (_led_value[a] & 32)
326 	printf("|");
327       else
328 	printf(" ");
329     }
330   printf("        \n");
331 
332   // --- line 6 ---------------
333 
334   for (a = 0;a < 6;a++)
335     {
336       if (_led_value[a] & 64)
337 	printf("|   ");
338       else
339 	printf("    ");
340 
341       if (_led_value[a] & 32)
342 	printf("|");
343       else
344 	printf(" ");
345     }
346   printf("        \n");
347 
348   // --- line 7 ---------------
349 
350   for (a = 0;a < 6;a++)
351     {
352       if (_led_value[a] & 128)
353 	printf(" --- ");
354       else
355 	printf("     ");
356     }
357   printf("        \n");
358   printf("                                      \n");
359 #endif
360 }
361 
PIO8_1(void)362 PIO8_1::PIO8_1(void)
363 {
364   __tape_test = new TapeTest();
365   reset(true);
366 }
367 
~PIO8_1(void)368 PIO8_1::~PIO8_1(void)
369 {
370 }
371 
372 byte_t
in(word_t addr)373 PIO8_1::in(word_t addr)
374 {
375   DBG(2, form("KCemu/PIO/8a/in",
376               "PIO8_1::in(): addr = %04x\n",
377               addr));
378 
379   switch (addr & 3)
380     {
381     case 0:
382       return in_A_DATA();
383     case 1:
384       return in_B_DATA();
385     case 2:
386       return in_A_CTRL();
387     case 3:
388       return in_B_CTRL();
389     }
390 
391   return 0; // shouldn't be reached
392 }
393 
394 void
out(word_t addr,byte_t val)395 PIO8_1::out(word_t addr, byte_t val)
396 {
397   DBG(2, form("KCemu/PIO/8a/out",
398               "PIO8_1::out(): addr = %04x, val = %02x\n",
399               addr, val));
400 
401   switch (addr & 3)
402     {
403     case 0:
404       out_A_DATA(val);
405       break;
406     case 1:
407       out_B_DATA(val);
408       break;
409     case 2:
410       out_A_CTRL(val);
411       break;
412     case 3:
413       out_B_CTRL(val);
414       break;
415     }
416 }
417 
418 void
change_A(byte_t changed,byte_t val)419 PIO8_1::change_A(byte_t changed, byte_t val)
420 {
421   _led_value_latch = ~val;
422 }
423 
424 void
change_B(byte_t changed,byte_t val)425 PIO8_1::change_B(byte_t changed, byte_t val)
426 {
427   int selected_led = -1;
428 
429   _led_value[6] = (val & 2) ? 1 : 0;
430 
431   if (changed & 2)
432     tape_signal(_led_value[6]);
433 
434   for (int a = 2;a < 8;a++)
435     {
436       if ((val & (1 << a)) == 0)
437 	{
438 	  selected_led = 5 - (a - 2);
439 	  break;
440 	}
441     }
442   if (selected_led < 0)
443     return;
444 
445   _led_value[selected_led] = _led_value_latch;
446   //draw_leds();
447 }
448 
449 byte_t
get_led_value(int index)450 PIO8_1::get_led_value(int index)
451 {
452   if (index < 0)
453     return 0;
454 
455   if (index > 6)
456     return 0;
457 
458   return _led_value[index];
459 }
460 
461 void
reset(bool power_on)462 PIO8_1::reset(bool power_on)
463 {
464   for (int a = 0;a < 7;a++)
465     _led_value[a] = 0;
466 }
467 
468 void
tape_callback(byte_t val)469 PIO8_1::tape_callback(byte_t val)
470 {
471   //cout << "PIO8_1::tape_callback()" << endl;
472 }
473 
474 void
tape_signal(int val)475 PIO8_1::tape_signal(int val)
476 {
477   int freq = 0;
478   long long c;
479   static long long diff;
480   static long long cnt = 0;
481   static int sync = 1000;
482 
483   c = z80->getCounter();
484 
485   if (val == 1)
486     {
487       //cout << "(" << dec << c - cnt << "/";
488       diff = c - cnt;
489       cnt = c;
490       return;
491     }
492   else
493     {
494       //cout << (c - cnt) << ")";
495       diff += c - cnt;
496       cnt = c;
497     }
498 
499   if (diff < 800)
500     freq = 2;           // 2 kHz
501   else if (diff > 1400)
502     sync = 1000;        // pause
503   else
504     freq = 1;           // 1 kHz
505 
506   // SYNC
507   if (sync > 0)
508     {
509       if (freq == 1)
510 	sync--;
511       else
512 	sync = 1000;
513       return;
514     }
515 
516   if (sync == 0)
517     {
518       if (freq == 1)
519 	return;
520       sync = -1;
521     }
522 
523 
524   //cout << "{" << dec << diff << "}";
525   tape_bit(freq);
526 }
527 
528 void
tape_bit(int freq)529 PIO8_1::tape_bit(int freq)
530 {
531   static int cnt = 0;
532   static int byte = 0;
533   static int val = 0;
534   static bool got1 = false;
535 
536   //cout << freq;
537 
538   if (freq == 2)
539     {
540       val++;
541       if (got1)
542 	{
543 	  int bit = (val >= 0) ? 0 : 1;
544 	  // cout << " [" << bit << "] " << endl;
545 	  val = 0;
546 	  got1 = false;
547 
548 	  byte >>= 1;
549 	  byte |= bit << 9;
550 	  cnt++;
551 	  if (cnt == 10)
552 	    {
553 	      tape_byte(byte);
554 	      cnt = 0;
555 	      byte = 0;
556 	    }
557 	}
558     }
559   else
560     {
561       val -= 2;
562       got1 = true;
563     }
564 
565   //cout << flush;
566 }
567 
568 void
tape_byte(int byte)569 PIO8_1::tape_byte(int byte)
570 {
571   byte = (byte >> 1) & 0xff;
572   cout << hex << " |" << setw(2) << byte << "|" << endl;
573 }
574 
PIO8_2(void)575 PIO8_2::PIO8_2(void)
576 {
577 }
578 
~PIO8_2(void)579 PIO8_2::~PIO8_2(void)
580 {
581 }
582 
583 byte_t
in(word_t addr)584 PIO8_2::in(word_t addr)
585 {
586   DBG(2, form("KCemu/PIO/8b/in",
587               "PIO8_2::in(): addr = %04x\n",
588               addr));
589 
590   switch (addr & 3)
591     {
592     case 0:
593       return in_A_DATA();
594     case 1:
595       return in_B_DATA();
596     case 2:
597       return in_A_CTRL();
598     case 3:
599       return in_B_CTRL();
600     }
601 
602   return 0; // shouldn't be reached
603 }
604 
605 void
out(word_t addr,byte_t val)606 PIO8_2::out(word_t addr, byte_t val)
607 {
608   DBG(2, form("KCemu/PIO/8b/out",
609               "PIO8_2::out(): addr = %04x, val = %02x\n",
610               addr, val));
611 
612   switch (addr & 3)
613     {
614     case 0:
615       out_A_DATA(val);
616       break;
617     case 1:
618       out_B_DATA(val);
619       break;
620     case 2:
621       out_A_CTRL(val);
622       break;
623     case 3:
624       out_B_CTRL(val);
625       break;
626     }
627 }
628 
629 void
change_A(byte_t changed,byte_t val)630 PIO8_2::change_A(byte_t changed, byte_t val)
631 {
632 }
633 
634 void
change_B(byte_t changed,byte_t val)635 PIO8_2::change_B(byte_t changed, byte_t val)
636 {
637   if (changed & 0x02)
638     {
639       cout << "tape_signal()" << endl;
640       tape->tape_signal();
641     }
642 }
643