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