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