mirror of https://github.com/xemu-project/xemu.git
hw/m68k: implement ADB bus support for via
VIA needs to be able to poll the ADB interface and to read/write data from/to the bus. This patch adds functions allowing that. 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> Reviewed-by: Hervé Poussineau <hpoussin@reactos.org> Reviewed-by: Thomas Huth <huth@tuxfamily.org> Message-Id: <20191026164546.30020-7-laurent@vivier.eu>
This commit is contained in:
parent
6dca62a000
commit
87a34e2adb
|
@ -123,5 +123,6 @@ config UNIMP
|
||||||
config MAC_VIA
|
config MAC_VIA
|
||||||
bool
|
bool
|
||||||
select MOS6522
|
select MOS6522
|
||||||
|
select ADB
|
||||||
|
|
||||||
source macio/Kconfig
|
source macio/Kconfig
|
||||||
|
|
|
@ -264,10 +264,16 @@
|
||||||
* Table 19-10 ADB transaction states
|
* 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_StateMask (VIA1B_vADBS1 | VIA1B_vADBS2)
|
||||||
#define VIA1B_vADB_StateShift 4
|
#define VIA1B_vADB_StateShift 4
|
||||||
|
|
||||||
#define VIA_TIMER_FREQ (783360)
|
#define VIA_TIMER_FREQ (783360)
|
||||||
|
#define VIA_ADB_POLL_FREQ 50 /* XXX: not real */
|
||||||
|
|
||||||
/* VIA returns time offset from Jan 1, 1904, not 1970 */
|
/* VIA returns time offset from Jan 1, 1904, not 1970 */
|
||||||
#define RTC_OFFSET 2082844800
|
#define RTC_OFFSET 2082844800
|
||||||
|
@ -472,6 +478,181 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(s->adb_data_out_index < sizeof(s->adb_data_out) - 1);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(s->adb_data_in_index < sizeof(s->adb_data_in) - 1);
|
||||||
|
|
||||||
|
*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)
|
static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
{
|
{
|
||||||
MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque);
|
MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque);
|
||||||
|
@ -553,6 +734,10 @@ static void mac_via_reset(DeviceState *dev)
|
||||||
MacVIAState *m = MAC_VIA(dev);
|
MacVIAState *m = MAC_VIA(dev);
|
||||||
MOS6522Q800VIA1State *v1s = &m->mos6522_via1;
|
MOS6522Q800VIA1State *v1s = &m->mos6522_via1;
|
||||||
|
|
||||||
|
timer_mod(m->adb_poll_timer,
|
||||||
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||||
|
(NANOSECONDS_PER_SECOND / VIA_ADB_POLL_FREQ));
|
||||||
|
|
||||||
timer_del(v1s->VBL_timer);
|
timer_del(v1s->VBL_timer);
|
||||||
v1s->next_VBL = 0;
|
v1s->next_VBL = 0;
|
||||||
timer_del(v1s->one_second_timer);
|
timer_del(v1s->one_second_timer);
|
||||||
|
@ -593,6 +778,10 @@ static void mac_via_realize(DeviceState *dev, Error **errp)
|
||||||
|
|
||||||
qemu_get_timedate(&tm, 0);
|
qemu_get_timedate(&tm, 0);
|
||||||
m->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
|
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)
|
static void mac_via_init(Object *obj)
|
||||||
|
@ -642,6 +831,13 @@ static const VMStateDescription vmstate_mac_via = {
|
||||||
VMSTATE_UINT8(cmd, MacVIAState),
|
VMSTATE_UINT8(cmd, MacVIAState),
|
||||||
VMSTATE_INT32(wprotect, MacVIAState),
|
VMSTATE_INT32(wprotect, MacVIAState),
|
||||||
VMSTATE_INT32(alt, MacVIAState),
|
VMSTATE_INT32(alt, MacVIAState),
|
||||||
|
/* ADB */
|
||||||
|
VMSTATE_TIMER_PTR(adb_poll_timer, MacVIAState),
|
||||||
|
VMSTATE_INT32(adb_data_in_size, MacVIAState),
|
||||||
|
VMSTATE_INT32(adb_data_in_index, MacVIAState),
|
||||||
|
VMSTATE_INT32(adb_data_out_index, MacVIAState),
|
||||||
|
VMSTATE_BUFFER(adb_data_in, MacVIAState),
|
||||||
|
VMSTATE_BUFFER(adb_data_out, MacVIAState),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -671,6 +867,7 @@ static void mos6522_q800_via1_portB_write(MOS6522State *s)
|
||||||
MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1);
|
MacVIAState *m = container_of(v1s, MacVIAState, mos6522_via1);
|
||||||
|
|
||||||
via1_rtc_update(m);
|
via1_rtc_update(m);
|
||||||
|
via1_adb_update(m);
|
||||||
|
|
||||||
v1s->last_b = s->b;
|
v1s->last_b = s->b;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,13 @@ typedef struct MacVIAState {
|
||||||
|
|
||||||
/* ADB */
|
/* ADB */
|
||||||
ADBBusState adb_bus;
|
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];
|
||||||
} MacVIAState;
|
} MacVIAState;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue