#include <avr/io.h>
#include <util/delay.h>
+#include <util/atomic.h>
#include <stdio.h>
#include "debug.h"
#include "z80-if.h"
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
-
+#define P_ZCLK PORTB
+#define ZCLK 7
+#define DDR_ZCLK DDRB
#define P_MREQ PORTD
#define MREQ 4
#define DDR_MREQ DDRD
//#define ADB_PORT PORTE
+#define Z80_O_ZCLK SBIT(P_ZCLK, 7)
#define Z80_O_MREQ SBIT(P_MREQ, 4)
#define Z80_O_RD SBIT(P_RD, 3)
#define Z80_O_WR SBIT(P_WR, 2)
//#define Z80_I_HALT SBIT(P_HALT, )
-#if 0
-void z80_busreq(level_t level)
-{
- Z80_O_BUSREQ = level;
-}
-#endif
+#define MASK(n) ((1<<(n))-1)
+#define SMASK(w,s) (MASK(w) << (s))
-void z80_reset(level_t level)
-{
- Z80_O_RST = level;
- if (level)
- Stat |= S_Z180_RUNNING;
- else
- Stat &= ~S_Z180_RUNNING;
-}
-void z80_reset_pulse(void)
+typedef union {
+ uint32_t l;
+ uint16_t w[2];
+ uint8_t b[4];
+} addr_t;
+
+
+static zstate_t zstate;
+
+/*--------------------------------------------------------------------------*/
+
+static
+void z80_setup_clock(void)
{
- Z80_O_RST = 0;
- _delay_us(10);
- Z80_O_RST = 1;
- Stat |= S_Z180_RUNNING;
+ /* ZCLK: Output and low */
+ DDR_ZCLK |= _BV(ZCLK);
+ Z80_O_ZCLK = 0;
+
+ DDRB |= _BV(6); /* Debug */
+ PORTB |= _BV(6); /* Debug */
+
+ PRR0 &= ~_BV(PRTIM1);
+
+ /* Timer1: CTC: Toggle OC1C on compare match */
+ OCR1A = 0;
+ OCR1C = 0;
+ TCCR1A = (0b01 << COM1C0) | (0b00 << WGM10);
+ TCCR1B = (0b01 << WGM12) | (0b001 << CS10);
}
-#if 0
-int z80_stat_halt(void)
+
+int z80_clock_set(unsigned long freq)
{
- return Z80_I_HALT;
-}
-#endif
+ unsigned long ocrval = F_CPU / freq / 2;
+ uint8_t prescale = 0;
+
+ while (ocrval > (1L<<16)) {
+ prescale++;
+ if (prescale < 3)
+ ocrval = ocrval / 8;
+ else
+ ocrval = ocrval / 4;
+ }
+ if ((ocrval == 0) || (prescale > 4))
+ return -1;
-#define MASK(n) ((1<<(n))-1)
-#define SMASK(w,s) (MASK(w) << (s))
+ ocrval -= 1;
+ PINB |= _BV(6); /* Debug */
+ /* Stop Timer */
+ TCCR1B = (0b01 << WGM12) | (0b000 << CS10);
+ TCNT1 = 0;
-typedef union {
- uint32_t l;
- uint16_t w[2];
- uint8_t b[4];
-} addr_t;
-
+ OCR1A = ocrval;
+ OCR1CL = ocrval;
+ TCCR1A = (0b01 << COM1C0) | (0b00 << WGM10);
+ TCCR1B = (0b01 << WGM12) | ((prescale+1) << CS10);
-/*--------------------------------------------------------------------------*/
+ if (ocrval == 0) {
+// TCCR1C |= _BV(FOC1C);
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ TCNT1 = 0xFFFF;
+ }
+ }
+
+ PINB |= _BV(6); /* Debug */
+
+ return 0;
+}
+
+uint32_t z80_clock_get(void)
+{
+ uint32_t count = (OCR1A + 1L) * 2;
+ uint8_t pre = (TCCR1B & 7) - 1;
+
+ while (pre) {
+ if (pre > 2)
+ count *= 4;
+ else
+ count *= 8;
+ pre--;
+ }
+
+ return F_CPU/count;
+}
-static void z80_setup_addrbus_tristate(void)
+
+
+static void z80_addrbus_set_tristate(void)
{
/* /MREQ, /RD, /WR: Input, no pullup */
DDR_MREQ &= ~(_BV(MREQ) | _BV(RD) | _BV(WR));
DDR_ADB = DDR_ADB & ~(MASK(ADB_WIDTH) << ADB_SHIFT);
}
-
-static void z80_setup_addrbus_active(void)
+
+static void z80_addrbus_set_active(void)
{
/* /MREQ, /RD, /WR: Output and high */
Z80_O_MREQ = 1;
}
-
-static void z80_setup_dbus_in(void)
+static void z80_dbus_set_in(void)
{
DDR_DB = 0;
P_DB = 0;
}
-static void z80_setup_dbus_out(void)
+
+static void z80_dbus_set_out(void)
{
DDR_DB = 0xff;
}
+
+static void z80_reset_pulse(void)
+{
+ Z80_O_RST = 0;
+ _delay_us(10);
+ Z80_O_RST = 1;
+}
+
+
void z80_setup_bus(void)
{
+ z80_setup_clock();
+
/* /ZRESET: Output and low */
Z80_O_RST = 0;
DDR_RST |= _BV(RST);
DDR_IOCS1 &= ~_BV(IOCS1);
P_IOCS1 &= ~_BV(IOCS1);
- z80_setup_addrbus_tristate();
- z80_setup_dbus_in();
+ z80_addrbus_set_tristate();
+ z80_dbus_set_in();
- Stat &= ~S_Z180_RUNNING;
+ zstate = RESET;
}
-/*--------------------------------------------------------------------------*/
-void z80_request_bus(void)
+zstate_t z80_bus_state(void)
{
- Z80_O_BUSREQ = 0;
+ return zstate;
+}
+
- if (!(Stat & S_Z180_RUNNING))
- Z80_O_RST = 1;
+static void z80_busreq_hpulse(void)
+{
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ Z80_O_BUSREQ = 1;
+ Z80_O_BUSREQ = 1; /* 2 AVR clock cycles */
+ Z80_O_BUSREQ = 0; /* 2 AVR clock cycles */
+ }
- while(Z80_I_BUSACK == 1);
- z80_setup_addrbus_active();
+ if (zstate & ZST_ACQUIRED) {
+ while(Z80_I_BUSACK == 1)
+ ;
+ z80_addrbus_set_active();
+ }
}
-void z80_release_bus(void)
+
+/*
+
+ + | | | | |
+ + 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)
{
- z80_setup_dbus_in();
- z80_setup_addrbus_tristate();
+ switch (cmd) {
- if (!(Stat & S_Z180_RUNNING))
+ case Reset:
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
Z80_O_RST = 0;
-
- Z80_O_BUSREQ = 1;
- //while(Z80_I_BUSACK == 0);
+ Z80_O_BUSREQ = 1;
+ zstate = RESET;
+ break;
+
+ case Request:
+ switch (zstate) {
+ case RESET:
+ Z80_O_BUSREQ = 0;
+ Z80_O_RST = 1;
+ while(Z80_I_BUSACK == 1)
+ ;
+ z80_addrbus_set_active();
+ zstate = RESET_AQRD;
+ break;
+
+ case RUNNING:
+ Z80_O_BUSREQ = 0;
+ while(Z80_I_BUSACK == 1)
+ ;
+ z80_addrbus_set_active();
+ zstate = RUNNING_AQRD;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case Release:
+ switch (zstate) {
+ case RESET_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+ Z80_O_RST = 0;
+ Z80_O_BUSREQ = 1;
+ zstate = RESET;
+ break;
+ case RUNNING_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+ Z80_O_BUSREQ = 1;
+ zstate = RUNNING;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case Run:
+ switch (zstate) {
+ case RESET:
+ Z80_O_RST = 1;
+ zstate = RUNNING;
+ break;
+
+ case RESET_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+ z80_reset_pulse();
+ z80_addrbus_set_active();
+ 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();
+ break;
+ default:
+ break;
+ }
+ }
+ return zstate;
}
+
/*--------------------------------------------------------------------------*/
-static
+static
//inline __attribute__ ((always_inline))
void z80_setaddress(uint32_t addr)
{
{
z80_setaddress(addr);
Z80_O_MREQ = 0;
- z80_setup_dbus_out();
+ z80_dbus_set_out();
P_DB = data;
P_DB = data;
Z80_O_WR = 0;
z80_setaddress(addr);
Z80_O_MREQ = 0;
- z80_setup_dbus_in();
+ z80_dbus_set_in();
Z80_O_RD = 0;
Z80_O_RD = 0;
Z80_O_RD = 0;
void z80_memset(uint32_t addr, uint8_t data, uint32_t length)
{
- z80_setup_dbus_out();
+ z80_dbus_set_out();
Z80_O_MREQ = 0;
while(length--) {
z80_setaddress(addr++);
void z80_write_block(const __flash uint8_t *src, uint32_t dest, uint32_t length)
{
uint8_t data;
-
- z80_setup_dbus_out();
+
+ z80_dbus_set_out();
Z80_O_MREQ = 0;
while(length--) {
z80_setaddress(dest++);
017B' rx.out_idx: ds 1 ;
017C' rx.buf: ds rx.buf_len ;
018B' rx.buf_end equ $-1 ; last byte (start+len-1)
-
+
018C' tx.bs_mask: ds 1 ; (buf_len - 1)
018D' tx.in_idx: ds 1 ;
018E' tx.out_idx: ds 1 ;
idx_in,
mask;
} fifo_dsc[NUM_FIFOS];
-
+
void z80_memfifo_init(const fifo_t f, uint32_t adr)
{
fifo_dsc[f].base = adr;
- z80_request_bus();
+ z80_bus_cmd(Request);
fifo_dsc[f].mask = z80_read(adr + FIFO_BUFSIZE_MASK);
fifo_dsc[f].idx_in = z80_read(adr + FIFO_INDEX_IN);
fifo_dsc[f].idx_out = z80_read(adr + FIFO_INDEX_OUT);
- z80_release_bus();
+ z80_bus_cmd(Release);
}
uint32_t adr = fifo_dsc[f].base + FIFO_INDEX_IN;
uint8_t idx;
- z80_request_bus();
+ z80_bus_cmd(Request);
idx = z80_read(adr);
- z80_release_bus();
+ z80_bus_cmd(Release);
rc = idx == fifo_dsc[f].idx_out;
}
int z80_memfifo_is_full(const fifo_t f)
{
int rc = 1;
-
+
if (fifo_dsc[f].base != 0) {
- z80_request_bus();
+ z80_bus_cmd(Request);
rc = ((fifo_dsc[f].idx_in + 1) & fifo_dsc[f].mask)
== z80_read(fifo_dsc[f].base+FIFO_INDEX_OUT);
- z80_release_bus();
+ z80_bus_cmd(Release);
}
return rc;
}
uint8_t z80_memfifo_getc(const fifo_t f)
{
uint8_t rc, idx;
-
+
while (z80_memfifo_is_empty(f))
;
- z80_request_bus();
+ z80_bus_cmd(Request);
idx = fifo_dsc[f].idx_out;
rc = z80_read(fifo_dsc[f].base+idx);
fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
- z80_release_bus();
-
+ z80_bus_cmd(Release);
+
return rc;
}
void z80_memfifo_putc(fifo_t f, uint8_t val)
{
int idx;
-
+
while (z80_memfifo_is_full(f))
;
- z80_request_bus();
+ z80_bus_cmd(Request);
idx = fifo_dsc[f].idx_in;
z80_write(fifo_dsc[f].base+idx, val);
fifo_dsc[f].idx_in = ++idx & fifo_dsc[f].mask;
z80_write(fifo_dsc[f].base+FIFO_INDEX_IN, fifo_dsc[f].idx_in);
- z80_release_bus();
+ z80_bus_cmd(Release);
}
/*--------------------------------------------------------------------------*/
DBG_P(1, "z80_init_msg_fifo: %lx\n", addr);
- z80_request_bus();
+ z80_bus_cmd(Request);
z80_write(addr+FIFO_INDEX_OUT, z80_read(addr+FIFO_INDEX_IN));
- z80_release_bus();
+ z80_bus_cmd(Release);
msg_fifo.base = addr;
}
int z80_msg_fifo_getc(void)
{
int c = -1;
-
+
#if 0
if (msg_fifo.count != (NELEMS(msg_fifo.buf) /*- DMA1_CNDTR4 */ )) {
c = msg_fifo.buf[msg_fifo.count];
msg_fifo.count = 0;
if (msg_fifo.base != 0) {
- z80_request_bus();
+ z80_bus_cmd(Request);
z80_write(msg_fifo.base+FIFO_INDEX_OUT, msg_fifo.count);
- z80_release_bus();
+ z80_bus_cmd(Release);
}
}
#endif