]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/z180-serv.c
clean up includes
[z180-stamp.git] / avr / z180-serv.c
CommitLineData
35edb766 1/*
1aed7fd5 2 * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
35edb766 3 *
ad12f284 4 * SPDX-License-Identifier: GPL-2.0
35edb766
L
5 */
6
cb4fb1ed 7#include "z180-serv.h"
72f58822 8#include "common.h"
89adce76 9#include <util/atomic.h>
72f58822 10
1aed7fd5 11#include "config.h"
89adce76 12#include "background.h"
5f7f3586
L
13#include "env.h"
14#include "ff.h"
72f58822
L
15#include "serial.h"
16#include "z80-if.h"
889202c4 17#include "debug.h"
5f7f3586 18#include "print-utils.h"
daacc6f9 19#include "timer.h"
845cbdbd
L
20#include "time.h"
21#include "bcd.h"
22#include "rtc.h"
7d60b20b 23
2ca8d8c7 24#define DEBUG_CPM_SDIO 0 /* set to 1 to debug */
7d60b20b
L
25
26#define debug_cpmsd(fmt, args...) \
27 debug_cond(DEBUG_CPM_SDIO, fmt, ##args)
28
29
72f58822
L
30/*--------------------------------------------------------------------------*/
31
32struct msg_item {
33 uint8_t fct;
34 uint8_t sub_min, sub_max;
35 void (*func)(uint8_t, int, uint8_t *);
36};
37
38uint32_t msg_to_addr(uint8_t *msg)
39{
40 union {
41 uint32_t as32;
42 uint8_t as8[4];
43 } addr;
44
45 addr.as8[0] = msg[0];
46 addr.as8[1] = msg[1];
47 addr.as8[2] = msg[2];
48 addr.as8[3] = 0;
49
50 return addr.as32;
51}
52
72f58822 53
1a2460dc
L
54static int msg_xmit_header(uint8_t func, uint8_t subf, int len)
55{
56 z80_memfifo_putc(fifo_msgout, 0xAE);
57 z80_memfifo_putc(fifo_msgout, len+2);
58 z80_memfifo_putc(fifo_msgout, func);
59 z80_memfifo_putc(fifo_msgout, subf);
60
61 return 0;
62}
63
64int msg_xmit(uint8_t func, uint8_t subf, int len, uint8_t *msg)
65{
66 msg_xmit_header(func, subf, len);
67 while (len--)
68 z80_memfifo_putc(fifo_msgout, *msg++);
69
70 return 0;
71}
72
72f58822
L
73void do_msg_ini_memfifo(uint8_t subf, int len, uint8_t * msg)
74{
75 (void)len;
76
89adce76 77 z80_memfifo_init(subf, msg_to_addr(msg));
72f58822
L
78}
79
80
81void do_msg_char_out(uint8_t subf, int len, uint8_t * msg)
82{
83 (void)subf;
84
85 while (len--)
86 putchar(*msg++);
87}
88
1a2460dc
L
89/* echo message */
90void do_msg_echo(uint8_t subf, int len, uint8_t * msg)
91{
92 (void)subf;
93
94 /* send re-echo */
95 msg_xmit(1, 3, len, msg);
96}
97
8590a76b
L
98/* get timer */
99void do_msg_get_timer(uint8_t subf, int len, uint8_t * msg)
100{
a8eb521f 101 uint32_t time_ms = (len >= 4) ? *(uint32_t *) msg : 0;
8590a76b 102
a8eb521f 103 time_ms = get_timer(time_ms);
8590a76b
L
104 msg_xmit(3, subf, sizeof(time_ms), (uint8_t *) &time_ms);
105}
106
5f7f3586
L
107/* ---------------------------------------------------------------------------*/
108
845cbdbd
L
109#define CPM_DAY_OFFSET ((1978-1900) * 365 + 19) /* 19 leap years */
110
111/*
112 * Convert CP/M time stamp to a broken-down time structure
113 *
114 */
115int mk_date_time (int len, uint8_t *msg, struct tm *tmp)
116{
117 time_t stamp;
118
119 if (len != 5)
120 return -1;
121
122 /* days since 2000-01-01 */
123 long days = msg[3] + (msg[4] << 8) - 8036;
124
125 if (days < 0)
126 return -1;
127
128 stamp = days * ONE_DAY;
129 stamp += bcd2bin(msg[0]);
130 stamp += bcd2bin(msg[1]) * 60 ;
8d0fad4c 131 stamp += bcd2bin(msg[2]) * 3600L;
845cbdbd
L
132 gmtime_r(&stamp, tmp);
133 return 0;
134}
135
136void mk_cpm_time(struct tm *tmp, uint8_t cpm_time[5])
137{
138 uint16_t days = 1;
139 uint_fast8_t leap=2;
140
141 for (int year=78; year < tmp->tm_year; year++) {
142 days = days + 365 + (leap == 0);
143 leap = (leap+1)%4;
144 }
145 days += tmp->tm_yday;
146
147 cpm_time[0] = bin2bcd(tmp->tm_sec);
148 cpm_time[1] = bin2bcd(tmp->tm_min);
149 cpm_time[2] = bin2bcd(tmp->tm_hour);
150 cpm_time[3] = days;
151 cpm_time[4] = days >> 8;
845cbdbd
L
152}
153
154/* get/set cp/m time */
155void do_msg_get_set_time(uint8_t subf, int len, uint8_t * msg)
156{
157 struct tm t;
158 uint8_t cpm_time[5];
159 int rc;
160
161 memset(cpm_time, 0, ARRAY_SIZE(cpm_time));
162
163 switch (subf) {
164 case 3: /* set date & time */
165 /* initialize t with current time */
166 rc = rtc_get (&t);
167
85046f8c 168 if (rc >= 0) {
845cbdbd
L
169 /* insert new date & time */
170 if (mk_date_time (len, msg, &t) != 0) {
171 my_puts_P(PSTR("## set_time: Bad date format\n"));
172 break;
173 }
174
175 time_t time;
176 time = mk_gmtime(&t);
177 gmtime_r(&time, &t);
178
179 /* and write to RTC */
180 rc = rtc_set (&t);
181 if(rc)
182 my_puts_P(PSTR("## set_time: Set date failed\n"));
183 } else {
184 my_puts_P(PSTR("## set_time: Get date failed\n"));
185 }
186 /* FALL TROUGH */
187 case 2: /* get date & time */
188 rc = rtc_get (&t);
85046f8c
L
189 if (rc >= 0) {
190 time_t time;
191 time = mk_gmtime(&t);
192 //mktime(&t);
193 gmtime_r(&time, &t);
845cbdbd 194
85046f8c
L
195 mk_cpm_time(&t, cpm_time);
196 } else {
845cbdbd 197 my_puts_P(PSTR("## get_time: Get date failed\n"));
845cbdbd 198 }
845cbdbd
L
199 break;
200 }
201
202 msg_xmit(3, subf, sizeof(cpm_time), cpm_time);
203}
204
205/* ---------------------------------------------------------------------------*/
206
78c90027 207static uint8_t drv;
1aed7fd5
L
208static uint8_t disk_buffer[CONFIG_CPM_BLOCK_SIZE];
209static struct cpm_drive_s drv_table[CONFIG_CPM_MAX_DRIVE];
393b1897
L
210static int handle_cpm_drv_to;
211
78c90027 212typedef enum {SINGLE, START, MIDDLE, END} dbgmsg_t;
393b1897 213
78c90027 214void drv_debug(dbgmsg_t phase, const FLASH char *const fmt, ...) \
9461ecf3
L
215{
216 struct cpm_drive_s *dp = &drv_table[drv];
217
218 if (dp->opt & DRV_OPT_DEBUG) {
219
220 va_list ap;
78c90027 221 va_start (ap, fmt);
9461ecf3 222
78c90027
L
223 if (phase == SINGLE || phase == START)
224 printf_P(PSTR("# %7lu dsk%d: "), get_timer(0), drv);
9461ecf3 225
9461ecf3 226 vfprintf_P (stdout, fmt, ap);
9461ecf3 227
78c90027
L
228 if (phase == SINGLE || phase == END)
229 putc('\n', stdout);
230
231 va_end (ap);
9461ecf3
L
232 }
233}
234
cb4fb1ed
L
235int drv_list(void)
236{
237 for (uint8_t i = 0; i < CONFIG_CPM_MAX_DRIVE; i++) {
238 struct cpm_drive_s * p = &drv_table[i];
239 if (p->img_name) {
209025e8
L
240 printf_P(PSTR(" dsk%d: %2S %3S attached to %s\n"), i,
241 p->opt&DRV_OPT_RO ? PSTR("RO") : PSTR("RW"),
242 p->opt&DRV_OPT_DEBUG ? PSTR("DBG") : PSTR(""),
cb4fb1ed
L
243 p->img_name);
244 }
245 }
246 return 0;
247}
248
78c90027 249int drv_detach(uint8_t unit)
cb4fb1ed 250{
78c90027 251 drv = unit;
cb4fb1ed
L
252 if (drv < CONFIG_CPM_MAX_DRIVE) {
253 struct cpm_drive_s *p = &drv_table[drv];
254
78c90027 255 drv_debug(SINGLE, PSTR("detach from '%s'"), p->img_name ? p->img_name : "-");
cb4fb1ed
L
256
257 if (p->img_name) {
258 f_close(&p->fd);
cb4fb1ed 259 free(p->img_name);
4122fe90
L
260 p->opt = 0;
261 p->flags &= ~DRV_FLG_DIRTY;
cb4fb1ed 262 p->img_name = NULL;
e34ae619 263
3b841cea 264 uint32_t scb = getenv_ulong(PSTR(ENV_CPM3_SCB), 16, 0);
e34ae619
L
265 if (scb && (z80_bus_cmd(Request) & ZST_ACQUIRED)) {
266 z80_write(scb + 0xf0, 0xff);
267 z80_write(p->dph + 11, 0xff);
268 z80_bus_cmd(Release);
269 }
cb4fb1ed
L
270 }
271 }
272 return 0;
273}
274
275static int drv_find_file_attached(const char *fn)
276{
277 for (uint8_t i = 0; i < CONFIG_CPM_MAX_DRIVE; i++) {
278 struct cpm_drive_s *p = &drv_table[i];
279 if (p->img_name && !strcmp(fn, p->img_name)) {
280 return i;
281 }
282 }
283 return -1;
284}
285
78c90027 286int drv_attach(uint8_t unit, const char *filename, drv_opt_t options)
cb4fb1ed
L
287{
288 int res;
289
78c90027 290 drv = unit;
cb4fb1ed 291 if (drv >= CONFIG_CPM_MAX_DRIVE)
5e8ac5e0 292 return EATRANGE;
cb4fb1ed
L
293
294 struct cpm_drive_s *p = &drv_table[drv];
295
296 if (options & DRV_OPT_REATTATCH) {
297 if (filename) {
5e8ac5e0 298 return EUNEXPARG;
cb4fb1ed
L
299 }
300
301 if (!p->img_name) {
5e8ac5e0 302 return EATNOT;
cb4fb1ed
L
303 }
304
9baecc6b
L
305 /* change options */
306 if ((p->opt ^ options) & DRV_OPT_RO) {
307 f_close(&p->fd);
308 res = f_open(&p->fd, p->img_name,
309 FA_READ | (options&DRV_OPT_RO ? 0 : FA_WRITE));
310 }
cb4fb1ed 311
9baecc6b 312 p->opt = options & ~DRV_OPT_REATTATCH;
cb4fb1ed
L
313
314 } else {
315
316 if (p->img_name)
5e8ac5e0 317 return EATALRDY;
cb4fb1ed 318 if (drv_find_file_attached(filename) >= 0)
5e8ac5e0 319 return EATOTHER;
cb4fb1ed 320
4122fe90 321 p->opt = options;
cb4fb1ed
L
322
323 /* new attachment */
324
325 if ((p->img_name = strdup(filename)) == NULL)
5e8ac5e0 326 return ENOMEM;
cb4fb1ed
L
327
328 res = f_open(&p->fd, p->img_name,
9baecc6b 329 FA_READ | (options&DRV_OPT_RO ? 0 : FA_WRITE));
cb4fb1ed
L
330
331 if (!res && f_size(&p->fd) < CONFIG_CPM_DISKSIZE) {
9baecc6b 332#if 0
cb4fb1ed 333 unsigned int bw;
cb4fb1ed
L
334 debug_cpmsd(" expanding image file from %ld to %ld\n",
335 f_size(&p->fd), CONFIG_CPM_DISKSIZE);
336
337 res = f_lseek(&p->fd, CONFIG_CPM_DISKSIZE-CONFIG_CPM_BLOCK_SIZE);
338 if (!res) {
339 memset(disk_buffer, 0xe5, CONFIG_CPM_BLOCK_SIZE);
340 res = f_write(&p->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &bw);
341 if (res || bw < CONFIG_CPM_BLOCK_SIZE) {
342 debug_cpmsd(" failed! res: %d, bytes written: %u\n", res, bw);
343 }
4122fe90 344 p->flags |= DRV_FLG_DIRTY;
cb4fb1ed
L
345 bg_setstat(handle_cpm_drv_to, 1);
346 }
9baecc6b 347#else
78c90027 348 drv_debug(SINGLE, PSTR("wrong image file size: %ld, should be %ld"),
9baecc6b
L
349 f_size(&p->fd), CONFIG_CPM_DISKSIZE);
350 res = 64;
351#endif
cb4fb1ed
L
352 }
353 if (res) {
354 drv_detach(drv);
5e8ac5e0 355 return EATOPEN;
cb4fb1ed
L
356 }
357 }
358
5e8ac5e0 359 return ESUCCESS;
cb4fb1ed
L
360}
361
362
393b1897
L
363int cpm_drv_to(int state)
364{
365 static uint32_t ts;
366
367 switch(state) {
368 case 0:
369 break;
370
371 case 1:
372 ts = get_timer(0);
373 state = 2;
374 break;
375
376 case 2:
377 if (get_timer(ts) > 1000) {
1aed7fd5 378 for (uint_fast8_t i=0; i < CONFIG_CPM_MAX_DRIVE; i++) {
4122fe90 379 if (drv_table[i].flags & DRV_FLG_DIRTY) {
4122fe90 380 drv_table[i].flags &= ~DRV_FLG_DIRTY;
9461ecf3 381 f_sync(&drv_table[i].fd);
78c90027
L
382 drv = i;
383 drv_debug(SINGLE, PSTR("f_sync"));
393b1897
L
384 }
385 }
386 state = 0;
387 }
388 }
389 return state;
390}
391
78c90027
L
392static const FLASH char * const FLASH rc_messages[] = {
393 FSTR("OK"),
394 FSTR("Internal error: wrong message len"), /* 01 */
395 FSTR("Invalid relative drive #"), /* 02 */
396 FSTR("Bus timeout"), /* 03 */
397 FSTR("Access byond disk size"), /* 04 */
398 FSTR("Write protect"), /* 05 */
399 FSTR("No media"), /* 06 */
910e7206 400 FSTR("R/W address == 0 !!!!"), /* 07 */
78c90027 401 };
393b1897
L
402
403void msg_cpm_result(uint8_t subf, uint8_t rc, int res)
404{
405 uint8_t result_msg[3];
406
407 if (res)
408 rc |= 0x80;
409
410 result_msg[0] = rc;
411 result_msg[1] = res;
412 result_msg[2] = res >> 8;
413
393b1897 414 msg_xmit(2, subf, sizeof(result_msg), result_msg);
78c90027 415
a4f40a90 416 if (rc) {
f1e16f88 417#if defined(GCC_BUG_61443)
a4f40a90
L
418 char msg[40];
419 strncpy_P(msg, rc_messages[rc & 0x7f], sizeof msg -1);
420 drv_debug(END, PSTR(" rc: %.02x/%d, '%s'"),
421 rc, res, msg);
422#else
78c90027
L
423 drv_debug(END, PSTR(" rc: %.02x/%d, '%S'"),
424 rc, res, rc_messages[rc & 0x7f]);
a4f40a90
L
425#endif
426 } else
78c90027
L
427 drv_debug(END, PSTR(""));
428
393b1897 429}
5f7f3586
L
430
431/*
432 db 2 ; disk command
433 ds 1 ; subcommand (login/read/write)
434 ds 1 ; @adrv (8 bits) +0
435 ds 1 ; @rdrv (8 bits) +1
436 ds 3 ; @xdph (24 bits) +2
437*/
438
439void do_msg_cpm_login(uint8_t subf, int len, uint8_t * msg)
440{
9baecc6b 441 struct cpm_drive_s *dp;
4122fe90 442 FRESULT res = 0;
5f7f3586
L
443
444 (void)subf;
445
78c90027
L
446 /* Get relative drive number */
447 drv = msg[1];
448 drv_debug(START, PSTR("login"));
449
afc7c4b4 450 if (len != 5) {
393b1897 451 return msg_cpm_result(subf, 0x01, res);
5f7f3586
L
452 }
453
cb4fb1ed 454 if ( drv >= CONFIG_CPM_MAX_DRIVE) {
78c90027 455 /* invalid relative drive number */
393b1897 456 return msg_cpm_result(subf, 0x02, res);
5f7f3586
L
457 }
458
9baecc6b
L
459 dp = &drv_table[drv];
460 dp->flags &= ~DRV_FLG_OPEN;
461 dp->dph = ((uint32_t)msg[4] << 16) + ((uint16_t)msg[3] << 8) + msg[2];
cb4fb1ed 462
9baecc6b 463 if (dp->img_name == NULL) {
4122fe90 464 /* no file attached */
78c90027 465 return msg_cpm_result(subf, 0x06, res);
5f7f3586
L
466 }
467
019dc5f9
L
468 f_close(&dp->fd);
469 res = f_open(&dp->fd, dp->img_name,
470 FA_READ | (dp->opt&DRV_OPT_RO ? 0 : FA_WRITE));
471
9baecc6b 472 dp->flags |= DRV_FLG_OPEN;
afc7c4b4 473
5f7f3586 474 /* send result*/
393b1897 475 msg_cpm_result(subf, 0x00, res);
5f7f3586
L
476}
477
478
479/*
480 db 2 ; disk command
481 ds 1 ; subcommand (login/read/write)
daacc6f9
L
482 ds 1 ; @adrv (8 bits) +0
483 ds 1 ; @rdrv (8 bits) +1
484 ds 2 ; @trk (16 bits) +2
485 ds 2 ; @sect(16 bits) +4
486 ds 1 ; @cnt (8 bits) +6
5f7f3586
L
487 ds 3 ; phys. transfer addr +7
488*/
489
daacc6f9
L
490#define ADRV 0
491#define RDRV 1
492#define TRK 2
493#define SEC 4
494#define CNT 6
495#define ADDR 7
496
5f7f3586
L
497void do_msg_cpm_rw(uint8_t subf, int len, uint8_t * msg)
498{
9baecc6b 499 struct cpm_drive_s *dp;
5f7f3586
L
500 uint32_t addr;
501 uint32_t pos;
9461ecf3
L
502 uint16_t track;
503 uint16_t sec;
7d60b20b 504 uint8_t secs;
9baecc6b 505 bool dowrite;
5f7f3586
L
506 FRESULT res = 0;
507 uint8_t rc = 0;
508 bool buserr = 0;
5f7f3586 509
78c90027
L
510 drv = msg[RDRV];
511 dowrite = (subf == 2);
512
513 drv_debug(START, PSTR("%2S"), dowrite ? PSTR("W ") : PSTR(" R"));
514
afc7c4b4 515 if (len != 10) {
393b1897 516 return msg_cpm_result(subf, 0x01, res);
5f7f3586 517 }
1aed7fd5 518 if ( drv>= CONFIG_CPM_MAX_DRIVE) {
393b1897 519 return msg_cpm_result(subf, 0x02, res);
5f7f3586
L
520 }
521
9baecc6b 522 dp = &drv_table[drv];
9461ecf3
L
523 track = (uint16_t)(msg[TRK+1] << 8) + msg[TRK];
524 sec = (uint16_t)(msg[SEC+1] << 8) + msg[SEC];
7d60b20b 525 secs = msg[CNT];
daacc6f9 526 addr = ((uint32_t)msg[ADDR+2] << 16) + ((uint16_t)msg[ADDR+1] << 8) + msg[ADDR];
5f7f3586 527
78c90027
L
528 if (dp->img_name == NULL) {
529 /* no media */
530 return msg_cpm_result(subf, 0x06, res);
531 }
5f7f3586 532
daacc6f9 533 /* TODO: tracks per sector from dpb */
9461ecf3 534 pos = (track * 8UL + sec) * CONFIG_CPM_BLOCK_SIZE;
5f7f3586 535
78c90027
L
536 drv_debug(MIDDLE, PSTR(" T:%4d, S:%2d, cnt:%2d, lba: %.8lx, addr: %.5lx"),
537 track, sec, secs, pos, addr);
538
910e7206
L
539 if (addr == 0) {
540 return msg_cpm_result(subf, 0x07, res);
541 }
542
78c90027
L
543 if (dowrite && dp->opt & DRV_OPT_RO) {
544 return msg_cpm_result(subf, 0x05, res);
545 }
546
5f7f3586 547
1aed7fd5 548 if (pos + secs * CONFIG_CPM_BLOCK_SIZE > CONFIG_CPM_DISKSIZE) {
78c90027
L
549 drv_debug(MIDDLE, PSTR(" access > DISKSIZE:%.8lx!"),
550 CONFIG_CPM_DISKSIZE);
1aed7fd5
L
551 return msg_cpm_result(subf, 0x04, res);
552 }
553
9baecc6b 554 res = f_lseek(&dp->fd, pos);
1aed7fd5 555
7d60b20b 556 while (!res && secs--) {
8bbf185e 557 unsigned int brw;
5f7f3586
L
558 if (dowrite) {
559 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
560 buserr = 1;
7d60b20b 561 break;
5f7f3586 562 } else {
1aed7fd5 563 z80_read_block(disk_buffer, addr, CONFIG_CPM_BLOCK_SIZE);
5f7f3586 564 z80_bus_cmd(Release);
5f7f3586 565 }
9baecc6b 566 res = f_write(&dp->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &brw);
5f7f3586 567 } else {
9baecc6b 568 res = f_read(&dp->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &brw);
1aed7fd5 569 if (res == FR_OK) {
5f7f3586
L
570 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
571 buserr = 1;
7d60b20b 572 break;
5f7f3586 573 } else {
afc7c4b4 574 z80_write_block(disk_buffer, addr, CONFIG_CPM_BLOCK_SIZE);
5f7f3586
L
575 z80_bus_cmd(Release);
576 }
577 }
578 }
1aed7fd5 579 if (brw != CONFIG_CPM_BLOCK_SIZE) {
78c90027
L
580 drv_debug(MIDDLE, PSTR(" short rd/wr: res: %d, brw: %u"),
581 res, brw);
afc7c4b4 582 res = 64;
5f7f3586 583 }
1aed7fd5 584 addr += CONFIG_CPM_BLOCK_SIZE;
5f7f3586
L
585 }
586
393b1897 587 if (dowrite && !res) {
9baecc6b 588 dp->flags |= DRV_FLG_DIRTY;
393b1897
L
589 bg_setstat(handle_cpm_drv_to, 1);
590 }
591
5f7f3586 592 if (buserr) {
78c90027 593 /* Bus timeout. how can this happen? */
5f7f3586
L
594 rc = 0x03;
595 }
5f7f3586
L
596
597 /* send result*/
393b1897 598 msg_cpm_result(subf, rc, res);
5f7f3586
L
599}
600
72f58822
L
601
602const FLASH struct msg_item z80_messages[] =
603{
604 { 0, /* fct nr. */
89adce76 605 1, 3, /* sub fct nr. from, to */
72f58822
L
606 do_msg_ini_memfifo},
607 { 1,
608 1, 1,
609 do_msg_char_out},
1a2460dc
L
610 { 1,
611 2, 2,
612 do_msg_echo},
5f7f3586
L
613 { 2,
614 0, 0,
615 do_msg_cpm_login},
616 { 2,
617 1, 2,
618 do_msg_cpm_rw},
8590a76b
L
619 { 3,
620 1, 1,
621 do_msg_get_timer},
845cbdbd
L
622 { 3,
623 2, 3, /* 2: get, 3: set time and date */
624 do_msg_get_set_time},
72f58822
L
625 { 0xff, /* end mark */
626 0, 0,
627 0},
628
629};
630
631
632
633
634void do_message(int len, uint8_t *msg)
635{
636 uint8_t fct, sub_fct;
637 int_fast8_t i = 0;
638
639 if (len >= 2) {
640 fct = *msg++;
641 sub_fct = *msg++;
642 len -= 2;
643
89adce76
L
644 while (fct != z80_messages[i].fct) {
645 if (z80_messages[i].fct == 0xff) {
646 DBG_P(1, "do_message: Unknown function: %i, %i\n",
647 fct, sub_fct);
648 return; /* TODO: unknown message # */
649 }
8a7decea 650
72f58822 651 ++i;
72f58822
L
652 }
653
654 while (fct == z80_messages[i].fct) {
8a7decea 655 if (sub_fct >= z80_messages[i].sub_min &&
89adce76 656 sub_fct <= z80_messages[i].sub_max )
72f58822
L
657 break;
658 ++i;
659 }
660
661 if (z80_messages[i].fct != fct) {
662 DBG_P(1, "do_message: Unknown sub function: %i, %i\n",
663 fct, sub_fct);
664 return; /* TODO: unknown message sub# */
665 }
666
667 (z80_messages[i].func)(sub_fct, len, msg);
668
669
670 } else {
671 /* TODO: error */
672 DBG_P(1, "do_message: to few arguments (%i); this shouldn't happen!\n", len);
673 }
674}
675
676
677
678#define CTRBUF_LEN 256
679
680void check_msg_fifo(void)
681{
682 int ch;
683 static int_fast8_t state;
684 static int msglen,idx;
685 static uint8_t buffer[CTRBUF_LEN];
686
89adce76 687 while ((ch = z80_memfifo_getc(fifo_msgin)) >= 0) {
72f58822
L
688 switch (state) {
689 case 0: /* wait for start of message */
3531528e 690 if (ch == 0xAE) { /* TODO: magic number */
72f58822
L
691 msglen = 0;
692 idx = 0;
693 state = 1;
694 }
695 break;
696 case 1: /* get msg len */
697 if (ch > 0 && ch <= CTRBUF_LEN) {
698 msglen = ch;
699 state = 2;
700 } else
701 state = 0;
702 break;
703 case 2: /* get message */
704 buffer[idx++] = ch;
89adce76
L
705 if (idx == msglen) {
706 do_message(msglen, buffer);
707 state = 0;
708 }
709 break;
710 }
711 }
712}
713
714
715int msg_handling(int state)
716{
50939dec 717 bool pending;
8a7decea
L
718
719 ATOMIC_BLOCK(ATOMIC_FORCEON) {
89adce76
L
720 pending = (Stat & S_MSG_PENDING) != 0;
721 Stat &= ~S_MSG_PENDING;
722 }
8a7decea 723
89adce76 724 if (pending) {
215ec4b2
L
725 uint8_t init_request;
726 z80_bus_cmd(Request);
727 init_request = z80_read(0x43);
728 z80_bus_cmd(Release);
729 if ( init_request != 0) {
8bbf185e 730 /* Get address of fifo 0 */
89adce76 731 z80_bus_cmd(Request);
8bbf185e
L
732 uint32_t fifo_addr = z80_read(0x40) +
733 ((uint16_t) z80_read(0x40+1) << 8) +
734 ((uint32_t) z80_read(0x40+2) << 16);
215ec4b2
L
735 z80_write(0x43, 0);
736 z80_bus_cmd(Release);
737
738 if (fifo_addr != 0) {
739 z80_memfifo_init(fifo_msgin, fifo_addr);
740 state = 1;
741 } else
742 state = 0;
743
744 } else {
89adce76 745 check_msg_fifo();
72f58822
L
746 }
747 }
748
89adce76
L
749 return state;
750}
89adce76
L
751
752
753static int handle_msg_handling;
754
755void setup_z180_serv(void)
756{
8a7decea 757
89adce76 758 handle_msg_handling = bg_register(msg_handling, 0);
393b1897 759 handle_cpm_drv_to = bg_register(cpm_drv_to, 0);
72f58822
L
760}
761
89adce76
L
762void restart_z180_serv(void)
763{
764 z80_bus_cmd(Request);
215ec4b2 765 z80_memset(0x40, 0, 4);
89adce76 766 z80_bus_cmd(Release);
8a7decea
L
767
768 for (int i = 0; i < NUM_FIFOS; i++)
769 z80_memfifo_init(i, 0);
89adce76 770 bg_setstat(handle_msg_handling, 0);
5f7f3586 771
89adce76 772}
72f58822 773
845cbdbd 774#if 0
72f58822
L
775/*--------------------------------------------------------------------------*/
776
72f58822
L
777const FLASH uint8_t iniprog[] = {
778 0xAF, // xor a
779 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
780 0x3E, 0x30, // ld a,030h
781 0xED, 0x39, 0x32 //out0 (dcntl),a ;0 mem, max i/0 wait states
782};
783
784const FLASH uint8_t sertest[] = {
785 0xAF, // xor a
786 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
787 0x3E, 0x30, // ld a,030h
788 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
789 0x3E, 0x80, // ld a,M_MPBT ;no MP, PS=10, DR=16, SS=0
790 0xED, 0x39, 0x03, // out0 (cntlb1),a
791 0x3E, 0x64, // ld a,M_RE + M_TE + M_MOD2 ;
792 0xED, 0x39, 0x01, // out0 (cntla1),a
793 0x3E, 0x00, // ld a,0
794 0xED, 0x39, 0x05, // out0 (stat1),a ;Enable rx interrupts
795 0xED, 0x38, 0x05, //l0:in0 a,(stat1)
796 0xE6, 0x80, // and 80h
797 0x28, 0xF9, // jr z,l0
798 0xED, 0x00, 0x09, // in0 b,(rdr1)
799 0xED, 0x38, 0x05, //l1:in0 a,(stat1)
800 0xE6, 0x02, // and 02h
801 0x28, 0xF9, // jr z,l1
802 0xED, 0x01, 0x07, // out0 (tdr1),b
803 0x18, 0xEA, // jr l0
804};
805
806const FLASH uint8_t test1[] = {
807 0xAF, // xor a
808 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
809 0x3E, 0x30, // ld a,030h
810 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
811 0x21, 0x1E, 0x00, // ld hl,dmclrt ;load DMA registers
812 0x06, 0x08, // ld b,dmct_e-dmclrt
813 0x0E, 0x20, // ld c,sar0l
8a7decea 814 0xED, 0x93, // otimr
72f58822
L
815 0x3E, 0xC3, // ld a,0c3h ;dst +1, src +1, burst
816 0xED, 0x39, 0x31, // out0 (dmode),a ;
8a7decea 817 0x3E, 0x62, // ld a,062h ;enable dma0,
72f58822
L
818 0xED, 0x39, 0x30, //cl_1: out0 (dstat),a ;copy 64k
819 0x18, 0xFB, // jr cl_1 ;
8a7decea 820 0x00, 0x00, //dmclrt: dw 0 ;src (inc)
72f58822
L
821 0x00, // db 0 ;src
822 0x00, 0x00, // dw 0 ;dst (inc),
823 0x00, // db 0 ;dst
824 0x00, 0x00, // dw 0 ;count (64k)
825};
845cbdbd 826#endif