]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/z80-if.c
Add CP/M 3 file i/o (initial version)
[z180-stamp.git] / avr / z80-if.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
0c5890bb
L
7/**
8 *
9 * Pin assignments
10 *
ea6971b8 11 * | Z180-Sig | AVR-Port | Dir | Special Function |
0c5890bb 12 * +------------+---------------+-------+-----------------------+
ea6971b8
L
13 * | A0 | PA 0 | O | |
14 * | A1 | PA 1 | O | |
15 * | A2 | PA 2 | O | |
16 * | A3 | PA 3 | O | |
17 * | A4 | PA 4 | O | |
18 * | A5 | PA 5 | O | |
19 * | A6 | PA 6 | O | |
20 * | A7 | PA 7 | O | |
21 * | A8 | PC 0 | O | |
22 * | A9 | PC 1 | O | |
23 * | A10 | PC 2 | O | |
24 * | A11 | PC 3 | O | |
25 * | A12 | PC 4 | O | |
26 * | A13 | PC 5 | O | |
27 * | A14 | PC 6 | O | |
28 * | A15 | PC 7 | O | |
29 * | A16 | PE 2 | O | |
30 * | A17 | PE 3 | O | |
31 * | A18 | PE 4 | O | |
32 * | D0 | PF 0 | I/O | |
33 * | D1 | PF 1 | I/O | |
34 * | D2 | PF 2 | I/O | |
35 * | D3 | PF 3 | I/O | |
36 * | D4 | PF 4 | I/O | |
37 * | D5 | PF 5 | I/O | |
38 * | D6 | PF 6 | I/O | |
39 * | D7 | PF 7 | I/O | |
40 * | RD | PD 3 | O | |
41 * | WR | PD 2 | O | |
42 * | MREQ | PD 4 | O | |
43 * | RST | PD 5 | O | |
44 * | BUSREQ | PD 7 | O | |
45 * | BUSACK | PD 6 | I | |
46 * | IOCS1 | PE 5 | I | |
47 * |* HALT | P | | |
48 * |* NMI | P | | |
49 * | | P | | |
50 * | | P | | af1 USART1_TX |
51 * | | P | | af1 USART1_RX |
52 * | | P |JTDI | remap SPI1_NSS' |
53 * | | P |JTDO | remap SPI1_SCK' |
54 * | | P |JTRST | remap SPI1_MISO' |
55 * | | P | | remap SPI1_MOSI' |
56 * | | P | | af1 OSC32 |
57 * | | P | | af1 OSC32 |
0c5890bb 58
0c5890bb
L
59 */
60
ea6971b8 61
26331e24 62#include "common.h"
f338df2a 63#include <util/atomic.h>
0c5890bb
L
64#include "debug.h"
65#include "z80-if.h"
66
67
0c5890bb 68
41d36f28
L
69//#define P_ZCLK PORTB
70//#define ZCLK 5
71//#define DDR_ZCLK DDRB
0c5890bb
L
72#define P_MREQ PORTD
73#define MREQ 4
74#define DDR_MREQ DDRD
75#define P_RD PORTD
76#define RD 3
77#define P_WR PORTD
78#define WR 2
79#define P_BUSREQ PORTD
80#define BUSREQ 7
81#define DDR_BUSREQ DDRD
82#define P_BUSACK PORTD
9b6b4b31 83#define PIN_BUSACK PIND
0c5890bb
L
84#define BUSACK 6
85#define DDR_BUSACK DDRD
86//#define P_HALT PORTA
87//#define HALT 12
88#define P_IOCS1 PORTE
89#define IOCS1 5
90#define DDR_IOCS1 DDRE
91//#define P_NMI PORTB
92//#define NMI 7
93#define P_RST PORTD
94#define DDR_RST DDRD
95#define RST 5
96
97
98#define P_DB PORTF
99#define PIN_DB PINF
100#define DDR_DB DDRF
101
102#define P_ADL PORTA
103#define P_ADH PORTC
104#define P_ADB PORTE
105#define PIN_ADB PINE
9b6b4b31
L
106#define DDR_ADL DDRA
107#define DDR_ADH DDRC
0c5890bb
L
108#define DDR_ADB DDRE
109
110#define ADB_WIDTH 3
111#define ADB_SHIFT 2
112//#define ADB_PORT PORTE
113
114
41d36f28 115//#define Z80_O_ZCLK SBIT(P_ZCLK, 5)
0c5890bb
L
116#define Z80_O_MREQ SBIT(P_MREQ, 4)
117#define Z80_O_RD SBIT(P_RD, 3)
118#define Z80_O_WR SBIT(P_WR, 2)
119#define Z80_O_BUSREQ SBIT(P_BUSREQ, 7)
120//#define Z80_O_NMI SBIT(P_NMI, )
121#define Z80_O_RST SBIT(P_RST, 5)
9b6b4b31 122#define Z80_I_BUSACK SBIT(PIN_BUSACK, 6)
0c5890bb
L
123//#define Z80_I_HALT SBIT(P_HALT, )
124
9b6b4b31 125
ea6971b8
L
126#define BUS_TO 20
127
128
0c5890bb
L
129#define MASK(n) ((1<<(n))-1)
130#define SMASK(w,s) (MASK(w) << (s))
131
0c5890bb 132
eded7ec4
L
133typedef union {
134 uint32_t l;
135 uint16_t w[2];
136 uint8_t b[4];
137} addr_t;
f338df2a
L
138
139
140static zstate_t zstate;
ea6971b8
L
141static volatile uint8_t timer; /* used for bus timeout */
142
143/*---------------------------------------------------------*/
144/* 10Hz timer interrupt generated by OC4A */
145/*---------------------------------------------------------*/
146
147ISR(TIMER4_COMPA_vect)
148{
149
150 uint8_t i = timer;
151
152 if (i)
153 timer = i - 1;
154}
eded7ec4 155
0c5890bb
L
156/*--------------------------------------------------------------------------*/
157
6035a17b
L
158
159static void z80_addrbus_set_tristate(void)
0c5890bb 160{
9b6b4b31
L
161 /* /MREQ, /RD, /WR: Input, no pullup */
162 DDR_MREQ &= ~(_BV(MREQ) | _BV(RD) | _BV(WR));
163 Z80_O_MREQ = 0;
164 Z80_O_RD = 0;
165 Z80_O_WR = 0;
166
0c5890bb
L
167 P_ADL = 0;
168 DDR_ADL = 0;
169 P_ADH = 0;
170 DDR_ADH = 0;
9b6b4b31 171 PIN_ADB = P_ADB & ~(MASK(ADB_WIDTH) << ADB_SHIFT);
0c5890bb
L
172 DDR_ADB = DDR_ADB & ~(MASK(ADB_WIDTH) << ADB_SHIFT);
173}
174
54678798 175
6035a17b 176static void z80_addrbus_set_active(void)
0c5890bb 177{
9b6b4b31
L
178 /* /MREQ, /RD, /WR: Output and high */
179 Z80_O_MREQ = 1;
180 Z80_O_RD = 1;
181 Z80_O_WR = 1;
182 DDR_MREQ |= _BV(MREQ) | _BV(RD) | _BV(WR);
183
0c5890bb
L
184 DDR_ADL = 0xff;
185 DDR_ADH = 0xff;
186 DDR_ADB = DDR_ADB | (MASK(ADB_WIDTH) << ADB_SHIFT);
187}
188
189
6035a17b 190static void z80_dbus_set_in(void)
0c5890bb
L
191{
192 DDR_DB = 0;
193 P_DB = 0;
194}
195
62f624d3 196
6035a17b 197static void z80_dbus_set_out(void)
0c5890bb
L
198{
199 DDR_DB = 0xff;
200}
201
62f624d3
L
202
203static void z80_reset_pulse(void)
204{
205 Z80_O_RST = 0;
206 _delay_us(10);
207 Z80_O_RST = 1;
208}
209
210
0c5890bb
L
211void z80_setup_bus(void)
212{
9b6b4b31 213 /* /ZRESET: Output and low */
0c5890bb
L
214 Z80_O_RST = 0;
215 DDR_RST |= _BV(RST);
216
9b6b4b31 217 /* /BUSREQ: Output and high */
0c5890bb
L
218 Z80_O_BUSREQ = 1;
219 DDR_BUSREQ |= _BV(BUSREQ);
220
9b6b4b31 221 /* /BUSACK: Input, no pullup */
0c5890bb
L
222 DDR_BUSACK &= ~_BV(BUSACK);
223 P_BUSACK &= ~_BV(BUSACK);
224
9b6b4b31 225 /* /IOCS1: Input, no pullup */
0c5890bb
L
226 DDR_IOCS1 &= ~_BV(IOCS1);
227 P_IOCS1 &= ~_BV(IOCS1);
228
6035a17b
L
229 z80_addrbus_set_tristate();
230 z80_dbus_set_in();
72f58822 231
f338df2a 232 zstate = RESET;
ea6971b8
L
233
234 /* Timer 4 */
235 PRR1 &= ~_BV(PRTIM4);
236 OCR4A = F_CPU / 1024 / 10 - 1; /* Timer: 10Hz interval (OC4A) */
237 TCCR4B = (0b01<<WGM42)|(0b101<<CS30); /* CTC Mode, Prescaler 1024 */
238 TIMSK4 = _BV(OCIE4A); /* Enable oca interrupt */
239
0c5890bb
L
240}
241
f338df2a 242
62f624d3 243zstate_t z80_bus_state(void)
f338df2a
L
244{
245 return zstate;
246}
247
62f624d3
L
248
249static void z80_busreq_hpulse(void)
0c5890bb 250{
6035a17b
L
251 z80_dbus_set_in();
252 z80_addrbus_set_tristate();
72f58822 253
8a7decea 254 ATOMIC_BLOCK(ATOMIC_FORCEON) {
62f624d3
L
255 Z80_O_BUSREQ = 1;
256 Z80_O_BUSREQ = 1; /* 2 AVR clock cycles */
257 Z80_O_BUSREQ = 0; /* 2 AVR clock cycles */
f338df2a 258 }
72f58822 259
62f624d3 260 if (zstate & ZST_ACQUIRED) {
ea6971b8
L
261 timer = BUS_TO;
262 while (Z80_I_BUSACK == 1 && timer)
f338df2a 263 ;
ea6971b8
L
264 if (Z80_I_BUSACK == 0)
265 z80_addrbus_set_active();
f338df2a 266 }
f338df2a
L
267}
268
f338df2a
L
269
270/*
f338df2a 271
ea6971b8 272 + | | | | |
62f624d3 273 + State | RESET | RESET_AQRD | RUNNING | RUNNING_AQRD |
ea6971b8
L
274 + | | | | |
275 + | 0 | 1 | 2 | 3 |
276Event + | | | | |
62f624d3 277----------------+---------------+---------------+---------------+---------------+
ea6971b8
L
278 | | | | |
279Reset | 0 | 0 | 0 | 0 |
280 | | | | |
281 | | | | |
282Request | 1 | | 3 | |
283 | | | | |
284 | | | | |
285Release | | 0 | | 2 |
286 | | | | |
287 | | | | |
288Run | 2 | 3 | | |
289 | | | | |
290 | | | | |
291Restart | | | 2 | 3 |
292 | | | | |
293 | | | | |
294M_Cycle | | | | 3 |
295 | | | | |
296 | | | | |
62f624d3 297*/
f338df2a 298
62f624d3 299zstate_t z80_bus_cmd(bus_cmd_t cmd)
f338df2a 300{
62f624d3 301 switch (cmd) {
f338df2a 302
62f624d3 303 case Reset:
6035a17b
L
304 z80_dbus_set_in();
305 z80_addrbus_set_tristate();
f338df2a 306 Z80_O_RST = 0;
62f624d3
L
307 Z80_O_BUSREQ = 1;
308 zstate = RESET;
f338df2a
L
309 break;
310
62f624d3
L
311 case Request:
312 switch (zstate) {
313 case RESET:
314 Z80_O_BUSREQ = 0;
315 Z80_O_RST = 1;
ea6971b8
L
316 timer = BUS_TO;
317 while (Z80_I_BUSACK == 1 && timer)
62f624d3 318 ;
ea6971b8
L
319 if (Z80_I_BUSACK == 0) {
320 z80_addrbus_set_active();
321 zstate = RESET_AQRD;
322 } else {
323 Z80_O_RST = 0;
324 Z80_O_BUSREQ = 1;
325 }
62f624d3
L
326 break;
327
328 case RUNNING:
329 Z80_O_BUSREQ = 0;
ea6971b8
L
330 timer = BUS_TO;
331 while (Z80_I_BUSACK == 1 && timer)
62f624d3 332 ;
ea6971b8
L
333 if (Z80_I_BUSACK == 0) {
334 z80_addrbus_set_active();
335 zstate = RUNNING_AQRD;
336 } else {
337 Z80_O_BUSREQ = 1;
338 }
62f624d3
L
339 break;
340
341 default:
342 break;
343 }
f338df2a 344 break;
f338df2a 345
62f624d3
L
346 case Release:
347 switch (zstate) {
348 case RESET_AQRD:
6035a17b
L
349 z80_dbus_set_in();
350 z80_addrbus_set_tristate();
62f624d3
L
351 Z80_O_RST = 0;
352 Z80_O_BUSREQ = 1;
353 zstate = RESET;
354 break;
355 case RUNNING_AQRD:
6035a17b
L
356 z80_dbus_set_in();
357 z80_addrbus_set_tristate();
62f624d3
L
358 Z80_O_BUSREQ = 1;
359 zstate = RUNNING;
360 break;
361 default:
362 break;
363 }
364 break;
f338df2a 365
62f624d3
L
366 case Run:
367 switch (zstate) {
368 case RESET:
369 Z80_O_RST = 1;
370 zstate = RUNNING;
371 break;
372
373 case RESET_AQRD:
6035a17b
L
374 z80_dbus_set_in();
375 z80_addrbus_set_tristate();
62f624d3 376 z80_reset_pulse();
6035a17b 377 z80_addrbus_set_active();
62f624d3
L
378 zstate = RUNNING_AQRD;
379 break;
380 default:
381 break;
382 }
383 break;
f338df2a 384
62f624d3
L
385 case Restart:
386 switch (zstate) {
387 case RUNNING:
388 case RUNNING_AQRD:
389 z80_reset_pulse();
390 break;
391 default:
392 break;
393 }
394 break;
f338df2a 395
62f624d3
L
396 case M_Cycle:
397 switch (zstate) {
398 case RUNNING_AQRD:
ea6971b8 399 z80_busreq_hpulse(); /* TODO: */
62f624d3
L
400 break;
401 default:
402 break;
403 }
f338df2a 404 }
62f624d3 405 return zstate;
9b6b4b31
L
406}
407
62f624d3 408
9b6b4b31
L
409/*--------------------------------------------------------------------------*/
410
54678798 411static
9b6b4b31
L
412//inline __attribute__ ((always_inline))
413void z80_setaddress(uint32_t addr)
414{
415 addr_t x; x.l = addr;
416
417 P_ADL = x.b[0];
418 P_ADH = x.b[1];
419 PIN_ADB = ((x.b[2] << ADB_SHIFT) ^ P_ADB) & MASK(ADB_WIDTH) << ADB_SHIFT ;
0c5890bb
L
420}
421
422void z80_write(uint32_t addr, uint8_t data)
423{
424 z80_setaddress(addr);
425 Z80_O_MREQ = 0;
6035a17b 426 z80_dbus_set_out();
9b6b4b31
L
427 P_DB = data;
428 P_DB = data;
429 Z80_O_WR = 0;
0c5890bb
L
430 Z80_O_WR = 0;
431 Z80_O_WR = 1;
432 Z80_O_MREQ = 1;
433}
434
435uint8_t z80_read(uint32_t addr)
436{
437 uint8_t data;
438
439 z80_setaddress(addr);
440 Z80_O_MREQ = 0;
6035a17b 441 z80_dbus_set_in();
0c5890bb
L
442 Z80_O_RD = 0;
443 Z80_O_RD = 0;
9b6b4b31 444 Z80_O_RD = 0;
0c5890bb
L
445 data = PIN_DB;
446 Z80_O_RD = 1;
447 Z80_O_MREQ = 1;
448
449 return data;
450}
451
452
453void z80_memset(uint32_t addr, uint8_t data, uint32_t length)
454{
6035a17b 455 z80_dbus_set_out();
0c5890bb 456 Z80_O_MREQ = 0;
ea6971b8 457 P_DB = data;
0c5890bb
L
458 while(length--) {
459 z80_setaddress(addr++);
ea6971b8
L
460 Z80_O_WR = 0;
461 Z80_O_WR = 0;
462 Z80_O_WR = 1;
463 }
464 Z80_O_MREQ = 1;
465}
466
467void z80_write_block_P(const FLASH uint8_t *src, uint32_t dest, uint32_t length)
468{
469 uint8_t data;
470
471 z80_dbus_set_out();
472 Z80_O_MREQ = 0;
473 while(length--) {
474 z80_setaddress(dest++);
475 data = *src++;
0c5890bb 476 P_DB = data;
9b6b4b31
L
477 P_DB = data;
478 Z80_O_WR = 0;
0c5890bb
L
479 Z80_O_WR = 0;
480 Z80_O_WR = 1;
481 }
482 Z80_O_MREQ = 1;
483}
484
ea6971b8 485void z80_write_block(const uint8_t *src, uint32_t dest, uint32_t length)
0c5890bb
L
486{
487 uint8_t data;
54678798 488
6035a17b 489 z80_dbus_set_out();
0c5890bb
L
490 Z80_O_MREQ = 0;
491 while(length--) {
492 z80_setaddress(dest++);
493 data = *src++;
494 P_DB = data;
9b6b4b31
L
495 P_DB = data;
496 Z80_O_WR = 0;
0c5890bb
L
497 Z80_O_WR = 0;
498 Z80_O_WR = 1;
499 }
500 Z80_O_MREQ = 1;
501}
502
ea6971b8
L
503void z80_read_block (uint8_t *dest, uint32_t src, size_t length)
504{
505 uint8_t data;
506
507 Z80_O_MREQ = 0;
508 z80_dbus_set_in();
509 while(length--) {
510 z80_setaddress(src++);
511 Z80_O_RD = 0;
512 Z80_O_RD = 0;
513 Z80_O_RD = 0;
514 data = PIN_DB;
515 Z80_O_RD = 1;
516 *dest++ = data;
517 }
518 Z80_O_MREQ = 1;
519}
520
521
0c5890bb
L
522/*
523 0179' rx.bs_mask: ds 1 ; (buf_len - 1)
524 017A' rx.in_idx: ds 1 ;
525 017B' rx.out_idx: ds 1 ;
526 017C' rx.buf: ds rx.buf_len ;
527 018B' rx.buf_end equ $-1 ; last byte (start+len-1)
54678798 528
0c5890bb
L
529 018C' tx.bs_mask: ds 1 ; (buf_len - 1)
530 018D' tx.in_idx: ds 1 ;
531 018E' tx.out_idx: ds 1 ;
532 018F' tx.buf: ds tx.buf_len ;
533 019E' tx.buf_end equ $-1 ; last byte
534*/
535
536
537typedef struct __attribute__((packed)) {
538 uint8_t mask;
539 uint8_t in_idx;
540 uint8_t out_idx;
541 uint8_t buf[];
542} zfifo_t;
543
544
545
546#define FIFO_BUFSIZE_MASK -3
547#define FIFO_INDEX_IN -2
548#define FIFO_INDEX_OUT -1
549
550
551static struct {
552 uint32_t base;
553 uint8_t idx_out,
554 idx_in,
555 mask;
556 } fifo_dsc[NUM_FIFOS];
54678798 557
0c5890bb 558
8a7decea 559void z80_memfifo_init(const fifo_t f, uint32_t addr)
0c5890bb 560{
8a7decea 561 fifo_dsc[f].base = addr;
0c5890bb 562
8a7decea 563 if (addr != 0) {
0c5890bb 564
8a7decea 565DBG_P(2, "z80_memfifo_init: %i, %lx\n", f, addr);
0c5890bb 566
8a7decea
L
567 z80_bus_cmd(Request);
568 fifo_dsc[f].mask = z80_read(addr + FIFO_BUFSIZE_MASK);
569 fifo_dsc[f].idx_in = z80_read(addr + FIFO_INDEX_IN);
570 fifo_dsc[f].idx_out = z80_read(addr + FIFO_INDEX_OUT);
571 z80_bus_cmd(Release);
572 }
0c5890bb
L
573}
574
575
576int z80_memfifo_is_empty(const fifo_t f)
577{
578 int rc = 1;
579
89adce76 580 if (fifo_dsc[f].base != 0) {
0c5890bb
L
581
582 uint32_t adr = fifo_dsc[f].base + FIFO_INDEX_IN;
583 uint8_t idx;
584
62f624d3 585 z80_bus_cmd(Request);
0c5890bb 586 idx = z80_read(adr);
62f624d3 587 z80_bus_cmd(Release);
0c5890bb
L
588 rc = idx == fifo_dsc[f].idx_out;
589 }
590
591 return rc;
592}
593
594int z80_memfifo_is_full(const fifo_t f)
595{
ce47d431 596 int rc = 0;
54678798 597
0c5890bb 598 if (fifo_dsc[f].base != 0) {
62f624d3 599 z80_bus_cmd(Request);
0c5890bb
L
600 rc = ((fifo_dsc[f].idx_in + 1) & fifo_dsc[f].mask)
601 == z80_read(fifo_dsc[f].base+FIFO_INDEX_OUT);
62f624d3 602 z80_bus_cmd(Release);
0c5890bb
L
603 }
604 return rc;
605}
606
89adce76
L
607
608uint8_t z80_memfifo_getc_wait(const fifo_t f)
0c5890bb
L
609{
610 uint8_t rc, idx;
54678798 611
0c5890bb
L
612 while (z80_memfifo_is_empty(f))
613 ;
614
62f624d3 615 z80_bus_cmd(Request);
0c5890bb
L
616 idx = fifo_dsc[f].idx_out;
617 rc = z80_read(fifo_dsc[f].base+idx);
618 fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
619 z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
62f624d3 620 z80_bus_cmd(Release);
54678798 621
0c5890bb
L
622 return rc;
623}
624
89adce76
L
625int z80_memfifo_getc(const fifo_t f)
626{
627 int rc = -1;
628
629 if (fifo_dsc[f].base != 0) {
630 uint8_t idx = fifo_dsc[f].idx_out;
631 z80_bus_cmd(Request);
632 if (idx != z80_read(fifo_dsc[f].base + FIFO_INDEX_IN)) {
633 rc = z80_read(fifo_dsc[f].base+idx);
634 fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
635 z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
636 }
637 z80_bus_cmd(Release);
638 }
639
640 return rc;
641}
642
0c5890bb
L
643
644void z80_memfifo_putc(fifo_t f, uint8_t val)
645{
646 int idx;
54678798 647
0c5890bb
L
648 while (z80_memfifo_is_full(f))
649 ;
650
62f624d3 651 z80_bus_cmd(Request);
0c5890bb
L
652 idx = fifo_dsc[f].idx_in;
653 z80_write(fifo_dsc[f].base+idx, val);
654 fifo_dsc[f].idx_in = ++idx & fifo_dsc[f].mask;
655 z80_write(fifo_dsc[f].base+FIFO_INDEX_IN, fifo_dsc[f].idx_in);
62f624d3 656 z80_bus_cmd(Release);
0c5890bb 657}