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
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJVeppzAAoJEFIRjjwLKdprnk8H/1owSOreh0sMFbosvqlEhjXl
 lvjjuprWMdX+8M1JlaDvTbw6+LDB3Rihp3A6/I9A0GFiZaORmPzg7efULAI1H6ST
 0HfxMAO17eW+PJ3lvk0HidNDr01+RzTvwpizrHgQ9WJubJv0xREU+YG5yn1gPS4N
 aMMTKCAQFDba7iQQLKXUYvLz76+xyzW4VIvHVLx/SU86yPg9T7CwLpppipR8+zY5
 3BC4NUw/xLlS0LCYQGM8XmYgBiQ6lEAz/Y29bGlUg+LeYysjSgNSeoNbOs1M3kQp
 X0Hn7b28I1CjM2wZQ9GkT/ig+jhMvw27motnAe8vKood4ytfcor+dCCS13sE8fg=
 =F564
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2015-06-12 12:49:40 +01:00
commit 4cb618abc1
22 changed files with 1298 additions and 847 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 },

View File

@ -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)
{
uint32_t v = rc4030_readl(opaque, addr & ~0x3);
return (v >> (8 * (addr & 0x3))) & 0xff;
}
static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
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 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);
qemu_log_mask(LOG_GUEST_ERROR,
"rc4030: invalid write of 0x%02x at 0x%x",
val, (int)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);
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;
}

View File

@ -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

View File

@ -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] */

View File

@ -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;

View File

@ -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);
qemu_check_nic_model(nd, "dp83932");
sysbus_init_mmio(sbd, &s->mmio);
sysbus_init_mmio(sbd, &s->prom);
sysbus_init_irq(sbd, &s->irq);
}
s = g_malloc0(sizeof(dp8393xState));
static void dp8393x_realize(DeviceState *dev, Error **errp)
{
dp8393xState *s = DP8393X(dev);
int i, checksum;
uint8_t *prom;
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;
s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
qemu_register_reset(nic_reset, s);
nic_reset(s);
memory_region_init_io(&s->mmio, NULL, &dp8393x_ops, s,
"dp8393x", 0x40 << it_shift);
memory_region_add_subregion(address_space, base, &s->mmio);
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;
}
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()
}
};
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);
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)

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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,

View File

@ -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 },

View File

@ -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