]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/z80-if.c
z80_toggle_reset(), z80_toggle_busreq()
[z180-stamp.git] / avr / z80-if.c
CommitLineData
35edb766
L
1/*
2 * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
3 *
a1595a8e 4 * SPDX-License-Identifier: GPL-2.0
35edb766
L
5 */
6
0c5890bb
L
7/**
8 *
9 * Pin assignments
10 *
a1595a8e
L
11 * | Z180-Sig | AVR-Port | Dir |
12 * +------------+---------------+-------+
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 * |
47 * | Optional
48 * +------------------------------------+
49 * | STEP | PG 0 | O |
50 * | RUN | PG 1 | O |
51 * | WAIT | PG 2 | I |
0c5890bb 52
0c5890bb
L
53 */
54
ea6971b8 55
a1595a8e 56#include "z80-if.h"
f338df2a 57#include <util/atomic.h>
0c5890bb 58#include "debug.h"
a1595a8e
L
59#include "config.h"
60#include "env.h"
0c5890bb 61
0c5890bb 62
41d36f28
L
63//#define P_ZCLK PORTB
64//#define ZCLK 5
65//#define DDR_ZCLK DDRB
0c5890bb
L
66#define P_MREQ PORTD
67#define MREQ 4
68#define DDR_MREQ DDRD
69#define P_RD PORTD
70#define RD 3
71#define P_WR PORTD
72#define WR 2
73#define P_BUSREQ PORTD
74#define BUSREQ 7
3ec6fa48 75#define PIN_BUSREQ PIND
0c5890bb
L
76#define DDR_BUSREQ DDRD
77#define P_BUSACK PORTD
9b6b4b31 78#define PIN_BUSACK PIND
0c5890bb
L
79#define BUSACK 6
80#define DDR_BUSACK DDRD
0c5890bb 81#define P_RST PORTD
61bd408c 82#define PIN_RST PIND
0c5890bb
L
83#define DDR_RST DDRD
84#define RST 5
85
86
87#define P_DB PORTF
88#define PIN_DB PINF
89#define DDR_DB DDRF
90
91#define P_ADL PORTA
92#define P_ADH PORTC
93#define P_ADB PORTE
94#define PIN_ADB PINE
9b6b4b31
L
95#define DDR_ADL DDRA
96#define DDR_ADH DDRC
0c5890bb
L
97#define DDR_ADB DDRE
98
99#define ADB_WIDTH 3
100#define ADB_SHIFT 2
101//#define ADB_PORT PORTE
102
103
41d36f28 104//#define Z80_O_ZCLK SBIT(P_ZCLK, 5)
0c5890bb
L
105#define Z80_O_MREQ SBIT(P_MREQ, 4)
106#define Z80_O_RD SBIT(P_RD, 3)
107#define Z80_O_WR SBIT(P_WR, 2)
108#define Z80_O_BUSREQ SBIT(P_BUSREQ, 7)
3ec6fa48 109#define Z80_I_BUSREQ SBIT(PIN_BUSREQ, 7)
0c5890bb
L
110//#define Z80_O_NMI SBIT(P_NMI, )
111#define Z80_O_RST SBIT(P_RST, 5)
61bd408c 112#define Z80_I_RST SBIT(PIN_RST, 5)
9b6b4b31 113#define Z80_I_BUSACK SBIT(PIN_BUSACK, 6)
0c5890bb
L
114//#define Z80_I_HALT SBIT(P_HALT, )
115
a1595a8e
L
116/* Optional */
117#define P_RUN PORTG
118#define RUN 1
119#define DDR_RUN DDRG
120#define P_STEP PORTG
121#define STEP 0
122#define DDR_STEP DDRG
123#define P_WAIT PORTG
124#define WAIT 2
125#define DDR_WAIT DDRG
126/* All three signals are on the same Port (PortG) */
127#define PORT_SS PORTG
128#define DDR_SS DDRG
129#define PIN_SS PING
130#define Z80_O_RUN SBIT(PORT_SS, RUN)
131#define Z80_O_STEP SBIT(PORT_SS, STEP)
132#define Z80_I_WAIT SBIT(PORT_SS, WAIT)
133
9b6b4b31 134
ea6971b8
L
135#define BUS_TO 20
136
137
0c5890bb
L
138#define MASK(n) ((1<<(n))-1)
139#define SMASK(w,s) (MASK(w) << (s))
140
b35fcb2f
L
141void z80_bus_request_or_exit(void)
142{
143 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED))
144 cmd_error(CMD_RET_FAILURE, EBUSTO, NULL);
145}
0c5890bb 146
f338df2a 147static zstate_t zstate;
ea6971b8
L
148static volatile uint8_t timer; /* used for bus timeout */
149
d66348b4
L
150
151static volatile uint16_t busack_cycles_ovl;
152
153static uint32_t busack_cycles;
51dd0948
L
154
155ISR(TIMER4_COMPB_vect)
156{
d66348b4 157 busack_cycles_ovl++;
51dd0948 158}
51dd0948 159
ea6971b8 160/*---------------------------------------------------------*/
f66d9570 161/* 10Hz timer interrupt generated by OC5A */
ea6971b8
L
162/*---------------------------------------------------------*/
163
a1595a8e 164ISR(TIMER5_COMPA_vect)
ea6971b8
L
165{
166
167 uint8_t i = timer;
168
169 if (i)
170 timer = i - 1;
171}
eded7ec4 172
0c5890bb
L
173/*--------------------------------------------------------------------------*/
174
6035a17b 175
a1595a8e 176static void z80_addrbus_set_in(void)
0c5890bb 177{
9b6b4b31
L
178 /* /MREQ, /RD, /WR: Input, no pullup */
179 DDR_MREQ &= ~(_BV(MREQ) | _BV(RD) | _BV(WR));
180 Z80_O_MREQ = 0;
181 Z80_O_RD = 0;
182 Z80_O_WR = 0;
183
0c5890bb
L
184 P_ADL = 0;
185 DDR_ADL = 0;
186 P_ADH = 0;
187 DDR_ADH = 0;
6353e862 188 PIN_ADB = P_ADB & (MASK(ADB_WIDTH) << ADB_SHIFT);
0c5890bb
L
189 DDR_ADB = DDR_ADB & ~(MASK(ADB_WIDTH) << ADB_SHIFT);
190}
191
54678798 192
a1595a8e 193static void z80_addrbus_set_out(void)
0c5890bb 194{
9b6b4b31
L
195 /* /MREQ, /RD, /WR: Output and high */
196 Z80_O_MREQ = 1;
197 Z80_O_RD = 1;
198 Z80_O_WR = 1;
199 DDR_MREQ |= _BV(MREQ) | _BV(RD) | _BV(WR);
200
0c5890bb
L
201 DDR_ADL = 0xff;
202 DDR_ADH = 0xff;
203 DDR_ADB = DDR_ADB | (MASK(ADB_WIDTH) << ADB_SHIFT);
204}
205
206
6035a17b 207static void z80_dbus_set_in(void)
0c5890bb
L
208{
209 DDR_DB = 0;
210 P_DB = 0;
211}
212
62f624d3 213
6035a17b 214static void z80_dbus_set_out(void)
0c5890bb
L
215{
216 DDR_DB = 0xff;
217}
218
61bd408c
L
219static void z80_reset_active(void)
220{
7dda03f3 221 if (Stat & S_RESET_POLARITY)
61bd408c
L
222 Z80_O_RST = 1;
223 else
224 Z80_O_RST = 0;
225}
226
227static void z80_reset_inactive(void)
228{
7dda03f3 229 if (Stat & S_RESET_POLARITY)
61bd408c
L
230 Z80_O_RST = 0;
231 else
232 Z80_O_RST = 1;
233}
62f624d3
L
234
235static void z80_reset_pulse(void)
236{
61bd408c 237 z80_reset_active();
62f624d3 238 _delay_us(10);
61bd408c 239 z80_reset_inactive();
62f624d3
L
240}
241
242
0c5890bb
L
243void z80_setup_bus(void)
244{
a1595a8e
L
245 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
246
61bd408c
L
247 /* /ZRESET: Input, no pullup */
248 DDR_RST &= ~_BV(RST);
a1595a8e 249 Z80_O_RST = 0;
0c5890bb 250
a1595a8e
L
251 /* /BUSREQ: Output and high */
252 Z80_O_BUSREQ = 1;
253 DDR_BUSREQ |= _BV(BUSREQ);
0c5890bb 254
a1595a8e
L
255 /* /BUSACK: Input, no pullup */
256 DDR_BUSACK &= ~_BV(BUSACK);
257 P_BUSACK &= ~_BV(BUSACK);
0c5890bb 258
a1595a8e
L
259 z80_addrbus_set_in();
260 z80_dbus_set_in();
0c5890bb 261
a1595a8e
L
262 if (getenv_yesno(PSTR(ENV_SINGLESTEP))) {
263 /* /RUN & /STEP: output, /WAIT: input */
72f58822 264
a1595a8e
L
265 PORT_SS = (PORT_SS & ~_BV(RUN)) | _BV(STEP);
266 DDR_SS = (DDR_SS & ~_BV(WAIT)) | _BV(RUN) | _BV(STEP);
267 }
268
7dda03f3
L
269 if (Z80_I_RST)
270 Stat |= S_RESET_POLARITY;
271 else
272 Stat &= ~S_RESET_POLARITY;
61bd408c
L
273 z80_reset_active();
274 DDR_RST |= _BV(RST);
275
a1595a8e
L
276 zstate = RESET;
277 }
ea6971b8 278
a1595a8e
L
279 /* Timer 5 */
280 PRR1 &= ~_BV(PRTIM5);
281 OCR5A = F_CPU / 1024 / 10 - 1; /* Timer: 10Hz interval (OC4A) */
282 TCCR5B = (0b01<<WGM52)|(0b101<<CS40); /* CTC Mode, Prescaler 1024 */
283 TIMSK5 = _BV(OCIE5A); /* Enable oca interrupt */
ea6971b8 284
0c5890bb
L
285}
286
f338df2a 287
d66348b4
L
288uint32_t z80_get_busreq_cycles(void)
289{
290 return busack_cycles;
291}
292
62f624d3 293zstate_t z80_bus_state(void)
f338df2a
L
294{
295 return zstate;
296}
297
3ec6fa48
L
298void z80_toggle_reset(void)
299{
300 Z80_I_RST = 1;
301}
302
303void z80_toggle_busreq(void)
304{
305 Z80_I_BUSREQ = 1;
306}
307
62f624d3
L
308
309static void z80_busreq_hpulse(void)
0c5890bb 310{
6035a17b 311 z80_dbus_set_in();
a1595a8e 312 z80_addrbus_set_in();
72f58822 313
a1595a8e 314#if 0
8a7decea 315 ATOMIC_BLOCK(ATOMIC_FORCEON) {
62f624d3
L
316 Z80_O_BUSREQ = 1;
317 Z80_O_BUSREQ = 1; /* 2 AVR clock cycles */
318 Z80_O_BUSREQ = 0; /* 2 AVR clock cycles */
f338df2a 319 }
a1595a8e
L
320#endif
321
4b0604a4 322#if 1
a1595a8e
L
323 ATOMIC_BLOCK(ATOMIC_FORCEON) {
324 Z80_O_BUSREQ = 1;
325
326 do {
327 if (Z80_I_BUSACK == 1) {
328 Z80_O_BUSREQ = 0;
329 break;
330 }
331 } while (1);
332 }
4b0604a4 333#endif
72f58822 334
62f624d3 335 if (zstate & ZST_ACQUIRED) {
ea6971b8
L
336 timer = BUS_TO;
337 while (Z80_I_BUSACK == 1 && timer)
f338df2a 338 ;
ea6971b8 339 if (Z80_I_BUSACK == 0)
a1595a8e 340 z80_addrbus_set_out();
f338df2a 341 }
f338df2a
L
342}
343
f338df2a
L
344
345/*
f338df2a 346
ea6971b8 347 + | | | | |
62f624d3 348 + State | RESET | RESET_AQRD | RUNNING | RUNNING_AQRD |
ea6971b8
L
349 + | | | | |
350 + | 0 | 1 | 2 | 3 |
351Event + | | | | |
62f624d3 352----------------+---------------+---------------+---------------+---------------+
ea6971b8
L
353 | | | | |
354Reset | 0 | 0 | 0 | 0 |
355 | | | | |
356 | | | | |
357Request | 1 | | 3 | |
358 | | | | |
359 | | | | |
360Release | | 0 | | 2 |
361 | | | | |
362 | | | | |
363Run | 2 | 3 | | |
364 | | | | |
365 | | | | |
366Restart | | | 2 | 3 |
367 | | | | |
368 | | | | |
369M_Cycle | | | | 3 |
370 | | | | |
371 | | | | |
62f624d3 372*/
f338df2a 373
62f624d3 374zstate_t z80_bus_cmd(bus_cmd_t cmd)
f338df2a 375{
62f624d3 376 switch (cmd) {
f338df2a 377
62f624d3 378 case Reset:
6035a17b 379 z80_dbus_set_in();
a1595a8e 380 z80_addrbus_set_in();
61bd408c 381 z80_reset_active();
51dd0948 382 _delay_us(10);
62f624d3 383 Z80_O_BUSREQ = 1;
f66d9570
L
384 timer = BUS_TO;
385 while (Z80_I_BUSACK == 0 && timer)
386 ;
62f624d3 387 zstate = RESET;
f338df2a
L
388 break;
389
62f624d3
L
390 case Request:
391 switch (zstate) {
392 case RESET:
393 Z80_O_BUSREQ = 0;
d66348b4
L
394 timer = 255; //BUS_TO;
395
396 uint16_t tcnt;
397 uint16_t ovl_cnt;
398 uint8_t ifr;
399 busack_cycles = 0;
400 busack_cycles_ovl = 0;
401 ATOMIC_BLOCK(ATOMIC_FORCEON) {
402 //z80_reset_inactive();
403 Z80_I_RST = 1; /* Toggle RESET --> inactive */
404 OCR4B = TCNT4;
405 TIFR4 = _BV(OCF4B); /* Clear compare match flag */
406 }
407 TIMSK4 |= _BV(OCIE4B); /* Enable compare match interrupt */
408
ea6971b8 409 while (Z80_I_BUSACK == 1 && timer)
62f624d3 410 ;
d66348b4
L
411
412 ATOMIC_BLOCK(ATOMIC_FORCEON) {
413 tcnt = TCNT4 - OCR4B;
414 ovl_cnt = busack_cycles_ovl;
415 ifr = TIFR4;
416 TIMSK4 &= ~_BV(OCIE4B); /* Disable compare match interrupt */
417 }
ea6971b8 418 if (Z80_I_BUSACK == 0) {
d66348b4
L
419 if ((ifr & _BV(OCF4B)) && !(tcnt & (1<<15)))
420 ovl_cnt++;
421 busack_cycles = tcnt + ((uint32_t) ovl_cnt << 16);
a1595a8e 422 z80_addrbus_set_out();
ea6971b8 423 zstate = RESET_AQRD;
d66348b4
L
424// debug("### ovl: %u, ifr: %u, beg: %u, end: %u\n", ovl_cnt,
425// (ifr & _BV(OCF4B)) != 0, OCR4B, tcnt);
ea6971b8 426 } else {
61bd408c 427 z80_reset_active();
ea6971b8
L
428 Z80_O_BUSREQ = 1;
429 }
62f624d3
L
430 break;
431
432 case RUNNING:
433 Z80_O_BUSREQ = 0;
ea6971b8
L
434 timer = BUS_TO;
435 while (Z80_I_BUSACK == 1 && timer)
62f624d3 436 ;
ea6971b8 437 if (Z80_I_BUSACK == 0) {
a1595a8e 438 z80_addrbus_set_out();
ea6971b8
L
439 zstate = RUNNING_AQRD;
440 } else {
441 Z80_O_BUSREQ = 1;
442 }
62f624d3
L
443 break;
444
445 default:
446 break;
447 }
f338df2a 448 break;
f338df2a 449
62f624d3
L
450 case Release:
451 switch (zstate) {
452 case RESET_AQRD:
6035a17b 453 z80_dbus_set_in();
a1595a8e 454 z80_addrbus_set_in();
61bd408c 455 z80_reset_active();
51dd0948 456 _delay_us(10);
62f624d3 457 Z80_O_BUSREQ = 1;
f66d9570
L
458 timer = BUS_TO;
459 while (Z80_I_BUSACK == 0 && timer)
460 ;
62f624d3
L
461 zstate = RESET;
462 break;
463 case RUNNING_AQRD:
6035a17b 464 z80_dbus_set_in();
a1595a8e 465 z80_addrbus_set_in();
62f624d3 466 Z80_O_BUSREQ = 1;
f66d9570
L
467 timer = BUS_TO;
468 while (Z80_I_BUSACK == 0 && timer)
469 ;
62f624d3
L
470 zstate = RUNNING;
471 break;
472 default:
473 break;
474 }
475 break;
f338df2a 476
62f624d3
L
477 case Run:
478 switch (zstate) {
479 case RESET:
f66d9570 480 _delay_ms(20); /* TODO: */
61bd408c 481 z80_reset_inactive();
62f624d3
L
482 zstate = RUNNING;
483 break;
484
485 case RESET_AQRD:
6035a17b 486 z80_dbus_set_in();
a1595a8e 487 z80_addrbus_set_in();
62f624d3 488 z80_reset_pulse();
a1595a8e 489 z80_addrbus_set_out();
62f624d3
L
490 zstate = RUNNING_AQRD;
491 break;
492 default:
493 break;
494 }
495 break;
f338df2a 496
62f624d3
L
497 case Restart:
498 switch (zstate) {
499 case RUNNING:
500 case RUNNING_AQRD:
501 z80_reset_pulse();
502 break;
503 default:
504 break;
505 }
506 break;
f338df2a 507
62f624d3
L
508 case M_Cycle:
509 switch (zstate) {
510 case RUNNING_AQRD:
ea6971b8 511 z80_busreq_hpulse(); /* TODO: */
62f624d3
L
512 break;
513 default:
514 break;
515 }
f338df2a 516 }
62f624d3 517 return zstate;
9b6b4b31
L
518}
519
62f624d3 520
9b6b4b31
L
521/*--------------------------------------------------------------------------*/
522
54678798 523static
9b6b4b31
L
524//inline __attribute__ ((always_inline))
525void z80_setaddress(uint32_t addr)
526{
a1595a8e
L
527 P_ADL = addr;
528 P_ADH = (addr & 0xff00) >> 8;
529 PIN_ADB = (((addr >> 16) << ADB_SHIFT) ^ P_ADB) & MASK(ADB_WIDTH) << ADB_SHIFT;
0c5890bb
L
530}
531
1e5609bf
L
532int32_t z80_memsize_detect(void)
533{
534 const uint8_t PATTERN_1 = 0x55;
535 const uint8_t PATTERN_2 = ~PATTERN_1;
536 uint32_t addr;
537
538 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED))
539 return -EBUSTO;
540
541 uint8_t ram_0 = z80_read(0);
542 uint8_t ram_1 = z80_read(1);
543
544 z80_write(0, ram_0 ^ 0xff);
545 z80_write(1, ram_1);
546 if ((z80_read(0) ^ ram_0) != 0xff) {
547 addr = 0;
548 } else {
549 z80_write(0, PATTERN_1);
550 for (addr=1; addr < CONFIG_SYS_RAMSIZE_MAX; addr <<= 1) {
551 uint8_t ram_i = z80_read(addr);
552 z80_write(addr, PATTERN_2);
553 if (z80_read(0) != PATTERN_1 || z80_read(addr) != PATTERN_2)
554 break;
555 z80_write(addr, ram_i);
556 }
557 }
558
559 z80_write(0, ram_0);
560 z80_bus_cmd(Release);
561
562 return addr;
563}
564
226d3221
L
565/*--------------------------------------------------------------------------*/
566
0c5890bb
L
567void z80_write(uint32_t addr, uint8_t data)
568{
569 z80_setaddress(addr);
570 Z80_O_MREQ = 0;
6035a17b 571 z80_dbus_set_out();
9b6b4b31
L
572 P_DB = data;
573 P_DB = data;
574 Z80_O_WR = 0;
0c5890bb
L
575 Z80_O_WR = 0;
576 Z80_O_WR = 1;
577 Z80_O_MREQ = 1;
578}
579
580uint8_t z80_read(uint32_t addr)
581{
582 uint8_t data;
583
584 z80_setaddress(addr);
585 Z80_O_MREQ = 0;
6035a17b 586 z80_dbus_set_in();
0c5890bb
L
587 Z80_O_RD = 0;
588 Z80_O_RD = 0;
9b6b4b31 589 Z80_O_RD = 0;
0c5890bb
L
590 data = PIN_DB;
591 Z80_O_RD = 1;
592 Z80_O_MREQ = 1;
593
594 return data;
595}
596
597
598void z80_memset(uint32_t addr, uint8_t data, uint32_t length)
599{
6035a17b 600 z80_dbus_set_out();
0c5890bb 601 Z80_O_MREQ = 0;
ea6971b8 602 P_DB = data;
0c5890bb
L
603 while(length--) {
604 z80_setaddress(addr++);
ea6971b8
L
605 Z80_O_WR = 0;
606 Z80_O_WR = 0;
607 Z80_O_WR = 1;
608 }
609 Z80_O_MREQ = 1;
610}
611
612void z80_write_block_P(const FLASH uint8_t *src, uint32_t dest, uint32_t length)
613{
614 uint8_t data;
615
616 z80_dbus_set_out();
617 Z80_O_MREQ = 0;
618 while(length--) {
619 z80_setaddress(dest++);
620 data = *src++;
0c5890bb 621 P_DB = data;
9b6b4b31
L
622 P_DB = data;
623 Z80_O_WR = 0;
0c5890bb
L
624 Z80_O_WR = 0;
625 Z80_O_WR = 1;
626 }
627 Z80_O_MREQ = 1;
628}
629
ea6971b8 630void z80_write_block(const uint8_t *src, uint32_t dest, uint32_t length)
0c5890bb
L
631{
632 uint8_t data;
54678798 633
6035a17b 634 z80_dbus_set_out();
0c5890bb
L
635 Z80_O_MREQ = 0;
636 while(length--) {
637 z80_setaddress(dest++);
638 data = *src++;
639 P_DB = data;
9b6b4b31
L
640 P_DB = data;
641 Z80_O_WR = 0;
0c5890bb
L
642 Z80_O_WR = 0;
643 Z80_O_WR = 1;
644 }
645 Z80_O_MREQ = 1;
646}
647
ea6971b8
L
648void z80_read_block (uint8_t *dest, uint32_t src, size_t length)
649{
650 uint8_t data;
651
652 Z80_O_MREQ = 0;
653 z80_dbus_set_in();
654 while(length--) {
655 z80_setaddress(src++);
656 Z80_O_RD = 0;
657 Z80_O_RD = 0;
658 Z80_O_RD = 0;
659 data = PIN_DB;
660 Z80_O_RD = 1;
661 *dest++ = data;
662 }
663 Z80_O_MREQ = 1;
664}
665
226d3221 666/*--------------------------------------------------------------------------*/
ea6971b8 667
0c5890bb
L
668/*
669 0179' rx.bs_mask: ds 1 ; (buf_len - 1)
670 017A' rx.in_idx: ds 1 ;
671 017B' rx.out_idx: ds 1 ;
672 017C' rx.buf: ds rx.buf_len ;
673 018B' rx.buf_end equ $-1 ; last byte (start+len-1)
54678798 674
0c5890bb
L
675 018C' tx.bs_mask: ds 1 ; (buf_len - 1)
676 018D' tx.in_idx: ds 1 ;
677 018E' tx.out_idx: ds 1 ;
678 018F' tx.buf: ds tx.buf_len ;
679 019E' tx.buf_end equ $-1 ; last byte
680*/
681
682
683typedef struct __attribute__((packed)) {
684 uint8_t mask;
685 uint8_t in_idx;
686 uint8_t out_idx;
687 uint8_t buf[];
688} zfifo_t;
689
690
691
692#define FIFO_BUFSIZE_MASK -3
693#define FIFO_INDEX_IN -2
694#define FIFO_INDEX_OUT -1
695
696
697static struct {
698 uint32_t base;
699 uint8_t idx_out,
700 idx_in,
701 mask;
702 } fifo_dsc[NUM_FIFOS];
54678798 703
0c5890bb 704
8a7decea 705void z80_memfifo_init(const fifo_t f, uint32_t addr)
0c5890bb 706{
8a7decea 707 fifo_dsc[f].base = addr;
0c5890bb 708
0c5890bb 709
bbd45c46 710 if (addr != 0) {
8a7decea
L
711 z80_bus_cmd(Request);
712 fifo_dsc[f].mask = z80_read(addr + FIFO_BUFSIZE_MASK);
713 fifo_dsc[f].idx_in = z80_read(addr + FIFO_INDEX_IN);
714 fifo_dsc[f].idx_out = z80_read(addr + FIFO_INDEX_OUT);
715 z80_bus_cmd(Release);
910e7206
L
716
717 if (fifo_dsc[f].idx_in != 0 || fifo_dsc[f].idx_out != 0) {
718 DBG_P(1, "## z80_memfifo_init: %i, %lx, in: %.2x, out: %.2x, mask: %.2x\n",
719 f, addr, fifo_dsc[f].idx_in, fifo_dsc[f].idx_out, fifo_dsc[f].mask);
720 }
8a7decea 721 }
0c5890bb
L
722}
723
724
725int z80_memfifo_is_empty(const fifo_t f)
726{
727 int rc = 1;
728
89adce76 729 if (fifo_dsc[f].base != 0) {
0c5890bb
L
730
731 uint32_t adr = fifo_dsc[f].base + FIFO_INDEX_IN;
732 uint8_t idx;
733
62f624d3 734 z80_bus_cmd(Request);
0c5890bb 735 idx = z80_read(adr);
62f624d3 736 z80_bus_cmd(Release);
0c5890bb
L
737 rc = idx == fifo_dsc[f].idx_out;
738 }
739
740 return rc;
741}
742
743int z80_memfifo_is_full(const fifo_t f)
744{
ce47d431 745 int rc = 0;
54678798 746
0c5890bb 747 if (fifo_dsc[f].base != 0) {
62f624d3 748 z80_bus_cmd(Request);
0c5890bb
L
749 rc = ((fifo_dsc[f].idx_in + 1) & fifo_dsc[f].mask)
750 == z80_read(fifo_dsc[f].base+FIFO_INDEX_OUT);
62f624d3 751 z80_bus_cmd(Release);
0c5890bb
L
752 }
753 return rc;
754}
755
89adce76
L
756
757uint8_t z80_memfifo_getc_wait(const fifo_t f)
0c5890bb
L
758{
759 uint8_t rc, idx;
54678798 760
0c5890bb
L
761 while (z80_memfifo_is_empty(f))
762 ;
763
62f624d3 764 z80_bus_cmd(Request);
0c5890bb
L
765 idx = fifo_dsc[f].idx_out;
766 rc = z80_read(fifo_dsc[f].base+idx);
767 fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
768 z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
62f624d3 769 z80_bus_cmd(Release);
54678798 770
0c5890bb
L
771 return rc;
772}
773
89adce76
L
774int z80_memfifo_getc(const fifo_t f)
775{
776 int rc = -1;
777
778 if (fifo_dsc[f].base != 0) {
779 uint8_t idx = fifo_dsc[f].idx_out;
780 z80_bus_cmd(Request);
781 if (idx != z80_read(fifo_dsc[f].base + FIFO_INDEX_IN)) {
782 rc = z80_read(fifo_dsc[f].base+idx);
783 fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
784 z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
785 }
786 z80_bus_cmd(Release);
787 }
788
789 return rc;
790}
791
0c5890bb
L
792
793void z80_memfifo_putc(fifo_t f, uint8_t val)
794{
795 int idx;
54678798 796
0c5890bb
L
797 while (z80_memfifo_is_full(f))
798 ;
799
62f624d3 800 z80_bus_cmd(Request);
0c5890bb
L
801 idx = fifo_dsc[f].idx_in;
802 z80_write(fifo_dsc[f].base+idx, val);
803 fifo_dsc[f].idx_in = ++idx & fifo_dsc[f].mask;
804 z80_write(fifo_dsc[f].base+FIFO_INDEX_IN, fifo_dsc[f].idx_in);
62f624d3 805 z80_bus_cmd(Release);
0c5890bb 806}
226d3221
L
807
808/*--------------------------------------------------------------------------*/
809
810void z80_load_mem(int_fast8_t verbosity,
811 const FLASH unsigned char data[],
812 const FLASH unsigned long *sections,
813 const FLASH unsigned long address[],
814 const FLASH unsigned long length_of_sections[])
815{
816 uint32_t sec_base = 0;
817
818 if (verbosity > 1)
819 printf_P(PSTR("Loading Z180 memory... \n"));
820
821 for (unsigned sec = 0; sec < *sections; sec++) {
822 if (verbosity > 0) {
823 printf_P(PSTR(" From: 0x%.5lX to: 0x%.5lX (%5li bytes)\n"),
824 address[sec],
825 address[sec]+length_of_sections[sec] - 1,
826 length_of_sections[sec]);
827 }
828
829 z80_write_block_P((const FLASH unsigned char *) &data[sec_base], /* src */
830 address[sec], /* dest */
831 length_of_sections[sec]); /* len */
832 sec_base += length_of_sections[sec];
833 }
834}