]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/z180-serv.c
d6ab10688718ddc9a5e236e1acd44cbd2a9c4be9
[z180-stamp.git] / avr / z180-serv.c
1 /*
2 * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7 #include "common.h"
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdbool.h>
11 #include <util/atomic.h>
12
13 #include "background.h"
14 #include "env.h"
15 #include "ff.h"
16 #include "serial.h"
17 #include "z80-if.h"
18 #include "debug.h"
19 #include "print-utils.h"
20 #include "z180-serv.h"
21 #include "timer.h"
22
23 /*--------------------------------------------------------------------------*/
24
25
26 uint8_t z80_get_byte(uint32_t adr)
27 {
28 uint8_t data;
29
30 z80_bus_cmd(Request);
31 data = z80_read(adr);
32 z80_bus_cmd(Release);
33
34 return data;
35 }
36
37
38 /*--------------------------------------------------------------------------*/
39
40 struct msg_item {
41 uint8_t fct;
42 uint8_t sub_min, sub_max;
43 void (*func)(uint8_t, int, uint8_t *);
44 };
45
46 uint32_t msg_to_addr(uint8_t *msg)
47 {
48 union {
49 uint32_t as32;
50 uint8_t as8[4];
51 } addr;
52
53 addr.as8[0] = msg[0];
54 addr.as8[1] = msg[1];
55 addr.as8[2] = msg[2];
56 addr.as8[3] = 0;
57
58 return addr.as32;
59 }
60
61
62 static int msg_xmit_header(uint8_t func, uint8_t subf, int len)
63 {
64 z80_memfifo_putc(fifo_msgout, 0xAE);
65 z80_memfifo_putc(fifo_msgout, len+2);
66 z80_memfifo_putc(fifo_msgout, func);
67 z80_memfifo_putc(fifo_msgout, subf);
68
69 return 0;
70 }
71
72 int msg_xmit(uint8_t func, uint8_t subf, int len, uint8_t *msg)
73 {
74 msg_xmit_header(func, subf, len);
75 while (len--)
76 z80_memfifo_putc(fifo_msgout, *msg++);
77
78 return 0;
79 }
80
81 void do_msg_ini_memfifo(uint8_t subf, int len, uint8_t * msg)
82 {
83 (void)len;
84
85 z80_memfifo_init(subf, msg_to_addr(msg));
86 }
87
88
89 void do_msg_char_out(uint8_t subf, int len, uint8_t * msg)
90 {
91 (void)subf;
92
93 while (len--)
94 putchar(*msg++);
95 }
96
97 /* echo message */
98 void do_msg_echo(uint8_t subf, int len, uint8_t * msg)
99 {
100 (void)subf;
101
102 /* send re-echo */
103 msg_xmit(1, 3, len, msg);
104 }
105
106 /* ---------------------------------------------------------------------------*/
107
108 #define MAX_DRIVE 4
109 #define BLOCK_SIZE 512
110 #define TPA_BASE 0x10000
111 #define COMMON_BASE 0xC000
112
113 struct cpm_drive_s {
114 uint8_t drv;
115 uint8_t device;
116 char *img_name;
117 FIL fd;
118 };
119
120 static uint8_t disk_buffer[BLOCK_SIZE];
121 static struct cpm_drive_s drv_table[MAX_DRIVE];
122
123 /*
124 db 2 ; disk command
125 ds 1 ; subcommand (login/read/write)
126 ds 1 ; @adrv (8 bits) +0
127 ds 1 ; @rdrv (8 bits) +1
128 ds 3 ; @xdph (24 bits) +2
129 */
130
131 void do_msg_cpm_login(uint8_t subf, int len, uint8_t * msg)
132 {
133
134 FRESULT res = 0;
135 uint8_t rc = 0;
136 uint8_t drv;
137 char *np;
138 uint8_t result_msg[3];
139
140 (void)subf;
141
142 if (len != 5) { /* TODO: check adrv, rdrv */
143 rc = 0x01;
144 goto out;
145 }
146
147 debug("\n## %7lu login: %c:\n", get_timer(0), msg[0]+'A');
148
149
150 drv = msg[0];
151 if ( drv>= MAX_DRIVE) {
152 rc = 0x02;
153 goto out;
154 }
155
156 /*
157 uint32_t dph = ((uint32_t)msg[4] << 16) + ((uint16_t)msg[3] << 8) + msg[2];
158 */
159
160 if (drv_table[drv].img_name != NULL) {
161 debug("## %7lu close: '%s'\n", get_timer(0), drv_table[drv].img_name);
162 f_close(&drv_table[drv].fd);
163 free(drv_table[drv].img_name);
164 drv_table[drv].img_name = NULL;
165 }
166
167 strcpy_P((char *)disk_buffer, PSTR("dsk0"));
168 disk_buffer[3] = msg[0] + '0';
169 if (((np = getenv((char*)disk_buffer)) == NULL) ||
170 ((drv_table[drv].img_name = strdup(np)) == NULL)) {
171 rc = 0x03;
172 goto out;
173 }
174
175
176 res = f_open(&drv_table[drv].fd, drv_table[drv].img_name,
177 FA_WRITE | FA_READ);
178
179 debug("## %7lu open: '%s', (env: '%s'), res: %d\n", get_timer(0),
180 drv_table[drv].img_name, disk_buffer, res);
181
182 out:
183
184 if (res)
185 rc |= 0x80;
186
187 result_msg[0] = rc;
188 result_msg[1] = res;
189 result_msg[2] = res >> 8;
190
191 if (rc) {
192 debug("## %7lu error rc: %.02x, res: %d\n", get_timer(0), rc, res);
193 };
194
195 /* send result*/
196 msg_xmit(2, subf, sizeof(result_msg), result_msg);
197 }
198
199
200 /*
201 db 2 ; disk command
202 ds 1 ; subcommand (login/read/write)
203 ds 1 ; @adrv (8 bits) +0
204 ds 1 ; @rdrv (8 bits) +1
205 ds 2 ; @trk (16 bits) +2
206 ds 2 ; @sect(16 bits) +4
207 ds 1 ; @cnt (8 bits) +6
208 ds 3 ; phys. transfer addr +7
209 */
210
211 #define ADRV 0
212 #define RDRV 1
213 #define TRK 2
214 #define SEC 4
215 #define CNT 6
216 #define ADDR 7
217
218 void do_msg_cpm_rw(uint8_t subf, int len, uint8_t * msg)
219 {
220 uint8_t drv;
221 uint32_t addr;
222 uint32_t pos;
223 unsigned int bytes;
224 bool dowrite = (subf == 2);
225 bool hightpa = false;
226 FRESULT res = 0;
227 uint8_t rc = 0;
228 bool buserr = 0;
229 uint8_t result_msg[3];
230
231 if (len != 10) { /* TODO: check adrv, rdrv */
232 rc = 0x01;
233 goto out;
234 }
235
236 drv = msg[ADRV];
237 if ( drv>= MAX_DRIVE) {
238 rc = 0x02;
239 goto out;
240 }
241
242 bytes = msg[CNT] * BLOCK_SIZE;
243 addr = ((uint32_t)msg[ADDR+2] << 16) + ((uint16_t)msg[ADDR+1] << 8) + msg[ADDR];
244
245
246 /* TODO: tracks per sector from dpb */
247 pos = (((uint16_t)(msg[TRK+1] << 8) + msg[TRK]) * 8
248 + ((uint32_t)(msg[SEC+1] << 8) + msg[SEC])) * BLOCK_SIZE;
249
250 debug("## %7lu cpm_rw: %s %c: trk: %4d, sec: %d, pos: 0x%.8lx, secs: %2d\n",
251 get_timer(0), dowrite ? "write" : " read", msg[ADRV]+'A',
252 ((uint16_t)(msg[TRK+1] << 8) + msg[TRK]), msg[SEC], pos, msg[CNT]);
253
254
255
256 /* TODO: check bank boundary crossing */
257
258 res = f_lseek(&drv_table[drv].fd, pos);
259 while (!res && bytes) {
260 unsigned int cnt, br;
261
262 if (bytes >= BLOCK_SIZE)
263 cnt = BLOCK_SIZE;
264 else
265 cnt = bytes;
266
267 if (addr < (TPA_BASE + COMMON_BASE) &&
268 (addr + cnt) > (TPA_BASE + COMMON_BASE)) {
269 cnt = (TPA_BASE + COMMON_BASE) - addr;
270 hightpa = true;
271 }
272
273 bytes -= cnt;
274
275 debug("## %7lu "
276 " addr: 0x%.5lx, cnt: %3d\n",
277 get_timer(0), addr, cnt);
278
279 if (dowrite) {
280 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
281 buserr = 1;
282 } else {
283 z80_read_block(disk_buffer, addr, cnt);
284 z80_bus_cmd(Release);
285 res = f_write(&drv_table[drv].fd, disk_buffer, cnt, &br);
286 }
287 } else {
288 res = f_read(&drv_table[drv].fd, disk_buffer, cnt, &br);
289 if (res == FR_OK) {
290 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
291 buserr = 1;
292 } else {
293 z80_write_block(disk_buffer, addr, br);
294 z80_bus_cmd(Release);
295 }
296 }
297 }
298
299 addr += br;
300 if (hightpa) {
301 addr -= TPA_BASE;
302 hightpa = false;
303 }
304
305 if (br != cnt) {
306 debug("## %7lu f_read res: %d, bytes rd/wr: %u\n", get_timer(0), res, br);
307 dump_ram(disk_buffer, 0, 64, "Read Data");
308 res = -1;
309 }
310
311 }
312
313 if (dowrite && !res)
314 res = f_sync(&drv_table[drv].fd);
315
316 out:
317 if (buserr) {
318 debug("Bus timeout\n");
319 rc = 0x03;
320 }
321 if (res)
322 rc |= 0x80;
323
324 result_msg[0] = rc;
325 result_msg[1] = res;
326 result_msg[2] = res >> 8;
327
328 if (rc) {
329 debug("###%7lu error rc: %.02x, res: %d\n", get_timer(0), rc, res);
330 }
331
332 /* send result*/
333 msg_xmit(2, subf, sizeof(result_msg), result_msg);
334 }
335
336
337 const FLASH struct msg_item z80_messages[] =
338 {
339 { 0, /* fct nr. */
340 1, 3, /* sub fct nr. from, to */
341 do_msg_ini_memfifo},
342 { 1,
343 1, 1,
344 do_msg_char_out},
345 { 1,
346 2, 2,
347 do_msg_echo},
348 { 2,
349 0, 0,
350 do_msg_cpm_login},
351 { 2,
352 1, 2,
353 do_msg_cpm_rw},
354 { 0xff, /* end mark */
355 0, 0,
356 0},
357
358 };
359
360
361
362
363 void do_message(int len, uint8_t *msg)
364 {
365 uint8_t fct, sub_fct;
366 int_fast8_t i = 0;
367
368 if (len >= 2) {
369 fct = *msg++;
370 sub_fct = *msg++;
371 len -= 2;
372
373 while (fct != z80_messages[i].fct) {
374 if (z80_messages[i].fct == 0xff) {
375 DBG_P(1, "do_message: Unknown function: %i, %i\n",
376 fct, sub_fct);
377 return; /* TODO: unknown message # */
378 }
379
380 ++i;
381 }
382
383 while (fct == z80_messages[i].fct) {
384 if (sub_fct >= z80_messages[i].sub_min &&
385 sub_fct <= z80_messages[i].sub_max )
386 break;
387 ++i;
388 }
389
390 if (z80_messages[i].fct != fct) {
391 DBG_P(1, "do_message: Unknown sub function: %i, %i\n",
392 fct, sub_fct);
393 return; /* TODO: unknown message sub# */
394 }
395
396 (z80_messages[i].func)(sub_fct, len, msg);
397
398
399 } else {
400 /* TODO: error */
401 DBG_P(1, "do_message: to few arguments (%i); this shouldn't happen!\n", len);
402 }
403 }
404
405
406
407 #define CTRBUF_LEN 256
408
409 void check_msg_fifo(void)
410 {
411 int ch;
412 static int_fast8_t state;
413 static int msglen,idx;
414 static uint8_t buffer[CTRBUF_LEN];
415
416 while ((ch = z80_memfifo_getc(fifo_msgin)) >= 0) {
417 switch (state) {
418 case 0: /* wait for start of message */
419 if (ch == 0xAE) { /* TODO: magic number */
420 msglen = 0;
421 idx = 0;
422 state = 1;
423 }
424 break;
425 case 1: /* get msg len */
426 if (ch > 0 && ch <= CTRBUF_LEN) {
427 msglen = ch;
428 state = 2;
429 } else
430 state = 0;
431 break;
432 case 2: /* get message */
433 buffer[idx++] = ch;
434 if (idx == msglen) {
435 do_message(msglen, buffer);
436 state = 0;
437 }
438 break;
439 }
440 }
441 }
442
443
444 int msg_handling(int state)
445 {
446 uint8_t pending;
447
448 ATOMIC_BLOCK(ATOMIC_FORCEON) {
449 pending = (Stat & S_MSG_PENDING) != 0;
450 Stat &= ~S_MSG_PENDING;
451 }
452
453 if (pending) {
454 switch (state) {
455 case 0: /* need init */
456 /* Get address of fifo_list */
457 z80_bus_cmd(Request);
458 uint32_t fifo_list = z80_read(0x40) +
459 ((uint16_t) z80_read(0x41) << 8) +
460 ((uint32_t) z80_read(0x42) << 16);
461 z80_bus_cmd(Release);
462 if (fifo_list != 0) {
463 /* Get address of fifo 0 */
464 z80_bus_cmd(Request);
465 uint32_t fifo_addr = z80_read(fifo_list) +
466 ((uint16_t) z80_read(fifo_list+1) << 8) +
467 ((uint32_t) z80_read(fifo_list+2) << 16);
468 z80_bus_cmd(Release);
469 if (fifo_addr != 0) {
470 z80_memfifo_init(fifo_msgin, fifo_addr);
471 state = 1;
472 }
473 }
474 break;
475 case 1: /* awaiting messages */
476 check_msg_fifo();
477 break;
478 }
479 }
480
481 return state;
482 }
483
484
485 static int handle_msg_handling;
486
487 void setup_z180_serv(void)
488 {
489
490 handle_msg_handling = bg_register(msg_handling, 0);
491 }
492
493 void restart_z180_serv(void)
494 {
495 z80_bus_cmd(Request);
496 z80_write(0x40, 0);
497 z80_write(0x41, 0);
498 z80_write(0x42, 0);
499 z80_bus_cmd(Release);
500
501 for (int i = 0; i < NUM_FIFOS; i++)
502 z80_memfifo_init(i, 0);
503 bg_setstat(handle_msg_handling, 0);
504
505 }
506
507 /*--------------------------------------------------------------------------*/
508
509 const FLASH uint8_t iniprog[] = {
510 0xAF, // xor a
511 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
512 0x3E, 0x30, // ld a,030h
513 0xED, 0x39, 0x32 //out0 (dcntl),a ;0 mem, max i/0 wait states
514 };
515
516 const FLASH uint8_t sertest[] = {
517 0xAF, // xor a
518 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
519 0x3E, 0x30, // ld a,030h
520 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
521 0x3E, 0x80, // ld a,M_MPBT ;no MP, PS=10, DR=16, SS=0
522 0xED, 0x39, 0x03, // out0 (cntlb1),a
523 0x3E, 0x64, // ld a,M_RE + M_TE + M_MOD2 ;
524 0xED, 0x39, 0x01, // out0 (cntla1),a
525 0x3E, 0x00, // ld a,0
526 0xED, 0x39, 0x05, // out0 (stat1),a ;Enable rx interrupts
527 0xED, 0x38, 0x05, //l0:in0 a,(stat1)
528 0xE6, 0x80, // and 80h
529 0x28, 0xF9, // jr z,l0
530 0xED, 0x00, 0x09, // in0 b,(rdr1)
531 0xED, 0x38, 0x05, //l1:in0 a,(stat1)
532 0xE6, 0x02, // and 02h
533 0x28, 0xF9, // jr z,l1
534 0xED, 0x01, 0x07, // out0 (tdr1),b
535 0x18, 0xEA, // jr l0
536 };
537
538 const FLASH uint8_t test1[] = {
539 0xAF, // xor a
540 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
541 0x3E, 0x30, // ld a,030h
542 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
543 0x21, 0x1E, 0x00, // ld hl,dmclrt ;load DMA registers
544 0x06, 0x08, // ld b,dmct_e-dmclrt
545 0x0E, 0x20, // ld c,sar0l
546 0xED, 0x93, // otimr
547 0x3E, 0xC3, // ld a,0c3h ;dst +1, src +1, burst
548 0xED, 0x39, 0x31, // out0 (dmode),a ;
549 0x3E, 0x62, // ld a,062h ;enable dma0,
550 0xED, 0x39, 0x30, //cl_1: out0 (dstat),a ;copy 64k
551 0x18, 0xFB, // jr cl_1 ;
552 0x00, 0x00, //dmclrt: dw 0 ;src (inc)
553 0x00, // db 0 ;src
554 0x00, 0x00, // dw 0 ;dst (inc),
555 0x00, // db 0 ;dst
556 0x00, 0x00, // dw 0 ;count (64k)
557 };