]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/z180-serv.c
connect command 'esc \' enhancement, new 'esc :' subcommand
[z180-stamp.git] / avr / z180-serv.c
CommitLineData
35edb766
L
1/*
2 * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
72f58822 7#include "common.h"
5f7f3586
L
8#include <stdlib.h>
9#include <string.h>
10#include <stdbool.h>
89adce76 11#include <util/atomic.h>
72f58822 12
89adce76 13#include "background.h"
5f7f3586
L
14#include "env.h"
15#include "ff.h"
72f58822
L
16#include "serial.h"
17#include "z80-if.h"
889202c4 18#include "debug.h"
5f7f3586 19#include "print-utils.h"
89adce76 20#include "z180-serv.h"
daacc6f9 21#include "timer.h"
845cbdbd
L
22#include "time.h"
23#include "bcd.h"
24#include "rtc.h"
7d60b20b
L
25
26#define DEBUG_CPM_SDIO 0 /* set to 1 to debug */
27
28#define debug_cpmsd(fmt, args...) \
29 debug_cond(DEBUG_CPM_SDIO, fmt, ##args)
30
31
72f58822
L
32/*--------------------------------------------------------------------------*/
33
34struct msg_item {
35 uint8_t fct;
36 uint8_t sub_min, sub_max;
37 void (*func)(uint8_t, int, uint8_t *);
38};
39
40uint32_t msg_to_addr(uint8_t *msg)
41{
42 union {
43 uint32_t as32;
44 uint8_t as8[4];
45 } addr;
46
47 addr.as8[0] = msg[0];
48 addr.as8[1] = msg[1];
49 addr.as8[2] = msg[2];
50 addr.as8[3] = 0;
51
52 return addr.as32;
53}
54
72f58822 55
1a2460dc
L
56static int msg_xmit_header(uint8_t func, uint8_t subf, int len)
57{
58 z80_memfifo_putc(fifo_msgout, 0xAE);
59 z80_memfifo_putc(fifo_msgout, len+2);
60 z80_memfifo_putc(fifo_msgout, func);
61 z80_memfifo_putc(fifo_msgout, subf);
62
63 return 0;
64}
65
66int msg_xmit(uint8_t func, uint8_t subf, int len, uint8_t *msg)
67{
68 msg_xmit_header(func, subf, len);
69 while (len--)
70 z80_memfifo_putc(fifo_msgout, *msg++);
71
72 return 0;
73}
74
72f58822
L
75void do_msg_ini_memfifo(uint8_t subf, int len, uint8_t * msg)
76{
77 (void)len;
78
89adce76 79 z80_memfifo_init(subf, msg_to_addr(msg));
72f58822
L
80}
81
82
83void do_msg_char_out(uint8_t subf, int len, uint8_t * msg)
84{
85 (void)subf;
86
87 while (len--)
88 putchar(*msg++);
89}
90
1a2460dc
L
91/* echo message */
92void do_msg_echo(uint8_t subf, int len, uint8_t * msg)
93{
94 (void)subf;
95
96 /* send re-echo */
97 msg_xmit(1, 3, len, msg);
98}
99
8590a76b
L
100/* get timer */
101void do_msg_get_timer(uint8_t subf, int len, uint8_t * msg)
102{
a8eb521f 103 uint32_t time_ms = (len >= 4) ? *(uint32_t *) msg : 0;
8590a76b 104
a8eb521f 105 time_ms = get_timer(time_ms);
8590a76b
L
106 msg_xmit(3, subf, sizeof(time_ms), (uint8_t *) &time_ms);
107}
108
5f7f3586
L
109/* ---------------------------------------------------------------------------*/
110
845cbdbd
L
111#define CPM_DAY_OFFSET ((1978-1900) * 365 + 19) /* 19 leap years */
112
113/*
114 * Convert CP/M time stamp to a broken-down time structure
115 *
116 */
117int mk_date_time (int len, uint8_t *msg, struct tm *tmp)
118{
119 time_t stamp;
120
121 if (len != 5)
122 return -1;
123
124 /* days since 2000-01-01 */
125 long days = msg[3] + (msg[4] << 8) - 8036;
126
127 if (days < 0)
128 return -1;
129
130 stamp = days * ONE_DAY;
131 stamp += bcd2bin(msg[0]);
132 stamp += bcd2bin(msg[1]) * 60 ;
8d0fad4c 133 stamp += bcd2bin(msg[2]) * 3600L;
845cbdbd
L
134 gmtime_r(&stamp, tmp);
135 return 0;
136}
137
138void mk_cpm_time(struct tm *tmp, uint8_t cpm_time[5])
139{
140 uint16_t days = 1;
141 uint_fast8_t leap=2;
142
143 for (int year=78; year < tmp->tm_year; year++) {
144 days = days + 365 + (leap == 0);
145 leap = (leap+1)%4;
146 }
147 days += tmp->tm_yday;
148
149 cpm_time[0] = bin2bcd(tmp->tm_sec);
150 cpm_time[1] = bin2bcd(tmp->tm_min);
151 cpm_time[2] = bin2bcd(tmp->tm_hour);
152 cpm_time[3] = days;
153 cpm_time[4] = days >> 8;
845cbdbd
L
154}
155
156/* get/set cp/m time */
157void do_msg_get_set_time(uint8_t subf, int len, uint8_t * msg)
158{
159 struct tm t;
160 uint8_t cpm_time[5];
161 int rc;
162
163 memset(cpm_time, 0, ARRAY_SIZE(cpm_time));
164
165 switch (subf) {
166 case 3: /* set date & time */
167 /* initialize t with current time */
168 rc = rtc_get (&t);
169
170 if (rc == 0) {
171 /* insert new date & time */
172 if (mk_date_time (len, msg, &t) != 0) {
173 my_puts_P(PSTR("## set_time: Bad date format\n"));
174 break;
175 }
176
177 time_t time;
178 time = mk_gmtime(&t);
179 gmtime_r(&time, &t);
180
181 /* and write to RTC */
182 rc = rtc_set (&t);
183 if(rc)
184 my_puts_P(PSTR("## set_time: Set date failed\n"));
185 } else {
186 my_puts_P(PSTR("## set_time: Get date failed\n"));
187 }
188 /* FALL TROUGH */
189 case 2: /* get date & time */
190 rc = rtc_get (&t);
191
192 if (rc) {
193 my_puts_P(PSTR("## get_time: Get date failed\n"));
194 break;
195 }
196
197 time_t time;
198 time = mk_gmtime(&t);
199 //mktime(&t);
200 gmtime_r(&time, &t);
201
202
203 mk_cpm_time(&t, cpm_time);
204 break;
205 }
206
207 msg_xmit(3, subf, sizeof(cpm_time), cpm_time);
208}
209
210/* ---------------------------------------------------------------------------*/
211
01484095 212#define MAX_DRIVE 4
5f7f3586 213#define BLOCK_SIZE 512
daacc6f9
L
214#define TPA_BASE 0x10000
215#define COMMON_BASE 0xC000
5f7f3586
L
216
217struct cpm_drive_s {
218 uint8_t drv;
219 uint8_t device;
220 char *img_name;
393b1897 221 bool dirty;
5f7f3586
L
222 FIL fd;
223};
224
225static uint8_t disk_buffer[BLOCK_SIZE];
5f7f3586 226static struct cpm_drive_s drv_table[MAX_DRIVE];
393b1897
L
227static int handle_cpm_drv_to;
228
229#define f_dirty(fp) ((fp)->fs->wflag != 0)
230
231
232int cpm_drv_to(int state)
233{
234 static uint32_t ts;
235
236 switch(state) {
237 case 0:
238 break;
239
240 case 1:
241 ts = get_timer(0);
242 state = 2;
243 break;
244
245 case 2:
246 if (get_timer(ts) > 1000) {
247 for (uint_fast8_t i=0; i < MAX_DRIVE; i++) {
248// if (&drv_table[i].fd && f_dirty(&drv_table[i].fd)) {
249 if (drv_table[i].dirty) {
250 f_sync(&drv_table[i].fd);
251 drv_table[i].dirty = false;
252 debug_cpmsd("## %7lu f_sync: %c:\n", get_timer(0), i+'A');
253 }
254 }
255 state = 0;
256 }
257 }
258 return state;
259}
260
261
262void msg_cpm_result(uint8_t subf, uint8_t rc, int res)
263{
264 uint8_t result_msg[3];
265
266 if (res)
267 rc |= 0x80;
268
269 result_msg[0] = rc;
270 result_msg[1] = res;
271 result_msg[2] = res >> 8;
272
273 if (rc) {
274 debug_cpmsd("###%7lu error rc: %.02x, res: %d\n", get_timer(0), rc, res);
275 }
276
277 msg_xmit(2, subf, sizeof(result_msg), result_msg);
278}
5f7f3586
L
279
280/*
281 db 2 ; disk command
282 ds 1 ; subcommand (login/read/write)
283 ds 1 ; @adrv (8 bits) +0
284 ds 1 ; @rdrv (8 bits) +1
285 ds 3 ; @xdph (24 bits) +2
286*/
287
288void do_msg_cpm_login(uint8_t subf, int len, uint8_t * msg)
289{
290
291 FRESULT res = 0;
5f7f3586
L
292 uint8_t drv;
293 char *np;
5f7f3586
L
294
295 (void)subf;
296
297 if (len != 5) { /* TODO: check adrv, rdrv */
393b1897 298 return msg_cpm_result(subf, 0x01, res);
5f7f3586
L
299 }
300
7d60b20b 301 debug_cpmsd("\n## %7lu login: %c:\n", get_timer(0), msg[0]+'A');
5f7f3586
L
302
303
304 drv = msg[0];
305 if ( drv>= MAX_DRIVE) {
393b1897 306 return msg_cpm_result(subf, 0x02, res);
5f7f3586
L
307 }
308
5f7f3586
L
309/*
310 uint32_t dph = ((uint32_t)msg[4] << 16) + ((uint16_t)msg[3] << 8) + msg[2];
311*/
312
313 if (drv_table[drv].img_name != NULL) {
7d60b20b 314 debug_cpmsd("## %7lu close: '%s'\n", get_timer(0), drv_table[drv].img_name);
5f7f3586 315 f_close(&drv_table[drv].fd);
393b1897 316 drv_table[drv].dirty = false;
5f7f3586
L
317 free(drv_table[drv].img_name);
318 drv_table[drv].img_name = NULL;
319 }
320
321 strcpy_P((char *)disk_buffer, PSTR("dsk0"));
322 disk_buffer[3] = msg[0] + '0';
323 if (((np = getenv((char*)disk_buffer)) == NULL) ||
324 ((drv_table[drv].img_name = strdup(np)) == NULL)) {
393b1897 325 return msg_cpm_result(subf, 0x03, res);
5f7f3586
L
326 }
327
328
329 res = f_open(&drv_table[drv].fd, drv_table[drv].img_name,
330 FA_WRITE | FA_READ);
331
7d60b20b 332 debug_cpmsd("## %7lu open: '%s', (env: '%s'), res: %d\n", get_timer(0),
5f7f3586
L
333 drv_table[drv].img_name, disk_buffer, res);
334
5f7f3586 335 /* send result*/
393b1897 336 msg_cpm_result(subf, 0x00, res);
5f7f3586
L
337}
338
339
340/*
341 db 2 ; disk command
342 ds 1 ; subcommand (login/read/write)
daacc6f9
L
343 ds 1 ; @adrv (8 bits) +0
344 ds 1 ; @rdrv (8 bits) +1
345 ds 2 ; @trk (16 bits) +2
346 ds 2 ; @sect(16 bits) +4
347 ds 1 ; @cnt (8 bits) +6
5f7f3586
L
348 ds 3 ; phys. transfer addr +7
349*/
350
daacc6f9
L
351#define ADRV 0
352#define RDRV 1
353#define TRK 2
354#define SEC 4
355#define CNT 6
356#define ADDR 7
357
5f7f3586
L
358void do_msg_cpm_rw(uint8_t subf, int len, uint8_t * msg)
359{
360 uint8_t drv;
361 uint32_t addr;
362 uint32_t pos;
7d60b20b 363 uint8_t secs;
5f7f3586
L
364 bool dowrite = (subf == 2);
365 FRESULT res = 0;
366 uint8_t rc = 0;
367 bool buserr = 0;
5f7f3586
L
368
369 if (len != 10) { /* TODO: check adrv, rdrv */
393b1897 370 return msg_cpm_result(subf, 0x01, res);
5f7f3586
L
371 }
372
daacc6f9 373 drv = msg[ADRV];
5f7f3586 374 if ( drv>= MAX_DRIVE) {
393b1897 375 return msg_cpm_result(subf, 0x02, res);
5f7f3586
L
376 }
377
7d60b20b 378 secs = msg[CNT];
daacc6f9 379 addr = ((uint32_t)msg[ADDR+2] << 16) + ((uint16_t)msg[ADDR+1] << 8) + msg[ADDR];
5f7f3586 380
5f7f3586 381
daacc6f9
L
382 /* TODO: tracks per sector from dpb */
383 pos = (((uint16_t)(msg[TRK+1] << 8) + msg[TRK]) * 8
384 + ((uint32_t)(msg[SEC+1] << 8) + msg[SEC])) * BLOCK_SIZE;
5f7f3586 385
7d60b20b
L
386 debug_cpmsd("## %7lu cpm_rw: %s %c: trk:%4d, sec: %d, pos: %.8lx, secs: %2d, "
387 "addr: %.5lx\n", get_timer(0), dowrite ? "write" : " read",
388 msg[ADRV]+'A', ((uint16_t)(msg[TRK+1] << 8) + msg[TRK]), msg[SEC],
389 pos, msg[CNT], addr);
5f7f3586
L
390
391 res = f_lseek(&drv_table[drv].fd, pos);
7d60b20b 392 while (!res && secs--) {
daacc6f9
L
393 unsigned int cnt, br;
394
7d60b20b
L
395 /* check bank boundary crossing */
396 cnt = 0;
daacc6f9 397 if (addr < (TPA_BASE + COMMON_BASE) &&
7d60b20b 398 (addr + BLOCK_SIZE) > (TPA_BASE + COMMON_BASE)) {
daacc6f9 399 cnt = (TPA_BASE + COMMON_BASE) - addr;
daacc6f9
L
400 }
401
7d60b20b
L
402 if (cnt) {
403 debug_cpmsd("## %67c addr: %.5lx, cnt: %3d\n", ' ', addr, cnt);
404 debug_cpmsd("## %67c addr: %.5lx, cnt: %3d\n", ' ', addr+cnt-TPA_BASE, BLOCK_SIZE-cnt);
405 }
5f7f3586
L
406
407 if (dowrite) {
408 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
409 buserr = 1;
7d60b20b 410 break;
5f7f3586 411 } else {
7d60b20b
L
412 if (cnt) {
413 z80_read_block(disk_buffer, addr, cnt);
414 addr = addr + cnt - TPA_BASE;
415 }
416 z80_read_block(disk_buffer+cnt, addr, BLOCK_SIZE - cnt);
5f7f3586 417 z80_bus_cmd(Release);
5f7f3586 418 }
7d60b20b 419 res = f_write(&drv_table[drv].fd, disk_buffer, BLOCK_SIZE, &br);
5f7f3586 420 } else {
7d60b20b
L
421 res = f_read(&drv_table[drv].fd, disk_buffer, BLOCK_SIZE, &br);
422 if (res == FR_OK && br == BLOCK_SIZE) {
5f7f3586
L
423 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
424 buserr = 1;
7d60b20b 425 break;
5f7f3586 426 } else {
7d60b20b
L
427 if (cnt) {
428 z80_write_block(disk_buffer, addr, cnt);
429 addr = addr + cnt - TPA_BASE;
430 }
431 z80_write_block(disk_buffer+cnt, addr, BLOCK_SIZE - cnt);
5f7f3586
L
432 z80_bus_cmd(Release);
433 }
434 }
435 }
436
7d60b20b
L
437 if (br != BLOCK_SIZE) {
438 debug_cpmsd("## %7lu f_read res: %d, bytes rd/wr: %u\n", get_timer(0), res, br);
5f7f3586
L
439 dump_ram(disk_buffer, 0, 64, "Read Data");
440 res = -1;
441 }
daacc6f9 442
7d60b20b 443 addr += BLOCK_SIZE;
5f7f3586
L
444 }
445
393b1897
L
446 if (dowrite && !res) {
447// res = f_sync(&drv_table[drv].fd);
448 drv_table[drv].dirty = true;
449 bg_setstat(handle_cpm_drv_to, 1);
450 }
451
daacc6f9 452
5f7f3586 453 if (buserr) {
7d60b20b 454 debug_cpmsd("Bus timeout\n");
5f7f3586
L
455 rc = 0x03;
456 }
5f7f3586
L
457
458 /* send result*/
393b1897 459 msg_cpm_result(subf, rc, res);
5f7f3586
L
460}
461
72f58822
L
462
463const FLASH struct msg_item z80_messages[] =
464{
465 { 0, /* fct nr. */
89adce76 466 1, 3, /* sub fct nr. from, to */
72f58822
L
467 do_msg_ini_memfifo},
468 { 1,
469 1, 1,
470 do_msg_char_out},
1a2460dc
L
471 { 1,
472 2, 2,
473 do_msg_echo},
5f7f3586
L
474 { 2,
475 0, 0,
476 do_msg_cpm_login},
477 { 2,
478 1, 2,
479 do_msg_cpm_rw},
8590a76b
L
480 { 3,
481 1, 1,
482 do_msg_get_timer},
845cbdbd
L
483 { 3,
484 2, 3, /* 2: get, 3: set time and date */
485 do_msg_get_set_time},
72f58822
L
486 { 0xff, /* end mark */
487 0, 0,
488 0},
489
490};
491
492
493
494
495void do_message(int len, uint8_t *msg)
496{
497 uint8_t fct, sub_fct;
498 int_fast8_t i = 0;
499
500 if (len >= 2) {
501 fct = *msg++;
502 sub_fct = *msg++;
503 len -= 2;
504
89adce76
L
505 while (fct != z80_messages[i].fct) {
506 if (z80_messages[i].fct == 0xff) {
507 DBG_P(1, "do_message: Unknown function: %i, %i\n",
508 fct, sub_fct);
509 return; /* TODO: unknown message # */
510 }
8a7decea 511
72f58822 512 ++i;
72f58822
L
513 }
514
515 while (fct == z80_messages[i].fct) {
8a7decea 516 if (sub_fct >= z80_messages[i].sub_min &&
89adce76 517 sub_fct <= z80_messages[i].sub_max )
72f58822
L
518 break;
519 ++i;
520 }
521
522 if (z80_messages[i].fct != fct) {
523 DBG_P(1, "do_message: Unknown sub function: %i, %i\n",
524 fct, sub_fct);
525 return; /* TODO: unknown message sub# */
526 }
527
528 (z80_messages[i].func)(sub_fct, len, msg);
529
530
531 } else {
532 /* TODO: error */
533 DBG_P(1, "do_message: to few arguments (%i); this shouldn't happen!\n", len);
534 }
535}
536
537
538
539#define CTRBUF_LEN 256
540
541void check_msg_fifo(void)
542{
543 int ch;
544 static int_fast8_t state;
545 static int msglen,idx;
546 static uint8_t buffer[CTRBUF_LEN];
547
89adce76 548 while ((ch = z80_memfifo_getc(fifo_msgin)) >= 0) {
72f58822
L
549 switch (state) {
550 case 0: /* wait for start of message */
3531528e 551 if (ch == 0xAE) { /* TODO: magic number */
72f58822
L
552 msglen = 0;
553 idx = 0;
554 state = 1;
555 }
556 break;
557 case 1: /* get msg len */
558 if (ch > 0 && ch <= CTRBUF_LEN) {
559 msglen = ch;
560 state = 2;
561 } else
562 state = 0;
563 break;
564 case 2: /* get message */
565 buffer[idx++] = ch;
89adce76
L
566 if (idx == msglen) {
567 do_message(msglen, buffer);
568 state = 0;
569 }
570 break;
571 }
572 }
573}
574
575
576int msg_handling(int state)
577{
50939dec 578 bool pending;
8a7decea
L
579
580 ATOMIC_BLOCK(ATOMIC_FORCEON) {
89adce76
L
581 pending = (Stat & S_MSG_PENDING) != 0;
582 Stat &= ~S_MSG_PENDING;
583 }
8a7decea 584
89adce76 585 if (pending) {
215ec4b2
L
586 uint8_t init_request;
587 z80_bus_cmd(Request);
588 init_request = z80_read(0x43);
589 z80_bus_cmd(Release);
590 if ( init_request != 0) {
cdc4625b 591 /* Get address of fifo_list */
215ec4b2 592 uint32_t fifo_addr = 0;
89adce76 593 z80_bus_cmd(Request);
cdc4625b 594 uint32_t fifo_list = z80_read(0x40) +
215ec4b2
L
595 ((uint16_t) z80_read(0x41) << 8) +
596 ((uint32_t) z80_read(0x42) << 16);
cdc4625b
L
597 if (fifo_list != 0) {
598 /* Get address of fifo 0 */
215ec4b2
L
599 fifo_addr = z80_read(fifo_list) +
600 ((uint16_t) z80_read(fifo_list+1) << 8);
601 /* TODO: log to phys addr translation
602 ((uint32_t) z80_read(fifo_list+2) << 16);
603 */
89adce76 604 }
215ec4b2
L
605 z80_write(0x43, 0);
606 z80_bus_cmd(Release);
607
608 if (fifo_addr != 0) {
609 z80_memfifo_init(fifo_msgin, fifo_addr);
610 state = 1;
611 } else
612 state = 0;
613
614 } else {
89adce76 615 check_msg_fifo();
72f58822
L
616 }
617 }
618
89adce76
L
619 return state;
620}
89adce76
L
621
622
623static int handle_msg_handling;
624
625void setup_z180_serv(void)
626{
8a7decea 627
89adce76 628 handle_msg_handling = bg_register(msg_handling, 0);
393b1897 629 handle_cpm_drv_to = bg_register(cpm_drv_to, 0);
72f58822
L
630}
631
89adce76
L
632void restart_z180_serv(void)
633{
634 z80_bus_cmd(Request);
215ec4b2 635 z80_memset(0x40, 0, 4);
89adce76 636 z80_bus_cmd(Release);
8a7decea
L
637
638 for (int i = 0; i < NUM_FIFOS; i++)
639 z80_memfifo_init(i, 0);
89adce76 640 bg_setstat(handle_msg_handling, 0);
5f7f3586 641
89adce76 642}
72f58822 643
845cbdbd 644#if 0
72f58822
L
645/*--------------------------------------------------------------------------*/
646
72f58822
L
647const FLASH uint8_t iniprog[] = {
648 0xAF, // xor a
649 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
650 0x3E, 0x30, // ld a,030h
651 0xED, 0x39, 0x32 //out0 (dcntl),a ;0 mem, max i/0 wait states
652};
653
654const FLASH uint8_t sertest[] = {
655 0xAF, // xor a
656 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
657 0x3E, 0x30, // ld a,030h
658 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
659 0x3E, 0x80, // ld a,M_MPBT ;no MP, PS=10, DR=16, SS=0
660 0xED, 0x39, 0x03, // out0 (cntlb1),a
661 0x3E, 0x64, // ld a,M_RE + M_TE + M_MOD2 ;
662 0xED, 0x39, 0x01, // out0 (cntla1),a
663 0x3E, 0x00, // ld a,0
664 0xED, 0x39, 0x05, // out0 (stat1),a ;Enable rx interrupts
665 0xED, 0x38, 0x05, //l0:in0 a,(stat1)
666 0xE6, 0x80, // and 80h
667 0x28, 0xF9, // jr z,l0
668 0xED, 0x00, 0x09, // in0 b,(rdr1)
669 0xED, 0x38, 0x05, //l1:in0 a,(stat1)
670 0xE6, 0x02, // and 02h
671 0x28, 0xF9, // jr z,l1
672 0xED, 0x01, 0x07, // out0 (tdr1),b
673 0x18, 0xEA, // jr l0
674};
675
676const FLASH uint8_t test1[] = {
677 0xAF, // xor a
678 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
679 0x3E, 0x30, // ld a,030h
680 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
681 0x21, 0x1E, 0x00, // ld hl,dmclrt ;load DMA registers
682 0x06, 0x08, // ld b,dmct_e-dmclrt
683 0x0E, 0x20, // ld c,sar0l
8a7decea 684 0xED, 0x93, // otimr
72f58822
L
685 0x3E, 0xC3, // ld a,0c3h ;dst +1, src +1, burst
686 0xED, 0x39, 0x31, // out0 (dmode),a ;
8a7decea 687 0x3E, 0x62, // ld a,062h ;enable dma0,
72f58822
L
688 0xED, 0x39, 0x30, //cl_1: out0 (dstat),a ;copy 64k
689 0x18, 0xFB, // jr cl_1 ;
8a7decea 690 0x00, 0x00, //dmclrt: dw 0 ;src (inc)
72f58822
L
691 0x00, // db 0 ;src
692 0x00, 0x00, // dw 0 ;dst (inc),
693 0x00, // db 0 ;dst
694 0x00, 0x00, // dw 0 ;count (64k)
695};
845cbdbd 696#endif