diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-06-12 12:49:40 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-06-12 12:49:40 +0100 |
commit | 4cb618abc1818586c08011ff0a84a015787b1672 (patch) | |
tree | e10d9c848bfe284a7687976310c4fafa1974e43b | |
parent | a4ef02fd9b3d12b105b56942166c8364ade9be0f (diff) | |
parent | 6773f9b687e0a8ab4b638ef88d075fb233fb7669 (diff) |
Merge remote-tracking branch 'remotes/lalrae/tags/mips-20150612' into staging
MIPS patches 2015-06-12
Changes:
* improve dp8393x network card and rc4030 chipset emulation
* support misaligned R6 and MSA memory accesses
* support MIPS eXtended and Large Physical Addressing
* add Config5.FRE bit and ERETNC instruction (Config5.LLB)
* support ememsize on MALTA
# gpg: Signature made Fri Jun 12 09:38:11 2015 BST using RSA key ID 0B29DA6B
# gpg: Good signature from "Leon Alrae <leon.alrae@imgtec.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 8DD3 2F98 5495 9D66 35D4 4FC0 5211 8E3C 0B29 DA6B
* remotes/lalrae/tags/mips-20150612: (29 commits)
target-mips: enable XPA and LPA features
target-mips: remove misleading comments in translate_init.c
target-mips: add MTHC0 and MFHC0 instructions
target-mips: add CP0.PageGrain.ELPA support
target-mips: support Page Frame Number Extension field
target-mips: extend selected CP0 registers to 64-bits in MIPS32
target-mips: correct MFC0 for CP0.EntryLo in MIPS64
net/dp8393x: fix hardware reset
net/dp8393x: correctly reset in_use field
net/dp8393x: add load/save support
net/dp8393x: add PROM to store MAC address
net/dp8393x: QOM'ify
net/dp8393x: use dp8393x_ prefix for all functions
net/dp8393x: do not use old_mmio accesses
net/dp8393x: always calculate proper checksums
dma/rc4030: convert to QOM
dma/rc4030: use trace events instead of custom logging
dma/rc4030: document register at offset 0x210
dma/rc4030: do not use old_mmio accesses
dma/rc4030: use AddressSpace and address_space_rw in users
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | default-configs/mips-softmmu.mak | 5 | ||||
-rw-r--r-- | default-configs/mips64-softmmu.mak | 1 | ||||
-rw-r--r-- | default-configs/mips64el-softmmu.mak | 1 | ||||
-rw-r--r-- | default-configs/mipsel-softmmu.mak | 5 | ||||
-rw-r--r-- | disas/mips.c | 3 | ||||
-rw-r--r-- | hw/dma/rc4030.c | 462 | ||||
-rw-r--r-- | hw/mips/Makefile.objs | 3 | ||||
-rw-r--r-- | hw/mips/mips_jazz.c | 53 | ||||
-rw-r--r-- | hw/mips/mips_malta.c | 15 | ||||
-rw-r--r-- | hw/net/dp8393x.c | 369 | ||||
-rw-r--r-- | include/exec/exec-all.h | 2 | ||||
-rw-r--r-- | include/hw/mips/mips.h | 11 | ||||
-rw-r--r-- | softmmu_template.h | 22 | ||||
-rw-r--r-- | target-mips/cpu.h | 52 | ||||
-rw-r--r-- | target-mips/helper.h | 11 | ||||
-rw-r--r-- | target-mips/machine.c | 21 | ||||
-rw-r--r-- | target-mips/mips-defs.h | 4 | ||||
-rw-r--r-- | target-mips/op_helper.c | 244 | ||||
-rw-r--r-- | target-mips/translate.c | 802 | ||||
-rw-r--r-- | target-mips/translate_init.c | 37 | ||||
-rw-r--r-- | tests/endianness-test.c | 2 | ||||
-rw-r--r-- | trace-events | 6 |
22 files changed, 1291 insertions, 840 deletions
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak index fd0607db6b..44467c37c1 100644 --- a/default-configs/mips-softmmu.mak +++ b/default-configs/mips-softmmu.mak @@ -24,14 +24,9 @@ CONFIG_PIIX4=y CONFIG_IDE_ISA=y CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y -CONFIG_RC4030=y -CONFIG_DP8393X=y -CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y -CONFIG_G364FB=y CONFIG_I8259=y -CONFIG_JAZZ_LED=y CONFIG_MC146818RTC=y CONFIG_ISA_TESTDEV=y CONFIG_EMPTY_SLOT=y diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak index b8c791021a..66ed5f94c5 100644 --- a/default-configs/mips64-softmmu.mak +++ b/default-configs/mips64-softmmu.mak @@ -29,6 +29,7 @@ CONFIG_DP8393X=y CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y +CONFIG_JAZZ=y CONFIG_G364FB=y CONFIG_I8259=y CONFIG_JAZZ_LED=y diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index ae4274b3a7..bfca2b2b7c 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -31,6 +31,7 @@ CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y CONFIG_FULONG=y +CONFIG_JAZZ=y CONFIG_G364FB=y CONFIG_I8259=y CONFIG_JAZZ_LED=y diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak index 1e2374be13..0162ef0249 100644 --- a/default-configs/mipsel-softmmu.mak +++ b/default-configs/mipsel-softmmu.mak @@ -24,14 +24,9 @@ CONFIG_PIIX4=y CONFIG_IDE_ISA=y CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y -CONFIG_RC4030=y -CONFIG_DP8393X=y -CONFIG_DS1225Y=y CONFIG_MIPSNET=y CONFIG_PFLASH_CFI01=y -CONFIG_G364FB=y CONFIG_I8259=y -CONFIG_JAZZ_LED=y CONFIG_MC146818RTC=y CONFIG_ISA_TESTDEV=y CONFIG_EMPTY_SLOT=y diff --git a/disas/mips.c b/disas/mips.c index 1afe0c5511..32940feb95 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -2238,6 +2238,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 }, {"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 }, {"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 }, +{"mfhc0", "t,G,H", 0x40400000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I33}, +{"mthc0", "t,G,H", 0x40c00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I33}, {"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 }, {"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, {"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 }, @@ -2407,6 +2409,7 @@ const struct mips_opcode mips_builtin_opcodes[] = {"emt", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 }, {"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, {"eret", "", 0x42000018, 0xffffffff, 0, 0, I3|I32 }, +{"eretnc", "", 0x42000058, 0xffffffff, 0, 0, I33}, {"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 }, {"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, {"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 }, diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index af2663256e..3efa6de352 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -1,7 +1,7 @@ /* * QEMU JAZZ RC4030 chipset * - * Copyright (c) 2007-2009 Herve Poussineau + * Copyright (c) 2007-2013 Hervé Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,29 +24,16 @@ #include "hw/hw.h" #include "hw/mips/mips.h" +#include "hw/sysbus.h" #include "qemu/timer.h" - -/********************************************************/ -/* debug rc4030 */ - -//#define DEBUG_RC4030 -//#define DEBUG_RC4030_DMA - -#ifdef DEBUG_RC4030 -#define DPRINTF(fmt, ...) \ -do { printf("rc4030: " fmt , ## __VA_ARGS__); } while (0) -static const char* irq_names[] = { "parallel", "floppy", "sound", "video", - "network", "scsi", "keyboard", "mouse", "serial0", "serial1" }; -#else -#define DPRINTF(fmt, ...) -#endif - -#define RC4030_ERROR(fmt, ...) \ -do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) +#include "exec/address-spaces.h" +#include "trace.h" /********************************************************/ /* rc4030 emulation */ +#define MAX_TL_ENTRIES 512 + typedef struct dma_pagetable_entry { int32_t frame; int32_t owner; @@ -63,8 +50,14 @@ typedef struct dma_pagetable_entry { #define DMA_FLAG_MEM_INTR 0x0200 #define DMA_FLAG_ADDR_INTR 0x0400 +#define TYPE_RC4030 "rc4030" +#define RC4030(obj) \ + OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030) + typedef struct rc4030State { + SysBusDevice parent; + uint32_t config; /* 0x0000: RC4030 config register */ uint32_t revision; /* 0x0008: RC4030 Revision register */ uint32_t invalid_address_register; /* 0x0010: Invalid Address register */ @@ -83,7 +76,7 @@ typedef struct rc4030State uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */ uint32_t nmi_interrupt; /* 0x0200: interrupt source */ - uint32_t offset210; + uint32_t memory_refresh_rate; /* 0x0210: memory refresh rate */ uint32_t nvram_protect; /* 0x0220: NV ram protect register */ uint32_t rem_speed[16]; uint32_t imr_jazz; /* Local bus int enable mask */ @@ -96,6 +89,16 @@ typedef struct rc4030State qemu_irq timer_irq; qemu_irq jazz_bus_irq; + /* biggest translation table */ + MemoryRegion dma_tt; + /* translation table memory region alias, added to system RAM */ + MemoryRegion dma_tt_alias; + /* whole DMA memory region, root of DMA address space */ + MemoryRegion dma_mr; + /* translation table entry aliases, added to DMA memory region */ + MemoryRegion dma_mrs[MAX_TL_ENTRIES]; + AddressSpace dma_as; + MemoryRegion iomem_chipset; MemoryRegion iomem_jazzio; } rc4030State; @@ -112,7 +115,7 @@ static void set_next_tick(rc4030State *s) } /* called for accesses to rc4030 */ -static uint32_t rc4030_readl(void *opaque, hwaddr addr) +static uint64_t rc4030_read(void *opaque, hwaddr addr, unsigned int size) { rc4030State *s = opaque; uint32_t val; @@ -220,9 +223,9 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr) case 0x0208: val = 0; break; - /* Offset 0x0210 */ + /* Memory refresh rate */ case 0x0210: - val = s->offset210; + val = s->memory_refresh_rate; break; /* NV ram protect register */ case 0x0220: @@ -238,39 +241,117 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr) val = 7; /* FIXME: should be read from EISA controller */ break; default: - RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030: invalid read at 0x%x", (int)addr); val = 0; break; } if ((addr & ~3) != 0x230) { - DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr); + trace_rc4030_read(addr, val); } return val; } -static uint32_t rc4030_readw(void *opaque, hwaddr addr) +static void rc4030_dma_as_update_one(rc4030State *s, int index, uint32_t frame) { - uint32_t v = rc4030_readl(opaque, addr & ~0x3); - if (addr & 0x2) - return v >> 16; - else - return v & 0xffff; + if (index < MAX_TL_ENTRIES) { + memory_region_set_enabled(&s->dma_mrs[index], false); + } + + if (!frame) { + return; + } + + if (index >= MAX_TL_ENTRIES) { + qemu_log_mask(LOG_UNIMP, + "rc4030: trying to use too high " + "translation table entry %d (max allowed=%d)", + index, MAX_TL_ENTRIES); + return; + } + memory_region_set_alias_offset(&s->dma_mrs[index], frame); + memory_region_set_enabled(&s->dma_mrs[index], true); } -static uint32_t rc4030_readb(void *opaque, hwaddr addr) +static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { - uint32_t v = rc4030_readl(opaque, addr & ~0x3); - return (v >> (8 * (addr & 0x3))) & 0xff; + rc4030State *s = opaque; + + /* write memory */ + memcpy(memory_region_get_ram_ptr(&s->dma_tt) + addr, &data, size); + + /* update dma address space (only if frame field has been written) */ + if (addr % sizeof(dma_pagetable_entry) == 0) { + int index = addr / sizeof(dma_pagetable_entry); + memory_region_transaction_begin(); + rc4030_dma_as_update_one(s, index, (uint32_t)data); + memory_region_transaction_commit(); + } } -static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) +static const MemoryRegionOps rc4030_dma_tt_ops = { + .write = rc4030_dma_tt_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, +}; + +static void rc4030_dma_tt_update(rc4030State *s, uint32_t new_tl_base, + uint32_t new_tl_limit) +{ + int entries, i; + dma_pagetable_entry *dma_tl_contents; + + if (s->dma_tl_limit) { + /* write old dma tl table to physical memory */ + memory_region_del_subregion(get_system_memory(), &s->dma_tt_alias); + cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff, + memory_region_get_ram_ptr(&s->dma_tt), + memory_region_size(&s->dma_tt_alias)); + } + object_unparent(OBJECT(&s->dma_tt_alias)); + + s->dma_tl_base = new_tl_base; + s->dma_tl_limit = new_tl_limit; + new_tl_base &= 0x7fffffff; + + if (s->dma_tl_limit) { + uint64_t dma_tt_size; + if (s->dma_tl_limit <= memory_region_size(&s->dma_tt)) { + dma_tt_size = s->dma_tl_limit; + } else { + dma_tt_size = memory_region_size(&s->dma_tt); + } + memory_region_init_alias(&s->dma_tt_alias, OBJECT(s), + "dma-table-alias", + &s->dma_tt, 0, dma_tt_size); + dma_tl_contents = memory_region_get_ram_ptr(&s->dma_tt); + cpu_physical_memory_read(new_tl_base, dma_tl_contents, dma_tt_size); + + memory_region_transaction_begin(); + entries = dma_tt_size / sizeof(dma_pagetable_entry); + for (i = 0; i < entries; i++) { + rc4030_dma_as_update_one(s, i, dma_tl_contents[i].frame); + } + memory_region_add_subregion(get_system_memory(), new_tl_base, + &s->dma_tt_alias); + memory_region_transaction_commit(); + } else { + memory_region_init(&s->dma_tt_alias, OBJECT(s), + "dma-table-alias", 0); + } +} + +static void rc4030_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { rc4030State *s = opaque; + uint32_t val = data; addr &= 0x3fff; - DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr); + trace_rc4030_write(addr, val); switch (addr & ~0x3) { /* Global config register */ @@ -279,11 +360,11 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) break; /* DMA transl. table base */ case 0x0018: - s->dma_tl_base = val; + rc4030_dma_tt_update(s, val, s->dma_tl_limit); break; /* DMA transl. table limit */ case 0x0020: - s->dma_tl_limit = val; + rc4030_dma_tt_update(s, s->dma_tl_base, val); break; /* DMA transl. table invalidated */ case 0x0028: @@ -371,9 +452,9 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) s->dma_regs[entry][idx] = val; } break; - /* Offset 0x0210 */ + /* Memory refresh rate */ case 0x0210: - s->offset210 = val; + s->memory_refresh_rate = val; break; /* Interval timer reload */ case 0x0228: @@ -385,48 +466,18 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) case 0x0238: break; default: - RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr); - break; - } -} - -static void rc4030_writew(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); - - if (addr & 0x2) - val = (val << 16) | (old_val & 0x0000ffff); - else - val = val | (old_val & 0xffff0000); - rc4030_writel(opaque, addr & ~0x3, val); -} - -static void rc4030_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); - - switch (addr & 3) { - case 0: - val = val | (old_val & 0xffffff00); - break; - case 1: - val = (val << 8) | (old_val & 0xffff00ff); - break; - case 2: - val = (val << 16) | (old_val & 0xff00ffff); - break; - case 3: - val = (val << 24) | (old_val & 0x00ffffff); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030: invalid write of 0x%02x at 0x%x", + val, (int)addr); break; } - rc4030_writel(opaque, addr & ~0x3, val); } static const MemoryRegionOps rc4030_ops = { - .old_mmio = { - .read = { rc4030_readb, rc4030_readw, rc4030_readl, }, - .write = { rc4030_writeb, rc4030_writew, rc4030_writel, }, - }, + .read = rc4030_read, + .write = rc4030_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, .endianness = DEVICE_NATIVE_ENDIAN, }; @@ -436,22 +487,6 @@ static void update_jazz_irq(rc4030State *s) pending = s->isr_jazz & s->imr_jazz; -#ifdef DEBUG_RC4030 - if (s->isr_jazz != 0) { - uint32_t irq = 0; - DPRINTF("pending irqs:"); - for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) { - if (s->isr_jazz & (1 << irq)) { - printf(" %s", irq_names[irq]); - if (!(s->imr_jazz & (1 << irq))) { - printf("(ignored)"); - } - } - } - printf("\n"); - } -#endif - if (pending != 0) qemu_irq_raise(s->jazz_bus_irq); else @@ -479,7 +514,7 @@ static void rc4030_periodic_timer(void *opaque) qemu_irq_raise(s->timer_irq); } -static uint32_t jazzio_readw(void *opaque, hwaddr addr) +static uint64_t jazzio_read(void *opaque, hwaddr addr, unsigned int size) { rc4030State *s = opaque; uint32_t val; @@ -494,7 +529,6 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr) irq = 0; while (pending) { if (pending & 1) { - DPRINTF("returning irq %s\n", irq_names[irq]); val = (irq + 1) << 2; break; } @@ -508,36 +542,25 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr) val = s->imr_jazz; break; default: - RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx "]\n", addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030/jazzio: invalid read at 0x%x", (int)addr); val = 0; + break; } - DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr); + trace_jazzio_read(addr, val); return val; } -static uint32_t jazzio_readb(void *opaque, hwaddr addr) -{ - uint32_t v; - v = jazzio_readw(opaque, addr & ~0x1); - return (v >> (8 * (addr & 0x1))) & 0xff; -} - -static uint32_t jazzio_readl(void *opaque, hwaddr addr) -{ - uint32_t v; - v = jazzio_readw(opaque, addr); - v |= jazzio_readw(opaque, addr + 2) << 16; - return v; -} - -static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val) +static void jazzio_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { rc4030State *s = opaque; + uint32_t val = data; addr &= 0xfff; - DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr); + trace_jazzio_write(addr, val); switch (addr) { /* Local bus int enable mask */ @@ -546,43 +569,24 @@ static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val) update_jazz_irq(s); break; default: - RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx "]\n", val, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030/jazzio: invalid write of 0x%02x at 0x%x", + val, (int)addr); break; } } -static void jazzio_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = jazzio_readw(opaque, addr & ~0x1); - - switch (addr & 1) { - case 0: - val = val | (old_val & 0xff00); - break; - case 1: - val = (val << 8) | (old_val & 0x00ff); - break; - } - jazzio_writew(opaque, addr & ~0x1, val); -} - -static void jazzio_writel(void *opaque, hwaddr addr, uint32_t val) -{ - jazzio_writew(opaque, addr, val & 0xffff); - jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff); -} - static const MemoryRegionOps jazzio_ops = { - .old_mmio = { - .read = { jazzio_readb, jazzio_readw, jazzio_readl, }, - .write = { jazzio_writeb, jazzio_writew, jazzio_writel, }, - }, + .read = jazzio_read, + .write = jazzio_write, + .impl.min_access_size = 2, + .impl.max_access_size = 2, .endianness = DEVICE_NATIVE_ENDIAN, }; -static void rc4030_reset(void *opaque) +static void rc4030_reset(DeviceState *dev) { - rc4030State *s = opaque; + rc4030State *s = RC4030(dev); int i; s->config = 0x410; /* some boards seem to accept 0x104 too */ @@ -590,14 +594,14 @@ static void rc4030_reset(void *opaque) s->invalid_address_register = 0; memset(s->dma_regs, 0, sizeof(s->dma_regs)); - s->dma_tl_base = s->dma_tl_limit = 0; + rc4030_dma_tt_update(s, 0, 0); s->remote_failed_address = s->memory_failed_address = 0; s->cache_maint = 0; s->cache_ptag = s->cache_ltag = 0; s->cache_bmask = 0; - s->offset210 = 0x18186; + s->memory_refresh_rate = 0x18186; s->nvram_protect = 7; for (i = 0; i < 15; i++) s->rem_speed[i] = 7; @@ -631,7 +635,7 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id) s->cache_ptag = qemu_get_be32(f); s->cache_ltag = qemu_get_be32(f); s->cache_bmask = qemu_get_be32(f); - s->offset210 = qemu_get_be32(f); + s->memory_refresh_rate = qemu_get_be32(f); s->nvram_protect = qemu_get_be32(f); for (i = 0; i < 15; i++) s->rem_speed[i] = qemu_get_be32(f); @@ -663,7 +667,7 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->cache_ptag); qemu_put_be32(f, s->cache_ltag); qemu_put_be32(f, s->cache_bmask); - qemu_put_be32(f, s->offset210); + qemu_put_be32(f, s->memory_refresh_rate); qemu_put_be32(f, s->nvram_protect); for (i = 0; i < 15; i++) qemu_put_be32(f, s->rem_speed[i]); @@ -672,44 +676,6 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->itr); } -void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write) -{ - rc4030State *s = opaque; - hwaddr entry_addr; - hwaddr phys_addr; - dma_pagetable_entry entry; - int index; - int ncpy, i; - - i = 0; - for (;;) { - if (i == len) { - break; - } - - ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1)); - if (ncpy > len - i) - ncpy = len - i; - - /* Get DMA translation table entry */ - index = addr / DMA_PAGESIZE; - if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) { - break; - } - entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry); - /* XXX: not sure. should we really use only lowest bits? */ - entry_addr &= 0x7fffffff; - cpu_physical_memory_read(entry_addr, &entry, sizeof(entry)); - - /* Read/write data at right place */ - phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1)); - cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write); - - i += ncpy; - addr += ncpy; - } -} - static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) { rc4030State *s = opaque; @@ -733,32 +699,11 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri dma_addr = s->dma_regs[n][DMA_REG_ADDRESS]; /* Read/write data at right place */ - rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write); + address_space_rw(&s->dma_as, dma_addr, MEMTXATTRS_UNSPECIFIED, + buf, len, is_write); s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR; s->dma_regs[n][DMA_REG_COUNT] -= len; - -#ifdef DEBUG_RC4030_DMA - { - int i, j; - printf("rc4030 dma: Copying %d bytes %s host %p\n", - len, is_write ? "from" : "to", buf); - for (i = 0; i < len; i += 16) { - int n = 16; - if (n > len - i) { - n = len - i; - } - for (j = 0; j < n; j++) - printf("%02x ", buf[i + j]); - while (j++ < 16) - printf(" "); - printf("| "); - for (j = 0; j < n; j++) - printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.'); - printf("\n"); - } - } -#endif } struct rc4030DMAState { @@ -795,31 +740,102 @@ static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n) return s; } -void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, - qemu_irq **irqs, rc4030_dma **dmas, - MemoryRegion *sysmem) +static void rc4030_initfn(Object *obj) { - rc4030State *s; + DeviceState *dev = DEVICE(obj); + rc4030State *s = RC4030(obj); + SysBusDevice *sysbus = SYS_BUS_DEVICE(obj); - s = g_malloc0(sizeof(rc4030State)); + qdev_init_gpio_in(dev, rc4030_irq_jazz_request, 16); - *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16); - *dmas = rc4030_allocate_dmas(s, 4); + sysbus_init_irq(sysbus, &s->timer_irq); + sysbus_init_irq(sysbus, &s->jazz_bus_irq); - s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rc4030_periodic_timer, s); - s->timer_irq = timer; - s->jazz_bus_irq = jazz_bus; - - qemu_register_reset(rc4030_reset, s); register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s); - rc4030_reset(s); + + sysbus_init_mmio(sysbus, &s->iomem_chipset); + sysbus_init_mmio(sysbus, &s->iomem_jazzio); +} + +static void rc4030_realize(DeviceState *dev, Error **errp) +{ + rc4030State *s = RC4030(dev); + Object *o = OBJECT(dev); + int i; + + s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + rc4030_periodic_timer, s); memory_region_init_io(&s->iomem_chipset, NULL, &rc4030_ops, s, "rc4030.chipset", 0x300); - memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset); memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s, "rc4030.jazzio", 0x00001000); - memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio); - return s; + memory_region_init_rom_device(&s->dma_tt, o, + &rc4030_dma_tt_ops, s, "dma-table", + MAX_TL_ENTRIES * sizeof(dma_pagetable_entry), + NULL); + memory_region_init(&s->dma_tt_alias, o, "dma-table-alias", 0); + memory_region_init(&s->dma_mr, o, "dma", INT32_MAX); + for (i = 0; i < MAX_TL_ENTRIES; ++i) { + memory_region_init_alias(&s->dma_mrs[i], o, "dma-alias", + get_system_memory(), 0, DMA_PAGESIZE); + memory_region_set_enabled(&s->dma_mrs[i], false); + memory_region_add_subregion(&s->dma_mr, i * DMA_PAGESIZE, + &s->dma_mrs[i]); + } + address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma"); +} + +static void rc4030_unrealize(DeviceState *dev, Error **errp) +{ + rc4030State *s = RC4030(dev); + int i; + + timer_free(s->periodic_timer); + + address_space_destroy(&s->dma_as); + object_unparent(OBJECT(&s->dma_tt)); + object_unparent(OBJECT(&s->dma_tt_alias)); + object_unparent(OBJECT(&s->dma_mr)); + for (i = 0; i < MAX_TL_ENTRIES; ++i) { + memory_region_del_subregion(&s->dma_mr, &s->dma_mrs[i]); + object_unparent(OBJECT(&s->dma_mrs[i])); + } +} + +static void rc4030_class_init(ObjectClass *klass, void *class_data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rc4030_realize; + dc->unrealize = rc4030_unrealize; + dc->reset = rc4030_reset; +} + +static const TypeInfo rc4030_info = { + .name = TYPE_RC4030, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(rc4030State), + .instance_init = rc4030_initfn, + .class_init = rc4030_class_init, +}; + +static void rc4030_register_types(void) +{ + type_register_static(&rc4030_info); +} + +type_init(rc4030_register_types) + +DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr) +{ + DeviceState *dev; + + dev = qdev_create(NULL, TYPE_RC4030); + qdev_init_nofail(dev); + + *dmas = rc4030_allocate_dmas(dev, 4); + *dma_mr = &RC4030(dev)->dma_mr; + return dev; } diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs index 0a652f8521..9633f3a57d 100644 --- a/hw/mips/Makefile.objs +++ b/hw/mips/Makefile.objs @@ -1,4 +1,5 @@ -obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o +obj-y += mips_r4k.o mips_malta.o mips_mipssim.o obj-y += addr.o cputimer.o mips_int.o +obj-$(CONFIG_JAZZ) += mips_jazz.o obj-$(CONFIG_FULONG) += mips_fulong2e.o obj-y += gt64xxx_pci.o diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 2c153e092f..9d60633efb 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -135,16 +135,16 @@ static void mips_jazz_init(MachineState *machine, MIPSCPU *cpu; CPUClass *cc; CPUMIPSState *env; - qemu_irq *rc4030, *i8259; + qemu_irq *i8259; rc4030_dma *dmas; - void* rc4030_opaque; + MemoryRegion *rc4030_dma_mr; MemoryRegion *isa_mem = g_new(MemoryRegion, 1); MemoryRegion *isa_io = g_new(MemoryRegion, 1); MemoryRegion *rtc = g_new(MemoryRegion, 1); MemoryRegion *i8042 = g_new(MemoryRegion, 1); MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); NICInfo *nd; - DeviceState *dev; + DeviceState *dev, *rc4030; SysBusDevice *sysbus; ISABus *isa_bus; ISADevice *pit; @@ -157,12 +157,7 @@ static void mips_jazz_init(MachineState *machine, /* init CPUs */ if (cpu_model == NULL) { -#ifdef TARGET_MIPS64 cpu_model = "R4000"; -#else - /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */ - cpu_model = "24Kf"; -#endif } cpu = cpu_mips_init(cpu_model); if (cpu == NULL) { @@ -218,8 +213,14 @@ static void mips_jazz_init(MachineState *machine, cpu_mips_clock_init(env); /* Chipset */ - rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas, - address_space); + rc4030 = rc4030_init(&dmas, &rc4030_dma_mr); + sysbus = SYS_BUS_DEVICE(rc4030); + sysbus_connect_irq(sysbus, 0, env->irq[6]); + sysbus_connect_irq(sysbus, 1, env->irq[3]); + memory_region_add_subregion(address_space, 0x80000000, + sysbus_mmio_get_region(sysbus, 0)); + memory_region_add_subregion(address_space, 0xf0000000, + sysbus_mmio_get_region(sysbus, 1)); memory_region_init_io(dma_dummy, NULL, &dma_dummy_ops, NULL, "dummy_dma", 0x1000); memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); @@ -246,7 +247,7 @@ static void mips_jazz_init(MachineState *machine, sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, 0x60080000); sysbus_mmio_map(sysbus, 1, 0x40000000); - sysbus_connect_irq(sysbus, 0, rc4030[3]); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 3)); { /* Simple ROM, so user doesn't have to provide one */ MemoryRegion *rom_mr = g_new(MemoryRegion, 1); @@ -272,8 +273,17 @@ static void mips_jazz_init(MachineState *machine, if (!nd->model) nd->model = g_strdup("dp83932"); if (strcmp(nd->model, "dp83932") == 0) { - dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4], - rc4030_opaque, rc4030_dma_memory_rw); + qemu_check_nic_model(nd, "dp83932"); + + dev = qdev_create(NULL, "dp8393x"); + qdev_set_nic_properties(dev, nd); + qdev_prop_set_uint8(dev, "it_shift", 2); + qdev_prop_set_ptr(dev, "dma_mr", rc4030_dma_mr); + qdev_init_nofail(dev); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sysbus, 0, 0x80001000); + sysbus_mmio_map(sysbus, 1, 0x8000b000); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4)); break; } else if (is_help_option(nd->model)) { fprintf(stderr, "qemu: Supported NICs: dp83932\n"); @@ -287,7 +297,7 @@ static void mips_jazz_init(MachineState *machine, /* SCSI adapter */ esp_init(0x80002000, 0, rc4030_dma_read, rc4030_dma_write, dmas[0], - rc4030[5], &esp_reset, &dma_enable); + qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable); /* Floppy */ if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) { @@ -297,7 +307,7 @@ static void mips_jazz_init(MachineState *machine, for (n = 0; n < MAX_FD; n++) { fds[n] = drive_get(IF_FLOPPY, 0, n); } - fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds); + fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), 0, 0x80003000, fds); /* Real time clock */ rtc_init(isa_bus, 1980, NULL); @@ -305,23 +315,26 @@ static void mips_jazz_init(MachineState *machine, memory_region_add_subregion(address_space, 0x80004000, rtc); /* Keyboard (i8042) */ - i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1); + i8042_mm_init(qdev_get_gpio_in(rc4030, 6), qdev_get_gpio_in(rc4030, 7), + i8042, 0x1000, 0x1); memory_region_add_subregion(address_space, 0x80005000, i8042); /* Serial ports */ if (serial_hds[0]) { - serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16, + serial_mm_init(address_space, 0x80006000, 0, + qdev_get_gpio_in(rc4030, 8), 8000000/16, serial_hds[0], DEVICE_NATIVE_ENDIAN); } if (serial_hds[1]) { - serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16, + serial_mm_init(address_space, 0x80007000, 0, + qdev_get_gpio_in(rc4030, 9), 8000000/16, serial_hds[1], DEVICE_NATIVE_ENDIAN); } /* Parallel port */ if (parallel_hds[0]) - parallel_mm_init(address_space, 0x80008000, 0, rc4030[0], - parallel_hds[0]); + parallel_mm_init(address_space, 0x80008000, 0, + qdev_get_gpio_in(rc4030, 0), parallel_hds[0]); /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 5140882c00..786a8f0638 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -97,7 +97,7 @@ typedef struct { static ISADevice *pit; static struct _loaderparams { - int ram_size; + int ram_size, ram_low_size; const char *kernel_filename; const char *kernel_cmdline; const char *initrd_filename; @@ -641,8 +641,8 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, stl_p(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */ stl_p(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ stl_p(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ - stl_p(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */ - stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */ + stl_p(p++, 0x3c070000 | (loaderparams.ram_low_size >> 16)); /* lui a3, high(ram_low_size) */ + stl_p(p++, 0x34e70000 | (loaderparams.ram_low_size & 0xffff)); /* ori a3, a3, low(ram_low_size) */ /* Load BAR registers as done by YAMON */ stl_p(p++, 0x3c09b400); /* lui t1, 0xb400 */ @@ -851,8 +851,10 @@ static int64_t load_kernel (void) } prom_set(prom_buf, prom_index++, "memsize"); - prom_set(prom_buf, prom_index++, "%i", - MIN(loaderparams.ram_size, 256 << 20)); + prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_low_size); + + prom_set(prom_buf, prom_index++, "ememsize"); + prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_size); prom_set(prom_buf, prom_index++, "modetty0"); prom_set(prom_buf, prom_index++, "38400n8r"); @@ -1054,7 +1056,8 @@ void mips_malta_init(MachineState *machine) } /* Write a small bootloader to the flash location. */ - loaderparams.ram_size = ram_low_size; + loaderparams.ram_size = ram_size; + loaderparams.ram_low_size = ram_low_size; loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.initrd_filename = initrd_filename; diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 7ce13d2b46..cd889bce86 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -17,20 +17,15 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "hw/hw.h" -#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/devices.h" #include "net/net.h" -#include "hw/mips/mips.h" +#include "qemu/timer.h" +#include <zlib.h> //#define DEBUG_SONIC -/* Calculate CRCs properly on Rx packets */ -#define SONIC_CALCULATE_RXCRC - -#if defined(SONIC_CALCULATE_RXCRC) -/* For crc32 */ -#include <zlib.h> -#endif +#define SONIC_PROM_SIZE 0x1000 #ifdef DEBUG_SONIC #define DPRINTF(fmt, ...) \ @@ -145,9 +140,14 @@ do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) #define SONIC_ISR_PINT 0x0800 #define SONIC_ISR_LCD 0x1000 +#define TYPE_DP8393X "dp8393x" +#define DP8393X(obj) OBJECT_CHECK(dp8393xState, (obj), TYPE_DP8393X) + typedef struct dp8393xState { + SysBusDevice parent_obj; + /* Hardware */ - int it_shift; + uint8_t it_shift; qemu_irq irq; #ifdef DEBUG_SONIC int irq_level; @@ -156,8 +156,8 @@ typedef struct dp8393xState { int64_t wt_last_update; NICConf conf; NICState *nic; - MemoryRegion *address_space; MemoryRegion mmio; + MemoryRegion prom; /* Registers */ uint8_t cam[16][6]; @@ -168,8 +168,8 @@ typedef struct dp8393xState { int loopback_packet; /* Memory access */ - void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); - void* mem_opaque; + void *dma_mr; + AddressSpace as; } dp8393xState; static void dp8393x_update_irq(dp8393xState *s) @@ -190,7 +190,7 @@ static void dp8393x_update_irq(dp8393xState *s) qemu_set_irq(s->irq, level); } -static void do_load_cam(dp8393xState *s) +static void dp8393x_do_load_cam(dp8393xState *s) { uint16_t data[8]; int width, size; @@ -201,9 +201,9 @@ static void do_load_cam(dp8393xState *s) while (s->regs[SONIC_CDC] & 0x1f) { /* Fill current entry */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->cam[index][0] = data[1 * width] & 0xff; s->cam[index][1] = data[1 * width] >> 8; s->cam[index][2] = data[2 * width] & 0xff; @@ -220,9 +220,9 @@ static void do_load_cam(dp8393xState *s) } /* Read CAM enable */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CE] = data[0 * width]; DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); @@ -232,7 +232,7 @@ static void do_load_cam(dp8393xState *s) dp8393x_update_irq(s); } -static void do_read_rra(dp8393xState *s) +static void dp8393x_do_read_rra(dp8393xState *s) { uint16_t data[8]; int width, size; @@ -240,9 +240,9 @@ static void do_read_rra(dp8393xState *s) /* Read memory */ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; size = sizeof(uint16_t) * 4 * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); /* Update SONIC registers */ s->regs[SONIC_CRBA0] = data[0 * width]; @@ -272,7 +272,7 @@ static void do_read_rra(dp8393xState *s) s->regs[SONIC_CR] &= ~SONIC_CR_RRRA; } -static void do_software_reset(dp8393xState *s) +static void dp8393x_do_software_reset(dp8393xState *s) { timer_del(s->watchdog); @@ -280,7 +280,7 @@ static void do_software_reset(dp8393xState *s) s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS; } -static void set_next_tick(dp8393xState *s) +static void dp8393x_set_next_tick(dp8393xState *s) { uint32_t ticks; int64_t delay; @@ -296,7 +296,7 @@ static void set_next_tick(dp8393xState *s) timer_mod(s->watchdog, s->wt_last_update + delay); } -static void update_wt_regs(dp8393xState *s) +static void dp8393x_update_wt_regs(dp8393xState *s) { int64_t elapsed; uint32_t val; @@ -311,33 +311,33 @@ static void update_wt_regs(dp8393xState *s) val -= elapsed / 5000000; s->regs[SONIC_WT1] = (val >> 16) & 0xffff; s->regs[SONIC_WT0] = (val >> 0) & 0xffff; - set_next_tick(s); + dp8393x_set_next_tick(s); } -static void do_start_timer(dp8393xState *s) +static void dp8393x_do_start_timer(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_STP; - set_next_tick(s); + dp8393x_set_next_tick(s); } -static void do_stop_timer(dp8393xState *s) +static void dp8393x_do_stop_timer(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_ST; - update_wt_regs(s); + dp8393x_update_wt_regs(s); } -static void do_receiver_enable(dp8393xState *s) +static void dp8393x_do_receiver_enable(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS; } -static void do_receiver_disable(dp8393xState *s) +static void dp8393x_do_receiver_disable(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_RXEN; } -static void do_transmit_packets(dp8393xState *s) +static void dp8393x_do_transmit_packets(dp8393xState *s) { NetClientState *nc = qemu_get_queue(s->nic); uint16_t data[12]; @@ -353,9 +353,9 @@ static void do_transmit_packets(dp8393xState *s) (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]); size = sizeof(uint16_t) * 6 * width; s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); tx_len = 0; /* Update registers */ @@ -379,18 +379,18 @@ static void do_transmit_packets(dp8393xState *s) if (tx_len + len > sizeof(s->tx_buffer)) { len = sizeof(s->tx_buffer) - tx_len; } - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0], - &s->tx_buffer[tx_len], len, 0); + MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0); tx_len += len; i++; if (i != s->regs[SONIC_TFC]) { /* Read next fragment details */ size = sizeof(uint16_t) * 3 * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_TSA0] = data[0 * width]; s->regs[SONIC_TSA1] = data[1 * width]; s->regs[SONIC_TFS] = data[2 * width]; @@ -422,16 +422,16 @@ static void do_transmit_packets(dp8393xState *s) /* Write status */ data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA], - (uint8_t *)data, size, 1); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) { /* Read footer of packet */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CTDA] = data[0 * width] & ~0x1; if (data[0 * width] & 0x1) { /* EOL detected */ @@ -446,12 +446,12 @@ static void do_transmit_packets(dp8393xState *s) dp8393x_update_irq(s); } -static void do_halt_transmission(dp8393xState *s) +static void dp8393x_do_halt_transmission(dp8393xState *s) { /* Nothing to do */ } -static void do_command(dp8393xState *s, uint16_t command) +static void dp8393x_do_command(dp8393xState *s, uint16_t command) { if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) { s->regs[SONIC_CR] &= ~SONIC_CR_RST; @@ -461,34 +461,36 @@ static void do_command(dp8393xState *s, uint16_t command) s->regs[SONIC_CR] |= (command & SONIC_CR_MASK); if (command & SONIC_CR_HTX) - do_halt_transmission(s); + dp8393x_do_halt_transmission(s); if (command & SONIC_CR_TXP) - do_transmit_packets(s); + dp8393x_do_transmit_packets(s); if (command & SONIC_CR_RXDIS) - do_receiver_disable(s); + dp8393x_do_receiver_disable(s); if (command & SONIC_CR_RXEN) - do_receiver_enable(s); + dp8393x_do_receiver_enable(s); if (command & SONIC_CR_STP) - do_stop_timer(s); + dp8393x_do_stop_timer(s); if (command & SONIC_CR_ST) - do_start_timer(s); + dp8393x_do_start_timer(s); if (command & SONIC_CR_RST) - do_software_reset(s); + dp8393x_do_software_reset(s); if (command & SONIC_CR_RRRA) - do_read_rra(s); + dp8393x_do_read_rra(s); if (command & SONIC_CR_LCAM) - do_load_cam(s); + dp8393x_do_load_cam(s); } -static uint16_t read_register(dp8393xState *s, int reg) +static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size) { + dp8393xState *s = opaque; + int reg = addr >> s->it_shift; uint16_t val = 0; switch (reg) { /* Update data before reading it */ case SONIC_WT0: case SONIC_WT1: - update_wt_regs(s); + dp8393x_update_wt_regs(s); val = s->regs[reg]; break; /* Accept read to some registers only when in reset mode */ @@ -510,14 +512,18 @@ static uint16_t read_register(dp8393xState *s, int reg) return val; } -static void write_register(dp8393xState *s, int reg, uint16_t val) +static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { - DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]); + dp8393xState *s = opaque; + int reg = addr >> s->it_shift; + + DPRINTF("write 0x%04x to reg %s\n", (uint16_t)data, reg_names[reg]); switch (reg) { /* Command register */ case SONIC_CR: - do_command(s, val); + dp8393x_do_command(s, data); break; /* Prevent write to read-only registers */ case SONIC_CAP2: @@ -530,37 +536,37 @@ static void write_register(dp8393xState *s, int reg, uint16_t val) /* Accept write to some registers only when in reset mode */ case SONIC_DCR: if (s->regs[SONIC_CR] & SONIC_CR_RST) { - s->regs[reg] = val & 0xbfff; + s->regs[reg] = data & 0xbfff; } else { DPRINTF("writing to DCR invalid\n"); } break; case SONIC_DCR2: if (s->regs[SONIC_CR] & SONIC_CR_RST) { - s->regs[reg] = val & 0xf017; + s->regs[reg] = data & 0xf017; } else { DPRINTF("writing to DCR2 invalid\n"); } break; /* 12 lower bytes are Read Only */ case SONIC_TCR: - s->regs[reg] = val & 0xf000; + s->regs[reg] = data & 0xf000; break; /* 9 lower bytes are Read Only */ case SONIC_RCR: - s->regs[reg] = val & 0xffe0; + s->regs[reg] = data & 0xffe0; break; /* Ignore most significant bit */ case SONIC_IMR: - s->regs[reg] = val & 0x7fff; + s->regs[reg] = data & 0x7fff; dp8393x_update_irq(s); break; /* Clear bits by writing 1 to them */ case SONIC_ISR: - val &= s->regs[reg]; - s->regs[reg] &= ~val; - if (val & SONIC_ISR_RBE) { - do_read_rra(s); + data &= s->regs[reg]; + s->regs[reg] &= ~data; + if (data & SONIC_ISR_RBE) { + dp8393x_do_read_rra(s); } dp8393x_update_irq(s); break; @@ -569,24 +575,32 @@ static void write_register(dp8393xState *s, int reg, uint16_t val) case SONIC_REA: case SONIC_RRP: case SONIC_RWP: - s->regs[reg] = val & 0xfffe; + s->regs[reg] = data & 0xfffe; break; /* Invert written value for some registers */ case SONIC_CRCT: case SONIC_FAET: case SONIC_MPT: - s->regs[reg] = val ^ 0xffff; + s->regs[reg] = data ^ 0xffff; break; /* All other registers have no special contrainst */ default: - s->regs[reg] = val; + s->regs[reg] = data; } if (reg == SONIC_WT0 || reg == SONIC_WT1) { - set_next_tick(s); + dp8393x_set_next_tick(s); } } +static const MemoryRegionOps dp8393x_ops = { + .read = dp8393x_read, + .write = dp8393x_write, + .impl.min_access_size = 2, + .impl.max_access_size = 2, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + static void dp8393x_watchdog(void *opaque) { dp8393xState *s = opaque; @@ -597,84 +611,14 @@ static void dp8393x_watchdog(void *opaque) s->regs[SONIC_WT1] = 0xffff; s->regs[SONIC_WT0] = 0xffff; - set_next_tick(s); + dp8393x_set_next_tick(s); /* Signal underflow */ s->regs[SONIC_ISR] |= SONIC_ISR_TC; dp8393x_update_irq(s); } -static uint32_t dp8393x_readw(void *opaque, hwaddr addr) -{ - dp8393xState *s = opaque; - int reg; - - if ((addr & ((1 << s->it_shift) - 1)) != 0) { - return 0; - } - - reg = addr >> s->it_shift; - return read_register(s, reg); -} - -static uint32_t dp8393x_readb(void *opaque, hwaddr addr) -{ - uint16_t v = dp8393x_readw(opaque, addr & ~0x1); - return (v >> (8 * (addr & 0x1))) & 0xff; -} - -static uint32_t dp8393x_readl(void *opaque, hwaddr addr) -{ - uint32_t v; - v = dp8393x_readw(opaque, addr); - v |= dp8393x_readw(opaque, addr + 2) << 16; - return v; -} - -static void dp8393x_writew(void *opaque, hwaddr addr, uint32_t val) -{ - dp8393xState *s = opaque; - int reg; - - if ((addr & ((1 << s->it_shift) - 1)) != 0) { - return; - } - - reg = addr >> s->it_shift; - - write_register(s, reg, (uint16_t)val); -} - -static void dp8393x_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1); - - switch (addr & 3) { - case 0: - val = val | (old_val & 0xff00); - break; - case 1: - val = (val << 8) | (old_val & 0x00ff); - break; - } - dp8393x_writew(opaque, addr & ~0x1, val); -} - -static void dp8393x_writel(void *opaque, hwaddr addr, uint32_t val) -{ - dp8393x_writew(opaque, addr, val & 0xffff); - dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff); -} - -static const MemoryRegionOps dp8393x_ops = { - .old_mmio = { - .read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, }, - .write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int nic_can_receive(NetClientState *nc) +static int dp8393x_can_receive(NetClientState *nc) { dp8393xState *s = qemu_get_nic_opaque(nc); @@ -685,7 +629,8 @@ static int nic_can_receive(NetClientState *nc) return 1; } -static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) +static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf, + int size) { static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int i; @@ -723,7 +668,8 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) return -1; } -static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) +static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, + size_t size) { dp8393xState *s = qemu_get_nic_opaque(nc); uint16_t data[10]; @@ -737,7 +683,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER | SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC); - packet_type = receive_filter(s, buf, size); + packet_type = dp8393x_receive_filter(s, buf, size); if (packet_type < 0) { DPRINTF("packet not for netcard\n"); return -1; @@ -750,7 +696,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) /* Are we still in resource exhaustion? */ size = sizeof(uint16_t) * 1 * width; address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width; - s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0); + address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)data, size, 0); if (data[0 * width] & 0x1) { /* Still EOL ; stop reception */ return -1; @@ -764,18 +711,16 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0]; /* Calculate the ethernet checksum */ -#ifdef SONIC_CALCULATE_RXCRC checksum = cpu_to_le32(crc32(0, buf, rx_len)); -#else - checksum = 0; -#endif /* Put packet into RBA */ DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]); address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]; - s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1); + address_space_rw(&s->as, address, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1); address += rx_len; - s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1); + address_space_rw(&s->as, address, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)&checksum, 4, 1); rx_len += 4; s->regs[SONIC_CRBA1] = address >> 16; s->regs[SONIC_CRBA0] = address & 0xffff; @@ -803,29 +748,30 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */ data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ size = sizeof(uint16_t) * 5 * width; - s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1); + address_space_rw(&s->as, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); /* Move to next descriptor */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_LLFA] = data[0 * width]; if (s->regs[SONIC_LLFA] & 0x1) { /* EOL detected */ s->regs[SONIC_ISR] |= SONIC_ISR_RDE; } else { data[0 * width] = 0; /* in_use */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width, - (uint8_t *)data, size, 1); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1); s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX; s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff); if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) { /* Read next RRA */ - do_read_rra(s); + dp8393x_do_read_rra(s); } } @@ -835,11 +781,12 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) return size; } -static void nic_reset(void *opaque) +static void dp8393x_reset(DeviceState *dev) { - dp8393xState *s = opaque; + dp8393xState *s = DP8393X(dev); timer_del(s->watchdog); + memset(s->regs, 0, sizeof(s->regs)); s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS; s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR); s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT); @@ -862,39 +809,91 @@ static void nic_reset(void *opaque) static NetClientInfo net_dp83932_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = nic_can_receive, - .receive = nic_receive, + .can_receive = dp8393x_can_receive, + .receive = dp8393x_receive, }; -void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, - MemoryRegion *address_space, - qemu_irq irq, void* mem_opaque, - void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)) +static void dp8393x_instance_init(Object *obj) { - dp8393xState *s; + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + dp8393xState *s = DP8393X(obj); + + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_mmio(sbd, &s->prom); + sysbus_init_irq(sbd, &s->irq); +} - qemu_check_nic_model(nd, "dp83932"); +static void dp8393x_realize(DeviceState *dev, Error **errp) +{ + dp8393xState *s = DP8393X(dev); + int i, checksum; + uint8_t *prom; - s = g_malloc0(sizeof(dp8393xState)); + address_space_init(&s->as, s->dma_mr, "dp8393x"); + memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s, + "dp8393x-regs", 0x40 << s->it_shift); + + s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, + object_get_typename(OBJECT(dev)), dev->id, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - s->address_space = address_space; - s->mem_opaque = mem_opaque; - s->memory_rw = memory_rw; - s->it_shift = it_shift; - s->irq = irq; s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s); s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ - s->conf.macaddr = nd->macaddr; - s->conf.peers.ncs[0] = nd->netdev; + memory_region_init_rom_device(&s->prom, OBJECT(dev), NULL, NULL, + "dp8393x-prom", SONIC_PROM_SIZE, NULL); + prom = memory_region_get_ram_ptr(&s->prom); + checksum = 0; + for (i = 0; i < 6; i++) { + prom[i] = s->conf.macaddr.a[i]; + checksum += prom[i]; + if (checksum > 0xff) { + checksum = (checksum + 1) & 0xff; + } + } + prom[7] = 0xff - checksum; +} - s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s); +static const VMStateDescription vmstate_dp8393x = { + .name = "dp8393x", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField []) { + VMSTATE_BUFFER_UNSAFE(cam, dp8393xState, 0, 16 * 6), + VMSTATE_UINT16_ARRAY(regs, dp8393xState, 0x40), + VMSTATE_END_OF_LIST() + } +}; - qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - qemu_register_reset(nic_reset, s); - nic_reset(s); +static Property dp8393x_properties[] = { + DEFINE_NIC_PROPERTIES(dp8393xState, conf), + DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr), + DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void dp8393x_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); - memory_region_init_io(&s->mmio, NULL, &dp8393x_ops, s, - "dp8393x", 0x40 << it_shift); - memory_region_add_subregion(address_space, base, &s->mmio); + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + dc->realize = dp8393x_realize; + dc->reset = dp8393x_reset; + dc->vmsd = &vmstate_dp8393x; + dc->props = dp8393x_properties; } + +static const TypeInfo dp8393x_info = { + .name = TYPE_DP8393X, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(dp8393xState), + .instance_init = dp8393x_instance_init, + .class_init = dp8393x_class_init, +}; + +static void dp8393x_register_types(void) +{ + type_register_static(&dp8393x_info); +} + +type_init(dp8393x_register_types) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 2f7a4f1700..2573e8c36e 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -105,6 +105,8 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, hwaddr paddr, MemTxAttrs attrs, int prot, int mmu_idx, target_ulong size); void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr); +void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx, + uintptr_t retaddr); #else static inline void tlb_flush_page(CPUState *cpu, target_ulong addr) { diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h index 2a7a9c9f42..e0065ce808 100644 --- a/include/hw/mips/mips.h +++ b/include/hw/mips/mips.h @@ -15,18 +15,9 @@ PCIBus *bonito_init(qemu_irq *pic); /* rc4030.c */ typedef struct rc4030DMAState *rc4030_dma; -void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); void rc4030_dma_read(void *dma, uint8_t *buf, int len); void rc4030_dma_write(void *dma, uint8_t *buf, int len); -void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, - qemu_irq **irqs, rc4030_dma **dmas, - MemoryRegion *sysmem); - -/* dp8393x.c */ -void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, - MemoryRegion *address_space, - qemu_irq irq, void* mem_opaque, - void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)); +DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr); #endif diff --git a/softmmu_template.h b/softmmu_template.h index 39f571b0ca..d42d89d541 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -548,6 +548,28 @@ glue(glue(helper_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr, helper_te_st_name(env, addr, val, oi, GETRA()); } +#if DATA_SIZE == 1 +/* Probe for whether the specified guest write access is permitted. + * If it is not permitted then an exception will be taken in the same + * way as if this were a real write access (and we will not return). + * Otherwise the function will return, and there will be a valid + * entry in the TLB for this access. + */ +void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx, + uintptr_t retaddr) +{ + int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write; + + if ((addr & TARGET_PAGE_MASK) + != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + /* TLB entry is for a different page */ + if (!VICTIM_TLB_HIT(addr_write)) { + tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr); + } + } +} +#endif #endif /* !defined(SOFTMMU_CODE_ACCESS) */ #undef READ_ACCESS_TYPE diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f9d2b4c5af..474a0e327d 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -34,7 +34,7 @@ struct r4k_tlb_t { uint_fast16_t RI0:1; uint_fast16_t RI1:1; uint_fast16_t EHINV:1; - target_ulong PFN[2]; + uint64_t PFN[2]; }; #if !defined(CONFIG_USER_ONLY) @@ -100,6 +100,7 @@ struct CPUMIPSFPUContext { float_status fp_status; /* fpu implementation/revision register (fir) */ uint32_t fcr0; +#define FCR0_FREP 29 #define FCR0_UFRP 28 #define FCR0_F64 22 #define FCR0_L 21 @@ -223,8 +224,14 @@ struct CPUMIPSState { uint32_t SEGBITS; uint32_t PABITS; +#if defined(TARGET_MIPS64) +# define PABITS_BASE 36 +#else +# define PABITS_BASE 32 +#endif target_ulong SEGMask; - target_ulong PAMask; + uint64_t PAMask; +#define PAMASK_BASE ((1ULL << PABITS_BASE) - 1) int32_t msair; #define MSAIR_ProcID 8 @@ -272,8 +279,8 @@ struct CPUMIPSState { #define CP0VPEOpt_DWX2 2 #define CP0VPEOpt_DWX1 1 #define CP0VPEOpt_DWX0 0 - target_ulong CP0_EntryLo0; - target_ulong CP0_EntryLo1; + uint64_t CP0_EntryLo0; + uint64_t CP0_EntryLo1; #if defined(TARGET_MIPS64) # define CP0EnLo_RI 63 # define CP0EnLo_XI 62 @@ -288,6 +295,7 @@ struct CPUMIPSState { int32_t CP0_PageGrain; #define CP0PG_RIE 31 #define CP0PG_XIE 30 +#define CP0PG_ELPA 29 #define CP0PG_IEC 27 int32_t CP0_Wired; int32_t CP0_SRSConf0_rw_bitmask; @@ -462,17 +470,21 @@ struct CPUMIPSState { #define CP0C5_CV 29 #define CP0C5_EVA 28 #define CP0C5_MSAEn 27 +#define CP0C5_UFE 9 +#define CP0C5_FRE 8 #define CP0C5_SBRI 6 +#define CP0C5_MVH 5 +#define CP0C5_LLB 4 #define CP0C5_UFR 2 #define CP0C5_NFExists 0 int32_t CP0_Config6; int32_t CP0_Config7; /* XXX: Maybe make LLAddr per-TC? */ - target_ulong lladdr; + uint64_t lladdr; target_ulong llval; target_ulong llnewval; target_ulong llreg; - target_ulong CP0_LLAddr_rw_bitmask; + uint64_t CP0_LLAddr_rw_bitmask; int CP0_LLAddr_shift; target_ulong CP0_WatchLo[8]; int32_t CP0_WatchHi[8]; @@ -499,7 +511,7 @@ struct CPUMIPSState { #define CP0DB_DSS 0 target_ulong CP0_DEPC; int32_t CP0_Performance0; - int32_t CP0_TagLo; + uint64_t CP0_TagLo; int32_t CP0_DataLo; int32_t CP0_TagHi; int32_t CP0_DataHi; @@ -514,7 +526,7 @@ struct CPUMIPSState { #define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0x15807FF +#define MIPS_HFLAG_TMASK 0x75807FF #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ /* The KSU flags must be the lowest bits in hflags. The flag order must be the same as defined for CP0 Status. This allows to use @@ -561,6 +573,8 @@ struct CPUMIPSState { #define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */ #define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */ #define MIPS_HFLAG_MSA 0x1000000 +#define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */ +#define MIPS_HFLAG_ELPA 0x4000000 target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ @@ -796,6 +810,15 @@ static inline void restore_msa_fp_status(CPUMIPSState *env) set_flush_inputs_to_zero(flush_to_zero, status); } +static inline void restore_pamask(CPUMIPSState *env) +{ + if (env->hflags & MIPS_HFLAG_ELPA) { + env->PAMask = (1ULL << env->PABITS) - 1; + } else { + env->PAMask = PAMASK_BASE; + } +} + static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { @@ -843,7 +866,8 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 | - MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA); + MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE | + MIPS_HFLAG_ELPA); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { @@ -924,6 +948,16 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags |= MIPS_HFLAG_MSA; } } + if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) { + if (env->CP0_Config5 & (1 << CP0C5_FRE)) { + env->hflags |= MIPS_HFLAG_FRE; + } + } + if (env->CP0_Config3 & (1 << CP0C3_LPA)) { + if (env->CP0_PageGrain & (1 << CP0PG_ELPA)) { + env->hflags |= MIPS_HFLAG_ELPA; + } + } } #ifndef CONFIG_USER_ONLY diff --git a/target-mips/helper.h b/target-mips/helper.h index 3bd0b029e4..8df98c71b8 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -348,6 +348,7 @@ DEF_HELPER_1(tlbinvf, void, env) DEF_HELPER_1(di, tl, env) DEF_HELPER_1(ei, tl, env) DEF_HELPER_1(eret, void, env) +DEF_HELPER_1(eretnc, void, env) DEF_HELPER_1(deret, void, env) #endif /* !CONFIG_USER_ONLY */ DEF_HELPER_1(rdhwr_cpunum, tl, env) @@ -931,5 +932,11 @@ DEF_HELPER_4(msa_ftint_u_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_ffint_s_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_ffint_u_df, void, env, i32, i32, i32) -DEF_HELPER_5(msa_ld_df, void, env, i32, i32, i32, s32) -DEF_HELPER_5(msa_st_df, void, env, i32, i32, i32, s32) +#define MSALDST_PROTO(type) \ +DEF_HELPER_3(msa_ld_ ## type, void, env, i32, tl) \ +DEF_HELPER_3(msa_st_ ## type, void, env, i32, tl) +MSALDST_PROTO(b) +MSALDST_PROTO(h) +MSALDST_PROTO(w) +MSALDST_PROTO(d) +#undef MSALDST_PROTO diff --git a/target-mips/machine.c b/target-mips/machine.c index 7d1fa32e57..8fa755cd39 100644 --- a/target-mips/machine.c +++ b/target-mips/machine.c @@ -10,6 +10,7 @@ static int cpu_post_load(void *opaque, int version_id) restore_fp_status(env); restore_msa_fp_status(env); compute_hflags(env); + restore_pamask(env); return 0; } @@ -142,8 +143,8 @@ static int get_tlb(QEMUFile *f, void *pv, size_t size) v->RI0 = (flags >> 13) & 1; v->XI1 = (flags >> 12) & 1; v->XI0 = (flags >> 11) & 1; - qemu_get_betls(f, &v->PFN[0]); - qemu_get_betls(f, &v->PFN[1]); + qemu_get_be64s(f, &v->PFN[0]); + qemu_get_be64s(f, &v->PFN[1]); return 0; } @@ -169,8 +170,8 @@ static void put_tlb(QEMUFile *f, void *pv, size_t size) qemu_put_be32s(f, &v->PageMask); qemu_put_8s(f, &v->ASID); qemu_put_be16s(f, &flags); - qemu_put_betls(f, &v->PFN[0]); - qemu_put_betls(f, &v->PFN[1]); + qemu_put_be64s(f, &v->PFN[0]); + qemu_put_be64s(f, &v->PFN[1]); } const VMStateInfo vmstate_info_tlb = { @@ -201,8 +202,8 @@ const VMStateDescription vmstate_tlb = { const VMStateDescription vmstate_mips_cpu = { .name = "cpu", - .version_id = 6, - .minimum_version_id = 6, + .version_id = 7, + .minimum_version_id = 7, .post_load = cpu_post_load, .fields = (VMStateField[]) { /* Active TC */ @@ -237,8 +238,8 @@ const VMStateDescription vmstate_mips_cpu = { VMSTATE_UINTTL(env.CP0_VPESchedule, MIPSCPU), VMSTATE_UINTTL(env.CP0_VPEScheFBack, MIPSCPU), VMSTATE_INT32(env.CP0_VPEOpt, MIPSCPU), - VMSTATE_UINTTL(env.CP0_EntryLo0, MIPSCPU), - VMSTATE_UINTTL(env.CP0_EntryLo1, MIPSCPU), + VMSTATE_UINT64(env.CP0_EntryLo0, MIPSCPU), + VMSTATE_UINT64(env.CP0_EntryLo1, MIPSCPU), VMSTATE_UINTTL(env.CP0_Context, MIPSCPU), VMSTATE_INT32(env.CP0_PageMask, MIPSCPU), VMSTATE_INT32(env.CP0_PageGrain, MIPSCPU), @@ -269,7 +270,7 @@ const VMStateDescription vmstate_mips_cpu = { VMSTATE_INT32(env.CP0_Config3, MIPSCPU), VMSTATE_INT32(env.CP0_Config6, MIPSCPU), VMSTATE_INT32(env.CP0_Config7, MIPSCPU), - VMSTATE_UINTTL(env.lladdr, MIPSCPU), + VMSTATE_UINT64(env.lladdr, MIPSCPU), VMSTATE_UINTTL_ARRAY(env.CP0_WatchLo, MIPSCPU, 8), VMSTATE_INT32_ARRAY(env.CP0_WatchHi, MIPSCPU, 8), VMSTATE_UINTTL(env.CP0_XContext, MIPSCPU), @@ -277,7 +278,7 @@ const VMStateDescription vmstate_mips_cpu = { VMSTATE_INT32(env.CP0_Debug, MIPSCPU), VMSTATE_UINTTL(env.CP0_DEPC, MIPSCPU), VMSTATE_INT32(env.CP0_Performance0, MIPSCPU), - VMSTATE_INT32(env.CP0_TagLo, MIPSCPU), + VMSTATE_UINT64(env.CP0_TagLo, MIPSCPU), VMSTATE_INT32(env.CP0_DataLo, MIPSCPU), VMSTATE_INT32(env.CP0_TagHi, MIPSCPU), VMSTATE_INT32(env.CP0_DataHi, MIPSCPU), diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h index 1784227494..20aa87c24c 100644 --- a/target-mips/mips-defs.h +++ b/target-mips/mips-defs.h @@ -10,11 +10,11 @@ #if defined(TARGET_MIPS64) #define TARGET_LONG_BITS 64 -#define TARGET_PHYS_ADDR_SPACE_BITS 36 +#define TARGET_PHYS_ADDR_SPACE_BITS 48 #define TARGET_VIRT_ADDR_SPACE_BITS 42 #else #define TARGET_LONG_BITS 32 -#define TARGET_PHYS_ADDR_SPACE_BITS 36 +#define TARGET_PHYS_ADDR_SPACE_BITS 40 #define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 73a8e458fc..2a9ddff70f 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -90,10 +90,10 @@ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \ } \ } #endif -HELPER_LD(lbu, ldub, uint8_t) -HELPER_LD(lhu, lduw, uint16_t) HELPER_LD(lw, ldl, int32_t) +#if defined(TARGET_MIPS64) HELPER_LD(ld, ldq, int64_t) +#endif #undef HELPER_LD #if defined(CONFIG_USER_ONLY) @@ -118,9 +118,10 @@ static inline void do_##name(CPUMIPSState *env, target_ulong addr, \ } #endif HELPER_ST(sb, stb, uint8_t) -HELPER_ST(sh, stw, uint16_t) HELPER_ST(sw, stl, uint32_t) +#if defined(TARGET_MIPS64) HELPER_ST(sd, stq, uint64_t) +#endif #undef HELPER_ST target_ulong helper_clo (target_ulong arg1) @@ -1067,19 +1068,23 @@ void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1) env->CP0_VPEOpt = arg1 & 0x0000ffff; } +#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF) + void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1) { - /* Large physaddr (PABITS) not implemented */ /* 1k pages not implemented */ target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); - env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30)); + env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env)) + | (rxi << (CP0EnLo_XI - 30)); } #if defined(TARGET_MIPS64) +#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6) + void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1) { uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); - env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | rxi; + env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi; } #endif @@ -1245,17 +1250,17 @@ void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1) { - /* Large physaddr (PABITS) not implemented */ /* 1k pages not implemented */ target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); - env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30)); + env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env)) + | (rxi << (CP0EnLo_XI - 30)); } #if defined(TARGET_MIPS64) void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1) { uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); - env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | rxi; + env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi; } #endif @@ -1278,10 +1283,11 @@ void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) { /* SmartMIPS not implemented */ - /* Large physaddr (PABITS) not implemented */ /* 1k pages not implemented */ env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) | (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask); + compute_hflags(env); + restore_pamask(env); } void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) @@ -1825,6 +1831,16 @@ static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first) } } +static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo) +{ +#if defined(TARGET_MIPS64) + return extract64(entrylo, 6, 54); +#else + return extract64(entrylo, 6, 24) | /* PFN */ + (extract64(entrylo, 32, 32) << 24); /* PFNX */ +#endif +} + static void r4k_fill_tlb(CPUMIPSState *env, int idx) { r4k_tlb_t *tlb; @@ -1848,13 +1864,13 @@ static void r4k_fill_tlb(CPUMIPSState *env, int idx) tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1; tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1; - tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12; + tlb->PFN[0] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) << 12; tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1; tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1; - tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; + tlb->PFN[1] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) << 12; } void r4k_helper_tlbinv(CPUMIPSState *env) @@ -1971,6 +1987,16 @@ void r4k_helper_tlbp(CPUMIPSState *env) } } +static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn) +{ +#if defined(TARGET_MIPS64) + return tlb_pfn << 6; +#else + return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */ + (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */ +#endif +} + void r4k_helper_tlbr(CPUMIPSState *env) { r4k_tlb_t *tlb; @@ -1996,13 +2022,13 @@ void r4k_helper_tlbr(CPUMIPSState *env) env->CP0_EntryHi = tlb->VPN | tlb->ASID; env->CP0_PageMask = tlb->PageMask; env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | - ((target_ulong)tlb->RI0 << CP0EnLo_RI) | - ((target_ulong)tlb->XI0 << CP0EnLo_XI) | - (tlb->C0 << 3) | (tlb->PFN[0] >> 6); + ((uint64_t)tlb->RI0 << CP0EnLo_RI) | + ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) | + get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12); env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | - ((target_ulong)tlb->RI1 << CP0EnLo_RI) | - ((target_ulong)tlb->XI1 << CP0EnLo_XI) | - (tlb->C1 << 3) | (tlb->PFN[1] >> 6); + ((uint64_t)tlb->RI1 << CP0EnLo_RI) | + ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) | + get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12); } } @@ -2098,7 +2124,7 @@ static void set_pc(CPUMIPSState *env, target_ulong error_pc) } } -void helper_eret(CPUMIPSState *env) +static inline void exception_return(CPUMIPSState *env) { debug_pre_eret(env); if (env->CP0_Status & (1 << CP0St_ERL)) { @@ -2110,9 +2136,19 @@ void helper_eret(CPUMIPSState *env) } compute_hflags(env); debug_post_eret(env); +} + +void helper_eret(CPUMIPSState *env) +{ + exception_return(env); env->lladdr = 1; } +void helper_eretnc(CPUMIPSState *env) +{ + exception_return(env); +} + void helper_deret(CPUMIPSState *env) { debug_pre_eret(env); @@ -2303,6 +2339,16 @@ target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) } } break; + case 5: + /* FRE Support - read Config5.FRE bit */ + if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) { + if (env->CP0_Config5 & (1 << CP0C5_UFE)) { + arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1; + } else { + helper_raise_exception(env, EXCP_RI); + } + } + break; case 25: arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1); break; @@ -2347,6 +2393,30 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) helper_raise_exception(env, EXCP_RI); } break; + case 5: + /* FRE Support - clear Config5.FRE bit */ + if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) { + return; + } + if (env->CP0_Config5 & (1 << CP0C5_UFE)) { + env->CP0_Config5 &= ~(1 << CP0C5_FRE); + compute_hflags(env); + } else { + helper_raise_exception(env, EXCP_RI); + } + break; + case 6: + /* FRE Support - set Config5.FRE bit */ + if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) { + return; + } + if (env->CP0_Config5 & (1 << CP0C5_UFE)) { + env->CP0_Config5 |= (1 << CP0C5_FRE); + compute_hflags(env); + } else { + helper_raise_exception(env, EXCP_RI); + } + break; case 25: if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) { return; @@ -3558,72 +3628,82 @@ FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status) /* Element-by-element access macros */ #define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df)) -void helper_msa_ld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs, - int32_t s10) -{ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); - target_ulong addr = env->active_tc.gpr[rs] + (s10 << df); - int i; +#if !defined(CONFIG_USER_ONLY) +#define MEMOP_IDX(DF) \ + TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \ + cpu_mmu_index(env)); +#else +#define MEMOP_IDX(DF) +#endif - switch (df) { - case DF_BYTE: - for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { - pwd->b[i] = do_lbu(env, addr + (i << DF_BYTE), - env->hflags & MIPS_HFLAG_KSU); - } - break; - case DF_HALF: - for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { - pwd->h[i] = do_lhu(env, addr + (i << DF_HALF), - env->hflags & MIPS_HFLAG_KSU); - } - break; - case DF_WORD: - for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { - pwd->w[i] = do_lw(env, addr + (i << DF_WORD), - env->hflags & MIPS_HFLAG_KSU); - } - break; - case DF_DOUBLE: - for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { - pwd->d[i] = do_ld(env, addr + (i << DF_DOUBLE), - env->hflags & MIPS_HFLAG_KSU); - } - break; - } +#define MSA_LD_DF(DF, TYPE, LD_INSN, ...) \ +void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \ + target_ulong addr) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t wx; \ + int i; \ + MEMOP_IDX(DF) \ + for (i = 0; i < DF_ELEMENTS(DF); i++) { \ + wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__); \ + } \ + memcpy(pwd, &wx, sizeof(wr_t)); \ } -void helper_msa_st_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs, - int32_t s10) -{ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); - target_ulong addr = env->active_tc.gpr[rs] + (s10 << df); - int i; +#if !defined(CONFIG_USER_ONLY) +MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETRA()) +MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETRA()) +MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETRA()) +MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETRA()) +#else +MSA_LD_DF(DF_BYTE, b, cpu_ldub_data) +MSA_LD_DF(DF_HALF, h, cpu_lduw_data) +MSA_LD_DF(DF_WORD, w, cpu_ldl_data) +MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data) +#endif - switch (df) { - case DF_BYTE: - for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { - do_sb(env, addr + (i << DF_BYTE), pwd->b[i], - env->hflags & MIPS_HFLAG_KSU); - } - break; - case DF_HALF: - for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { - do_sh(env, addr + (i << DF_HALF), pwd->h[i], - env->hflags & MIPS_HFLAG_KSU); - } - break; - case DF_WORD: - for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { - do_sw(env, addr + (i << DF_WORD), pwd->w[i], - env->hflags & MIPS_HFLAG_KSU); - } - break; - case DF_DOUBLE: - for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { - do_sd(env, addr + (i << DF_DOUBLE), pwd->d[i], - env->hflags & MIPS_HFLAG_KSU); - } - break; +#define MSA_PAGESPAN(x) \ + ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE) + +static inline void ensure_writable_pages(CPUMIPSState *env, + target_ulong addr, + int mmu_idx, + uintptr_t retaddr) +{ +#if !defined(CONFIG_USER_ONLY) + target_ulong page_addr; + if (unlikely(MSA_PAGESPAN(addr))) { + /* first page */ + probe_write(env, addr, mmu_idx, retaddr); + /* second page */ + page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + probe_write(env, page_addr, mmu_idx, retaddr); } +#endif +} + +#define MSA_ST_DF(DF, TYPE, ST_INSN, ...) \ +void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \ + target_ulong addr) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + int mmu_idx = cpu_mmu_index(env); \ + int i; \ + MEMOP_IDX(DF) \ + ensure_writable_pages(env, addr, mmu_idx, GETRA()); \ + for (i = 0; i < DF_ELEMENTS(DF); i++) { \ + ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__); \ + } \ } + +#if !defined(CONFIG_USER_ONLY) +MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETRA()) +MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETRA()) +MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETRA()) +MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETRA()) +#else +MSA_ST_DF(DF_BYTE, b, cpu_stb_data) +MSA_ST_DF(DF_HALF, h, cpu_stw_data) +MSA_ST_DF(DF_WORD, w, cpu_stl_data) +MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data) +#endif diff --git a/target-mips/translate.c b/target-mips/translate.c index fd063a2aae..1d128eef02 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -868,8 +868,10 @@ enum { enum { OPC_MFC0 = (0x00 << 21) | OPC_CP0, OPC_DMFC0 = (0x01 << 21) | OPC_CP0, + OPC_MFHC0 = (0x02 << 21) | OPC_CP0, OPC_MTC0 = (0x04 << 21) | OPC_CP0, OPC_DMTC0 = (0x05 << 21) | OPC_CP0, + OPC_MTHC0 = (0x06 << 21) | OPC_CP0, OPC_MFTR = (0x08 << 21) | OPC_CP0, OPC_RDPGPR = (0x0A << 21) | OPC_CP0, OPC_MFMC0 = (0x0B << 21) | OPC_CP0, @@ -1414,6 +1416,7 @@ typedef struct DisasContext { int32_t CP0_Config1; /* Routine used to access memory */ int mem_idx; + TCGMemOp default_tcg_memop_mask; uint32_t hflags, saved_hflags; int bstate; target_ulong btarget; @@ -1423,6 +1426,9 @@ typedef struct DisasContext { int ie; bool bi; bool bp; + uint64_t PAMask; + bool mvh; + int CP0_LLAddr_shift; } DisasContext; enum { @@ -1557,15 +1563,80 @@ static inline void gen_store_srsgpr (int from, int to) } } +/* Tests */ +static inline void gen_save_pc(target_ulong pc) +{ + tcg_gen_movi_tl(cpu_PC, pc); +} + +static inline void save_cpu_state(DisasContext *ctx, int do_save_pc) +{ + LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); + if (do_save_pc && ctx->pc != ctx->saved_pc) { + gen_save_pc(ctx->pc); + ctx->saved_pc = ctx->pc; + } + if (ctx->hflags != ctx->saved_hflags) { + tcg_gen_movi_i32(hflags, ctx->hflags); + ctx->saved_hflags = ctx->hflags; + switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { + case MIPS_HFLAG_BR: + break; + case MIPS_HFLAG_BC: + case MIPS_HFLAG_BL: + case MIPS_HFLAG_B: + tcg_gen_movi_tl(btarget, ctx->btarget); + break; + } + } +} + +static inline void restore_cpu_state(CPUMIPSState *env, DisasContext *ctx) +{ + ctx->saved_hflags = ctx->hflags; + switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { + case MIPS_HFLAG_BR: + break; + case MIPS_HFLAG_BC: + case MIPS_HFLAG_BL: + case MIPS_HFLAG_B: + ctx->btarget = env->btarget; + break; + } +} + +static inline void generate_exception_err(DisasContext *ctx, int excp, int err) +{ + TCGv_i32 texcp = tcg_const_i32(excp); + TCGv_i32 terr = tcg_const_i32(err); + save_cpu_state(ctx, 1); + gen_helper_raise_exception_err(cpu_env, texcp, terr); + tcg_temp_free_i32(terr); + tcg_temp_free_i32(texcp); +} + +static inline void generate_exception(DisasContext *ctx, int excp) +{ + save_cpu_state(ctx, 1); + gen_helper_0e0i(raise_exception, excp); +} + /* Floating point register moves. */ -static void gen_load_fpr32(TCGv_i32 t, int reg) +static void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) { + if (ctx->hflags & MIPS_HFLAG_FRE) { + generate_exception(ctx, EXCP_RI); + } tcg_gen_trunc_i64_i32(t, fpu_f64[reg]); } -static void gen_store_fpr32(TCGv_i32 t, int reg) +static void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) { - TCGv_i64 t64 = tcg_temp_new_i64(); + TCGv_i64 t64; + if (ctx->hflags & MIPS_HFLAG_FRE) { + generate_exception(ctx, EXCP_RI); + } + t64 = tcg_temp_new_i64(); tcg_gen_extu_i32_i64(t64, t); tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 0, 32); tcg_temp_free_i64(t64); @@ -1579,7 +1650,7 @@ static void gen_load_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) tcg_gen_trunc_i64_i32(t, t64); tcg_temp_free_i64(t64); } else { - gen_load_fpr32(t, reg | 1); + gen_load_fpr32(ctx, t, reg | 1); } } @@ -1591,7 +1662,7 @@ static void gen_store_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 32, 32); tcg_temp_free_i64(t64); } else { - gen_store_fpr32(t, reg | 1); + gen_store_fpr32(ctx, t, reg | 1); } } @@ -1626,66 +1697,6 @@ static inline int get_fp_bit (int cc) return 23; } -/* Tests */ -static inline void gen_save_pc(target_ulong pc) -{ - tcg_gen_movi_tl(cpu_PC, pc); -} - -static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) -{ - LOG_DISAS("hflags %08x saved %08x\n", ctx->hflags, ctx->saved_hflags); - if (do_save_pc && ctx->pc != ctx->saved_pc) { - gen_save_pc(ctx->pc); - ctx->saved_pc = ctx->pc; - } - if (ctx->hflags != ctx->saved_hflags) { - tcg_gen_movi_i32(hflags, ctx->hflags); - ctx->saved_hflags = ctx->hflags; - switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { - case MIPS_HFLAG_BR: - break; - case MIPS_HFLAG_BC: - case MIPS_HFLAG_BL: - case MIPS_HFLAG_B: - tcg_gen_movi_tl(btarget, ctx->btarget); - break; - } - } -} - -static inline void restore_cpu_state (CPUMIPSState *env, DisasContext *ctx) -{ - ctx->saved_hflags = ctx->hflags; - switch (ctx->hflags & MIPS_HFLAG_BMASK_BASE) { - case MIPS_HFLAG_BR: - break; - case MIPS_HFLAG_BC: - case MIPS_HFLAG_BL: - case MIPS_HFLAG_B: - ctx->btarget = env->btarget; - break; - } -} - -static inline void -generate_exception_err (DisasContext *ctx, int excp, int err) -{ - TCGv_i32 texcp = tcg_const_i32(excp); - TCGv_i32 terr = tcg_const_i32(err); - save_cpu_state(ctx, 1); - gen_helper_raise_exception_err(cpu_env, texcp, terr); - tcg_temp_free_i32(terr); - tcg_temp_free_i32(texcp); -} - -static inline void -generate_exception (DisasContext *ctx, int excp) -{ - save_cpu_state(ctx, 1); - gen_helper_0e0i(raise_exception, excp); -} - /* Addresses computation */ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1) { @@ -1815,11 +1826,20 @@ static inline void check_mips_64(DisasContext *ctx) } #endif +#ifndef CONFIG_USER_ONLY +static inline void check_mvh(DisasContext *ctx) +{ + if (unlikely(!ctx->mvh)) { + generate_exception(ctx, EXCP_RI); + } +} +#endif + /* Define small wrappers for gen_load_fpr* so that we have a uniform calling interface for 32 and 64-bit FPRs. No sense in changing all callers for gen_load_fpr32 when we need the CTX parameter for this one use. */ -#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(x, y) +#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(ctx, x, y) #define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y) #define FOP_CONDS(type, abs, fmt, ifmt, bits) \ static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n, \ @@ -1963,7 +1983,7 @@ static inline void gen_r6_cmp_ ## fmt(DisasContext * ctx, int n, \ } FOP_CONDNS(d, FMT_D, 64, gen_store_fpr64(ctx, fp0, fd)) -FOP_CONDNS(s, FMT_S, 32, gen_store_fpr32(fp0, fd)) +FOP_CONDNS(s, FMT_S, 32, gen_store_fpr32(ctx, fp0, fd)) #undef FOP_CONDNS #undef gen_ldcmp_fpr32 #undef gen_ldcmp_fpr64 @@ -2081,12 +2101,14 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, switch (opc) { #if defined(TARGET_MIPS64) case OPC_LWU: - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); gen_store_gpr(t0, rt); opn = "lwu"; break; case OPC_LD: - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); gen_store_gpr(t0, rt); opn = "ld"; break; @@ -2157,17 +2179,20 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, opn = "lwpc"; break; case OPC_LW: - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL | + ctx->default_tcg_memop_mask); gen_store_gpr(t0, rt); opn = "lw"; break; case OPC_LH: - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW | + ctx->default_tcg_memop_mask); gen_store_gpr(t0, rt); opn = "lh"; break; case OPC_LHU: - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUW); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUW | + ctx->default_tcg_memop_mask); gen_store_gpr(t0, rt); opn = "lhu"; break; @@ -2251,7 +2276,8 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt, switch (opc) { #if defined(TARGET_MIPS64) case OPC_SD: - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); opn = "sd"; break; case OPC_SDL: @@ -2266,11 +2292,13 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt, break; #endif case OPC_SW: - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); opn = "sw"; break; case OPC_SH: - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW | + ctx->default_tcg_memop_mask); opn = "sh"; break; case OPC_SB: @@ -2347,8 +2375,9 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, case OPC_LWC1: { TCGv_i32 fp0 = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL); - gen_store_fpr32(fp0, ft); + tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL | + ctx->default_tcg_memop_mask); + gen_store_fpr32(ctx, fp0, ft); tcg_temp_free_i32(fp0); } opn = "lwc1"; @@ -2356,8 +2385,9 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, case OPC_SWC1: { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, ft); - tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL); + gen_load_fpr32(ctx, fp0, ft); + tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); tcg_temp_free_i32(fp0); } opn = "swc1"; @@ -2365,7 +2395,8 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, case OPC_LDC1: { TCGv_i64 fp0 = tcg_temp_new_i64(); - tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ); + tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); gen_store_fpr64(ctx, fp0, ft); tcg_temp_free_i64(fp0); } @@ -2375,7 +2406,8 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft, { TCGv_i64 fp0 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, ft); - tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ); + tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); tcg_temp_free_i64(fp0); } opn = "sdc1"; @@ -4815,6 +4847,69 @@ static void gen_bshfl (DisasContext *ctx, uint32_t op2, int rt, int rd) #ifndef CONFIG_USER_ONLY /* CP0 (MMU and control) */ +static inline void gen_move_low32(TCGv ret, TCGv_i64 arg) +{ +#if defined(TARGET_MIPS64) + tcg_gen_ext32s_tl(ret, arg); +#else + tcg_gen_trunc_i64_tl(ret, arg); +#endif +} + +static inline void gen_mthc0_entrylo(TCGv arg, target_ulong off) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t0, arg); + tcg_gen_ld_i64(t1, cpu_env, off); +#if defined(TARGET_MIPS64) + tcg_gen_deposit_i64(t1, t1, t0, 30, 32); +#else + tcg_gen_concat32_i64(t1, t1, t0); +#endif + tcg_gen_st_i64(t1, cpu_env, off); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static inline void gen_mthc0_store64(TCGv arg, target_ulong off) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(t0, arg); + tcg_gen_ld_i64(t1, cpu_env, off); + tcg_gen_concat32_i64(t1, t1, t0); + tcg_gen_st_i64(t1, cpu_env, off); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); +} + +static inline void gen_mfhc0_entrylo(TCGv arg, target_ulong off) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + + tcg_gen_ld_i64(t0, cpu_env, off); +#if defined(TARGET_MIPS64) + tcg_gen_shri_i64(t0, t0, 30); +#else + tcg_gen_shri_i64(t0, t0, 32); +#endif + gen_move_low32(arg, t0); + tcg_temp_free_i64(t0); +} + +static inline void gen_mfhc0_load64(TCGv arg, target_ulong off, int shift) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + + tcg_gen_ld_i64(t0, cpu_env, off); + tcg_gen_shri_i64(t0, t0, 32 + shift); + gen_move_low32(arg, t0); + tcg_temp_free_i64(t0); +} + static inline void gen_mfc0_load32 (TCGv arg, target_ulong off) { TCGv_i32 t0 = tcg_temp_new_i32(); @@ -4845,6 +4940,140 @@ static inline void gen_mtc0_store64 (TCGv arg, target_ulong off) tcg_gen_st_tl(arg, cpu_env, off); } +static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel) +{ + const char *rn = "invalid"; + + if (!(ctx->hflags & MIPS_HFLAG_ELPA)) { + goto mfhc0_read_zero; + } + + switch (reg) { + case 2: + switch (sel) { + case 0: + gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo0)); + rn = "EntryLo0"; + break; + default: + goto mfhc0_read_zero; + } + break; + case 3: + switch (sel) { + case 0: + gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1)); + rn = "EntryLo1"; + break; + default: + goto mfhc0_read_zero; + } + break; + case 17: + switch (sel) { + case 0: + gen_mfhc0_load64(arg, offsetof(CPUMIPSState, lladdr), + ctx->CP0_LLAddr_shift); + rn = "LLAddr"; + break; + default: + goto mfhc0_read_zero; + } + break; + case 28: + switch (sel) { + case 0: + case 2: + case 4: + case 6: + gen_mfhc0_load64(arg, offsetof(CPUMIPSState, CP0_TagLo), 0); + rn = "TagLo"; + break; + default: + goto mfhc0_read_zero; + } + break; + default: + goto mfhc0_read_zero; + } + + (void)rn; /* avoid a compiler warning */ + LOG_DISAS("mfhc0 %s (reg %d sel %d)\n", rn, reg, sel); + return; + +mfhc0_read_zero: + LOG_DISAS("mfhc0 %s (reg %d sel %d)\n", rn, reg, sel); + tcg_gen_movi_tl(arg, 0); +} + +static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) +{ + const char *rn = "invalid"; + uint64_t mask = ctx->PAMask >> 36; + + if (!(ctx->hflags & MIPS_HFLAG_ELPA)) { + goto mthc0_nop; + } + + switch (reg) { + case 2: + switch (sel) { + case 0: + tcg_gen_andi_tl(arg, arg, mask); + gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo0)); + rn = "EntryLo0"; + break; + default: + goto mthc0_nop; + } + break; + case 3: + switch (sel) { + case 0: + tcg_gen_andi_tl(arg, arg, mask); + gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1)); + rn = "EntryLo1"; + break; + default: + goto mthc0_nop; + } + break; + case 17: + switch (sel) { + case 0: + /* LLAddr is read-only (the only exception is bit 0 if LLB is + supported); the CP0_LLAddr_rw_bitmask does not seem to be + relevant for modern MIPS cores supporting MTHC0, therefore + treating MTHC0 to LLAddr as NOP. */ + rn = "LLAddr"; + break; + default: + goto mthc0_nop; + } + break; + case 28: + switch (sel) { + case 0: + case 2: + case 4: + case 6: + tcg_gen_andi_tl(arg, arg, mask); + gen_mthc0_store64(arg, offsetof(CPUMIPSState, CP0_TagLo)); + rn = "TagLo"; + break; + default: + goto mthc0_nop; + } + break; + default: + goto mthc0_nop; + } + + (void)rn; /* avoid a compiler warning */ +mthc0_nop: + LOG_DISAS("mthc0 %s (reg %d sel %d)\n", rn, reg, sel); +} + static inline void gen_mfc0_unimplemented(DisasContext *ctx, TCGv arg) { if (ctx->insn_flags & ISA_MIPS32R6) { @@ -4943,17 +5172,20 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 2: switch (sel) { case 0: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0)); + { + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_ld_i64(tmp, cpu_env, + offsetof(CPUMIPSState, CP0_EntryLo0)); #if defined(TARGET_MIPS64) - if (ctx->rxi) { - TCGv tmp = tcg_temp_new(); - tcg_gen_andi_tl(tmp, arg, (3ull << CP0EnLo_XI)); - tcg_gen_shri_tl(tmp, tmp, 32); - tcg_gen_or_tl(arg, arg, tmp); - tcg_temp_free(tmp); - } + if (ctx->rxi) { + /* Move RI/XI fields to bits 31:30 */ + tcg_gen_shri_tl(arg, tmp, CP0EnLo_XI); + tcg_gen_deposit_tl(tmp, tmp, arg, 30, 2); + } #endif - tcg_gen_ext32s_tl(arg, arg); + gen_move_low32(arg, tmp); + tcg_temp_free_i64(tmp); + } rn = "EntryLo0"; break; case 1: @@ -4998,17 +5230,20 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 3: switch (sel) { case 0: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1)); + { + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_ld_i64(tmp, cpu_env, + offsetof(CPUMIPSState, CP0_EntryLo1)); #if defined(TARGET_MIPS64) - if (ctx->rxi) { - TCGv tmp = tcg_temp_new(); - tcg_gen_andi_tl(tmp, arg, (3ull << CP0EnLo_XI)); - tcg_gen_shri_tl(tmp, tmp, 32); - tcg_gen_or_tl(arg, arg, tmp); - tcg_temp_free(tmp); - } + if (ctx->rxi) { + /* Move RI/XI fields to bits 31:30 */ + tcg_gen_shri_tl(arg, tmp, CP0EnLo_XI); + tcg_gen_deposit_tl(tmp, tmp, arg, 30, 2); + } #endif - tcg_gen_ext32s_tl(arg, arg); + gen_move_low32(arg, tmp); + tcg_temp_free_i64(tmp); + } rn = "EntryLo1"; break; default: @@ -5418,7 +5653,12 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 2: case 4: case 6: - gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagLo)); + { + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUMIPSState, CP0_TagLo)); + gen_move_low32(arg, tmp); + tcg_temp_free_i64(tmp); + } rn = "TagLo"; break; case 1: @@ -5661,6 +5901,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_pagegrain(cpu_env, arg); rn = "PageGrain"; + ctx->bstate = BS_STOP; break; default: goto cp0_unimplemented; @@ -7557,7 +7798,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, if (h == 0) { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, rt); + gen_load_fpr32(ctx, fp0, rt); tcg_gen_ext_i32_tl(t0, fp0); tcg_temp_free_i32(fp0); } else { @@ -7756,7 +7997,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, TCGv_i32 fp0 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(fp0, t0); - gen_store_fpr32(fp0, rd); + gen_store_fpr32(ctx, fp0, rd); tcg_temp_free_i32(fp0); } else { TCGv_i32 fp0 = tcg_temp_new_i32(); @@ -7841,6 +8082,25 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, opn = "dmtc0"; break; #endif + case OPC_MFHC0: + check_mvh(ctx); + if (rt == 0) { + /* Treat as NOP. */ + return; + } + gen_mfhc0(ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); + opn = "mfhc0"; + break; + case OPC_MTHC0: + check_mvh(ctx); + { + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, rt); + gen_mthc0(ctx, t0, rd, ctx->opcode & 0x7); + tcg_temp_free(t0); + } + opn = "mthc0"; + break; case OPC_MFTR: check_insn(ctx, ASE_MT); if (rd == 0) { @@ -7899,16 +8159,26 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, goto die; gen_helper_tlbr(cpu_env); break; - case OPC_ERET: - opn = "eret"; - check_insn(ctx, ISA_MIPS2); + case OPC_ERET: /* OPC_ERETNC */ if ((ctx->insn_flags & ISA_MIPS32R6) && (ctx->hflags & MIPS_HFLAG_BMASK)) { MIPS_DEBUG("CTI in delay / forbidden slot"); goto die; + } else { + int bit_shift = (ctx->hflags & MIPS_HFLAG_M16) ? 16 : 6; + if (ctx->opcode & (1 << bit_shift)) { + /* OPC_ERETNC */ + opn = "eretnc"; + check_insn(ctx, ISA_MIPS32R5); + gen_helper_eretnc(cpu_env); + } else { + /* OPC_ERET */ + opn = "eret"; + check_insn(ctx, ISA_MIPS2); + gen_helper_eret(cpu_env); + } + ctx->bstate = BS_EXCP; } - gen_helper_eret(cpu_env); - ctx->bstate = BS_EXCP; break; case OPC_DERET: opn = "deret"; @@ -8346,7 +8616,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); tcg_gen_ext_i32_tl(t0, fp0); tcg_temp_free_i32(fp0); } @@ -8359,7 +8629,7 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) TCGv_i32 fp0 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(fp0, t0); - gen_store_fpr32(fp0, fs); + gen_store_fpr32(ctx, fp0, fs); tcg_temp_free_i32(fp0); } opn = "mtc1"; @@ -8457,7 +8727,8 @@ static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf) gen_set_label(l1); } -static inline void gen_movcf_s (int fs, int fd, int cc, int tf) +static inline void gen_movcf_s(DisasContext *ctx, int fs, int fd, int cc, + int tf) { int cond; TCGv_i32 t0 = tcg_temp_new_i32(); @@ -8470,8 +8741,8 @@ static inline void gen_movcf_s (int fs, int fd, int cc, int tf) tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); tcg_gen_brcondi_i32(cond, t0, 0, l1); - gen_load_fpr32(t0, fs); - gen_store_fpr32(t0, fd); + gen_load_fpr32(ctx, t0, fs); + gen_store_fpr32(ctx, t0, fd); gen_set_label(l1); tcg_temp_free_i32(t0); } @@ -8513,8 +8784,8 @@ static inline void gen_movcf_ps(DisasContext *ctx, int fs, int fd, tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc)); tcg_gen_brcondi_i32(cond, t0, 0, l1); - gen_load_fpr32(t0, fs); - gen_store_fpr32(t0, fd); + gen_load_fpr32(ctx, t0, fs); + gen_store_fpr32(ctx, t0, fd); gen_set_label(l1); tcg_gen_andi_i32(t0, fpu_fcr31, 1 << get_fp_bit(cc+1)); @@ -8532,9 +8803,9 @@ static void gen_sel_s(DisasContext *ctx, enum fopcode op1, int fd, int ft, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fd); - gen_load_fpr32(fp1, ft); - gen_load_fpr32(fp2, fs); + gen_load_fpr32(ctx, fp0, fd); + gen_load_fpr32(ctx, fp1, ft); + gen_load_fpr32(ctx, fp2, fs); switch (op1) { case OPC_SEL_S: @@ -8555,7 +8826,7 @@ static void gen_sel_s(DisasContext *ctx, enum fopcode op1, int fd, int ft, break; } - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp2); tcg_temp_free_i32(fp1); tcg_temp_free_i32(fp0); @@ -8648,11 +8919,11 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_add_s(fp0, cpu_env, fp0, fp1); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "add.s"; @@ -8663,11 +8934,11 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_sub_s(fp0, cpu_env, fp0, fp1); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "sub.s"; @@ -8678,11 +8949,11 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_mul_s(fp0, cpu_env, fp0, fp1); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "mul.s"; @@ -8693,11 +8964,11 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_div_s(fp0, cpu_env, fp0, fp1); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "div.s"; @@ -8707,9 +8978,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_sqrt_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "sqrt.s"; @@ -8718,9 +8989,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_abs_s(fp0, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "abs.s"; @@ -8729,8 +9000,8 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_store_fpr32(fp0, fd); + gen_load_fpr32(ctx, fp0, fs); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "mov.s"; @@ -8739,9 +9010,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_chs_s(fp0, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "neg.s"; @@ -8752,7 +9023,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp32 = tcg_temp_new_i32(); TCGv_i64 fp64 = tcg_temp_new_i64(); - gen_load_fpr32(fp32, fs); + gen_load_fpr32(ctx, fp32, fs); gen_helper_float_roundl_s(fp64, cpu_env, fp32); tcg_temp_free_i32(fp32); gen_store_fpr64(ctx, fp64, fd); @@ -8766,7 +9037,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp32 = tcg_temp_new_i32(); TCGv_i64 fp64 = tcg_temp_new_i64(); - gen_load_fpr32(fp32, fs); + gen_load_fpr32(ctx, fp32, fs); gen_helper_float_truncl_s(fp64, cpu_env, fp32); tcg_temp_free_i32(fp32); gen_store_fpr64(ctx, fp64, fd); @@ -8780,7 +9051,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp32 = tcg_temp_new_i32(); TCGv_i64 fp64 = tcg_temp_new_i64(); - gen_load_fpr32(fp32, fs); + gen_load_fpr32(ctx, fp32, fs); gen_helper_float_ceill_s(fp64, cpu_env, fp32); tcg_temp_free_i32(fp32); gen_store_fpr64(ctx, fp64, fd); @@ -8794,7 +9065,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp32 = tcg_temp_new_i32(); TCGv_i64 fp64 = tcg_temp_new_i64(); - gen_load_fpr32(fp32, fs); + gen_load_fpr32(ctx, fp32, fs); gen_helper_float_floorl_s(fp64, cpu_env, fp32); tcg_temp_free_i32(fp32); gen_store_fpr64(ctx, fp64, fd); @@ -8806,9 +9077,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_roundw_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "round.w.s"; @@ -8817,9 +9088,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_truncw_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "trunc.w.s"; @@ -8828,9 +9099,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_ceilw_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "ceil.w.s"; @@ -8839,9 +9110,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_floorw_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "floor.w.s"; @@ -8863,7 +9134,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, break; case OPC_MOVCF_S: check_insn_opc_removed(ctx, ISA_MIPS32R6); - gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1); + gen_movcf_s(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1); opn = "movcf.s"; break; case OPC_MOVZ_S: @@ -8876,8 +9147,8 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[ft], 0, l1); } fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_store_fpr32(fp0, fd); + gen_load_fpr32(ctx, fp0, fs); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); gen_set_label(l1); } @@ -8892,8 +9163,8 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, if (ft != 0) { tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[ft], 0, l1); fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_store_fpr32(fp0, fd); + gen_load_fpr32(ctx, fp0, fs); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); gen_set_label(l1); } @@ -8905,9 +9176,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_recip_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "recip.s"; @@ -8917,9 +9188,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_rsqrt_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "rsqrt.s"; @@ -8930,11 +9201,11 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); - gen_load_fpr32(fp2, fd); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); + gen_load_fpr32(ctx, fp2, fd); gen_helper_float_maddf_s(fp2, cpu_env, fp0, fp1, fp2); - gen_store_fpr32(fp2, fd); + gen_store_fpr32(ctx, fp2, fd); tcg_temp_free_i32(fp2); tcg_temp_free_i32(fp1); tcg_temp_free_i32(fp0); @@ -8947,11 +9218,11 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); - gen_load_fpr32(fp2, fd); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); + gen_load_fpr32(ctx, fp2, fd); gen_helper_float_msubf_s(fp2, cpu_env, fp0, fp1, fp2); - gen_store_fpr32(fp2, fd); + gen_store_fpr32(ctx, fp2, fd); tcg_temp_free_i32(fp2); tcg_temp_free_i32(fp1); tcg_temp_free_i32(fp0); @@ -8962,9 +9233,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, check_insn(ctx, ISA_MIPS32R6); { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_rint_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); opn = "rint.s"; } @@ -8973,9 +9244,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, check_insn(ctx, ISA_MIPS32R6); { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_class_s(fp0, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); opn = "class.s"; } @@ -8986,10 +9257,10 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_min_s(fp2, cpu_env, fp0, fp1); - gen_store_fpr32(fp2, fd); + gen_store_fpr32(ctx, fp2, fd); tcg_temp_free_i32(fp2); tcg_temp_free_i32(fp1); tcg_temp_free_i32(fp0); @@ -9001,11 +9272,11 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "recip2.s"; @@ -9017,10 +9288,10 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_mina_s(fp2, cpu_env, fp0, fp1); - gen_store_fpr32(fp2, fd); + gen_store_fpr32(ctx, fp2, fd); tcg_temp_free_i32(fp2); tcg_temp_free_i32(fp1); tcg_temp_free_i32(fp0); @@ -9031,9 +9302,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_recip1_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "recip1.s"; @@ -9044,10 +9315,10 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, /* OPC_MAX_S */ TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_max_s(fp1, cpu_env, fp0, fp1); - gen_store_fpr32(fp1, fd); + gen_store_fpr32(ctx, fp1, fd); tcg_temp_free_i32(fp1); tcg_temp_free_i32(fp0); opn = "max.s"; @@ -9057,9 +9328,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "rsqrt1.s"; @@ -9070,10 +9341,10 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, /* OPC_MAXA_S */ TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_maxa_s(fp1, cpu_env, fp0, fp1); - gen_store_fpr32(fp1, fd); + gen_store_fpr32(ctx, fp1, fd); tcg_temp_free_i32(fp1); tcg_temp_free_i32(fp0); opn = "maxa.s"; @@ -9084,11 +9355,11 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "rsqrt2.s"; @@ -9100,7 +9371,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp32 = tcg_temp_new_i32(); TCGv_i64 fp64 = tcg_temp_new_i64(); - gen_load_fpr32(fp32, fs); + gen_load_fpr32(ctx, fp32, fs); gen_helper_float_cvtd_s(fp64, cpu_env, fp32); tcg_temp_free_i32(fp32); gen_store_fpr64(ctx, fp64, fd); @@ -9112,9 +9383,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_cvtw_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "cvt.w.s"; @@ -9125,7 +9396,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp32 = tcg_temp_new_i32(); TCGv_i64 fp64 = tcg_temp_new_i64(); - gen_load_fpr32(fp32, fs); + gen_load_fpr32(ctx, fp32, fs); gen_helper_float_cvtl_s(fp64, cpu_env, fp32); tcg_temp_free_i32(fp32); gen_store_fpr64(ctx, fp64, fd); @@ -9141,8 +9412,8 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp32_0 = tcg_temp_new_i32(); TCGv_i32 fp32_1 = tcg_temp_new_i32(); - gen_load_fpr32(fp32_0, fs); - gen_load_fpr32(fp32_1, ft); + gen_load_fpr32(ctx, fp32_0, fs); + gen_load_fpr32(ctx, fp32_1, ft); tcg_gen_concat_i32_i64(fp64, fp32_1, fp32_0); tcg_temp_free_i32(fp32_1); tcg_temp_free_i32(fp32_0); @@ -9344,7 +9615,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); gen_helper_float_roundw_d(fp32, cpu_env, fp64); tcg_temp_free_i64(fp64); - gen_store_fpr32(fp32, fd); + gen_store_fpr32(ctx, fp32, fd); tcg_temp_free_i32(fp32); } opn = "round.w.d"; @@ -9358,7 +9629,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); gen_helper_float_truncw_d(fp32, cpu_env, fp64); tcg_temp_free_i64(fp64); - gen_store_fpr32(fp32, fd); + gen_store_fpr32(ctx, fp32, fd); tcg_temp_free_i32(fp32); } opn = "trunc.w.d"; @@ -9372,7 +9643,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); gen_helper_float_ceilw_d(fp32, cpu_env, fp64); tcg_temp_free_i64(fp64); - gen_store_fpr32(fp32, fd); + gen_store_fpr32(ctx, fp32, fd); tcg_temp_free_i32(fp32); } opn = "ceil.w.d"; @@ -9386,7 +9657,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); gen_helper_float_floorw_d(fp32, cpu_env, fp64); tcg_temp_free_i64(fp64); - gen_store_fpr32(fp32, fd); + gen_store_fpr32(ctx, fp32, fd); tcg_temp_free_i32(fp32); } opn = "floor.w.d"; @@ -9669,7 +9940,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); gen_helper_float_cvts_d(fp32, cpu_env, fp64); tcg_temp_free_i64(fp64); - gen_store_fpr32(fp32, fd); + gen_store_fpr32(ctx, fp32, fd); tcg_temp_free_i32(fp32); } opn = "cvt.s.d"; @@ -9683,7 +9954,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); gen_helper_float_cvtw_d(fp32, cpu_env, fp64); tcg_temp_free_i64(fp64); - gen_store_fpr32(fp32, fd); + gen_store_fpr32(ctx, fp32, fd); tcg_temp_free_i32(fp32); } opn = "cvt.w.d"; @@ -9704,9 +9975,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_cvts_w(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "cvt.s.w"; @@ -9717,7 +9988,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp32 = tcg_temp_new_i32(); TCGv_i64 fp64 = tcg_temp_new_i64(); - gen_load_fpr32(fp32, fs); + gen_load_fpr32(ctx, fp32, fs); gen_helper_float_cvtd_w(fp64, cpu_env, fp32); tcg_temp_free_i32(fp32); gen_store_fpr64(ctx, fp64, fd); @@ -9734,7 +10005,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr64(ctx, fp64, fs); gen_helper_float_cvts_l(fp32, cpu_env, fp64); tcg_temp_free_i64(fp64); - gen_store_fpr32(fp32, fd); + gen_store_fpr32(ctx, fp32, fd); tcg_temp_free_i32(fp32); } opn = "cvt.s.l"; @@ -9973,7 +10244,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr32h(ctx, fp0, fs); gen_helper_float_cvts_pu(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "cvt.s.pu"; @@ -9995,9 +10266,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_helper_float_cvts_pl(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "cvt.s.pl"; @@ -10008,10 +10279,10 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); gen_store_fpr32h(ctx, fp0, fd); - gen_store_fpr32(fp1, fd); + gen_store_fpr32(ctx, fp1, fd); tcg_temp_free_i32(fp0); tcg_temp_free_i32(fp1); } @@ -10023,9 +10294,9 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); gen_load_fpr32h(ctx, fp1, ft); - gen_store_fpr32(fp1, fd); + gen_store_fpr32(ctx, fp1, fd); gen_store_fpr32h(ctx, fp0, fd); tcg_temp_free_i32(fp0); tcg_temp_free_i32(fp1); @@ -10039,8 +10310,8 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, TCGv_i32 fp1 = tcg_temp_new_i32(); gen_load_fpr32h(ctx, fp0, fs); - gen_load_fpr32(fp1, ft); - gen_store_fpr32(fp1, fd); + gen_load_fpr32(ctx, fp1, ft); + gen_store_fpr32(ctx, fp1, fd); gen_store_fpr32h(ctx, fp0, fd); tcg_temp_free_i32(fp0); tcg_temp_free_i32(fp1); @@ -10055,7 +10326,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, gen_load_fpr32h(ctx, fp0, fs); gen_load_fpr32h(ctx, fp1, ft); - gen_store_fpr32(fp1, fd); + gen_store_fpr32(ctx, fp1, fd); gen_store_fpr32h(ctx, fp0, fd); tcg_temp_free_i32(fp0); tcg_temp_free_i32(fp1); @@ -10130,7 +10401,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL); tcg_gen_trunc_tl_i32(fp0, t0); - gen_store_fpr32(fp0, fd); + gen_store_fpr32(ctx, fp0, fd); tcg_temp_free_i32(fp0); } opn = "lwxc1"; @@ -10162,7 +10433,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, check_cop1x(ctx); { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); + gen_load_fpr32(ctx, fp0, fs); tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL); tcg_temp_free_i32(fp0); } @@ -10219,23 +10490,23 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, tcg_gen_andi_tl(t0, t0, 0x7); tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); - gen_load_fpr32(fp, fs); + gen_load_fpr32(ctx, fp, fs); gen_load_fpr32h(ctx, fph, fs); - gen_store_fpr32(fp, fd); + gen_store_fpr32(ctx, fp, fd); gen_store_fpr32h(ctx, fph, fd); tcg_gen_br(l2); gen_set_label(l1); tcg_gen_brcondi_tl(TCG_COND_NE, t0, 4, l2); tcg_temp_free(t0); #ifdef TARGET_WORDS_BIGENDIAN - gen_load_fpr32(fp, fs); + gen_load_fpr32(ctx, fp, fs); gen_load_fpr32h(ctx, fph, ft); gen_store_fpr32h(ctx, fp, fd); - gen_store_fpr32(fph, fd); + gen_store_fpr32(ctx, fph, fd); #else gen_load_fpr32h(ctx, fph, fs); - gen_load_fpr32(fp, ft); - gen_store_fpr32(fph, fd); + gen_load_fpr32(ctx, fp, ft); + gen_store_fpr32(ctx, fph, fd); gen_store_fpr32h(ctx, fp, fd); #endif gen_set_label(l2); @@ -10251,13 +10522,13 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); - gen_load_fpr32(fp2, fr); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); + gen_load_fpr32(ctx, fp2, fr); gen_helper_float_madd_s(fp2, cpu_env, fp0, fp1, fp2); tcg_temp_free_i32(fp0); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp2, fd); + gen_store_fpr32(ctx, fp2, fd); tcg_temp_free_i32(fp2); } opn = "madd.s"; @@ -10306,13 +10577,13 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); - gen_load_fpr32(fp2, fr); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); + gen_load_fpr32(ctx, fp2, fr); gen_helper_float_msub_s(fp2, cpu_env, fp0, fp1, fp2); tcg_temp_free_i32(fp0); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp2, fd); + gen_store_fpr32(ctx, fp2, fd); tcg_temp_free_i32(fp2); } opn = "msub.s"; @@ -10361,13 +10632,13 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); - gen_load_fpr32(fp2, fr); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); + gen_load_fpr32(ctx, fp2, fr); gen_helper_float_nmadd_s(fp2, cpu_env, fp0, fp1, fp2); tcg_temp_free_i32(fp0); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp2, fd); + gen_store_fpr32(ctx, fp2, fd); tcg_temp_free_i32(fp2); } opn = "nmadd.s"; @@ -10416,13 +10687,13 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, TCGv_i32 fp1 = tcg_temp_new_i32(); TCGv_i32 fp2 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_load_fpr32(fp1, ft); - gen_load_fpr32(fp2, fr); + gen_load_fpr32(ctx, fp0, fs); + gen_load_fpr32(ctx, fp1, ft); + gen_load_fpr32(ctx, fp2, fr); gen_helper_float_nmsub_s(fp2, cpu_env, fp0, fp1, fp2); tcg_temp_free_i32(fp0); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp2, fd); + gen_store_fpr32(ctx, fp2, fd); tcg_temp_free_i32(fp2); } opn = "nmsub.s"; @@ -13502,7 +13773,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case MOVF_FMT: switch (fmt) { case FMT_SDPS_S: - gen_movcf_s(rs, rt, cc, 0); + gen_movcf_s(ctx, rs, rt, cc, 0); break; case FMT_SDPS_D: gen_movcf_d(ctx, rs, rt, cc, 0); @@ -13517,7 +13788,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case MOVT_FMT: switch (fmt) { case FMT_SDPS_S: - gen_movcf_s(rs, rt, cc, 1); + gen_movcf_s(ctx, rs, rt, cc, 1); break; case FMT_SDPS_D: gen_movcf_d(ctx, rs, rt, cc, 1); @@ -18404,32 +18675,39 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) uint8_t wd = (ctx->opcode >> 6) & 0x1f; uint8_t df = (ctx->opcode >> 0) & 0x3; - TCGv_i32 tdf = tcg_const_i32(df); TCGv_i32 twd = tcg_const_i32(wd); - TCGv_i32 trs = tcg_const_i32(rs); - TCGv_i32 ts10 = tcg_const_i32(s10); + TCGv taddr = tcg_temp_new(); + gen_base_offset_addr(ctx, taddr, rs, s10 << df); switch (MASK_MSA_MINOR(opcode)) { case OPC_LD_B: + gen_helper_msa_ld_b(cpu_env, twd, taddr); + break; case OPC_LD_H: + gen_helper_msa_ld_h(cpu_env, twd, taddr); + break; case OPC_LD_W: + gen_helper_msa_ld_w(cpu_env, twd, taddr); + break; case OPC_LD_D: - save_cpu_state(ctx, 1); - gen_helper_msa_ld_df(cpu_env, tdf, twd, trs, ts10); + gen_helper_msa_ld_d(cpu_env, twd, taddr); break; case OPC_ST_B: + gen_helper_msa_st_b(cpu_env, twd, taddr); + break; case OPC_ST_H: + gen_helper_msa_st_h(cpu_env, twd, taddr); + break; case OPC_ST_W: + gen_helper_msa_st_w(cpu_env, twd, taddr); + break; case OPC_ST_D: - save_cpu_state(ctx, 1); - gen_helper_msa_st_df(cpu_env, tdf, twd, trs, ts10); + gen_helper_msa_st_d(cpu_env, twd, taddr); break; } tcg_temp_free_i32(twd); - tcg_temp_free_i32(tdf); - tcg_temp_free_i32(trs); - tcg_temp_free_i32(ts10); + tcg_temp_free(taddr); } break; default: @@ -18564,6 +18842,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) case OPC_MTC0: case OPC_MFTR: case OPC_MTTR: + case OPC_MFHC0: + case OPC_MTHC0: #if defined(TARGET_MIPS64) case OPC_DMFC0: case OPC_DMTC0: @@ -19134,6 +19414,9 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.ie = (env->CP0_Config4 >> CP0C4_IE) & 3; ctx.bi = (env->CP0_Config3 >> CP0C3_BI) & 1; ctx.bp = (env->CP0_Config3 >> CP0C3_BP) & 1; + ctx.PAMask = env->PAMask; + ctx.mvh = (env->CP0_Config5 >> CP0C5_MVH) & 1; + ctx.CP0_LLAddr_shift = env->CP0_LLAddr_shift; /* Restore delay slot state from the tb context. */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1; @@ -19143,6 +19426,8 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, #else ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; #endif + ctx.default_tcg_memop_mask = (ctx.insn_flags & ISA_MIPS32R6) ? + MO_UNALN : MO_ALIGN; num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) @@ -19385,7 +19670,8 @@ void mips_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", env->CP0_Status, env->CP0_Cause, env->CP0_EPC); - cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n", + cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016" + PRIx64 "\n", env->CP0_Config0, env->CP0_Config1, env->lladdr); cpu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n", env->CP0_Config2, env->CP0_Config3); @@ -19519,7 +19805,6 @@ void cpu_state_reset(CPUMIPSState *env) } #endif env->PABITS = env->cpu_model->PABITS; - env->PAMask = (target_ulong)((1ULL << env->cpu_model->PABITS) - 1); env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask; env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0; env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask; @@ -19640,6 +19925,7 @@ void cpu_state_reset(CPUMIPSState *env) compute_hflags(env); restore_rounding_mode(env); restore_flush_mode(env); + restore_pamask(env); cs->exception_index = EXCP_NONE; } diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 85a65e74b4..30605dab06 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -400,10 +400,12 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) | (1 << CP0C1_CA), .CP0_Config2 = MIPS_CONFIG2, - .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP), + .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) | + (1 << CP0C3_LPA), .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M), .CP0_Config4_rw_bitmask = 0, - .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_UFR), + .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_UFR) | (1 << CP0C5_LLB) | + (1 << CP0C5_MVH), .CP0_Config5_rw_bitmask = (0 << CP0C5_M) | (1 << CP0C5_K) | (1 << CP0C5_CV) | (0 << CP0C5_EVA) | (1 << CP0C5_MSAEn) | (1 << CP0C5_UFR) | @@ -413,11 +415,12 @@ static const mips_def_t mips_defs[] = .SYNCI_Step = 32, .CCRes = 2, .CP0_Status_rw_bitmask = 0x3778FF1F, + .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA), .CP1_fcr0 = (1 << FCR0_UFRP) | (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID), .SEGBITS = 32, - .PABITS = 32, + .PABITS = 40, .insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_MSA, .mmu_type = MMU_TYPE_R4000, }, @@ -553,9 +556,6 @@ static const mips_def_t mips_defs[] = (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), .SEGBITS = 42, - /* The architectural limit is 59, but we have hardcoded 36 bit - in some places... - .PABITS = 59, */ /* the architectural limit */ .PABITS = 36, .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D, .mmu_type = MMU_TYPE_R4000, @@ -607,7 +607,7 @@ static const mips_def_t mips_defs[] = }, { /* A generic CPU supporting MIPS64 Release 6 ISA. - FIXME: Support IEEE 754-2008 FP and misaligned memory accesses. + FIXME: Support IEEE 754-2008 FP. Eventually this should be replaced by a real CPU model. */ .name = "MIPS64R6-generic", .CP0_PRid = 0x00010000, @@ -619,10 +619,13 @@ static const mips_def_t mips_defs[] = (0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_RXI) | (1 << CP0C3_BP) | - (1 << CP0C3_BI) | (1 << CP0C3_ULRI) | (1U << CP0C3_M), + (1 << CP0C3_BI) | (1 << CP0C3_ULRI) | (1 << CP0C3_LPA) | + (1U << CP0C3_M), .CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) | (3 << CP0C4_IE) | (1 << CP0C4_M), - .CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI), + .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_LLB), + .CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) | + (1 << CP0C5_UFE), .CP0_LLAddr_rw_bitmask = 0, .CP0_LLAddr_shift = 0, .SYNCI_Step = 32, @@ -630,15 +633,12 @@ static const mips_def_t mips_defs[] = .CP0_Status_rw_bitmask = 0x30D8FFFF, .CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) | (1U << CP0PG_RIE), - .CP0_PageGrain_rw_bitmask = 0, - .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | - (1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) | - (0x0 << FCR0_REV), + .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA), + .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_F64) | (1 << FCR0_L) | + (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | + (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), .SEGBITS = 42, - /* The architectural limit is 59, but we have hardcoded 36 bit - in some places... - .PABITS = 59, */ /* the architectural limit */ - .PABITS = 36, + .PABITS = 48, .insn_flags = CPU_MIPS64R6, .mmu_type = MMU_TYPE_R4000, }, @@ -701,9 +701,6 @@ static const mips_def_t mips_defs[] = (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), .SEGBITS = 42, - /* The architectural limit is 59, but we have hardcoded 36 bit - in some places... - .PABITS = 59, */ /* the architectural limit */ .PABITS = 36, .insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSPR2, .mmu_type = MMU_TYPE_R4000, diff --git a/tests/endianness-test.c b/tests/endianness-test.c index 92e17d251a..26ee734f42 100644 --- a/tests/endianness-test.c +++ b/tests/endianness-test.c @@ -31,8 +31,6 @@ struct TestCase { static const TestCase test_cases[] = { { "i386", "pc", -1 }, - { "mips", "magnum", 0x90000000, .bswap = true }, - { "mips", "pica61", 0x90000000, .bswap = true }, { "mips", "mips", 0x14000000, .bswap = true }, { "mips", "malta", 0x10000000, .bswap = true }, { "mips64", "magnum", 0x90000000, .bswap = true }, diff --git a/trace-events b/trace-events index 1abca7a1e5..6060d36773 100644 --- a/trace-events +++ b/trace-events @@ -280,6 +280,12 @@ slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d cha slavio_timer_mem_writel_mode_invalid(void) "not system timer" slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64 +# hw/dma/rc4030.c +jazzio_read(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x" +jazzio_write(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x" +rc4030_read(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x" +rc4030_write(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x" + # hw/dma/sparc32_dma.c ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64 ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64 |