Message ID | 20181018182856.28001-3-mark.cave-ayland@ilande.co.uk |
---|---|
State | New |
Headers | show |
Series | hw/m68k: add Apple Machintosh Quadra 800 machine | expand |
On 2018-10-18 19:28, Mark Cave-Ayland wrote: > From: Laurent Vivier <laurent@vivier.eu> > > Co-developed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> > Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> > Signed-off-by: Laurent Vivier <laurent@vivier.eu> > --- > hw/input/adb.c | 2 + > hw/misc/mac_via.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ > include/hw/misc/mac_via.h | 7 ++ > 3 files changed, 175 insertions(+) > > diff --git a/hw/input/adb.c b/hw/input/adb.c > index bbb40aeef1..d69ca74364 100644 > --- a/hw/input/adb.c > +++ b/hw/input/adb.c > @@ -25,6 +25,8 @@ > #include "hw/input/adb.h" > #include "adb-internal.h" > > +#define ADB_POLL_FREQ 50 A single define without a user in a .c file? Looks suspicious... As far as I can see, this has been replace by VIA_ADB_POLL_FREQ which has been introduced in the previous patch already, so you can remove this define here. > /* error codes */ > #define ADB_RET_NOTPRESENT (-2) > > diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c > index 084974a24d..1ec563a707 100644 > --- a/hw/misc/mac_via.c > +++ b/hw/misc/mac_via.c [...] > +static int adb_via_send(MacVIAState *s, int state, uint8_t data) > +{ > + switch (state) { > + case ADB_STATE_NEW: > + s->adb_data_out_index = 0; > + break; > + case ADB_STATE_EVEN: > + if ((s->adb_data_out_index & 1) == 0) { > + return 0; > + } > + break; > + case ADB_STATE_ODD: > + if (s->adb_data_out_index & 1) { > + return 0; > + } > + break; > + case ADB_STATE_IDLE: > + return 0; > + } Could you please add a assert(s->adb_data_out_index < sizeof(s->adb_data_out) -1); here, just in case? > + s->adb_data_out[s->adb_data_out_index++] = data; > + qemu_irq_raise(s->adb_data_ready); > + return 1; > +} > + > +static int adb_via_receive(MacVIAState *s, int state, uint8_t *data) > +{ > + switch (state) { > + case ADB_STATE_NEW: > + return 0; > + case ADB_STATE_EVEN: > + if (s->adb_data_in_size <= 0) { > + qemu_irq_raise(s->adb_data_ready); > + return 0; > + } > + if (s->adb_data_in_index >= s->adb_data_in_size) { > + *data = 0; > + qemu_irq_raise(s->adb_data_ready); > + return 1; > + } > + if ((s->adb_data_in_index & 1) == 0) { > + return 0; > + } > + break; > + case ADB_STATE_ODD: > + if (s->adb_data_in_size <= 0) { > + qemu_irq_raise(s->adb_data_ready); > + return 0; > + } > + if (s->adb_data_in_index >= s->adb_data_in_size) { > + *data = 0; > + qemu_irq_raise(s->adb_data_ready); > + return 1; > + } > + if (s->adb_data_in_index & 1) { > + return 0; > + } > + break; > + case ADB_STATE_IDLE: > + if (s->adb_data_out_index == 0) { > + return 0; > + } > + s->adb_data_in_size = adb_request(&s->adb_bus, s->adb_data_in, > + s->adb_data_out, > + s->adb_data_out_index); > + s->adb_data_out_index = 0; > + s->adb_data_in_index = 0; > + if (s->adb_data_in_size < 0) { > + *data = 0xff; > + qemu_irq_raise(s->adb_data_ready); > + return -1; > + } > + if (s->adb_data_in_size == 0) { > + return 0; > + } > + break; > + } Please also add an assert before the next line here - just in case... > + *data = s->adb_data_in[s->adb_data_in_index++]; > + qemu_irq_raise(s->adb_data_ready); > + if (*data == 0xff || *data == 0) { > + return 0; > + } > + return 1; > +} Thomas
On 23/10/2018 07:49, Thomas Huth wrote: > On 2018-10-18 19:28, Mark Cave-Ayland wrote: >> From: Laurent Vivier <laurent@vivier.eu> >> >> Co-developed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> >> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> >> Signed-off-by: Laurent Vivier <laurent@vivier.eu> >> --- >> hw/input/adb.c | 2 + >> hw/misc/mac_via.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ >> include/hw/misc/mac_via.h | 7 ++ >> 3 files changed, 175 insertions(+) >> >> diff --git a/hw/input/adb.c b/hw/input/adb.c >> index bbb40aeef1..d69ca74364 100644 >> --- a/hw/input/adb.c >> +++ b/hw/input/adb.c >> @@ -25,6 +25,8 @@ >> #include "hw/input/adb.h" >> #include "adb-internal.h" >> >> +#define ADB_POLL_FREQ 50 > > A single define without a user in a .c file? Looks suspicious... > > As far as I can see, this has been replace by VIA_ADB_POLL_FREQ which > has been introduced in the previous patch already, so you can remove > this define here. Ooops yes, this should have been removed from my previous refactoring - I've now fixed this. >> /* error codes */ >> #define ADB_RET_NOTPRESENT (-2) >> >> diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c >> index 084974a24d..1ec563a707 100644 >> --- a/hw/misc/mac_via.c >> +++ b/hw/misc/mac_via.c > [...] >> +static int adb_via_send(MacVIAState *s, int state, uint8_t data) >> +{ >> + switch (state) { >> + case ADB_STATE_NEW: >> + s->adb_data_out_index = 0; >> + break; >> + case ADB_STATE_EVEN: >> + if ((s->adb_data_out_index & 1) == 0) { >> + return 0; >> + } >> + break; >> + case ADB_STATE_ODD: >> + if (s->adb_data_out_index & 1) { >> + return 0; >> + } >> + break; >> + case ADB_STATE_IDLE: >> + return 0; >> + } > > Could you please add a > > assert(s->adb_data_out_index < sizeof(s->adb_data_out) -1); > > here, just in case? Done. >> + s->adb_data_out[s->adb_data_out_index++] = data; >> + qemu_irq_raise(s->adb_data_ready); >> + return 1; >> +} >> + >> +static int adb_via_receive(MacVIAState *s, int state, uint8_t *data) >> +{ >> + switch (state) { >> + case ADB_STATE_NEW: >> + return 0; >> + case ADB_STATE_EVEN: >> + if (s->adb_data_in_size <= 0) { >> + qemu_irq_raise(s->adb_data_ready); >> + return 0; >> + } >> + if (s->adb_data_in_index >= s->adb_data_in_size) { >> + *data = 0; >> + qemu_irq_raise(s->adb_data_ready); >> + return 1; >> + } >> + if ((s->adb_data_in_index & 1) == 0) { >> + return 0; >> + } >> + break; >> + case ADB_STATE_ODD: >> + if (s->adb_data_in_size <= 0) { >> + qemu_irq_raise(s->adb_data_ready); >> + return 0; >> + } >> + if (s->adb_data_in_index >= s->adb_data_in_size) { >> + *data = 0; >> + qemu_irq_raise(s->adb_data_ready); >> + return 1; >> + } >> + if (s->adb_data_in_index & 1) { >> + return 0; >> + } >> + break; >> + case ADB_STATE_IDLE: >> + if (s->adb_data_out_index == 0) { >> + return 0; >> + } >> + s->adb_data_in_size = adb_request(&s->adb_bus, s->adb_data_in, >> + s->adb_data_out, >> + s->adb_data_out_index); >> + s->adb_data_out_index = 0; >> + s->adb_data_in_index = 0; >> + if (s->adb_data_in_size < 0) { >> + *data = 0xff; >> + qemu_irq_raise(s->adb_data_ready); >> + return -1; >> + } >> + if (s->adb_data_in_size == 0) { >> + return 0; >> + } >> + break; >> + } > > Please also add an assert before the next line here - just in case... And also done here. >> + *data = s->adb_data_in[s->adb_data_in_index++]; >> + qemu_irq_raise(s->adb_data_ready); >> + if (*data == 0xff || *data == 0) { >> + return 0; >> + } >> + return 1; >> +} ATB, Mark.
diff --git a/hw/input/adb.c b/hw/input/adb.c index bbb40aeef1..d69ca74364 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -25,6 +25,8 @@ #include "hw/input/adb.h" #include "adb-internal.h" +#define ADB_POLL_FREQ 50 + /* error codes */ #define ADB_RET_NOTPRESENT (-2) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 084974a24d..1ec563a707 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -237,6 +237,11 @@ * Table 19-10 ADB transaction states */ +#define ADB_STATE_NEW 0 +#define ADB_STATE_EVEN 1 +#define ADB_STATE_ODD 2 +#define ADB_STATE_IDLE 3 + #define VIA1B_vADB_StateMask (VIA1B_vADBS1 | VIA1B_vADBS2) #define VIA1B_vADB_StateShift 4 @@ -424,6 +429,158 @@ static void via1_rtc_update(MacVIAState *m) } } +static int adb_via_poll(MacVIAState *s, int state, uint8_t *data) +{ + if (state != ADB_STATE_IDLE) { + return 0; + } + if (s->adb_data_in_size < s->adb_data_in_index) { + return 0; + } + if (s->adb_data_out_index != 0) { + return 0; + } + s->adb_data_in_index = 0; + s->adb_data_out_index = 0; + s->adb_data_in_size = adb_poll(&s->adb_bus, s->adb_data_in, 0xffff); + if (s->adb_data_in_size) { + *data = s->adb_data_in[s->adb_data_in_index++]; + qemu_irq_raise(s->adb_data_ready); + } + return s->adb_data_in_size; +} + +static int adb_via_send(MacVIAState *s, int state, uint8_t data) +{ + switch (state) { + case ADB_STATE_NEW: + s->adb_data_out_index = 0; + break; + case ADB_STATE_EVEN: + if ((s->adb_data_out_index & 1) == 0) { + return 0; + } + break; + case ADB_STATE_ODD: + if (s->adb_data_out_index & 1) { + return 0; + } + break; + case ADB_STATE_IDLE: + return 0; + } + s->adb_data_out[s->adb_data_out_index++] = data; + qemu_irq_raise(s->adb_data_ready); + return 1; +} + +static int adb_via_receive(MacVIAState *s, int state, uint8_t *data) +{ + switch (state) { + case ADB_STATE_NEW: + return 0; + case ADB_STATE_EVEN: + if (s->adb_data_in_size <= 0) { + qemu_irq_raise(s->adb_data_ready); + return 0; + } + if (s->adb_data_in_index >= s->adb_data_in_size) { + *data = 0; + qemu_irq_raise(s->adb_data_ready); + return 1; + } + if ((s->adb_data_in_index & 1) == 0) { + return 0; + } + break; + case ADB_STATE_ODD: + if (s->adb_data_in_size <= 0) { + qemu_irq_raise(s->adb_data_ready); + return 0; + } + if (s->adb_data_in_index >= s->adb_data_in_size) { + *data = 0; + qemu_irq_raise(s->adb_data_ready); + return 1; + } + if (s->adb_data_in_index & 1) { + return 0; + } + break; + case ADB_STATE_IDLE: + if (s->adb_data_out_index == 0) { + return 0; + } + s->adb_data_in_size = adb_request(&s->adb_bus, s->adb_data_in, + s->adb_data_out, + s->adb_data_out_index); + s->adb_data_out_index = 0; + s->adb_data_in_index = 0; + if (s->adb_data_in_size < 0) { + *data = 0xff; + qemu_irq_raise(s->adb_data_ready); + return -1; + } + if (s->adb_data_in_size == 0) { + return 0; + } + break; + } + *data = s->adb_data_in[s->adb_data_in_index++]; + qemu_irq_raise(s->adb_data_ready); + if (*data == 0xff || *data == 0) { + return 0; + } + return 1; +} + +static void via1_adb_update(MacVIAState *m) +{ + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); + MOS6522State *s = MOS6522(v1s); + int state; + int ret; + + state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; + + if (s->acr & VIA1ACR_vShiftOut) { + /* output mode */ + ret = adb_via_send(m, state, s->sr); + if (ret > 0) { + s->b &= ~VIA1B_vADBInt; + } else { + s->b |= VIA1B_vADBInt; + } + } else { + /* input mode */ + ret = adb_via_receive(m, state, &s->sr); + if (ret > 0 && s->sr != 0xff) { + s->b &= ~VIA1B_vADBInt; + } else { + s->b |= VIA1B_vADBInt; + } + } +} + +static void via_adb_poll(void *opaque) +{ + MacVIAState *m = opaque; + MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(&m->mos6522_via1); + MOS6522State *s = MOS6522(v1s); + int state; + + if (s->b & VIA1B_vADBInt) { + state = (s->b & VIA1B_vADB_StateMask) >> VIA1B_vADB_StateShift; + if (adb_via_poll(m, state, &s->sr)) { + s->b &= ~VIA1B_vADBInt; + } + } + + timer_mod(m->adb_poll_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ)); +} + static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size) { MOS6522Q800VIA1State *s = opaque; @@ -486,6 +643,10 @@ static void mac_via_reset(DeviceState *dev) { MacVIAState *m = MAC_VIA(dev); + timer_mod(m->adb_poll_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + (NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ)); + timer_mod(m->VBL_timer, (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16630) / 16630 * 16630); @@ -524,6 +685,10 @@ static void mac_via_realize(DeviceState *dev, Error **errp) qemu_get_timedate(&tm, 0); m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; + + m->adb_poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, via_adb_poll, m); + m->adb_data_ready = qdev_get_gpio_in_named(dev, "via1-irq", + VIA1_IRQ_ADB_READY_BIT); } static void mac_via_init(Object *obj) @@ -572,6 +737,7 @@ static void mos6522_q800_via1_portB_write(MOS6522State *s) MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1); via1_rtc_update(m); + via1_adb_update(m); v1s->last_b = s->b; } diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h index a3a972ccc5..ac56df8c35 100644 --- a/include/hw/misc/mac_via.h +++ b/include/hw/misc/mac_via.h @@ -96,6 +96,13 @@ typedef struct MacVIAState { /* ADB */ ADBBusState adb_bus; + QEMUTimer *adb_poll_timer; + qemu_irq adb_data_ready; + int adb_data_in_size; + int adb_data_in_index; + int adb_data_out_index; + uint8_t adb_data_in[128]; + uint8_t adb_data_out[16]; /* external timers */ QEMUTimer *one_second_timer;