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_ISA=y
CONFIG_IDE_PIIX=y CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
CONFIG_MIPSNET=y CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y
CONFIG_G364FB=y
CONFIG_I8259=y CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y CONFIG_MC146818RTC=y
CONFIG_ISA_TESTDEV=y CONFIG_ISA_TESTDEV=y
CONFIG_EMPTY_SLOT=y CONFIG_EMPTY_SLOT=y

View File

@ -29,6 +29,7 @@ CONFIG_DP8393X=y
CONFIG_DS1225Y=y CONFIG_DS1225Y=y
CONFIG_MIPSNET=y CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y
CONFIG_JAZZ=y
CONFIG_G364FB=y CONFIG_G364FB=y
CONFIG_I8259=y CONFIG_I8259=y
CONFIG_JAZZ_LED=y CONFIG_JAZZ_LED=y

View File

@ -31,6 +31,7 @@ CONFIG_DS1225Y=y
CONFIG_MIPSNET=y CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y
CONFIG_FULONG=y CONFIG_FULONG=y
CONFIG_JAZZ=y
CONFIG_G364FB=y CONFIG_G364FB=y
CONFIG_I8259=y CONFIG_I8259=y
CONFIG_JAZZ_LED=y CONFIG_JAZZ_LED=y

View File

@ -24,14 +24,9 @@ CONFIG_PIIX4=y
CONFIG_IDE_ISA=y CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y CONFIG_NE2000_ISA=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
CONFIG_MIPSNET=y CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y CONFIG_PFLASH_CFI01=y
CONFIG_G364FB=y
CONFIG_I8259=y CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y CONFIG_MC146818RTC=y
CONFIG_ISA_TESTDEV=y CONFIG_ISA_TESTDEV=y
CONFIG_EMPTY_SLOT=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.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.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 }, {"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 }, {"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,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 }, {"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", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 },
{"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, {"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 },
{"eret", "", 0x42000018, 0xffffffff, 0, 0, I3|I32 }, {"eret", "", 0x42000018, 0xffffffff, 0, 0, I3|I32 },
{"eretnc", "", 0x42000058, 0xffffffff, 0, 0, I33},
{"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 }, {"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 },
{"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 }, {"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 },
{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 }, {"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 },

View File

@ -1,7 +1,7 @@
/* /*
* QEMU JAZZ RC4030 chipset * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -24,29 +24,16 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/mips/mips.h" #include "hw/mips/mips.h"
#include "hw/sysbus.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "exec/address-spaces.h"
/********************************************************/ #include "trace.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)
/********************************************************/ /********************************************************/
/* rc4030 emulation */ /* rc4030 emulation */
#define MAX_TL_ENTRIES 512
typedef struct dma_pagetable_entry { typedef struct dma_pagetable_entry {
int32_t frame; int32_t frame;
int32_t owner; int32_t owner;
@ -63,8 +50,14 @@ typedef struct dma_pagetable_entry {
#define DMA_FLAG_MEM_INTR 0x0200 #define DMA_FLAG_MEM_INTR 0x0200
#define DMA_FLAG_ADDR_INTR 0x0400 #define DMA_FLAG_ADDR_INTR 0x0400
#define TYPE_RC4030 "rc4030"
#define RC4030(obj) \
OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030)
typedef struct rc4030State typedef struct rc4030State
{ {
SysBusDevice parent;
uint32_t config; /* 0x0000: RC4030 config register */ uint32_t config; /* 0x0000: RC4030 config register */
uint32_t revision; /* 0x0008: RC4030 Revision register */ uint32_t revision; /* 0x0008: RC4030 Revision register */
uint32_t invalid_address_register; /* 0x0010: Invalid Address 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 cache_bmask; /* 0x0058: I/O Cache Byte Mask */
uint32_t nmi_interrupt; /* 0x0200: interrupt source */ 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 nvram_protect; /* 0x0220: NV ram protect register */
uint32_t rem_speed[16]; uint32_t rem_speed[16];
uint32_t imr_jazz; /* Local bus int enable mask */ uint32_t imr_jazz; /* Local bus int enable mask */
@ -96,6 +89,16 @@ typedef struct rc4030State
qemu_irq timer_irq; qemu_irq timer_irq;
qemu_irq jazz_bus_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_chipset;
MemoryRegion iomem_jazzio; MemoryRegion iomem_jazzio;
} rc4030State; } rc4030State;
@ -112,7 +115,7 @@ static void set_next_tick(rc4030State *s)
} }
/* called for accesses to rc4030 */ /* 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; rc4030State *s = opaque;
uint32_t val; uint32_t val;
@ -220,9 +223,9 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr)
case 0x0208: case 0x0208:
val = 0; val = 0;
break; break;
/* Offset 0x0210 */ /* Memory refresh rate */
case 0x0210: case 0x0210:
val = s->offset210; val = s->memory_refresh_rate;
break; break;
/* NV ram protect register */ /* NV ram protect register */
case 0x0220: case 0x0220:
@ -238,39 +241,117 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr)
val = 7; /* FIXME: should be read from EISA controller */ val = 7; /* FIXME: should be read from EISA controller */
break; break;
default: 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; val = 0;
break; break;
} }
if ((addr & ~3) != 0x230) { if ((addr & ~3) != 0x230) {
DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr); trace_rc4030_read(addr, val);
} }
return 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 (index < MAX_TL_ENTRIES) {
if (addr & 0x2) memory_region_set_enabled(&s->dma_mrs[index], false);
return v >> 16; }
else
return v & 0xffff; 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;
}
static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
{ {
rc4030State *s = opaque; 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; addr &= 0x3fff;
DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr); trace_rc4030_write(addr, val);
switch (addr & ~0x3) { switch (addr & ~0x3) {
/* Global config register */ /* Global config register */
@ -279,11 +360,11 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
break; break;
/* DMA transl. table base */ /* DMA transl. table base */
case 0x0018: case 0x0018:
s->dma_tl_base = val; rc4030_dma_tt_update(s, val, s->dma_tl_limit);
break; break;
/* DMA transl. table limit */ /* DMA transl. table limit */
case 0x0020: case 0x0020:
s->dma_tl_limit = val; rc4030_dma_tt_update(s, s->dma_tl_base, val);
break; break;
/* DMA transl. table invalidated */ /* DMA transl. table invalidated */
case 0x0028: case 0x0028:
@ -371,9 +452,9 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
s->dma_regs[entry][idx] = val; s->dma_regs[entry][idx] = val;
} }
break; break;
/* Offset 0x0210 */ /* Memory refresh rate */
case 0x0210: case 0x0210:
s->offset210 = val; s->memory_refresh_rate = val;
break; break;
/* Interval timer reload */ /* Interval timer reload */
case 0x0228: case 0x0228:
@ -385,48 +466,18 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
case 0x0238: case 0x0238:
break; break;
default: 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; 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 = { static const MemoryRegionOps rc4030_ops = {
.old_mmio = { .read = rc4030_read,
.read = { rc4030_readb, rc4030_readw, rc4030_readl, }, .write = rc4030_write,
.write = { rc4030_writeb, rc4030_writew, rc4030_writel, }, .impl.min_access_size = 4,
}, .impl.max_access_size = 4,
.endianness = DEVICE_NATIVE_ENDIAN, .endianness = DEVICE_NATIVE_ENDIAN,
}; };
@ -436,22 +487,6 @@ static void update_jazz_irq(rc4030State *s)
pending = s->isr_jazz & s->imr_jazz; 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) if (pending != 0)
qemu_irq_raise(s->jazz_bus_irq); qemu_irq_raise(s->jazz_bus_irq);
else else
@ -479,7 +514,7 @@ static void rc4030_periodic_timer(void *opaque)
qemu_irq_raise(s->timer_irq); 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; rc4030State *s = opaque;
uint32_t val; uint32_t val;
@ -494,7 +529,6 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr)
irq = 0; irq = 0;
while (pending) { while (pending) {
if (pending & 1) { if (pending & 1) {
DPRINTF("returning irq %s\n", irq_names[irq]);
val = (irq + 1) << 2; val = (irq + 1) << 2;
break; break;
} }
@ -508,36 +542,25 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr)
val = s->imr_jazz; val = s->imr_jazz;
break; break;
default: 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; val = 0;
break;
} }
DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr); trace_jazzio_read(addr, val);
return val; return val;
} }
static uint32_t jazzio_readb(void *opaque, hwaddr addr) static void jazzio_write(void *opaque, hwaddr addr, uint64_t data,
{ unsigned int size)
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)
{ {
rc4030State *s = opaque; rc4030State *s = opaque;
uint32_t val = data;
addr &= 0xfff; addr &= 0xfff;
DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr); trace_jazzio_write(addr, val);
switch (addr) { switch (addr) {
/* Local bus int enable mask */ /* Local bus int enable mask */
@ -546,43 +569,24 @@ static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val)
update_jazz_irq(s); update_jazz_irq(s);
break; break;
default: 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; 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 = { static const MemoryRegionOps jazzio_ops = {
.old_mmio = { .read = jazzio_read,
.read = { jazzio_readb, jazzio_readw, jazzio_readl, }, .write = jazzio_write,
.write = { jazzio_writeb, jazzio_writew, jazzio_writel, }, .impl.min_access_size = 2,
}, .impl.max_access_size = 2,
.endianness = DEVICE_NATIVE_ENDIAN, .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; int i;
s->config = 0x410; /* some boards seem to accept 0x104 too */ 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; s->invalid_address_register = 0;
memset(s->dma_regs, 0, sizeof(s->dma_regs)); 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->remote_failed_address = s->memory_failed_address = 0;
s->cache_maint = 0; s->cache_maint = 0;
s->cache_ptag = s->cache_ltag = 0; s->cache_ptag = s->cache_ltag = 0;
s->cache_bmask = 0; s->cache_bmask = 0;
s->offset210 = 0x18186; s->memory_refresh_rate = 0x18186;
s->nvram_protect = 7; s->nvram_protect = 7;
for (i = 0; i < 15; i++) for (i = 0; i < 15; i++)
s->rem_speed[i] = 7; 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_ptag = qemu_get_be32(f);
s->cache_ltag = qemu_get_be32(f); s->cache_ltag = qemu_get_be32(f);
s->cache_bmask = 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); s->nvram_protect = qemu_get_be32(f);
for (i = 0; i < 15; i++) for (i = 0; i < 15; i++)
s->rem_speed[i] = qemu_get_be32(f); 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_ptag);
qemu_put_be32(f, s->cache_ltag); qemu_put_be32(f, s->cache_ltag);
qemu_put_be32(f, s->cache_bmask); 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); qemu_put_be32(f, s->nvram_protect);
for (i = 0; i < 15; i++) for (i = 0; i < 15; i++)
qemu_put_be32(f, s->rem_speed[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); 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) static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
{ {
rc4030State *s = opaque; 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]; dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
/* Read/write data at right place */ /* 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_ENABLE] |= DMA_FLAG_TC_INTR;
s->dma_regs[n][DMA_REG_COUNT] -= len; 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 { struct rc4030DMAState {
@ -795,31 +740,102 @@ static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
return s; return s;
} }
void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, static void rc4030_initfn(Object *obj)
qemu_irq **irqs, rc4030_dma **dmas,
MemoryRegion *sysmem)
{ {
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); sysbus_init_irq(sysbus, &s->timer_irq);
*dmas = rc4030_allocate_dmas(s, 4); 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); 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, memory_region_init_io(&s->iomem_chipset, NULL, &rc4030_ops, s,
"rc4030.chipset", 0x300); "rc4030.chipset", 0x300);
memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset);
memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s, memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s,
"rc4030.jazzio", 0x00001000); "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-y += addr.o cputimer.o mips_int.o
obj-$(CONFIG_JAZZ) += mips_jazz.o
obj-$(CONFIG_FULONG) += mips_fulong2e.o obj-$(CONFIG_FULONG) += mips_fulong2e.o
obj-y += gt64xxx_pci.o obj-y += gt64xxx_pci.o

View File

@ -135,16 +135,16 @@ static void mips_jazz_init(MachineState *machine,
MIPSCPU *cpu; MIPSCPU *cpu;
CPUClass *cc; CPUClass *cc;
CPUMIPSState *env; CPUMIPSState *env;
qemu_irq *rc4030, *i8259; qemu_irq *i8259;
rc4030_dma *dmas; rc4030_dma *dmas;
void* rc4030_opaque; MemoryRegion *rc4030_dma_mr;
MemoryRegion *isa_mem = g_new(MemoryRegion, 1); MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
MemoryRegion *isa_io = g_new(MemoryRegion, 1); MemoryRegion *isa_io = g_new(MemoryRegion, 1);
MemoryRegion *rtc = g_new(MemoryRegion, 1); MemoryRegion *rtc = g_new(MemoryRegion, 1);
MemoryRegion *i8042 = g_new(MemoryRegion, 1); MemoryRegion *i8042 = g_new(MemoryRegion, 1);
MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
NICInfo *nd; NICInfo *nd;
DeviceState *dev; DeviceState *dev, *rc4030;
SysBusDevice *sysbus; SysBusDevice *sysbus;
ISABus *isa_bus; ISABus *isa_bus;
ISADevice *pit; ISADevice *pit;
@ -157,12 +157,7 @@ static void mips_jazz_init(MachineState *machine,
/* init CPUs */ /* init CPUs */
if (cpu_model == NULL) { if (cpu_model == NULL) {
#ifdef TARGET_MIPS64
cpu_model = "R4000"; 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); cpu = cpu_mips_init(cpu_model);
if (cpu == NULL) { if (cpu == NULL) {
@ -218,8 +213,14 @@ static void mips_jazz_init(MachineState *machine,
cpu_mips_clock_init(env); cpu_mips_clock_init(env);
/* Chipset */ /* Chipset */
rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas, rc4030 = rc4030_init(&dmas, &rc4030_dma_mr);
address_space); 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_init_io(dma_dummy, NULL, &dma_dummy_ops, NULL, "dummy_dma", 0x1000);
memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); 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 = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sysbus, 0, 0x60080000); sysbus_mmio_map(sysbus, 0, 0x60080000);
sysbus_mmio_map(sysbus, 1, 0x40000000); 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 */ /* Simple ROM, so user doesn't have to provide one */
MemoryRegion *rom_mr = g_new(MemoryRegion, 1); MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
@ -272,8 +273,17 @@ static void mips_jazz_init(MachineState *machine,
if (!nd->model) if (!nd->model)
nd->model = g_strdup("dp83932"); nd->model = g_strdup("dp83932");
if (strcmp(nd->model, "dp83932") == 0) { if (strcmp(nd->model, "dp83932") == 0) {
dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4], qemu_check_nic_model(nd, "dp83932");
rc4030_opaque, rc4030_dma_memory_rw);
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; break;
} else if (is_help_option(nd->model)) { } else if (is_help_option(nd->model)) {
fprintf(stderr, "qemu: Supported NICs: dp83932\n"); fprintf(stderr, "qemu: Supported NICs: dp83932\n");
@ -287,7 +297,7 @@ static void mips_jazz_init(MachineState *machine,
/* SCSI adapter */ /* SCSI adapter */
esp_init(0x80002000, 0, esp_init(0x80002000, 0,
rc4030_dma_read, rc4030_dma_write, dmas[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 */ /* Floppy */
if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) { 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++) { for (n = 0; n < MAX_FD; n++) {
fds[n] = drive_get(IF_FLOPPY, 0, 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 */ /* Real time clock */
rtc_init(isa_bus, 1980, NULL); 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); memory_region_add_subregion(address_space, 0x80004000, rtc);
/* Keyboard (i8042) */ /* 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); memory_region_add_subregion(address_space, 0x80005000, i8042);
/* Serial ports */ /* Serial ports */
if (serial_hds[0]) { 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); serial_hds[0], DEVICE_NATIVE_ENDIAN);
} }
if (serial_hds[1]) { 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); serial_hds[1], DEVICE_NATIVE_ENDIAN);
} }
/* Parallel port */ /* Parallel port */
if (parallel_hds[0]) if (parallel_hds[0])
parallel_mm_init(address_space, 0x80008000, 0, rc4030[0], parallel_mm_init(address_space, 0x80008000, 0,
parallel_hds[0]); qdev_get_gpio_in(rc4030, 0), parallel_hds[0]);
/* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */

View File

@ -97,7 +97,7 @@ typedef struct {
static ISADevice *pit; static ISADevice *pit;
static struct _loaderparams { static struct _loaderparams {
int ram_size; int ram_size, ram_low_size;
const char *kernel_filename; const char *kernel_filename;
const char *kernel_cmdline; const char *kernel_cmdline;
const char *initrd_filename; 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++, 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++, 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++, 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++, 0x3c070000 | (loaderparams.ram_low_size >> 16)); /* lui a3, high(ram_low_size) */
stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */ stl_p(p++, 0x34e70000 | (loaderparams.ram_low_size & 0xffff)); /* ori a3, a3, low(ram_low_size) */
/* Load BAR registers as done by YAMON */ /* Load BAR registers as done by YAMON */
stl_p(p++, 0x3c09b400); /* lui t1, 0xb400 */ 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++, "memsize");
prom_set(prom_buf, prom_index++, "%i", prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_low_size);
MIN(loaderparams.ram_size, 256 << 20));
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++, "modetty0");
prom_set(prom_buf, prom_index++, "38400n8r"); 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. */ /* 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_filename = kernel_filename;
loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.kernel_cmdline = kernel_cmdline;
loaderparams.initrd_filename = initrd_filename; loaderparams.initrd_filename = initrd_filename;

View File

@ -17,20 +17,15 @@
* with this program; if not, see <http://www.gnu.org/licenses/>. * with this program; if not, see <http://www.gnu.org/licenses/>.
*/ */
#include "hw/hw.h" #include "hw/sysbus.h"
#include "qemu/timer.h" #include "hw/devices.h"
#include "net/net.h" #include "net/net.h"
#include "hw/mips/mips.h" #include "qemu/timer.h"
#include <zlib.h>
//#define DEBUG_SONIC //#define DEBUG_SONIC
/* Calculate CRCs properly on Rx packets */ #define SONIC_PROM_SIZE 0x1000
#define SONIC_CALCULATE_RXCRC
#if defined(SONIC_CALCULATE_RXCRC)
/* For crc32 */
#include <zlib.h>
#endif
#ifdef DEBUG_SONIC #ifdef DEBUG_SONIC
#define DPRINTF(fmt, ...) \ #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_PINT 0x0800
#define SONIC_ISR_LCD 0x1000 #define SONIC_ISR_LCD 0x1000
#define TYPE_DP8393X "dp8393x"
#define DP8393X(obj) OBJECT_CHECK(dp8393xState, (obj), TYPE_DP8393X)
typedef struct dp8393xState { typedef struct dp8393xState {
SysBusDevice parent_obj;
/* Hardware */ /* Hardware */
int it_shift; uint8_t it_shift;
qemu_irq irq; qemu_irq irq;
#ifdef DEBUG_SONIC #ifdef DEBUG_SONIC
int irq_level; int irq_level;
@ -156,8 +156,8 @@ typedef struct dp8393xState {
int64_t wt_last_update; int64_t wt_last_update;
NICConf conf; NICConf conf;
NICState *nic; NICState *nic;
MemoryRegion *address_space;
MemoryRegion mmio; MemoryRegion mmio;
MemoryRegion prom;
/* Registers */ /* Registers */
uint8_t cam[16][6]; uint8_t cam[16][6];
@ -168,8 +168,8 @@ typedef struct dp8393xState {
int loopback_packet; int loopback_packet;
/* Memory access */ /* Memory access */
void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); void *dma_mr;
void* mem_opaque; AddressSpace as;
} dp8393xState; } dp8393xState;
static void dp8393x_update_irq(dp8393xState *s) static void dp8393x_update_irq(dp8393xState *s)
@ -190,7 +190,7 @@ static void dp8393x_update_irq(dp8393xState *s)
qemu_set_irq(s->irq, level); 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]; uint16_t data[8];
int width, size; int width, size;
@ -201,9 +201,9 @@ static void do_load_cam(dp8393xState *s)
while (s->regs[SONIC_CDC] & 0x1f) { while (s->regs[SONIC_CDC] & 0x1f) {
/* Fill current entry */ /* Fill current entry */
s->memory_rw(s->mem_opaque, address_space_rw(&s->as,
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], (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][0] = data[1 * width] & 0xff;
s->cam[index][1] = data[1 * width] >> 8; s->cam[index][1] = data[1 * width] >> 8;
s->cam[index][2] = data[2 * width] & 0xff; s->cam[index][2] = data[2 * width] & 0xff;
@ -220,9 +220,9 @@ static void do_load_cam(dp8393xState *s)
} }
/* Read CAM enable */ /* Read CAM enable */
s->memory_rw(s->mem_opaque, address_space_rw(&s->as,
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], (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]; s->regs[SONIC_CE] = data[0 * width];
DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); 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); dp8393x_update_irq(s);
} }
static void do_read_rra(dp8393xState *s) static void dp8393x_do_read_rra(dp8393xState *s)
{ {
uint16_t data[8]; uint16_t data[8];
int width, size; int width, size;
@ -240,9 +240,9 @@ static void do_read_rra(dp8393xState *s)
/* Read memory */ /* Read memory */
width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
size = sizeof(uint16_t) * 4 * width; 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], (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
(uint8_t *)data, size, 0); MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
/* Update SONIC registers */ /* Update SONIC registers */
s->regs[SONIC_CRBA0] = data[0 * width]; 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; 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); 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; 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; uint32_t ticks;
int64_t delay; int64_t delay;
@ -296,7 +296,7 @@ static void set_next_tick(dp8393xState *s)
timer_mod(s->watchdog, s->wt_last_update + delay); 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; int64_t elapsed;
uint32_t val; uint32_t val;
@ -311,33 +311,33 @@ static void update_wt_regs(dp8393xState *s)
val -= elapsed / 5000000; val -= elapsed / 5000000;
s->regs[SONIC_WT1] = (val >> 16) & 0xffff; s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
s->regs[SONIC_WT0] = (val >> 0) & 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; 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; 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; 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; 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); NetClientState *nc = qemu_get_queue(s->nic);
uint16_t data[12]; uint16_t data[12];
@ -353,9 +353,9 @@ static void do_transmit_packets(dp8393xState *s)
(s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]); (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
size = sizeof(uint16_t) * 6 * width; size = sizeof(uint16_t) * 6 * width;
s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; 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, ((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; tx_len = 0;
/* Update registers */ /* Update registers */
@ -379,18 +379,18 @@ static void do_transmit_packets(dp8393xState *s)
if (tx_len + len > sizeof(s->tx_buffer)) { if (tx_len + len > sizeof(s->tx_buffer)) {
len = sizeof(s->tx_buffer) - tx_len; 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->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; tx_len += len;
i++; i++;
if (i != s->regs[SONIC_TFC]) { if (i != s->regs[SONIC_TFC]) {
/* Read next fragment details */ /* Read next fragment details */
size = sizeof(uint16_t) * 3 * width; 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, ((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_TSA0] = data[0 * width];
s->regs[SONIC_TSA1] = data[1 * width]; s->regs[SONIC_TSA1] = data[1 * width];
s->regs[SONIC_TFS] = data[2 * width]; s->regs[SONIC_TFS] = data[2 * width];
@ -422,16 +422,16 @@ static void do_transmit_packets(dp8393xState *s)
/* Write status */ /* Write status */
data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
size = sizeof(uint16_t) * width; 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], (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)) { if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
/* Read footer of packet */ /* Read footer of packet */
size = sizeof(uint16_t) * width; 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, ((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; s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
if (data[0 * width] & 0x1) { if (data[0 * width] & 0x1) {
/* EOL detected */ /* EOL detected */
@ -446,12 +446,12 @@ static void do_transmit_packets(dp8393xState *s)
dp8393x_update_irq(s); dp8393x_update_irq(s);
} }
static void do_halt_transmission(dp8393xState *s) static void dp8393x_do_halt_transmission(dp8393xState *s)
{ {
/* Nothing to do */ /* 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)) { if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
s->regs[SONIC_CR] &= ~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); s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
if (command & SONIC_CR_HTX) if (command & SONIC_CR_HTX)
do_halt_transmission(s); dp8393x_do_halt_transmission(s);
if (command & SONIC_CR_TXP) if (command & SONIC_CR_TXP)
do_transmit_packets(s); dp8393x_do_transmit_packets(s);
if (command & SONIC_CR_RXDIS) if (command & SONIC_CR_RXDIS)
do_receiver_disable(s); dp8393x_do_receiver_disable(s);
if (command & SONIC_CR_RXEN) if (command & SONIC_CR_RXEN)
do_receiver_enable(s); dp8393x_do_receiver_enable(s);
if (command & SONIC_CR_STP) if (command & SONIC_CR_STP)
do_stop_timer(s); dp8393x_do_stop_timer(s);
if (command & SONIC_CR_ST) if (command & SONIC_CR_ST)
do_start_timer(s); dp8393x_do_start_timer(s);
if (command & SONIC_CR_RST) if (command & SONIC_CR_RST)
do_software_reset(s); dp8393x_do_software_reset(s);
if (command & SONIC_CR_RRRA) if (command & SONIC_CR_RRRA)
do_read_rra(s); dp8393x_do_read_rra(s);
if (command & SONIC_CR_LCAM) 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; uint16_t val = 0;
switch (reg) { switch (reg) {
/* Update data before reading it */ /* Update data before reading it */
case SONIC_WT0: case SONIC_WT0:
case SONIC_WT1: case SONIC_WT1:
update_wt_regs(s); dp8393x_update_wt_regs(s);
val = s->regs[reg]; val = s->regs[reg];
break; break;
/* Accept read to some registers only when in reset mode */ /* 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; 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) { switch (reg) {
/* Command register */ /* Command register */
case SONIC_CR: case SONIC_CR:
do_command(s, val); dp8393x_do_command(s, data);
break; break;
/* Prevent write to read-only registers */ /* Prevent write to read-only registers */
case SONIC_CAP2: 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 */ /* Accept write to some registers only when in reset mode */
case SONIC_DCR: case SONIC_DCR:
if (s->regs[SONIC_CR] & SONIC_CR_RST) { if (s->regs[SONIC_CR] & SONIC_CR_RST) {
s->regs[reg] = val & 0xbfff; s->regs[reg] = data & 0xbfff;
} else { } else {
DPRINTF("writing to DCR invalid\n"); DPRINTF("writing to DCR invalid\n");
} }
break; break;
case SONIC_DCR2: case SONIC_DCR2:
if (s->regs[SONIC_CR] & SONIC_CR_RST) { if (s->regs[SONIC_CR] & SONIC_CR_RST) {
s->regs[reg] = val & 0xf017; s->regs[reg] = data & 0xf017;
} else { } else {
DPRINTF("writing to DCR2 invalid\n"); DPRINTF("writing to DCR2 invalid\n");
} }
break; break;
/* 12 lower bytes are Read Only */ /* 12 lower bytes are Read Only */
case SONIC_TCR: case SONIC_TCR:
s->regs[reg] = val & 0xf000; s->regs[reg] = data & 0xf000;
break; break;
/* 9 lower bytes are Read Only */ /* 9 lower bytes are Read Only */
case SONIC_RCR: case SONIC_RCR:
s->regs[reg] = val & 0xffe0; s->regs[reg] = data & 0xffe0;
break; break;
/* Ignore most significant bit */ /* Ignore most significant bit */
case SONIC_IMR: case SONIC_IMR:
s->regs[reg] = val & 0x7fff; s->regs[reg] = data & 0x7fff;
dp8393x_update_irq(s); dp8393x_update_irq(s);
break; break;
/* Clear bits by writing 1 to them */ /* Clear bits by writing 1 to them */
case SONIC_ISR: case SONIC_ISR:
val &= s->regs[reg]; data &= s->regs[reg];
s->regs[reg] &= ~val; s->regs[reg] &= ~data;
if (val & SONIC_ISR_RBE) { if (data & SONIC_ISR_RBE) {
do_read_rra(s); dp8393x_do_read_rra(s);
} }
dp8393x_update_irq(s); dp8393x_update_irq(s);
break; break;
@ -569,24 +575,32 @@ static void write_register(dp8393xState *s, int reg, uint16_t val)
case SONIC_REA: case SONIC_REA:
case SONIC_RRP: case SONIC_RRP:
case SONIC_RWP: case SONIC_RWP:
s->regs[reg] = val & 0xfffe; s->regs[reg] = data & 0xfffe;
break; break;
/* Invert written value for some registers */ /* Invert written value for some registers */
case SONIC_CRCT: case SONIC_CRCT:
case SONIC_FAET: case SONIC_FAET:
case SONIC_MPT: case SONIC_MPT:
s->regs[reg] = val ^ 0xffff; s->regs[reg] = data ^ 0xffff;
break; break;
/* All other registers have no special contrainst */ /* All other registers have no special contrainst */
default: default:
s->regs[reg] = val; s->regs[reg] = data;
} }
if (reg == SONIC_WT0 || reg == SONIC_WT1) { 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) static void dp8393x_watchdog(void *opaque)
{ {
dp8393xState *s = opaque; dp8393xState *s = opaque;
@ -597,84 +611,14 @@ static void dp8393x_watchdog(void *opaque)
s->regs[SONIC_WT1] = 0xffff; s->regs[SONIC_WT1] = 0xffff;
s->regs[SONIC_WT0] = 0xffff; s->regs[SONIC_WT0] = 0xffff;
set_next_tick(s); dp8393x_set_next_tick(s);
/* Signal underflow */ /* Signal underflow */
s->regs[SONIC_ISR] |= SONIC_ISR_TC; s->regs[SONIC_ISR] |= SONIC_ISR_TC;
dp8393x_update_irq(s); dp8393x_update_irq(s);
} }
static uint32_t dp8393x_readw(void *opaque, hwaddr addr) static int dp8393x_can_receive(NetClientState *nc)
{
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)
{ {
dp8393xState *s = qemu_get_nic_opaque(nc); dp8393xState *s = qemu_get_nic_opaque(nc);
@ -685,7 +629,8 @@ static int nic_can_receive(NetClientState *nc)
return 1; 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}; static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
int i; int i;
@ -723,7 +668,8 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
return -1; 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); dp8393xState *s = qemu_get_nic_opaque(nc);
uint16_t data[10]; 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 | 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); 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) { if (packet_type < 0) {
DPRINTF("packet not for netcard\n"); DPRINTF("packet not for netcard\n");
return -1; 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? */ /* Are we still in resource exhaustion? */
size = sizeof(uint16_t) * 1 * width; size = sizeof(uint16_t) * 1 * width;
address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * 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) { if (data[0 * width] & 0x1) {
/* Still EOL ; stop reception */ /* Still EOL ; stop reception */
return -1; 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]; s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
/* Calculate the ethernet checksum */ /* Calculate the ethernet checksum */
#ifdef SONIC_CALCULATE_RXCRC
checksum = cpu_to_le32(crc32(0, buf, rx_len)); checksum = cpu_to_le32(crc32(0, buf, rx_len));
#else
checksum = 0;
#endif
/* Put packet into RBA */ /* Put packet into RBA */
DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]); 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]; 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; 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; rx_len += 4;
s->regs[SONIC_CRBA1] = address >> 16; s->regs[SONIC_CRBA1] = address >> 16;
s->regs[SONIC_CRBA0] = address & 0xffff; 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[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
size = sizeof(uint16_t) * 5 * width; 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 */ /* Move to next descriptor */
size = sizeof(uint16_t) * width; 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, ((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]; s->regs[SONIC_LLFA] = data[0 * width];
if (s->regs[SONIC_LLFA] & 0x1) { if (s->regs[SONIC_LLFA] & 0x1) {
/* EOL detected */ /* EOL detected */
s->regs[SONIC_ISR] |= SONIC_ISR_RDE; s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
} else { } else {
data[0 * width] = 0; /* in_use */ 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, ((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_CRDA] = s->regs[SONIC_LLFA];
s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX; s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff); s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) { if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
/* Read next RRA */ /* 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; 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); 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_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR); 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); 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 = { static NetClientInfo net_dp83932_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC, .type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState), .size = sizeof(NICState),
.can_receive = nic_can_receive, .can_receive = dp8393x_can_receive,
.receive = nic_receive, .receive = dp8393x_receive,
}; };
void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, static void dp8393x_instance_init(Object *obj)
MemoryRegion *address_space,
qemu_irq irq, void* mem_opaque,
void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write))
{ {
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->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s);
s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
s->conf.macaddr = nd->macaddr; memory_region_init_rom_device(&s->prom, OBJECT(dev), NULL, NULL,
s->conf.peers.ncs[0] = nd->netdev; "dp8393x-prom", SONIC_PROM_SIZE, NULL);
prom = memory_region_get_ram_ptr(&s->prom);
s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s); checksum = 0;
for (i = 0; i < 6; i++) {
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); prom[i] = s->conf.macaddr.a[i];
qemu_register_reset(nic_reset, s); checksum += prom[i];
nic_reset(s); if (checksum > 0xff) {
checksum = (checksum + 1) & 0xff;
memory_region_init_io(&s->mmio, NULL, &dp8393x_ops, s, }
"dp8393x", 0x40 << it_shift); }
memory_region_add_subregion(address_space, base, &s->mmio); 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, hwaddr paddr, MemTxAttrs attrs,
int prot, int mmu_idx, target_ulong size); int prot, int mmu_idx, target_ulong size);
void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr); void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
uintptr_t retaddr);
#else #else
static inline void tlb_flush_page(CPUState *cpu, target_ulong addr) 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 */ /* rc4030.c */
typedef struct rc4030DMAState *rc4030_dma; 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_read(void *dma, uint8_t *buf, int len);
void rc4030_dma_write(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, DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr);
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));
#endif #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()); 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) */ #endif /* !defined(SOFTMMU_CODE_ACCESS) */
#undef READ_ACCESS_TYPE #undef READ_ACCESS_TYPE

View File

@ -34,7 +34,7 @@ struct r4k_tlb_t {
uint_fast16_t RI0:1; uint_fast16_t RI0:1;
uint_fast16_t RI1:1; uint_fast16_t RI1:1;
uint_fast16_t EHINV:1; uint_fast16_t EHINV:1;
target_ulong PFN[2]; uint64_t PFN[2];
}; };
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
@ -100,6 +100,7 @@ struct CPUMIPSFPUContext {
float_status fp_status; float_status fp_status;
/* fpu implementation/revision register (fir) */ /* fpu implementation/revision register (fir) */
uint32_t fcr0; uint32_t fcr0;
#define FCR0_FREP 29
#define FCR0_UFRP 28 #define FCR0_UFRP 28
#define FCR0_F64 22 #define FCR0_F64 22
#define FCR0_L 21 #define FCR0_L 21
@ -223,8 +224,14 @@ struct CPUMIPSState {
uint32_t SEGBITS; uint32_t SEGBITS;
uint32_t PABITS; uint32_t PABITS;
#if defined(TARGET_MIPS64)
# define PABITS_BASE 36
#else
# define PABITS_BASE 32
#endif
target_ulong SEGMask; target_ulong SEGMask;
target_ulong PAMask; uint64_t PAMask;
#define PAMASK_BASE ((1ULL << PABITS_BASE) - 1)
int32_t msair; int32_t msair;
#define MSAIR_ProcID 8 #define MSAIR_ProcID 8
@ -272,8 +279,8 @@ struct CPUMIPSState {
#define CP0VPEOpt_DWX2 2 #define CP0VPEOpt_DWX2 2
#define CP0VPEOpt_DWX1 1 #define CP0VPEOpt_DWX1 1
#define CP0VPEOpt_DWX0 0 #define CP0VPEOpt_DWX0 0
target_ulong CP0_EntryLo0; uint64_t CP0_EntryLo0;
target_ulong CP0_EntryLo1; uint64_t CP0_EntryLo1;
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
# define CP0EnLo_RI 63 # define CP0EnLo_RI 63
# define CP0EnLo_XI 62 # define CP0EnLo_XI 62
@ -288,6 +295,7 @@ struct CPUMIPSState {
int32_t CP0_PageGrain; int32_t CP0_PageGrain;
#define CP0PG_RIE 31 #define CP0PG_RIE 31
#define CP0PG_XIE 30 #define CP0PG_XIE 30
#define CP0PG_ELPA 29
#define CP0PG_IEC 27 #define CP0PG_IEC 27
int32_t CP0_Wired; int32_t CP0_Wired;
int32_t CP0_SRSConf0_rw_bitmask; int32_t CP0_SRSConf0_rw_bitmask;
@ -462,17 +470,21 @@ struct CPUMIPSState {
#define CP0C5_CV 29 #define CP0C5_CV 29
#define CP0C5_EVA 28 #define CP0C5_EVA 28
#define CP0C5_MSAEn 27 #define CP0C5_MSAEn 27
#define CP0C5_UFE 9
#define CP0C5_FRE 8
#define CP0C5_SBRI 6 #define CP0C5_SBRI 6
#define CP0C5_MVH 5
#define CP0C5_LLB 4
#define CP0C5_UFR 2 #define CP0C5_UFR 2
#define CP0C5_NFExists 0 #define CP0C5_NFExists 0
int32_t CP0_Config6; int32_t CP0_Config6;
int32_t CP0_Config7; int32_t CP0_Config7;
/* XXX: Maybe make LLAddr per-TC? */ /* XXX: Maybe make LLAddr per-TC? */
target_ulong lladdr; uint64_t lladdr;
target_ulong llval; target_ulong llval;
target_ulong llnewval; target_ulong llnewval;
target_ulong llreg; target_ulong llreg;
target_ulong CP0_LLAddr_rw_bitmask; uint64_t CP0_LLAddr_rw_bitmask;
int CP0_LLAddr_shift; int CP0_LLAddr_shift;
target_ulong CP0_WatchLo[8]; target_ulong CP0_WatchLo[8];
int32_t CP0_WatchHi[8]; int32_t CP0_WatchHi[8];
@ -499,7 +511,7 @@ struct CPUMIPSState {
#define CP0DB_DSS 0 #define CP0DB_DSS 0
target_ulong CP0_DEPC; target_ulong CP0_DEPC;
int32_t CP0_Performance0; int32_t CP0_Performance0;
int32_t CP0_TagLo; uint64_t CP0_TagLo;
int32_t CP0_DataLo; int32_t CP0_DataLo;
int32_t CP0_TagHi; int32_t CP0_TagHi;
int32_t CP0_DataHi; int32_t CP0_DataHi;
@ -514,7 +526,7 @@ struct CPUMIPSState {
#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */ #define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */
uint32_t hflags; /* CPU State */ uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */ /* TMASK defines different execution modes */
#define MIPS_HFLAG_TMASK 0x15807FF #define MIPS_HFLAG_TMASK 0x75807FF
#define MIPS_HFLAG_MODE 0x00007 /* execution modes */ #define MIPS_HFLAG_MODE 0x00007 /* execution modes */
/* The KSU flags must be the lowest bits in hflags. The flag order /* 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 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_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */
#define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */ #define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */
#define MIPS_HFLAG_MSA 0x1000000 #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 btarget; /* Jump / branch target */
target_ulong bcond; /* Branch condition (if needed) */ 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); 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, static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
target_ulong *cs_base, int *flags) 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 | env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 | 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)) && if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
!(env->CP0_Status & (1 << CP0St_ERL)) && !(env->CP0_Status & (1 << CP0St_ERL)) &&
!(env->hflags & MIPS_HFLAG_DM)) { !(env->hflags & MIPS_HFLAG_DM)) {
@ -924,6 +948,16 @@ static inline void compute_hflags(CPUMIPSState *env)
env->hflags |= MIPS_HFLAG_MSA; 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 #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(di, tl, env)
DEF_HELPER_1(ei, tl, env) DEF_HELPER_1(ei, tl, env)
DEF_HELPER_1(eret, void, env) DEF_HELPER_1(eret, void, env)
DEF_HELPER_1(eretnc, void, env)
DEF_HELPER_1(deret, void, env) DEF_HELPER_1(deret, void, env)
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
DEF_HELPER_1(rdhwr_cpunum, tl, env) 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_s_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ffint_u_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) #define MSALDST_PROTO(type) \
DEF_HELPER_5(msa_st_df, void, env, i32, i32, i32, s32) 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_fp_status(env);
restore_msa_fp_status(env); restore_msa_fp_status(env);
compute_hflags(env); compute_hflags(env);
restore_pamask(env);
return 0; return 0;
} }
@ -142,8 +143,8 @@ static int get_tlb(QEMUFile *f, void *pv, size_t size)
v->RI0 = (flags >> 13) & 1; v->RI0 = (flags >> 13) & 1;
v->XI1 = (flags >> 12) & 1; v->XI1 = (flags >> 12) & 1;
v->XI0 = (flags >> 11) & 1; v->XI0 = (flags >> 11) & 1;
qemu_get_betls(f, &v->PFN[0]); qemu_get_be64s(f, &v->PFN[0]);
qemu_get_betls(f, &v->PFN[1]); qemu_get_be64s(f, &v->PFN[1]);
return 0; 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_be32s(f, &v->PageMask);
qemu_put_8s(f, &v->ASID); qemu_put_8s(f, &v->ASID);
qemu_put_be16s(f, &flags); qemu_put_be16s(f, &flags);
qemu_put_betls(f, &v->PFN[0]); qemu_put_be64s(f, &v->PFN[0]);
qemu_put_betls(f, &v->PFN[1]); qemu_put_be64s(f, &v->PFN[1]);
} }
const VMStateInfo vmstate_info_tlb = { const VMStateInfo vmstate_info_tlb = {
@ -201,8 +202,8 @@ const VMStateDescription vmstate_tlb = {
const VMStateDescription vmstate_mips_cpu = { const VMStateDescription vmstate_mips_cpu = {
.name = "cpu", .name = "cpu",
.version_id = 6, .version_id = 7,
.minimum_version_id = 6, .minimum_version_id = 7,
.post_load = cpu_post_load, .post_load = cpu_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
/* Active TC */ /* Active TC */
@ -237,8 +238,8 @@ const VMStateDescription vmstate_mips_cpu = {
VMSTATE_UINTTL(env.CP0_VPESchedule, MIPSCPU), VMSTATE_UINTTL(env.CP0_VPESchedule, MIPSCPU),
VMSTATE_UINTTL(env.CP0_VPEScheFBack, MIPSCPU), VMSTATE_UINTTL(env.CP0_VPEScheFBack, MIPSCPU),
VMSTATE_INT32(env.CP0_VPEOpt, MIPSCPU), VMSTATE_INT32(env.CP0_VPEOpt, MIPSCPU),
VMSTATE_UINTTL(env.CP0_EntryLo0, MIPSCPU), VMSTATE_UINT64(env.CP0_EntryLo0, MIPSCPU),
VMSTATE_UINTTL(env.CP0_EntryLo1, MIPSCPU), VMSTATE_UINT64(env.CP0_EntryLo1, MIPSCPU),
VMSTATE_UINTTL(env.CP0_Context, MIPSCPU), VMSTATE_UINTTL(env.CP0_Context, MIPSCPU),
VMSTATE_INT32(env.CP0_PageMask, MIPSCPU), VMSTATE_INT32(env.CP0_PageMask, MIPSCPU),
VMSTATE_INT32(env.CP0_PageGrain, 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_Config3, MIPSCPU),
VMSTATE_INT32(env.CP0_Config6, MIPSCPU), VMSTATE_INT32(env.CP0_Config6, MIPSCPU),
VMSTATE_INT32(env.CP0_Config7, 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_UINTTL_ARRAY(env.CP0_WatchLo, MIPSCPU, 8),
VMSTATE_INT32_ARRAY(env.CP0_WatchHi, MIPSCPU, 8), VMSTATE_INT32_ARRAY(env.CP0_WatchHi, MIPSCPU, 8),
VMSTATE_UINTTL(env.CP0_XContext, MIPSCPU), VMSTATE_UINTTL(env.CP0_XContext, MIPSCPU),
@ -277,7 +278,7 @@ const VMStateDescription vmstate_mips_cpu = {
VMSTATE_INT32(env.CP0_Debug, MIPSCPU), VMSTATE_INT32(env.CP0_Debug, MIPSCPU),
VMSTATE_UINTTL(env.CP0_DEPC, MIPSCPU), VMSTATE_UINTTL(env.CP0_DEPC, MIPSCPU),
VMSTATE_INT32(env.CP0_Performance0, 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_DataLo, MIPSCPU),
VMSTATE_INT32(env.CP0_TagHi, MIPSCPU), VMSTATE_INT32(env.CP0_TagHi, MIPSCPU),
VMSTATE_INT32(env.CP0_DataHi, MIPSCPU), VMSTATE_INT32(env.CP0_DataHi, MIPSCPU),

View File

@ -10,11 +10,11 @@
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
#define TARGET_LONG_BITS 64 #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 #define TARGET_VIRT_ADDR_SPACE_BITS 42
#else #else
#define TARGET_LONG_BITS 32 #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 #define TARGET_VIRT_ADDR_SPACE_BITS 32
#endif #endif

View File

@ -90,10 +90,10 @@ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
} \ } \
} }
#endif #endif
HELPER_LD(lbu, ldub, uint8_t)
HELPER_LD(lhu, lduw, uint16_t)
HELPER_LD(lw, ldl, int32_t) HELPER_LD(lw, ldl, int32_t)
#if defined(TARGET_MIPS64)
HELPER_LD(ld, ldq, int64_t) HELPER_LD(ld, ldq, int64_t)
#endif
#undef HELPER_LD #undef HELPER_LD
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
@ -118,9 +118,10 @@ static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
} }
#endif #endif
HELPER_ST(sb, stb, uint8_t) HELPER_ST(sb, stb, uint8_t)
HELPER_ST(sh, stw, uint16_t)
HELPER_ST(sw, stl, uint32_t) HELPER_ST(sw, stl, uint32_t)
#if defined(TARGET_MIPS64)
HELPER_ST(sd, stq, uint64_t) HELPER_ST(sd, stq, uint64_t)
#endif
#undef HELPER_ST #undef HELPER_ST
target_ulong helper_clo (target_ulong arg1) 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; env->CP0_VPEOpt = arg1 & 0x0000ffff;
} }
#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
{ {
/* Large physaddr (PABITS) not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); 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) #if defined(TARGET_MIPS64)
#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1) void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
{ {
uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); 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 #endif
@ -1245,17 +1250,17 @@ void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
{ {
/* Large physaddr (PABITS) not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE)); 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) #if defined(TARGET_MIPS64)
void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1) void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
{ {
uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32); 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 #endif
@ -1278,10 +1283,11 @@ void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
{ {
/* SmartMIPS not implemented */ /* SmartMIPS not implemented */
/* Large physaddr (PABITS) not implemented */
/* 1k pages not implemented */ /* 1k pages not implemented */
env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) | env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
(env->CP0_PageGrain & ~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) 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) static void r4k_fill_tlb(CPUMIPSState *env, int idx)
{ {
r4k_tlb_t *tlb; 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->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1; tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 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->V1 = (env->CP0_EntryLo1 & 2) != 0;
tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1; tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 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) 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) void r4k_helper_tlbr(CPUMIPSState *env)
{ {
r4k_tlb_t *tlb; r4k_tlb_t *tlb;
@ -1996,13 +2022,13 @@ void r4k_helper_tlbr(CPUMIPSState *env)
env->CP0_EntryHi = tlb->VPN | tlb->ASID; env->CP0_EntryHi = tlb->VPN | tlb->ASID;
env->CP0_PageMask = tlb->PageMask; env->CP0_PageMask = tlb->PageMask;
env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
((target_ulong)tlb->RI0 << CP0EnLo_RI) | ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
((target_ulong)tlb->XI0 << CP0EnLo_XI) | ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
(tlb->C0 << 3) | (tlb->PFN[0] >> 6); get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
((target_ulong)tlb->RI1 << CP0EnLo_RI) | ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
((target_ulong)tlb->XI1 << CP0EnLo_XI) | ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
(tlb->C1 << 3) | (tlb->PFN[1] >> 6); 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); debug_pre_eret(env);
if (env->CP0_Status & (1 << CP0St_ERL)) { if (env->CP0_Status & (1 << CP0St_ERL)) {
@ -2110,9 +2136,19 @@ void helper_eret(CPUMIPSState *env)
} }
compute_hflags(env); compute_hflags(env);
debug_post_eret(env); debug_post_eret(env);
}
void helper_eret(CPUMIPSState *env)
{
exception_return(env);
env->lladdr = 1; env->lladdr = 1;
} }
void helper_eretnc(CPUMIPSState *env)
{
exception_return(env);
}
void helper_deret(CPUMIPSState *env) void helper_deret(CPUMIPSState *env)
{ {
debug_pre_eret(env); debug_pre_eret(env);
@ -2303,6 +2339,16 @@ target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
} }
} }
break; 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: case 25:
arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1); arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
break; 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); helper_raise_exception(env, EXCP_RI);
} }
break; 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: case 25:
if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) { if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
return; return;
@ -3558,72 +3628,82 @@ FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
/* Element-by-element access macros */ /* Element-by-element access macros */
#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df)) #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, #if !defined(CONFIG_USER_ONLY)
int32_t s10) #define MEMOP_IDX(DF) \
{ TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \
wr_t *pwd = &(env->active_fpu.fpr[wd].wr); cpu_mmu_index(env));
target_ulong addr = env->active_tc.gpr[rs] + (s10 << df); #else
int i; #define MEMOP_IDX(DF)
#endif
switch (df) { #define MSA_LD_DF(DF, TYPE, LD_INSN, ...) \
case DF_BYTE: void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { target_ulong addr) \
pwd->b[i] = do_lbu(env, addr + (i << DF_BYTE), { \
env->hflags & MIPS_HFLAG_KSU); wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
} wr_t wx; \
break; int i; \
case DF_HALF: MEMOP_IDX(DF) \
for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { for (i = 0; i < DF_ELEMENTS(DF); i++) { \
pwd->h[i] = do_lhu(env, addr + (i << DF_HALF), wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__); \
env->hflags & MIPS_HFLAG_KSU); } \
} memcpy(pwd, &wx, sizeof(wr_t)); \
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;
}
} }
void helper_msa_st_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs, #if !defined(CONFIG_USER_ONLY)
int32_t s10) MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETRA())
{ MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETRA())
wr_t *pwd = &(env->active_fpu.fpr[wd].wr); MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETRA())
target_ulong addr = env->active_tc.gpr[rs] + (s10 << df); MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETRA())
int i; #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) { #define MSA_PAGESPAN(x) \
case DF_BYTE: ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) {
do_sb(env, addr + (i << DF_BYTE), pwd->b[i], static inline void ensure_writable_pages(CPUMIPSState *env,
env->hflags & MIPS_HFLAG_KSU); target_ulong addr,
} int mmu_idx,
break; uintptr_t retaddr)
case DF_HALF: {
for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { #if !defined(CONFIG_USER_ONLY)
do_sh(env, addr + (i << DF_HALF), pwd->h[i], target_ulong page_addr;
env->hflags & MIPS_HFLAG_KSU); if (unlikely(MSA_PAGESPAN(addr))) {
} /* first page */
break; probe_write(env, addr, mmu_idx, retaddr);
case DF_WORD: /* second page */
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
do_sw(env, addr + (i << DF_WORD), pwd->w[i], probe_write(env, page_addr, mmu_idx, retaddr);
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;
} }
#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) | (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA), (1 << CP0C1_CA),
.CP0_Config2 = MIPS_CONFIG2, .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 = MIPS_CONFIG4 | (1U << CP0C4_M),
.CP0_Config4_rw_bitmask = 0, .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) | .CP0_Config5_rw_bitmask = (0 << CP0C5_M) | (1 << CP0C5_K) |
(1 << CP0C5_CV) | (0 << CP0C5_EVA) | (1 << CP0C5_CV) | (0 << CP0C5_EVA) |
(1 << CP0C5_MSAEn) | (1 << CP0C5_UFR) | (1 << CP0C5_MSAEn) | (1 << CP0C5_UFR) |
@ -413,11 +415,12 @@ static const mips_def_t mips_defs[] =
.SYNCI_Step = 32, .SYNCI_Step = 32,
.CCRes = 2, .CCRes = 2,
.CP0_Status_rw_bitmask = 0x3778FF1F, .CP0_Status_rw_bitmask = 0x3778FF1F,
.CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
.CP1_fcr0 = (1 << FCR0_UFRP) | (1 << FCR0_F64) | (1 << FCR0_L) | .CP1_fcr0 = (1 << FCR0_UFRP) | (1 << FCR0_F64) | (1 << FCR0_L) |
(1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
(0x93 << FCR0_PRID), (0x93 << FCR0_PRID),
.SEGBITS = 32, .SEGBITS = 32,
.PABITS = 32, .PABITS = 40,
.insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_MSA, .insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_MSA,
.mmu_type = MMU_TYPE_R4000, .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_L) | (1 << FCR0_W) | (1 << FCR0_D) |
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
.SEGBITS = 42, .SEGBITS = 42,
/* The architectural limit is 59, but we have hardcoded 36 bit
in some places...
.PABITS = 59, */ /* the architectural limit */
.PABITS = 36, .PABITS = 36,
.insn_flags = CPU_MIPS64R2 | ASE_MIPS3D, .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D,
.mmu_type = MMU_TYPE_R4000, .mmu_type = MMU_TYPE_R4000,
@ -607,7 +607,7 @@ static const mips_def_t mips_defs[] =
}, },
{ {
/* A generic CPU supporting MIPS64 Release 6 ISA. /* 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. */ Eventually this should be replaced by a real CPU model. */
.name = "MIPS64R6-generic", .name = "MIPS64R6-generic",
.CP0_PRid = 0x00010000, .CP0_PRid = 0x00010000,
@ -619,10 +619,13 @@ static const mips_def_t mips_defs[] =
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), (0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
.CP0_Config2 = MIPS_CONFIG2, .CP0_Config2 = MIPS_CONFIG2,
.CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_RXI) | (1 << CP0C3_BP) | .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) | .CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) |
(3 << CP0C4_IE) | (1 << CP0C4_M), (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_rw_bitmask = 0,
.CP0_LLAddr_shift = 0, .CP0_LLAddr_shift = 0,
.SYNCI_Step = 32, .SYNCI_Step = 32,
@ -630,15 +633,12 @@ static const mips_def_t mips_defs[] =
.CP0_Status_rw_bitmask = 0x30D8FFFF, .CP0_Status_rw_bitmask = 0x30D8FFFF,
.CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) | .CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) |
(1U << CP0PG_RIE), (1U << CP0PG_RIE),
.CP0_PageGrain_rw_bitmask = 0, .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_F64) | (1 << FCR0_L) |
(1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) | (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
(0x0 << FCR0_REV), (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
.SEGBITS = 42, .SEGBITS = 42,
/* The architectural limit is 59, but we have hardcoded 36 bit .PABITS = 48,
in some places...
.PABITS = 59, */ /* the architectural limit */
.PABITS = 36,
.insn_flags = CPU_MIPS64R6, .insn_flags = CPU_MIPS64R6,
.mmu_type = MMU_TYPE_R4000, .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_L) | (1 << FCR0_W) | (1 << FCR0_D) |
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV), (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
.SEGBITS = 42, .SEGBITS = 42,
/* The architectural limit is 59, but we have hardcoded 36 bit
in some places...
.PABITS = 59, */ /* the architectural limit */
.PABITS = 36, .PABITS = 36,
.insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSPR2, .insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSPR2,
.mmu_type = MMU_TYPE_R4000, .mmu_type = MMU_TYPE_R4000,

View File

@ -31,8 +31,6 @@ struct TestCase {
static const TestCase test_cases[] = { static const TestCase test_cases[] = {
{ "i386", "pc", -1 }, { "i386", "pc", -1 },
{ "mips", "magnum", 0x90000000, .bswap = true },
{ "mips", "pica61", 0x90000000, .bswap = true },
{ "mips", "mips", 0x14000000, .bswap = true }, { "mips", "mips", 0x14000000, .bswap = true },
{ "mips", "malta", 0x10000000, .bswap = true }, { "mips", "malta", 0x10000000, .bswap = true },
{ "mips64", "magnum", 0x90000000, .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_mode_invalid(void) "not system timer"
slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64 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 # hw/dma/sparc32_dma.c
ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64 ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64
ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64 ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64