q800-updates-for-7.0 queue
-----BEGIN PGP SIGNATURE----- iQFSBAABCgA8FiEEzGIauY6CIA2RXMnEW8LFb64PMh8FAmIoiAMeHG1hcmsuY2F2 ZS1heWxhbmRAaWxhbmRlLmNvLnVrAAoJEFvCxW+uDzIfcn0H+wfeA9uKZ9DNc20O XDkq2lnUiEyrKsZrVn8jRlw/zHnuElX2WmMGckisJpcaBpZSwlypHBhrjssUXu7v nHlrOYqoKxiYFSZVPj1n+P849BW3LKNgcA5/njA87QUjMOCW6eq4Sp9beDsSbw57 cPAXUhGNI4uvLh6ew9aoxz01KhBSY1hFMmX0U6gcDx48f5cr/NU81+Vae0+Ks3B+ BPbYjED3yr7G6nu63MT63WXlAnKBQpndkjbVYubQCwVJqLRBb6p37Gm81KXozpos QxF9miWdzA2dRCrSutcAd84rTWq2w8T2Wf2sW3B8lXNy+s+qTSnvsiOUjoaESzv7 UKXmYZE= =RwkZ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mcayland/tags/q800-updates-for-7.0-20220309' into staging q800-updates-for-7.0 queue # gpg: Signature made Wed 09 Mar 2022 10:57:07 GMT # gpg: using RSA key CC621AB98E82200D915CC9C45BC2C56FAE0F321F # gpg: issuer "mark.cave-ayland@ilande.co.uk" # gpg: Good signature from "Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>" [full] # Primary key fingerprint: CC62 1AB9 8E82 200D 915C C9C4 5BC2 C56F AE0F 321F * remotes/mcayland/tags/q800-updates-for-7.0-20220309: (22 commits) esp: recreate ESPState current_req after migration esp: include the current PDMA callback in the migration stream esp: convert ESPState pdma_cb from a function pointer to an integer esp: introduce esp_pdma_cb() function esp: introduce esp_set_pdma_cb() function macfb: set initial value of mode control registers in macfb_common_realize() macfb: add VMStateDescription fields for display type and VBL timer macfb: increase number of registers saved in MacfbState macfb: don't use special irq_state and irq_mask variables in MacfbState macfb: add VMStateDescription for MacfbNubusState and MacfbSysBusState macio/pmu.c: remove redundant code mos6522: implement edge-triggering for CA1/2 and CB1/2 control line IRQs mac_via: make SCSI_DATA (DRQ) bit live rather than latched mos6522: record last_irq_levels in mos6522_set_irq() mos6522: add "info via" HMP command for debugging mos6522: add register names to register read/write trace events mos6522: use device_class_set_parent_reset() to propagate reset to parent mos6522: remove update_irq() and set_sr_int() methods from MOS6522DeviceClass mos6522: switch over to use qdev gpios for IRQs mac_via: use IFR bit flag constants for VIA2 IRQs ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
1416688c53
@ -879,3 +879,18 @@ SRST
|
||||
``info sgx``
|
||||
Show intel SGX information.
|
||||
ERST
|
||||
|
||||
#if defined(TARGET_M68K) || defined(TARGET_PPC)
|
||||
{
|
||||
.name = "via",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show guest mos6522 VIA devices",
|
||||
.cmd = hmp_info_via,
|
||||
},
|
||||
#endif
|
||||
|
||||
SRST
|
||||
``info via``
|
||||
Show guest mos6522 VIA devices.
|
||||
ERST
|
||||
|
@ -476,7 +476,8 @@ static void macfb_update_display(void *opaque)
|
||||
|
||||
static void macfb_update_irq(MacfbState *s)
|
||||
{
|
||||
uint32_t irq_state = s->irq_state & s->irq_mask;
|
||||
uint32_t irq_state = s->regs[DAFB_INTR_STAT >> 2] &
|
||||
s->regs[DAFB_INTR_MASK >> 2];
|
||||
|
||||
if (irq_state) {
|
||||
qemu_irq_raise(s->irq);
|
||||
@ -496,7 +497,7 @@ static void macfb_vbl_timer(void *opaque)
|
||||
MacfbState *s = opaque;
|
||||
int64_t next_vbl;
|
||||
|
||||
s->irq_state |= DAFB_INTR_VBL;
|
||||
s->regs[DAFB_INTR_STAT >> 2] |= DAFB_INTR_VBL;
|
||||
macfb_update_irq(s);
|
||||
|
||||
/* 60 Hz irq */
|
||||
@ -530,14 +531,16 @@ static uint64_t macfb_ctrl_read(void *opaque,
|
||||
case DAFB_MODE_VADDR2:
|
||||
case DAFB_MODE_CTRL1:
|
||||
case DAFB_MODE_CTRL2:
|
||||
val = s->regs[addr >> 2];
|
||||
break;
|
||||
case DAFB_INTR_STAT:
|
||||
val = s->irq_state;
|
||||
val = s->regs[addr >> 2];
|
||||
break;
|
||||
case DAFB_MODE_SENSE:
|
||||
val = macfb_sense_read(s);
|
||||
break;
|
||||
default:
|
||||
if (addr < MACFB_CTRL_TOPADDR) {
|
||||
val = s->regs[addr >> 2];
|
||||
}
|
||||
}
|
||||
|
||||
trace_macfb_ctrl_read(addr, val, size);
|
||||
@ -568,7 +571,7 @@ static void macfb_ctrl_write(void *opaque,
|
||||
macfb_sense_write(s, val);
|
||||
break;
|
||||
case DAFB_INTR_MASK:
|
||||
s->irq_mask = val;
|
||||
s->regs[addr >> 2] = val;
|
||||
if (val & DAFB_INTR_VBL) {
|
||||
next_vbl = macfb_next_vbl();
|
||||
timer_mod(s->vbl_timer, next_vbl);
|
||||
@ -577,12 +580,12 @@ static void macfb_ctrl_write(void *opaque,
|
||||
}
|
||||
break;
|
||||
case DAFB_INTR_CLEAR:
|
||||
s->irq_state &= ~DAFB_INTR_VBL;
|
||||
s->regs[DAFB_INTR_STAT >> 2] &= ~DAFB_INTR_VBL;
|
||||
macfb_update_irq(s);
|
||||
break;
|
||||
case DAFB_RESET:
|
||||
s->palette_current = 0;
|
||||
s->irq_state &= ~DAFB_INTR_VBL;
|
||||
s->regs[DAFB_INTR_STAT >> 2] &= ~DAFB_INTR_VBL;
|
||||
macfb_update_irq(s);
|
||||
break;
|
||||
case DAFB_LUT:
|
||||
@ -593,6 +596,10 @@ static void macfb_ctrl_write(void *opaque,
|
||||
macfb_invalidate_display(s);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (addr < MACFB_CTRL_TOPADDR) {
|
||||
s->regs[addr >> 2] = val;
|
||||
}
|
||||
}
|
||||
|
||||
trace_macfb_ctrl_write(addr, val, size);
|
||||
@ -618,9 +625,11 @@ static const VMStateDescription vmstate_macfb = {
|
||||
.minimum_version_id = 1,
|
||||
.post_load = macfb_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(type, MacfbState),
|
||||
VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
|
||||
VMSTATE_UINT32(palette_current, MacfbState),
|
||||
VMSTATE_UINT32_ARRAY(regs, MacfbState, MACFB_NUM_REGS),
|
||||
VMSTATE_TIMER_PTR(vbl_timer, MacfbState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@ -646,6 +655,14 @@ static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set mode control registers to match the mode found above so that
|
||||
* macfb_mode_write() does the right thing if no MacOS toolbox ROM
|
||||
* is present to initialise them
|
||||
*/
|
||||
s->regs[DAFB_MODE_CTRL1 >> 2] = s->mode->mode_ctrl1;
|
||||
s->regs[DAFB_MODE_CTRL2 >> 2] = s->mode->mode_ctrl2;
|
||||
|
||||
s->con = graphic_console_init(dev, 0, &macfb_ops, s);
|
||||
surface = qemu_console_surface(s->con);
|
||||
|
||||
@ -746,6 +763,16 @@ static Property macfb_sysbus_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_macfb_sysbus = {
|
||||
.name = "macfb-sysbus",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(macfb, MacfbSysBusState, 1, vmstate_macfb, MacfbState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property macfb_nubus_properties[] = {
|
||||
DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640),
|
||||
DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480),
|
||||
@ -755,6 +782,16 @@ static Property macfb_nubus_properties[] = {
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_macfb_nubus = {
|
||||
.name = "macfb-nubus",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(macfb, MacfbNubusState, 1, vmstate_macfb, MacfbState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -762,7 +799,7 @@ static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
dc->realize = macfb_sysbus_realize;
|
||||
dc->desc = "SysBus Macintosh framebuffer";
|
||||
dc->reset = macfb_sysbus_reset;
|
||||
dc->vmsd = &vmstate_macfb;
|
||||
dc->vmsd = &vmstate_macfb_sysbus;
|
||||
device_class_set_props(dc, macfb_sysbus_properties);
|
||||
}
|
||||
|
||||
@ -777,7 +814,7 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data)
|
||||
&ndc->parent_unrealize);
|
||||
dc->desc = "Nubus Macintosh framebuffer";
|
||||
dc->reset = macfb_nubus_reset;
|
||||
dc->vmsd = &vmstate_macfb;
|
||||
dc->vmsd = &vmstate_macfb_nubus;
|
||||
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||
device_class_set_props(dc, macfb_nubus_properties);
|
||||
}
|
||||
|
@ -533,10 +533,11 @@ static void q800_init(MachineState *machine)
|
||||
|
||||
sysbus = SYS_BUS_DEVICE(dev);
|
||||
sysbus_realize_and_unref(sysbus, &error_fatal);
|
||||
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(via2_dev,
|
||||
VIA2_IRQ_SCSI_BIT));
|
||||
sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(via2_dev,
|
||||
VIA2_IRQ_SCSI_DATA_BIT));
|
||||
/* SCSI and SCSI data IRQs are negative edge triggered */
|
||||
sysbus_connect_irq(sysbus, 0, qemu_irq_invert(qdev_get_gpio_in(via2_dev,
|
||||
VIA2_IRQ_SCSI_BIT)));
|
||||
sysbus_connect_irq(sysbus, 1, qemu_irq_invert(qdev_get_gpio_in(via2_dev,
|
||||
VIA2_IRQ_SCSI_DATA_BIT)));
|
||||
sysbus_mmio_map(sysbus, 0, ESP_BASE);
|
||||
sysbus_mmio_map(sysbus, 1, ESP_PDMA);
|
||||
|
||||
|
@ -325,10 +325,11 @@ static void via1_sixty_hz(void *opaque)
|
||||
{
|
||||
MOS6522Q800VIA1State *v1s = opaque;
|
||||
MOS6522State *s = MOS6522(v1s);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(s), VIA1_IRQ_60HZ_BIT);
|
||||
|
||||
s->ifr |= VIA1_IRQ_60HZ;
|
||||
mdc->update_irq(s);
|
||||
/* Negative edge trigger */
|
||||
qemu_irq_lower(irq);
|
||||
qemu_irq_raise(irq);
|
||||
|
||||
via1_sixty_hz_update(v1s);
|
||||
}
|
||||
@ -337,44 +338,15 @@ static void via1_one_second(void *opaque)
|
||||
{
|
||||
MOS6522Q800VIA1State *v1s = opaque;
|
||||
MOS6522State *s = MOS6522(v1s);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(s), VIA1_IRQ_ONE_SECOND_BIT);
|
||||
|
||||
s->ifr |= VIA1_IRQ_ONE_SECOND;
|
||||
mdc->update_irq(s);
|
||||
/* Negative edge trigger */
|
||||
qemu_irq_lower(irq);
|
||||
qemu_irq_raise(irq);
|
||||
|
||||
via1_one_second_update(v1s);
|
||||
}
|
||||
|
||||
static void via1_irq_request(void *opaque, int irq, int level)
|
||||
{
|
||||
MOS6522Q800VIA1State *v1s = opaque;
|
||||
MOS6522State *s = MOS6522(v1s);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
|
||||
|
||||
if (level) {
|
||||
s->ifr |= 1 << irq;
|
||||
} else {
|
||||
s->ifr &= ~(1 << irq);
|
||||
}
|
||||
|
||||
mdc->update_irq(s);
|
||||
}
|
||||
|
||||
static void via2_irq_request(void *opaque, int irq, int level)
|
||||
{
|
||||
MOS6522Q800VIA2State *v2s = opaque;
|
||||
MOS6522State *s = MOS6522(v2s);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
|
||||
|
||||
if (level) {
|
||||
s->ifr |= 1 << irq;
|
||||
} else {
|
||||
s->ifr &= ~(1 << irq);
|
||||
}
|
||||
|
||||
mdc->update_irq(s);
|
||||
}
|
||||
|
||||
|
||||
static void pram_update(MOS6522Q800VIA1State *v1s)
|
||||
{
|
||||
@ -938,9 +910,26 @@ static uint64_t mos6522_q800_via2_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
MOS6522Q800VIA2State *s = MOS6522_Q800_VIA2(opaque);
|
||||
MOS6522State *ms = MOS6522(s);
|
||||
uint64_t val;
|
||||
|
||||
addr = (addr >> 9) & 0xf;
|
||||
return mos6522_read(ms, addr, size);
|
||||
val = mos6522_read(ms, addr, size);
|
||||
|
||||
switch (addr) {
|
||||
case VIA_REG_IFR:
|
||||
/*
|
||||
* On a Q800 an emulated VIA2 is integrated into the onboard logic. The
|
||||
* expectation of most OSs is that the DRQ bit is live, rather than
|
||||
* latched as it would be on a real VIA so do the same here.
|
||||
*
|
||||
* Note: DRQ is negative edge triggered
|
||||
*/
|
||||
val &= ~VIA2_IRQ_SCSI_DATA;
|
||||
val |= (~ms->last_irq_levels & VIA2_IRQ_SCSI_DATA);
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void mos6522_q800_via2_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
@ -1061,8 +1050,6 @@ static void mos6522_q800_via1_init(Object *obj)
|
||||
qbus_init((BusState *)&v1s->adb_bus, sizeof(v1s->adb_bus),
|
||||
TYPE_ADB_BUS, DEVICE(v1s), "adb.0");
|
||||
|
||||
qdev_init_gpio_in(DEVICE(obj), via1_irq_request, VIA1_IRQ_NB);
|
||||
|
||||
/* A/UX mode */
|
||||
qdev_init_gpio_out(DEVICE(obj), &v1s->auxmode_irq, 1);
|
||||
}
|
||||
@ -1110,9 +1097,11 @@ static Property mos6522_q800_via1_properties[] = {
|
||||
static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
|
||||
|
||||
dc->realize = mos6522_q800_via1_realize;
|
||||
dc->reset = mos6522_q800_via1_reset;
|
||||
device_class_set_parent_reset(dc, mos6522_q800_via1_reset,
|
||||
&mdc->parent_reset);
|
||||
dc->vmsd = &vmstate_q800_via1;
|
||||
device_class_set_props(dc, mos6522_q800_via1_properties);
|
||||
}
|
||||
@ -1150,22 +1139,21 @@ static void mos6522_q800_via2_reset(DeviceState *dev)
|
||||
ms->a = 0x7f;
|
||||
}
|
||||
|
||||
static void via2_nubus_irq_request(void *opaque, int irq, int level)
|
||||
static void via2_nubus_irq_request(void *opaque, int n, int level)
|
||||
{
|
||||
MOS6522Q800VIA2State *v2s = opaque;
|
||||
MOS6522State *s = MOS6522(v2s);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(s), VIA2_IRQ_NUBUS_BIT);
|
||||
|
||||
if (level) {
|
||||
/* Port A nubus IRQ inputs are active LOW */
|
||||
s->a &= ~(1 << irq);
|
||||
s->ifr |= 1 << VIA2_IRQ_NUBUS_BIT;
|
||||
s->a &= ~(1 << n);
|
||||
} else {
|
||||
s->a |= (1 << irq);
|
||||
s->ifr &= ~(1 << VIA2_IRQ_NUBUS_BIT);
|
||||
s->a |= (1 << n);
|
||||
}
|
||||
|
||||
mdc->update_irq(s);
|
||||
/* Negative edge trigger */
|
||||
qemu_set_irq(irq, !level);
|
||||
}
|
||||
|
||||
static void mos6522_q800_via2_init(Object *obj)
|
||||
@ -1177,8 +1165,6 @@ static void mos6522_q800_via2_init(Object *obj)
|
||||
"via2", VIA_SIZE);
|
||||
sysbus_init_mmio(sbd, &v2s->via_mem);
|
||||
|
||||
qdev_init_gpio_in(DEVICE(obj), via2_irq_request, VIA2_IRQ_NB);
|
||||
|
||||
qdev_init_gpio_in_named(DEVICE(obj), via2_nubus_irq_request, "nubus-irq",
|
||||
VIA2_NUBUS_IRQ_NB);
|
||||
}
|
||||
@ -1199,7 +1185,8 @@ static void mos6522_q800_via2_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
|
||||
|
||||
dc->reset = mos6522_q800_via2_reset;
|
||||
device_class_set_parent_reset(dc, mos6522_q800_via2_reset,
|
||||
&mdc->parent_reset);
|
||||
dc->vmsd = &vmstate_q800_via2;
|
||||
mdc->portB_write = mos6522_q800_via2_portB_write;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/ppc/mac.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
@ -96,9 +97,9 @@ static void cuda_set_sr_int(void *opaque)
|
||||
CUDAState *s = opaque;
|
||||
MOS6522CUDAState *mcs = &s->mos6522_cuda;
|
||||
MOS6522State *ms = MOS6522(mcs);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(ms), SR_INT_BIT);
|
||||
|
||||
mdc->set_sr_int(ms);
|
||||
qemu_set_irq(irq, 1);
|
||||
}
|
||||
|
||||
static void cuda_delay_set_sr_int(CUDAState *s)
|
||||
@ -605,7 +606,8 @@ static void mos6522_cuda_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
|
||||
|
||||
dc->reset = mos6522_cuda_reset;
|
||||
device_class_set_parent_reset(dc, mos6522_cuda_reset,
|
||||
&mdc->parent_reset);
|
||||
mdc->portB_write = mos6522_cuda_portB_write;
|
||||
mdc->get_timer1_counter_value = cuda_get_counter_value;
|
||||
mdc->get_timer2_counter_value = cuda_get_counter_value;
|
||||
|
@ -57,27 +57,14 @@
|
||||
|
||||
#define VIA_TIMER_FREQ (4700000 / 6)
|
||||
|
||||
static void via_update_irq(PMUState *s)
|
||||
{
|
||||
MOS6522PMUState *mps = MOS6522_PMU(&s->mos6522_pmu);
|
||||
MOS6522State *ms = MOS6522(mps);
|
||||
|
||||
bool new_state = !!(ms->ifr & ms->ier & (SR_INT | T1_INT | T2_INT));
|
||||
|
||||
if (new_state != s->via_irq_state) {
|
||||
s->via_irq_state = new_state;
|
||||
qemu_set_irq(s->via_irq, new_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void via_set_sr_int(void *opaque)
|
||||
{
|
||||
PMUState *s = opaque;
|
||||
MOS6522PMUState *mps = MOS6522_PMU(&s->mos6522_pmu);
|
||||
MOS6522State *ms = MOS6522(mps);
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms);
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(ms), SR_INT_BIT);
|
||||
|
||||
mdc->set_sr_int(ms);
|
||||
qemu_set_irq(irq, 1);
|
||||
}
|
||||
|
||||
static void pmu_update_extirq(PMUState *s)
|
||||
@ -808,28 +795,9 @@ static void mos6522_pmu_portB_write(MOS6522State *s)
|
||||
MOS6522PMUState *mps = container_of(s, MOS6522PMUState, parent_obj);
|
||||
PMUState *ps = container_of(mps, PMUState, mos6522_pmu);
|
||||
|
||||
if ((s->pcr & 0xe0) == 0x20 || (s->pcr & 0xe0) == 0x60) {
|
||||
s->ifr &= ~CB2_INT;
|
||||
}
|
||||
s->ifr &= ~CB1_INT;
|
||||
|
||||
via_update_irq(ps);
|
||||
pmu_update(ps);
|
||||
}
|
||||
|
||||
static void mos6522_pmu_portA_write(MOS6522State *s)
|
||||
{
|
||||
MOS6522PMUState *mps = container_of(s, MOS6522PMUState, parent_obj);
|
||||
PMUState *ps = container_of(mps, PMUState, mos6522_pmu);
|
||||
|
||||
if ((s->pcr & 0x0e) == 0x02 || (s->pcr & 0x0e) == 0x06) {
|
||||
s->ifr &= ~CA2_INT;
|
||||
}
|
||||
s->ifr &= ~CA1_INT;
|
||||
|
||||
via_update_irq(ps);
|
||||
}
|
||||
|
||||
static void mos6522_pmu_reset(DeviceState *dev)
|
||||
{
|
||||
MOS6522State *ms = MOS6522(dev);
|
||||
@ -850,9 +818,9 @@ static void mos6522_pmu_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
MOS6522DeviceClass *mdc = MOS6522_CLASS(oc);
|
||||
|
||||
dc->reset = mos6522_pmu_reset;
|
||||
device_class_set_parent_reset(dc, mos6522_pmu_reset,
|
||||
&mdc->parent_reset);
|
||||
mdc->portB_write = mos6522_pmu_portB_write;
|
||||
mdc->portA_write = mos6522_pmu_portA_write;
|
||||
}
|
||||
|
||||
static const TypeInfo mos6522_pmu_type_info = {
|
||||
|
@ -30,12 +30,21 @@
|
||||
#include "hw/misc/mos6522.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "monitor/hmp.h"
|
||||
#include "qapi/type-helpers.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
static const char *mos6522_reg_names[MOS6522_NUM_REGS] = {
|
||||
"ORB", "ORA", "DDRB", "DDRA", "T1CL", "T1CH", "T1LL", "T1LH",
|
||||
"T2CL", "T2CH", "SR", "ACR", "PCR", "IFR", "IER", "ANH"
|
||||
};
|
||||
|
||||
/* XXX: implement all timer modes */
|
||||
|
||||
static void mos6522_timer1_update(MOS6522State *s, MOS6522Timer *ti,
|
||||
@ -52,6 +61,73 @@ static void mos6522_update_irq(MOS6522State *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void mos6522_set_irq(void *opaque, int n, int level)
|
||||
{
|
||||
MOS6522State *s = MOS6522(opaque);
|
||||
int last_level = !!(s->last_irq_levels & (1 << n));
|
||||
uint8_t last_ifr = s->ifr;
|
||||
bool positive_edge = true;
|
||||
int ctrl;
|
||||
|
||||
/*
|
||||
* SR_INT is managed by mos6522 instances and cleared upon SR
|
||||
* read. It is only the external CA1/2 and CB1/2 lines that
|
||||
* are edge-triggered and latched in IFR
|
||||
*/
|
||||
if (n != SR_INT_BIT && level == last_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Detect negative edge trigger */
|
||||
if (last_level == 1 && level == 0) {
|
||||
positive_edge = false;
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case CA2_INT_BIT:
|
||||
ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT;
|
||||
if ((positive_edge && (ctrl & C2_POS)) ||
|
||||
(!positive_edge && !(ctrl & C2_POS))) {
|
||||
s->ifr |= 1 << n;
|
||||
}
|
||||
break;
|
||||
case CA1_INT_BIT:
|
||||
ctrl = (s->pcr & CA1_CTRL_MASK) >> CA1_CTRL_SHIFT;
|
||||
if ((positive_edge && (ctrl & C1_POS)) ||
|
||||
(!positive_edge && !(ctrl & C1_POS))) {
|
||||
s->ifr |= 1 << n;
|
||||
}
|
||||
break;
|
||||
case SR_INT_BIT:
|
||||
s->ifr |= 1 << n;
|
||||
break;
|
||||
case CB2_INT_BIT:
|
||||
ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT;
|
||||
if ((positive_edge && (ctrl & C2_POS)) ||
|
||||
(!positive_edge && !(ctrl & C2_POS))) {
|
||||
s->ifr |= 1 << n;
|
||||
}
|
||||
break;
|
||||
case CB1_INT_BIT:
|
||||
ctrl = (s->pcr & CB1_CTRL_MASK) >> CB1_CTRL_SHIFT;
|
||||
if ((positive_edge && (ctrl & C1_POS)) ||
|
||||
(!positive_edge && !(ctrl & C1_POS))) {
|
||||
s->ifr |= 1 << n;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->ifr != last_ifr) {
|
||||
mos6522_update_irq(s);
|
||||
}
|
||||
|
||||
if (level) {
|
||||
s->last_irq_levels |= 1 << n;
|
||||
} else {
|
||||
s->last_irq_levels &= ~(1 << n);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t get_counter_value(MOS6522State *s, MOS6522Timer *ti)
|
||||
{
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
|
||||
@ -195,13 +271,6 @@ static void mos6522_timer2(void *opaque)
|
||||
mos6522_update_irq(s);
|
||||
}
|
||||
|
||||
static void mos6522_set_sr_int(MOS6522State *s)
|
||||
{
|
||||
trace_mos6522_set_sr_int();
|
||||
s->ifr |= SR_INT;
|
||||
mos6522_update_irq(s);
|
||||
}
|
||||
|
||||
static uint64_t mos6522_get_counter_value(MOS6522State *s, MOS6522Timer *ti)
|
||||
{
|
||||
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ti->load_time,
|
||||
@ -229,6 +298,7 @@ uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
MOS6522State *s = opaque;
|
||||
uint32_t val;
|
||||
int ctrl;
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
|
||||
if (now >= s->timers[0].next_irq_time) {
|
||||
@ -242,12 +312,24 @@ uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
|
||||
switch (addr) {
|
||||
case VIA_REG_B:
|
||||
val = s->b;
|
||||
ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT;
|
||||
if (!(ctrl & C2_IND)) {
|
||||
s->ifr &= ~CB2_INT;
|
||||
}
|
||||
s->ifr &= ~CB1_INT;
|
||||
mos6522_update_irq(s);
|
||||
break;
|
||||
case VIA_REG_A:
|
||||
qemu_log_mask(LOG_UNIMP, "Read access to register A with handshake");
|
||||
/* fall through */
|
||||
case VIA_REG_ANH:
|
||||
val = s->a;
|
||||
ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT;
|
||||
if (!(ctrl & C2_IND)) {
|
||||
s->ifr &= ~CA2_INT;
|
||||
}
|
||||
s->ifr &= ~CA1_INT;
|
||||
mos6522_update_irq(s);
|
||||
break;
|
||||
case VIA_REG_DIRB:
|
||||
val = s->dirb;
|
||||
@ -304,7 +386,7 @@ uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size)
|
||||
}
|
||||
|
||||
if (addr != VIA_REG_IFR || val != 0) {
|
||||
trace_mos6522_read(addr, val);
|
||||
trace_mos6522_read(addr, mos6522_reg_names[addr], val);
|
||||
}
|
||||
|
||||
return val;
|
||||
@ -314,13 +396,20 @@ void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
||||
{
|
||||
MOS6522State *s = opaque;
|
||||
MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(s);
|
||||
int ctrl;
|
||||
|
||||
trace_mos6522_write(addr, val);
|
||||
trace_mos6522_write(addr, mos6522_reg_names[addr], val);
|
||||
|
||||
switch (addr) {
|
||||
case VIA_REG_B:
|
||||
s->b = (s->b & ~s->dirb) | (val & s->dirb);
|
||||
mdc->portB_write(s);
|
||||
ctrl = (s->pcr & CB2_CTRL_MASK) >> CB2_CTRL_SHIFT;
|
||||
if (!(ctrl & C2_IND)) {
|
||||
s->ifr &= ~CB2_INT;
|
||||
}
|
||||
s->ifr &= ~CB1_INT;
|
||||
mos6522_update_irq(s);
|
||||
break;
|
||||
case VIA_REG_A:
|
||||
qemu_log_mask(LOG_UNIMP, "Write access to register A with handshake");
|
||||
@ -328,6 +417,12 @@ void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
||||
case VIA_REG_ANH:
|
||||
s->a = (s->a & ~s->dira) | (val & s->dira);
|
||||
mdc->portA_write(s);
|
||||
ctrl = (s->pcr & CA2_CTRL_MASK) >> CA2_CTRL_SHIFT;
|
||||
if (!(ctrl & C2_IND)) {
|
||||
s->ifr &= ~CA2_INT;
|
||||
}
|
||||
s->ifr &= ~CA1_INT;
|
||||
mos6522_update_irq(s);
|
||||
break;
|
||||
case VIA_REG_DIRB:
|
||||
s->dirb = val;
|
||||
@ -403,6 +498,106 @@ void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
|
||||
}
|
||||
}
|
||||
|
||||
static int qmp_x_query_via_foreach(Object *obj, void *opaque)
|
||||
{
|
||||
GString *buf = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_MOS6522)) {
|
||||
MOS6522State *s = MOS6522(obj);
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
uint16_t t1counter = get_counter(s, &s->timers[0]);
|
||||
uint16_t t2counter = get_counter(s, &s->timers[1]);
|
||||
|
||||
g_string_append_printf(buf, "%s:\n", object_get_typename(obj));
|
||||
|
||||
g_string_append_printf(buf, " Registers:\n");
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[0], s->b);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[1], s->a);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[2], s->dirb);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[3], s->dira);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[4], t1counter & 0xff);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[5], t1counter >> 8);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[6],
|
||||
s->timers[0].latch & 0xff);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[7],
|
||||
s->timers[0].latch >> 8);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[8], t2counter & 0xff);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[9], t2counter >> 8);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[10], s->sr);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[11], s->acr);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[12], s->pcr);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[13], s->ifr);
|
||||
g_string_append_printf(buf, " %-*s: 0x%x\n", 4,
|
||||
mos6522_reg_names[14], s->ier);
|
||||
|
||||
g_string_append_printf(buf, " Timers:\n");
|
||||
g_string_append_printf(buf, " Using current time now(ns)=%"PRId64
|
||||
"\n", now);
|
||||
g_string_append_printf(buf, " T1 freq(hz)=%"PRId64
|
||||
" mode=%s"
|
||||
" counter=0x%x"
|
||||
" latch=0x%x\n"
|
||||
" load_time(ns)=%"PRId64
|
||||
" next_irq_time(ns)=%"PRId64 "\n",
|
||||
s->timers[0].frequency,
|
||||
((s->acr & T1MODE) == T1MODE_CONT) ? "continuous"
|
||||
: "one-shot",
|
||||
t1counter,
|
||||
s->timers[0].latch,
|
||||
s->timers[0].load_time,
|
||||
get_next_irq_time(s, &s->timers[0], now));
|
||||
g_string_append_printf(buf, " T2 freq(hz)=%"PRId64
|
||||
" mode=%s"
|
||||
" counter=0x%x"
|
||||
" latch=0x%x\n"
|
||||
" load_time(ns)=%"PRId64
|
||||
" next_irq_time(ns)=%"PRId64 "\n",
|
||||
s->timers[1].frequency,
|
||||
"one-shot",
|
||||
t2counter,
|
||||
s->timers[1].latch,
|
||||
s->timers[1].load_time,
|
||||
get_next_irq_time(s, &s->timers[1], now));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HumanReadableText *qmp_x_query_via(Error **errp)
|
||||
{
|
||||
g_autoptr(GString) buf = g_string_new("");
|
||||
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
qmp_x_query_via_foreach, buf);
|
||||
|
||||
return human_readable_text_from_str(buf);
|
||||
}
|
||||
|
||||
void hmp_info_via(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
g_autoptr(HumanReadableText) info = qmp_x_query_via(&err);
|
||||
|
||||
if (hmp_handle_error(mon, err)) {
|
||||
return;
|
||||
}
|
||||
monitor_printf(mon, "%s", info->human_readable_text);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mos6522_ops = {
|
||||
.read = mos6522_read,
|
||||
.write = mos6522_write,
|
||||
@ -429,8 +624,8 @@ static const VMStateDescription vmstate_mos6522_timer = {
|
||||
|
||||
const VMStateDescription vmstate_mos6522 = {
|
||||
.name = "mos6522",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(a, MOS6522State),
|
||||
VMSTATE_UINT8(b, MOS6522State),
|
||||
@ -441,6 +636,7 @@ const VMStateDescription vmstate_mos6522 = {
|
||||
VMSTATE_UINT8(pcr, MOS6522State),
|
||||
VMSTATE_UINT8(ifr, MOS6522State),
|
||||
VMSTATE_UINT8(ier, MOS6522State),
|
||||
VMSTATE_UINT8(last_irq_levels, MOS6522State),
|
||||
VMSTATE_STRUCT_ARRAY(timers, MOS6522State, 2, 0,
|
||||
vmstate_mos6522_timer, MOS6522Timer),
|
||||
VMSTATE_END_OF_LIST()
|
||||
@ -478,7 +674,8 @@ static void mos6522_init(Object *obj)
|
||||
MOS6522State *s = MOS6522(obj);
|
||||
int i;
|
||||
|
||||
memory_region_init_io(&s->mem, obj, &mos6522_ops, s, "mos6522", 0x10);
|
||||
memory_region_init_io(&s->mem, obj, &mos6522_ops, s, "mos6522",
|
||||
MOS6522_NUM_REGS);
|
||||
sysbus_init_mmio(sbd, &s->mem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
@ -488,6 +685,8 @@ static void mos6522_init(Object *obj)
|
||||
|
||||
s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer1, s);
|
||||
s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, mos6522_timer2, s);
|
||||
|
||||
qdev_init_gpio_in(DEVICE(obj), mos6522_set_irq, VIA_NUM_INTS);
|
||||
}
|
||||
|
||||
static void mos6522_finalize(Object *obj)
|
||||
@ -511,11 +710,8 @@ static void mos6522_class_init(ObjectClass *oc, void *data)
|
||||
dc->reset = mos6522_reset;
|
||||
dc->vmsd = &vmstate_mos6522;
|
||||
device_class_set_props(dc, mos6522_properties);
|
||||
mdc->parent_reset = dc->reset;
|
||||
mdc->set_sr_int = mos6522_set_sr_int;
|
||||
mdc->portB_write = mos6522_portB_write;
|
||||
mdc->portA_write = mos6522_portA_write;
|
||||
mdc->update_irq = mos6522_update_irq;
|
||||
mdc->get_timer1_counter_value = mos6522_get_counter_value;
|
||||
mdc->get_timer2_counter_value = mos6522_get_counter_value;
|
||||
mdc->get_timer1_load_time = mos6522_get_load_time;
|
||||
|
@ -95,8 +95,8 @@ imx7_gpr_write(uint64_t offset, uint64_t value) "addr 0x%08" PRIx64 "value 0x%08
|
||||
mos6522_set_counter(int index, unsigned int val) "T%d.counter=%d"
|
||||
mos6522_get_next_irq_time(uint16_t latch, int64_t d, int64_t delta) "latch=%d counter=0x%"PRId64 " delta_next=0x%"PRId64
|
||||
mos6522_set_sr_int(void) "set sr_int"
|
||||
mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
|
||||
mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
|
||||
mos6522_write(uint64_t addr, const char *name, uint64_t val) "reg=0x%"PRIx64 " [%s] val=0x%"PRIx64
|
||||
mos6522_read(uint64_t addr, const char *name, unsigned val) "reg=0x%"PRIx64 " [%s] val=0x%x"
|
||||
|
||||
# npcm7xx_clk.c
|
||||
npcm7xx_clk_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
|
||||
|
@ -195,6 +195,11 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
|
||||
esp_set_tc(s, dmalen);
|
||||
}
|
||||
|
||||
static void esp_set_pdma_cb(ESPState *s, enum pdma_cb cb)
|
||||
{
|
||||
s->pdma_cb = cb;
|
||||
}
|
||||
|
||||
static int esp_select(ESPState *s)
|
||||
{
|
||||
int target;
|
||||
@ -356,7 +361,7 @@ static void handle_satn(ESPState *s)
|
||||
s->dma_cb = handle_satn;
|
||||
return;
|
||||
}
|
||||
s->pdma_cb = satn_pdma_cb;
|
||||
esp_set_pdma_cb(s, SATN_PDMA_CB);
|
||||
cmdlen = get_cmd(s, ESP_CMDFIFO_SZ);
|
||||
if (cmdlen > 0) {
|
||||
s->cmdfifo_cdb_offset = 1;
|
||||
@ -387,7 +392,7 @@ static void handle_s_without_atn(ESPState *s)
|
||||
s->dma_cb = handle_s_without_atn;
|
||||
return;
|
||||
}
|
||||
s->pdma_cb = s_without_satn_pdma_cb;
|
||||
esp_set_pdma_cb(s, S_WITHOUT_SATN_PDMA_CB);
|
||||
cmdlen = get_cmd(s, ESP_CMDFIFO_SZ);
|
||||
if (cmdlen > 0) {
|
||||
s->cmdfifo_cdb_offset = 0;
|
||||
@ -422,7 +427,7 @@ static void handle_satn_stop(ESPState *s)
|
||||
s->dma_cb = handle_satn_stop;
|
||||
return;
|
||||
}
|
||||
s->pdma_cb = satn_stop_pdma_cb;
|
||||
esp_set_pdma_cb(s, SATN_STOP_PDMA_CB);
|
||||
cmdlen = get_cmd(s, 1);
|
||||
if (cmdlen > 0) {
|
||||
trace_esp_handle_satn_stop(fifo8_num_used(&s->cmdfifo));
|
||||
@ -464,7 +469,7 @@ static void write_response(ESPState *s)
|
||||
s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
|
||||
s->rregs[ESP_RSEQ] = SEQ_CD;
|
||||
} else {
|
||||
s->pdma_cb = write_response_pdma_cb;
|
||||
esp_set_pdma_cb(s, WRITE_RESPONSE_PDMA_CB);
|
||||
esp_raise_drq(s);
|
||||
return;
|
||||
}
|
||||
@ -604,7 +609,7 @@ static void esp_do_dma(ESPState *s)
|
||||
s->dma_memory_read(s->dma_opaque, buf, len);
|
||||
fifo8_push_all(&s->cmdfifo, buf, len);
|
||||
} else {
|
||||
s->pdma_cb = do_dma_pdma_cb;
|
||||
esp_set_pdma_cb(s, DO_DMA_PDMA_CB);
|
||||
esp_raise_drq(s);
|
||||
return;
|
||||
}
|
||||
@ -646,7 +651,7 @@ static void esp_do_dma(ESPState *s)
|
||||
if (s->dma_memory_read) {
|
||||
s->dma_memory_read(s->dma_opaque, s->async_buf, len);
|
||||
} else {
|
||||
s->pdma_cb = do_dma_pdma_cb;
|
||||
esp_set_pdma_cb(s, DO_DMA_PDMA_CB);
|
||||
esp_raise_drq(s);
|
||||
return;
|
||||
}
|
||||
@ -678,7 +683,7 @@ static void esp_do_dma(ESPState *s)
|
||||
}
|
||||
|
||||
esp_set_tc(s, esp_get_tc(s) - len);
|
||||
s->pdma_cb = do_dma_pdma_cb;
|
||||
esp_set_pdma_cb(s, DO_DMA_PDMA_CB);
|
||||
esp_raise_drq(s);
|
||||
|
||||
/* Indicate transfer to FIFO is complete */
|
||||
@ -777,6 +782,29 @@ static void esp_do_nodma(ESPState *s)
|
||||
esp_raise_irq(s);
|
||||
}
|
||||
|
||||
static void esp_pdma_cb(ESPState *s)
|
||||
{
|
||||
switch (s->pdma_cb) {
|
||||
case SATN_PDMA_CB:
|
||||
satn_pdma_cb(s);
|
||||
break;
|
||||
case S_WITHOUT_SATN_PDMA_CB:
|
||||
s_without_satn_pdma_cb(s);
|
||||
break;
|
||||
case SATN_STOP_PDMA_CB:
|
||||
satn_stop_pdma_cb(s);
|
||||
break;
|
||||
case WRITE_RESPONSE_PDMA_CB:
|
||||
write_response_pdma_cb(s);
|
||||
break;
|
||||
case DO_DMA_PDMA_CB:
|
||||
do_dma_pdma_cb(s);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
void esp_command_complete(SCSIRequest *req, size_t resid)
|
||||
{
|
||||
ESPState *s = req->hba_private;
|
||||
@ -1181,6 +1209,33 @@ static int esp_post_load(void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* PDMA (or pseudo-DMA) is only used on the Macintosh and requires the
|
||||
* guest CPU to perform the transfers between the SCSI bus and memory
|
||||
* itself. This is indicated by the dma_memory_read and dma_memory_write
|
||||
* functions being NULL (in contrast to the ESP PCI device) whilst
|
||||
* dma_enabled is still set.
|
||||
*/
|
||||
|
||||
static bool esp_pdma_needed(void *opaque)
|
||||
{
|
||||
ESPState *s = ESP(opaque);
|
||||
|
||||
return s->dma_memory_read == NULL && s->dma_memory_write == NULL &&
|
||||
s->dma_enabled;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_esp_pdma = {
|
||||
.name = "esp/pdma",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.needed = esp_pdma_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(pdma_cb, ESPState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
const VMStateDescription vmstate_esp = {
|
||||
.name = "esp",
|
||||
.version_id = 6,
|
||||
@ -1215,6 +1270,10 @@ const VMStateDescription vmstate_esp = {
|
||||
VMSTATE_UINT8_TEST(lun, ESPState, esp_is_version_6),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (const VMStateDescription * []) {
|
||||
&vmstate_esp_pdma,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
|
||||
@ -1263,7 +1322,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
|
||||
esp_pdma_write(s, val);
|
||||
break;
|
||||
}
|
||||
s->pdma_cb(s);
|
||||
esp_pdma_cb(s);
|
||||
}
|
||||
|
||||
static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
|
||||
@ -1285,11 +1344,20 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
|
||||
break;
|
||||
}
|
||||
if (fifo8_num_used(&s->fifo) < 2) {
|
||||
s->pdma_cb(s);
|
||||
esp_pdma_cb(s);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void *esp_load_request(QEMUFile *f, SCSIRequest *req)
|
||||
{
|
||||
ESPState *s = container_of(req->bus, ESPState, bus);
|
||||
|
||||
scsi_req_ref(req);
|
||||
s->current_req = req;
|
||||
return s;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps sysbus_esp_pdma_ops = {
|
||||
.read = sysbus_esp_pdma_read,
|
||||
.write = sysbus_esp_pdma_write,
|
||||
@ -1305,6 +1373,7 @@ static const struct SCSIBusInfo esp_scsi_info = {
|
||||
.max_target = ESP_MAX_DEVS,
|
||||
.max_lun = 7,
|
||||
|
||||
.load_request = esp_load_request,
|
||||
.transfer_data = esp_transfer_data,
|
||||
.complete = esp_command_complete,
|
||||
.cancel = esp_request_cancelled
|
||||
|
@ -48,7 +48,8 @@ typedef struct MacFbMode {
|
||||
uint32_t offset;
|
||||
} MacFbMode;
|
||||
|
||||
#define MACFB_NUM_REGS 8
|
||||
#define MACFB_CTRL_TOPADDR 0x200
|
||||
#define MACFB_NUM_REGS (MACFB_CTRL_TOPADDR / sizeof(uint32_t))
|
||||
|
||||
typedef struct MacfbState {
|
||||
MemoryRegion mem_vram;
|
||||
@ -66,8 +67,6 @@ typedef struct MacfbState {
|
||||
uint32_t regs[MACFB_NUM_REGS];
|
||||
MacFbMode *mode;
|
||||
|
||||
uint32_t irq_state;
|
||||
uint32_t irq_mask;
|
||||
QEMUTimer *vbl_timer;
|
||||
qemu_irq irq;
|
||||
} MacfbState;
|
||||
|
@ -18,19 +18,17 @@
|
||||
#define VIA_SIZE 0x2000
|
||||
|
||||
/* VIA 1 */
|
||||
#define VIA1_IRQ_ONE_SECOND_BIT 0
|
||||
#define VIA1_IRQ_60HZ_BIT 1
|
||||
#define VIA1_IRQ_ADB_READY_BIT 2
|
||||
#define VIA1_IRQ_ADB_DATA_BIT 3
|
||||
#define VIA1_IRQ_ADB_CLOCK_BIT 4
|
||||
#define VIA1_IRQ_ONE_SECOND_BIT CA2_INT_BIT
|
||||
#define VIA1_IRQ_60HZ_BIT CA1_INT_BIT
|
||||
#define VIA1_IRQ_ADB_READY_BIT SR_INT_BIT
|
||||
#define VIA1_IRQ_ADB_DATA_BIT CB2_INT_BIT
|
||||
#define VIA1_IRQ_ADB_CLOCK_BIT CB1_INT_BIT
|
||||
|
||||
#define VIA1_IRQ_NB 8
|
||||
|
||||
#define VIA1_IRQ_ONE_SECOND (1 << VIA1_IRQ_ONE_SECOND_BIT)
|
||||
#define VIA1_IRQ_60HZ (1 << VIA1_IRQ_60HZ_BIT)
|
||||
#define VIA1_IRQ_ADB_READY (1 << VIA1_IRQ_ADB_READY_BIT)
|
||||
#define VIA1_IRQ_ADB_DATA (1 << VIA1_IRQ_ADB_DATA_BIT)
|
||||
#define VIA1_IRQ_ADB_CLOCK (1 << VIA1_IRQ_ADB_CLOCK_BIT)
|
||||
#define VIA1_IRQ_ONE_SECOND BIT(VIA1_IRQ_ONE_SECOND_BIT)
|
||||
#define VIA1_IRQ_60HZ BIT(VIA1_IRQ_60HZ_BIT)
|
||||
#define VIA1_IRQ_ADB_READY BIT(VIA1_IRQ_ADB_READY_BIT)
|
||||
#define VIA1_IRQ_ADB_DATA BIT(VIA1_IRQ_ADB_DATA_BIT)
|
||||
#define VIA1_IRQ_ADB_CLOCK BIT(VIA1_IRQ_ADB_CLOCK_BIT)
|
||||
|
||||
|
||||
#define TYPE_MOS6522_Q800_VIA1 "mos6522-q800-via1"
|
||||
@ -42,7 +40,6 @@ struct MOS6522Q800VIA1State {
|
||||
|
||||
MemoryRegion via_mem;
|
||||
|
||||
qemu_irq irqs[VIA1_IRQ_NB];
|
||||
qemu_irq auxmode_irq;
|
||||
uint8_t last_b;
|
||||
|
||||
@ -80,19 +77,16 @@ struct MOS6522Q800VIA1State {
|
||||
|
||||
|
||||
/* VIA 2 */
|
||||
#define VIA2_IRQ_SCSI_DATA_BIT 0
|
||||
#define VIA2_IRQ_NUBUS_BIT 1
|
||||
#define VIA2_IRQ_UNUSED_BIT 2
|
||||
#define VIA2_IRQ_SCSI_BIT 3
|
||||
#define VIA2_IRQ_ASC_BIT 4
|
||||
#define VIA2_IRQ_SCSI_DATA_BIT CA2_INT_BIT
|
||||
#define VIA2_IRQ_NUBUS_BIT CA1_INT_BIT
|
||||
#define VIA2_IRQ_SCSI_BIT CB2_INT_BIT
|
||||
#define VIA2_IRQ_ASC_BIT CB1_INT_BIT
|
||||
|
||||
#define VIA2_IRQ_NB 8
|
||||
|
||||
#define VIA2_IRQ_SCSI_DATA (1 << VIA2_IRQ_SCSI_DATA_BIT)
|
||||
#define VIA2_IRQ_NUBUS (1 << VIA2_IRQ_NUBUS_BIT)
|
||||
#define VIA2_IRQ_UNUSED (1 << VIA2_IRQ_SCSI_BIT)
|
||||
#define VIA2_IRQ_SCSI (1 << VIA2_IRQ_UNUSED_BIT)
|
||||
#define VIA2_IRQ_ASC (1 << VIA2_IRQ_ASC_BIT)
|
||||
#define VIA2_IRQ_SCSI_DATA BIT(VIA2_IRQ_SCSI_DATA_BIT)
|
||||
#define VIA2_IRQ_NUBUS BIT(VIA2_IRQ_NUBUS_BIT)
|
||||
#define VIA2_IRQ_UNUSED BIT(VIA2_IRQ_SCSI_BIT)
|
||||
#define VIA2_IRQ_SCSI BIT(VIA2_IRQ_UNUSED_BIT)
|
||||
#define VIA2_IRQ_ASC BIT(VIA2_IRQ_ASC_BIT)
|
||||
|
||||
#define VIA2_NUBUS_IRQ_NB 7
|
||||
|
||||
|
@ -193,8 +193,6 @@ struct PMUState {
|
||||
|
||||
MemoryRegion mem;
|
||||
uint64_t frequency;
|
||||
qemu_irq via_irq;
|
||||
bool via_irq_state;
|
||||
|
||||
/* PMU state */
|
||||
MOS6522PMUState mos6522_pmu;
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "hw/input/adb.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define MOS6522_NUM_REGS 16
|
||||
|
||||
/* Bits in ACR */
|
||||
#define SR_CTRL 0x1c /* Shift register control bits */
|
||||
#define SR_EXT 0x0c /* Shift on external clock */
|
||||
@ -41,18 +43,43 @@
|
||||
#define IER_SET 0x80 /* set bits in IER */
|
||||
#define IER_CLR 0 /* clear bits in IER */
|
||||
|
||||
#define CA2_INT 0x01
|
||||
#define CA1_INT 0x02
|
||||
#define SR_INT 0x04 /* Shift register full/empty */
|
||||
#define CB2_INT 0x08
|
||||
#define CB1_INT 0x10
|
||||
#define T2_INT 0x20 /* Timer 2 interrupt */
|
||||
#define T1_INT 0x40 /* Timer 1 interrupt */
|
||||
#define CA2_INT_BIT 0
|
||||
#define CA1_INT_BIT 1
|
||||
#define SR_INT_BIT 2 /* Shift register full/empty */
|
||||
#define CB2_INT_BIT 3
|
||||
#define CB1_INT_BIT 4
|
||||
#define T2_INT_BIT 5 /* Timer 2 interrupt */
|
||||
#define T1_INT_BIT 6 /* Timer 1 interrupt */
|
||||
|
||||
#define CA2_INT BIT(CA2_INT_BIT)
|
||||
#define CA1_INT BIT(CA1_INT_BIT)
|
||||
#define SR_INT BIT(SR_INT_BIT)
|
||||
#define CB2_INT BIT(CB2_INT_BIT)
|
||||
#define CB1_INT BIT(CB1_INT_BIT)
|
||||
#define T2_INT BIT(T2_INT_BIT)
|
||||
#define T1_INT BIT(T1_INT_BIT)
|
||||
|
||||
#define VIA_NUM_INTS 5
|
||||
|
||||
/* Bits in ACR */
|
||||
#define T1MODE 0xc0 /* Timer 1 mode */
|
||||
#define T1MODE_CONT 0x40 /* continuous interrupts */
|
||||
|
||||
/* Bits in PCR */
|
||||
#define CB2_CTRL_MASK 0xe0
|
||||
#define CB2_CTRL_SHIFT 5
|
||||
#define CB1_CTRL_MASK 0x10
|
||||
#define CB1_CTRL_SHIFT 4
|
||||
#define CA2_CTRL_MASK 0x0e
|
||||
#define CA2_CTRL_SHIFT 1
|
||||
#define CA1_CTRL_MASK 0x1
|
||||
#define CA1_CTRL_SHIFT 0
|
||||
|
||||
#define C2_POS 0x2
|
||||
#define C2_IND 0x1
|
||||
|
||||
#define C1_POS 0x1
|
||||
|
||||
/* VIA registers */
|
||||
#define VIA_REG_B 0x00
|
||||
#define VIA_REG_A 0x01
|
||||
@ -121,6 +148,7 @@ struct MOS6522State {
|
||||
uint64_t frequency;
|
||||
|
||||
qemu_irq irq;
|
||||
uint8_t last_irq_levels;
|
||||
};
|
||||
|
||||
#define TYPE_MOS6522 "mos6522"
|
||||
@ -130,10 +158,8 @@ struct MOS6522DeviceClass {
|
||||
DeviceClass parent_class;
|
||||
|
||||
DeviceReset parent_reset;
|
||||
void (*set_sr_int)(MOS6522State *dev);
|
||||
void (*portB_write)(MOS6522State *dev);
|
||||
void (*portA_write)(MOS6522State *dev);
|
||||
void (*update_irq)(MOS6522State *dev);
|
||||
/* These are used to influence the CUDA MacOS timebase calibration */
|
||||
uint64_t (*get_timer1_counter_value)(MOS6522State *dev, MOS6522Timer *ti);
|
||||
uint64_t (*get_timer2_counter_value)(MOS6522State *dev, MOS6522Timer *ti);
|
||||
@ -147,4 +173,6 @@ extern const VMStateDescription vmstate_mos6522;
|
||||
uint64_t mos6522_read(void *opaque, hwaddr addr, unsigned size);
|
||||
void mos6522_write(void *opaque, hwaddr addr, uint64_t val, unsigned size);
|
||||
|
||||
void hmp_info_via(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif /* MOS6522_H */
|
||||
|
@ -51,7 +51,7 @@ struct ESPState {
|
||||
ESPDMAMemoryReadWriteFunc dma_memory_write;
|
||||
void *dma_opaque;
|
||||
void (*dma_cb)(ESPState *s);
|
||||
void (*pdma_cb)(ESPState *s);
|
||||
uint8_t pdma_cb;
|
||||
|
||||
uint8_t mig_version_id;
|
||||
|
||||
@ -150,6 +150,15 @@ struct SysBusESPState {
|
||||
#define TCHI_FAS100A 0x4
|
||||
#define TCHI_AM53C974 0x12
|
||||
|
||||
/* PDMA callbacks */
|
||||
enum pdma_cb {
|
||||
SATN_PDMA_CB = 0,
|
||||
S_WITHOUT_SATN_PDMA_CB = 1,
|
||||
SATN_STOP_PDMA_CB = 2,
|
||||
WRITE_RESPONSE_PDMA_CB = 3,
|
||||
DO_DMA_PDMA_CB = 4
|
||||
};
|
||||
|
||||
void esp_dma_enable(ESPState *s, int irq, int level);
|
||||
void esp_request_cancelled(SCSIRequest *req);
|
||||
void esp_command_complete(SCSIRequest *req, size_t resid);
|
||||
|
@ -50,5 +50,6 @@ void hmp_mce(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_local_apic(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_sev(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_sgx(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_via(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif /* MONITOR_HMP_TARGET_H */
|
||||
|
Loading…
Reference in New Issue
Block a user