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