hw/hppa/dino.c: Improve emulation of Dino PCI chip

The tests of the dino chip with the Online-diagnostics CD
("ODE DINOTEST") now succeeds.
Additionally add some qemu trace events.

Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20191220211512.3289-2-svens@stackframe.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Helge Deller 2019-12-20 22:15:07 +01:00 committed by Richard Henderson
parent 105b07f1ba
commit 18092598a5
3 changed files with 89 additions and 15 deletions

View File

@ -890,7 +890,7 @@ F: hw/*/etraxfs_*.c
HP-PARISC Machines HP-PARISC Machines
------------------ ------------------
Dino HP B160L
M: Richard Henderson <rth@twiddle.net> M: Richard Henderson <rth@twiddle.net>
R: Helge Deller <deller@gmx.de> R: Helge Deller <deller@gmx.de>
S: Odd Fixes S: Odd Fixes

View File

@ -1,7 +1,7 @@
/* /*
* HP-PARISC Dino PCI chipset emulation. * HP-PARISC Dino PCI chipset emulation, as in B160L and similiar machines
* *
* (C) 2017 by Helge Deller <deller@gmx.de> * (C) 2017-2019 by Helge Deller <deller@gmx.de>
* *
* This work is licensed under the GNU GPL license version 2 or later. * This work is licensed under the GNU GPL license version 2 or later.
* *
@ -21,6 +21,7 @@
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "hppa_sys.h" #include "hppa_sys.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "trace.h"
#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost" #define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost"
@ -82,11 +83,28 @@
#define DINO_PCI_HOST_BRIDGE(obj) \ #define DINO_PCI_HOST_BRIDGE(obj) \
OBJECT_CHECK(DinoState, (obj), TYPE_DINO_PCI_HOST_BRIDGE) OBJECT_CHECK(DinoState, (obj), TYPE_DINO_PCI_HOST_BRIDGE)
#define DINO800_REGS ((DINO_TLTIM - DINO_GMASK) / 4)
static const uint32_t reg800_keep_bits[DINO800_REGS] = {
MAKE_64BIT_MASK(0, 1),
MAKE_64BIT_MASK(0, 7),
MAKE_64BIT_MASK(0, 7),
MAKE_64BIT_MASK(0, 8),
MAKE_64BIT_MASK(0, 7),
MAKE_64BIT_MASK(0, 9),
MAKE_64BIT_MASK(0, 32),
MAKE_64BIT_MASK(0, 8),
MAKE_64BIT_MASK(0, 30),
MAKE_64BIT_MASK(0, 25),
MAKE_64BIT_MASK(0, 22),
MAKE_64BIT_MASK(0, 9),
};
typedef struct DinoState { typedef struct DinoState {
PCIHostState parent_obj; PCIHostState parent_obj;
/* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, /* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops,
so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. */ so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. */
uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */
uint32_t iar0; uint32_t iar0;
uint32_t iar1; uint32_t iar1;
@ -94,8 +112,12 @@ typedef struct DinoState {
uint32_t ipr; uint32_t ipr;
uint32_t icr; uint32_t icr;
uint32_t ilr; uint32_t ilr;
uint32_t io_fbb_en;
uint32_t io_addr_en; uint32_t io_addr_en;
uint32_t io_control; uint32_t io_control;
uint32_t toc_addr;
uint32_t reg800[DINO800_REGS];
MemoryRegion this_mem; MemoryRegion this_mem;
MemoryRegion pci_mem; MemoryRegion pci_mem;
@ -106,8 +128,6 @@ typedef struct DinoState {
MemoryRegion bm_ram_alias; MemoryRegion bm_ram_alias;
MemoryRegion bm_pci_alias; MemoryRegion bm_pci_alias;
MemoryRegion bm_cpu_alias; MemoryRegion bm_cpu_alias;
MemoryRegion cpu0_eir_mem;
} DinoState; } DinoState;
/* /*
@ -122,6 +142,8 @@ static void gsc_to_pci_forwarding(DinoState *s)
tmp = extract32(s->io_control, 7, 2); tmp = extract32(s->io_control, 7, 2);
enabled = (tmp == 0x01); enabled = (tmp == 0x01);
io_addr_en = s->io_addr_en; io_addr_en = s->io_addr_en;
/* Mask out first (=firmware) and last (=Dino) areas. */
io_addr_en &= ~(BIT(31) | BIT(0));
memory_region_transaction_begin(); memory_region_transaction_begin();
for (i = 1; i < 31; i++) { for (i = 1; i < 31; i++) {
@ -142,6 +164,8 @@ static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
unsigned size, bool is_write, unsigned size, bool is_write,
MemTxAttrs attrs) MemTxAttrs attrs)
{ {
bool ret = false;
switch (addr) { switch (addr) {
case DINO_IAR0: case DINO_IAR0:
case DINO_IAR1: case DINO_IAR1:
@ -152,16 +176,22 @@ static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
case DINO_ICR: case DINO_ICR:
case DINO_ILR: case DINO_ILR:
case DINO_IO_CONTROL: case DINO_IO_CONTROL:
case DINO_IO_FBB_EN:
case DINO_IO_ADDR_EN: case DINO_IO_ADDR_EN:
case DINO_PCI_IO_DATA: case DINO_PCI_IO_DATA:
return true; case DINO_TOC_ADDR:
case DINO_GMASK ... DINO_TLTIM:
ret = true;
break;
case DINO_PCI_IO_DATA + 2: case DINO_PCI_IO_DATA + 2:
return size <= 2; ret = (size <= 2);
break;
case DINO_PCI_IO_DATA + 1: case DINO_PCI_IO_DATA + 1:
case DINO_PCI_IO_DATA + 3: case DINO_PCI_IO_DATA + 3:
return size == 1; ret = (size == 1);
} }
return false; trace_dino_chip_mem_valid(addr, ret);
return ret;
} }
static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr, static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr,
@ -194,6 +224,9 @@ static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr,
} }
break; break;
case DINO_IO_FBB_EN:
val = s->io_fbb_en;
break;
case DINO_IO_ADDR_EN: case DINO_IO_ADDR_EN:
val = s->io_addr_en; val = s->io_addr_en;
break; break;
@ -227,12 +260,28 @@ static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr,
case DINO_IRR1: case DINO_IRR1:
val = s->ilr & s->imr & s->icr; val = s->ilr & s->imr & s->icr;
break; break;
case DINO_TOC_ADDR:
val = s->toc_addr;
break;
case DINO_GMASK ... DINO_TLTIM:
val = s->reg800[(addr - DINO_GMASK) / 4];
if (addr == DINO_PAMR) {
val &= ~0x01; /* LSB is hardwired to 0 */
}
if (addr == DINO_MLTIM) {
val &= ~0x07; /* 3 LSB are hardwired to 0 */
}
if (addr == DINO_BRDG_FEAT) {
val &= ~(0x10710E0ul | 8); /* bits 5-7, 24 & 15 reserved */
}
break;
default: default:
/* Controlled by dino_chip_mem_valid above. */ /* Controlled by dino_chip_mem_valid above. */
g_assert_not_reached(); g_assert_not_reached();
} }
trace_dino_chip_read(addr, val);
*data = val; *data = val;
return ret; return ret;
} }
@ -245,6 +294,9 @@ static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr,
AddressSpace *io; AddressSpace *io;
MemTxResult ret; MemTxResult ret;
uint16_t ioaddr; uint16_t ioaddr;
int i;
trace_dino_chip_write(addr, val);
switch (addr) { switch (addr) {
case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3: case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3:
@ -266,9 +318,11 @@ static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr,
} }
return ret; return ret;
case DINO_IO_FBB_EN:
s->io_fbb_en = val & 0x03;
break;
case DINO_IO_ADDR_EN: case DINO_IO_ADDR_EN:
/* Never allow first (=firmware) and last (=Dino) areas. */ s->io_addr_en = val;
s->io_addr_en = val & 0x7ffffffe;
gsc_to_pci_forwarding(s); gsc_to_pci_forwarding(s);
break; break;
case DINO_IO_CONTROL: case DINO_IO_CONTROL:
@ -292,6 +346,10 @@ static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr,
/* Any write to IPR clears the register. */ /* Any write to IPR clears the register. */
s->ipr = 0; s->ipr = 0;
break; break;
case DINO_TOC_ADDR:
/* IO_COMMAND of CPU with client_id bits */
s->toc_addr = 0xFFFA0030 | (val & 0x1e000);
break;
case DINO_ILR: case DINO_ILR:
case DINO_IRR0: case DINO_IRR0:
@ -299,6 +357,12 @@ static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr,
/* These registers are read-only. */ /* These registers are read-only. */
break; break;
case DINO_GMASK ... DINO_TLTIM:
i = (addr - DINO_GMASK) / 4;
val &= reg800_keep_bits[i];
s->reg800[i] = val;
break;
default: default:
/* Controlled by dino_chip_mem_valid above. */ /* Controlled by dino_chip_mem_valid above. */
g_assert_not_reached(); g_assert_not_reached();
@ -323,7 +387,7 @@ static const MemoryRegionOps dino_chip_ops = {
static const VMStateDescription vmstate_dino = { static const VMStateDescription vmstate_dino = {
.name = "Dino", .name = "Dino",
.version_id = 1, .version_id = 2,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(iar0, DinoState), VMSTATE_UINT32(iar0, DinoState),
@ -332,13 +396,14 @@ static const VMStateDescription vmstate_dino = {
VMSTATE_UINT32(ipr, DinoState), VMSTATE_UINT32(ipr, DinoState),
VMSTATE_UINT32(icr, DinoState), VMSTATE_UINT32(icr, DinoState),
VMSTATE_UINT32(ilr, DinoState), VMSTATE_UINT32(ilr, DinoState),
VMSTATE_UINT32(io_fbb_en, DinoState),
VMSTATE_UINT32(io_addr_en, DinoState), VMSTATE_UINT32(io_addr_en, DinoState),
VMSTATE_UINT32(io_control, DinoState), VMSTATE_UINT32(io_control, DinoState),
VMSTATE_UINT32(toc_addr, DinoState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }
}; };
/* Unlike pci_config_data_le_ops, no check of high bit set in config_reg. */ /* Unlike pci_config_data_le_ops, no check of high bit set in config_reg. */
static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len) static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len)
@ -362,14 +427,16 @@ static const MemoryRegionOps dino_config_data_ops = {
static uint64_t dino_config_addr_read(void *opaque, hwaddr addr, unsigned len) static uint64_t dino_config_addr_read(void *opaque, hwaddr addr, unsigned len)
{ {
PCIHostState *s = opaque; DinoState *s = opaque;
return s->config_reg; return s->config_reg_dino;
} }
static void dino_config_addr_write(void *opaque, hwaddr addr, static void dino_config_addr_write(void *opaque, hwaddr addr,
uint64_t val, unsigned len) uint64_t val, unsigned len)
{ {
PCIHostState *s = opaque; PCIHostState *s = opaque;
DinoState *ds = opaque;
ds->config_reg_dino = val; /* keep a copy of original value */
s->config_reg = val & ~3U; s->config_reg = val & ~3U;
} }
@ -453,6 +520,8 @@ PCIBus *dino_init(MemoryRegion *addr_space,
dev = qdev_create(NULL, TYPE_DINO_PCI_HOST_BRIDGE); dev = qdev_create(NULL, TYPE_DINO_PCI_HOST_BRIDGE);
s = DINO_PCI_HOST_BRIDGE(dev); s = DINO_PCI_HOST_BRIDGE(dev);
s->iar0 = s->iar1 = CPU_HPA + 3;
s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */
/* Dino PCI access from main memory. */ /* Dino PCI access from main memory. */
memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops, memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops,

View File

@ -2,3 +2,8 @@
# pci.c # pci.c
hppa_pci_iack_write(void) "" hppa_pci_iack_write(void) ""
# dino.c
dino_chip_mem_valid(uint64_t addr, uint32_t val) "access to addr 0x%"PRIx64" is %d"
dino_chip_read(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x"
dino_chip_write(uint64_t addr, uint32_t val) "addr 0x%"PRIx64" val 0x%08x"