+
+static void z80_busreq_hpulse(void)
+{
+ z80_dbus_set_in();
+ z80_addrbus_set_in();
+
+#if 0
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ Z80_O_BUSREQ = 1;
+ Z80_O_BUSREQ = 1; /* 2 AVR clock cycles */
+ Z80_O_BUSREQ = 0; /* 2 AVR clock cycles */
+ }
+#endif
+
+#if 1
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ Z80_O_BUSREQ = 1;
+
+ do {
+ if (Z80_I_BUSACK == 1) {
+ Z80_O_BUSREQ = 0;
+ break;
+ }
+ } while (1);
+ }
+#endif
+
+ if (zstate & ZST_ACQUIRED) {
+ timer = BUS_TO;
+ while (Z80_I_BUSACK == 1 && timer)
+ ;
+ if (Z80_I_BUSACK == 0)
+ z80_addrbus_set_out();
+ }
+}
+
+
+/*
+
+ + | | | | |
+ + State | RESET | RESET_AQRD | RUNNING | RUNNING_AQRD |
+ + | | | | |
+ + | 0 | 1 | 2 | 3 |
+Event + | | | | |
+----------------+---------------+---------------+---------------+---------------+
+ | | | | |
+Reset | 0 | 0 | 0 | 0 |
+ | | | | |
+ | | | | |
+Request | 1 | | 3 | |
+ | | | | |
+ | | | | |
+Release | | 0 | | 2 |
+ | | | | |
+ | | | | |
+Run | 2 | 3 | | |
+ | | | | |
+ | | | | |
+Restart | | | 2 | 3 |
+ | | | | |
+ | | | | |
+M_Cycle | | | | 3 |
+ | | | | |
+ | | | | |
+*/
+
+zstate_t z80_bus_cmd(bus_cmd_t cmd)
+{
+ switch (cmd) {
+
+ case Reset:
+ z80_dbus_set_in();
+ z80_addrbus_set_in();
+ z80_reset_active();
+ _delay_us(10);
+ Z80_O_BUSREQ = 1;
+ timer = BUS_TO;
+ while (Z80_I_BUSACK == 0 && timer)
+ ;
+ zstate = RESET;
+ break;
+
+ case Request:
+ switch (zstate) {
+ case RESET:
+ Z80_O_BUSREQ = 0;
+ timer = 255; //BUS_TO;
+
+ uint16_t tcnt;
+ uint16_t ovl_cnt;
+ uint8_t ifr;
+ busack_cycles = 0;
+ busack_cycles_ovl = 0;
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ //z80_reset_inactive();
+ Z80_I_RST = 1; /* Toggle RESET --> inactive */
+ OCR4B = TCNT4;
+ TIFR4 = _BV(OCF4B); /* Clear compare match flag */
+ }
+ TIMSK4 |= _BV(OCIE4B); /* Enable compare match interrupt */
+
+ while (Z80_I_BUSACK == 1 && timer)
+ ;
+
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ tcnt = TCNT4 - OCR4B;
+ ovl_cnt = busack_cycles_ovl;
+ ifr = TIFR4;
+ TIMSK4 &= ~_BV(OCIE4B); /* Disable compare match interrupt */
+ }
+ if (Z80_I_BUSACK == 0) {
+ if ((ifr & _BV(OCF4B)) && !(tcnt & (1<<15)))
+ ovl_cnt++;
+ busack_cycles = tcnt + ((uint32_t) ovl_cnt << 16);
+ z80_addrbus_set_out();
+ zstate = RESET_AQRD;
+// debug("### ovl: %u, ifr: %u, beg: %u, end: %u\n", ovl_cnt,
+// (ifr & _BV(OCF4B)) != 0, OCR4B, tcnt);
+ } else {
+ z80_reset_active();
+ Z80_O_BUSREQ = 1;
+ }
+ break;
+
+ case RUNNING:
+ Z80_O_BUSREQ = 0;
+ timer = BUS_TO;
+ while (Z80_I_BUSACK == 1 && timer)
+ ;
+ if (Z80_I_BUSACK == 0) {
+ z80_addrbus_set_out();
+ zstate = RUNNING_AQRD;
+ } else {
+ Z80_O_BUSREQ = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case Release:
+ switch (zstate) {
+ case RESET_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_in();
+ z80_reset_active();
+ _delay_us(10);
+ Z80_O_BUSREQ = 1;
+ timer = BUS_TO;
+ while (Z80_I_BUSACK == 0 && timer)
+ ;
+ zstate = RESET;
+ break;
+ case RUNNING_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_in();
+ Z80_O_BUSREQ = 1;
+ timer = BUS_TO;
+ while (Z80_I_BUSACK == 0 && timer)
+ ;
+ zstate = RUNNING;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case Run:
+ switch (zstate) {
+ case RESET:
+ _delay_ms(20); /* TODO: */
+ z80_reset_inactive();
+ zstate = RUNNING;
+ break;
+
+ case RESET_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_in();
+ z80_reset_pulse();
+ z80_addrbus_set_out();
+ zstate = RUNNING_AQRD;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case Restart:
+ switch (zstate) {
+ case RUNNING:
+ case RUNNING_AQRD:
+ z80_reset_pulse();
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case M_Cycle:
+ switch (zstate) {
+ case RUNNING_AQRD:
+ z80_busreq_hpulse(); /* TODO: */
+ break;
+ default:
+ break;
+ }
+ }
+ return zstate;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+static
+//inline __attribute__ ((always_inline))
+void z80_setaddress(uint32_t addr)
+{
+ P_ADL = addr;
+ P_ADH = (addr & 0xff00) >> 8;
+ PIN_ADB = (((addr >> 16) << ADB_SHIFT) ^ P_ADB) & MASK(ADB_WIDTH) << ADB_SHIFT;
+}
+
+int32_t z80_memsize_detect(void)
+{
+ const uint8_t PATTERN_1 = 0x55;
+ const uint8_t PATTERN_2 = ~PATTERN_1;
+ uint32_t addr;
+
+ if (!(z80_bus_cmd(Request) & ZST_ACQUIRED))
+ return -EBUSTO;
+
+ uint8_t ram_0 = z80_read(0);
+ uint8_t ram_1 = z80_read(1);
+
+ z80_write(0, ram_0 ^ 0xff);
+ z80_write(1, ram_1);
+ if ((z80_read(0) ^ ram_0) != 0xff) {
+ addr = 0;
+ } else {
+ z80_write(0, PATTERN_1);
+ for (addr=1; addr < CONFIG_SYS_RAMSIZE_MAX; addr <<= 1) {
+ uint8_t ram_i = z80_read(addr);
+ z80_write(addr, PATTERN_2);
+ if (z80_read(0) != PATTERN_1 || z80_read(addr) != PATTERN_2)
+ break;
+ z80_write(addr, ram_i);
+ }
+ }
+
+ z80_write(0, ram_0);
+ z80_bus_cmd(Release);
+
+ return addr;
+}
+
+/*--------------------------------------------------------------------------*/
+