mirror of https://gitee.com/openkylin/qemu.git
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:
commit
4cb618abc1
|
@ -24,14 +24,9 @@ CONFIG_PIIX4=y
|
|||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
CONFIG_MIPSNET=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
|
|
|
@ -29,6 +29,7 @@ CONFIG_DP8393X=y
|
|||
CONFIG_DS1225Y=y
|
||||
CONFIG_MIPSNET=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_JAZZ=y
|
||||
CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
|
|
|
@ -31,6 +31,7 @@ CONFIG_DS1225Y=y
|
|||
CONFIG_MIPSNET=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_FULONG=y
|
||||
CONFIG_JAZZ=y
|
||||
CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
|
|
|
@ -24,14 +24,9 @@ CONFIG_PIIX4=y
|
|||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
CONFIG_MIPSNET=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
|
|
|
@ -2238,6 +2238,8 @@ const struct mips_opcode mips_builtin_opcodes[] =
|
|||
{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 },
|
||||
{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 },
|
||||
{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 },
|
||||
{"mfhc0", "t,G,H", 0x40400000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I33},
|
||||
{"mthc0", "t,G,H", 0x40c00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I33},
|
||||
{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 },
|
||||
{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 },
|
||||
{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 },
|
||||
|
@ -2407,6 +2409,7 @@ const struct mips_opcode mips_builtin_opcodes[] =
|
|||
{"emt", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 },
|
||||
{"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 },
|
||||
{"eret", "", 0x42000018, 0xffffffff, 0, 0, I3|I32 },
|
||||
{"eretnc", "", 0x42000058, 0xffffffff, 0, 0, I33},
|
||||
{"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 },
|
||||
{"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 },
|
||||
{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 },
|
||||
|
|
468
hw/dma/rc4030.c
468
hw/dma/rc4030.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* QEMU JAZZ RC4030 chipset
|
||||
*
|
||||
* Copyright (c) 2007-2009 Herve Poussineau
|
||||
* Copyright (c) 2007-2013 Hervé Poussineau
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -24,29 +24,16 @@
|
|||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/mips/mips.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
/********************************************************/
|
||||
/* debug rc4030 */
|
||||
|
||||
//#define DEBUG_RC4030
|
||||
//#define DEBUG_RC4030_DMA
|
||||
|
||||
#ifdef DEBUG_RC4030
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { printf("rc4030: " fmt , ## __VA_ARGS__); } while (0)
|
||||
static const char* irq_names[] = { "parallel", "floppy", "sound", "video",
|
||||
"network", "scsi", "keyboard", "mouse", "serial0", "serial1" };
|
||||
#else
|
||||
#define DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define RC4030_ERROR(fmt, ...) \
|
||||
do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
|
||||
#include "exec/address-spaces.h"
|
||||
#include "trace.h"
|
||||
|
||||
/********************************************************/
|
||||
/* rc4030 emulation */
|
||||
|
||||
#define MAX_TL_ENTRIES 512
|
||||
|
||||
typedef struct dma_pagetable_entry {
|
||||
int32_t frame;
|
||||
int32_t owner;
|
||||
|
@ -63,8 +50,14 @@ typedef struct dma_pagetable_entry {
|
|||
#define DMA_FLAG_MEM_INTR 0x0200
|
||||
#define DMA_FLAG_ADDR_INTR 0x0400
|
||||
|
||||
#define TYPE_RC4030 "rc4030"
|
||||
#define RC4030(obj) \
|
||||
OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030)
|
||||
|
||||
typedef struct rc4030State
|
||||
{
|
||||
SysBusDevice parent;
|
||||
|
||||
uint32_t config; /* 0x0000: RC4030 config register */
|
||||
uint32_t revision; /* 0x0008: RC4030 Revision register */
|
||||
uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
|
||||
|
@ -83,7 +76,7 @@ typedef struct rc4030State
|
|||
uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
|
||||
|
||||
uint32_t nmi_interrupt; /* 0x0200: interrupt source */
|
||||
uint32_t offset210;
|
||||
uint32_t memory_refresh_rate; /* 0x0210: memory refresh rate */
|
||||
uint32_t nvram_protect; /* 0x0220: NV ram protect register */
|
||||
uint32_t rem_speed[16];
|
||||
uint32_t imr_jazz; /* Local bus int enable mask */
|
||||
|
@ -96,6 +89,16 @@ typedef struct rc4030State
|
|||
qemu_irq timer_irq;
|
||||
qemu_irq jazz_bus_irq;
|
||||
|
||||
/* biggest translation table */
|
||||
MemoryRegion dma_tt;
|
||||
/* translation table memory region alias, added to system RAM */
|
||||
MemoryRegion dma_tt_alias;
|
||||
/* whole DMA memory region, root of DMA address space */
|
||||
MemoryRegion dma_mr;
|
||||
/* translation table entry aliases, added to DMA memory region */
|
||||
MemoryRegion dma_mrs[MAX_TL_ENTRIES];
|
||||
AddressSpace dma_as;
|
||||
|
||||
MemoryRegion iomem_chipset;
|
||||
MemoryRegion iomem_jazzio;
|
||||
} rc4030State;
|
||||
|
@ -112,7 +115,7 @@ static void set_next_tick(rc4030State *s)
|
|||
}
|
||||
|
||||
/* called for accesses to rc4030 */
|
||||
static uint32_t rc4030_readl(void *opaque, hwaddr addr)
|
||||
static uint64_t rc4030_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
rc4030State *s = opaque;
|
||||
uint32_t val;
|
||||
|
@ -220,9 +223,9 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr)
|
|||
case 0x0208:
|
||||
val = 0;
|
||||
break;
|
||||
/* Offset 0x0210 */
|
||||
/* Memory refresh rate */
|
||||
case 0x0210:
|
||||
val = s->offset210;
|
||||
val = s->memory_refresh_rate;
|
||||
break;
|
||||
/* NV ram protect register */
|
||||
case 0x0220:
|
||||
|
@ -238,39 +241,117 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr)
|
|||
val = 7; /* FIXME: should be read from EISA controller */
|
||||
break;
|
||||
default:
|
||||
RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"rc4030: invalid read at 0x%x", (int)addr);
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((addr & ~3) != 0x230) {
|
||||
DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr);
|
||||
trace_rc4030_read(addr, val);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t rc4030_readw(void *opaque, hwaddr addr)
|
||||
static void rc4030_dma_as_update_one(rc4030State *s, int index, uint32_t frame)
|
||||
{
|
||||
uint32_t v = rc4030_readl(opaque, addr & ~0x3);
|
||||
if (addr & 0x2)
|
||||
return v >> 16;
|
||||
else
|
||||
return v & 0xffff;
|
||||
if (index < MAX_TL_ENTRIES) {
|
||||
memory_region_set_enabled(&s->dma_mrs[index], false);
|
||||
}
|
||||
|
||||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index >= MAX_TL_ENTRIES) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"rc4030: trying to use too high "
|
||||
"translation table entry %d (max allowed=%d)",
|
||||
index, MAX_TL_ENTRIES);
|
||||
return;
|
||||
}
|
||||
memory_region_set_alias_offset(&s->dma_mrs[index], frame);
|
||||
memory_region_set_enabled(&s->dma_mrs[index], true);
|
||||
}
|
||||
|
||||
static uint32_t rc4030_readb(void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t v = rc4030_readl(opaque, addr & ~0x3);
|
||||
return (v >> (8 * (addr & 0x3))) & 0xff;
|
||||
}
|
||||
|
||||
static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
|
||||
static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
rc4030State *s = opaque;
|
||||
|
||||
/* write memory */
|
||||
memcpy(memory_region_get_ram_ptr(&s->dma_tt) + addr, &data, size);
|
||||
|
||||
/* update dma address space (only if frame field has been written) */
|
||||
if (addr % sizeof(dma_pagetable_entry) == 0) {
|
||||
int index = addr / sizeof(dma_pagetable_entry);
|
||||
memory_region_transaction_begin();
|
||||
rc4030_dma_as_update_one(s, index, (uint32_t)data);
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps rc4030_dma_tt_ops = {
|
||||
.write = rc4030_dma_tt_write,
|
||||
.impl.min_access_size = 4,
|
||||
.impl.max_access_size = 4,
|
||||
};
|
||||
|
||||
static void rc4030_dma_tt_update(rc4030State *s, uint32_t new_tl_base,
|
||||
uint32_t new_tl_limit)
|
||||
{
|
||||
int entries, i;
|
||||
dma_pagetable_entry *dma_tl_contents;
|
||||
|
||||
if (s->dma_tl_limit) {
|
||||
/* write old dma tl table to physical memory */
|
||||
memory_region_del_subregion(get_system_memory(), &s->dma_tt_alias);
|
||||
cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff,
|
||||
memory_region_get_ram_ptr(&s->dma_tt),
|
||||
memory_region_size(&s->dma_tt_alias));
|
||||
}
|
||||
object_unparent(OBJECT(&s->dma_tt_alias));
|
||||
|
||||
s->dma_tl_base = new_tl_base;
|
||||
s->dma_tl_limit = new_tl_limit;
|
||||
new_tl_base &= 0x7fffffff;
|
||||
|
||||
if (s->dma_tl_limit) {
|
||||
uint64_t dma_tt_size;
|
||||
if (s->dma_tl_limit <= memory_region_size(&s->dma_tt)) {
|
||||
dma_tt_size = s->dma_tl_limit;
|
||||
} else {
|
||||
dma_tt_size = memory_region_size(&s->dma_tt);
|
||||
}
|
||||
memory_region_init_alias(&s->dma_tt_alias, OBJECT(s),
|
||||
"dma-table-alias",
|
||||
&s->dma_tt, 0, dma_tt_size);
|
||||
dma_tl_contents = memory_region_get_ram_ptr(&s->dma_tt);
|
||||
cpu_physical_memory_read(new_tl_base, dma_tl_contents, dma_tt_size);
|
||||
|
||||
memory_region_transaction_begin();
|
||||
entries = dma_tt_size / sizeof(dma_pagetable_entry);
|
||||
for (i = 0; i < entries; i++) {
|
||||
rc4030_dma_as_update_one(s, i, dma_tl_contents[i].frame);
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), new_tl_base,
|
||||
&s->dma_tt_alias);
|
||||
memory_region_transaction_commit();
|
||||
} else {
|
||||
memory_region_init(&s->dma_tt_alias, OBJECT(s),
|
||||
"dma-table-alias", 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void rc4030_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
rc4030State *s = opaque;
|
||||
uint32_t val = data;
|
||||
addr &= 0x3fff;
|
||||
|
||||
DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr);
|
||||
trace_rc4030_write(addr, val);
|
||||
|
||||
switch (addr & ~0x3) {
|
||||
/* Global config register */
|
||||
|
@ -279,11 +360,11 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
|
|||
break;
|
||||
/* DMA transl. table base */
|
||||
case 0x0018:
|
||||
s->dma_tl_base = val;
|
||||
rc4030_dma_tt_update(s, val, s->dma_tl_limit);
|
||||
break;
|
||||
/* DMA transl. table limit */
|
||||
case 0x0020:
|
||||
s->dma_tl_limit = val;
|
||||
rc4030_dma_tt_update(s, s->dma_tl_base, val);
|
||||
break;
|
||||
/* DMA transl. table invalidated */
|
||||
case 0x0028:
|
||||
|
@ -371,9 +452,9 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
|
|||
s->dma_regs[entry][idx] = val;
|
||||
}
|
||||
break;
|
||||
/* Offset 0x0210 */
|
||||
/* Memory refresh rate */
|
||||
case 0x0210:
|
||||
s->offset210 = val;
|
||||
s->memory_refresh_rate = val;
|
||||
break;
|
||||
/* Interval timer reload */
|
||||
case 0x0228:
|
||||
|
@ -385,48 +466,18 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
|
|||
case 0x0238:
|
||||
break;
|
||||
default:
|
||||
RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"rc4030: invalid write of 0x%02x at 0x%x",
|
||||
val, (int)addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rc4030_writew(void *opaque, hwaddr addr, uint32_t val)
|
||||
{
|
||||
uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
|
||||
|
||||
if (addr & 0x2)
|
||||
val = (val << 16) | (old_val & 0x0000ffff);
|
||||
else
|
||||
val = val | (old_val & 0xffff0000);
|
||||
rc4030_writel(opaque, addr & ~0x3, val);
|
||||
}
|
||||
|
||||
static void rc4030_writeb(void *opaque, hwaddr addr, uint32_t val)
|
||||
{
|
||||
uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
|
||||
|
||||
switch (addr & 3) {
|
||||
case 0:
|
||||
val = val | (old_val & 0xffffff00);
|
||||
break;
|
||||
case 1:
|
||||
val = (val << 8) | (old_val & 0xffff00ff);
|
||||
break;
|
||||
case 2:
|
||||
val = (val << 16) | (old_val & 0xff00ffff);
|
||||
break;
|
||||
case 3:
|
||||
val = (val << 24) | (old_val & 0x00ffffff);
|
||||
break;
|
||||
}
|
||||
rc4030_writel(opaque, addr & ~0x3, val);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps rc4030_ops = {
|
||||
.old_mmio = {
|
||||
.read = { rc4030_readb, rc4030_readw, rc4030_readl, },
|
||||
.write = { rc4030_writeb, rc4030_writew, rc4030_writel, },
|
||||
},
|
||||
.read = rc4030_read,
|
||||
.write = rc4030_write,
|
||||
.impl.min_access_size = 4,
|
||||
.impl.max_access_size = 4,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
@ -436,22 +487,6 @@ static void update_jazz_irq(rc4030State *s)
|
|||
|
||||
pending = s->isr_jazz & s->imr_jazz;
|
||||
|
||||
#ifdef DEBUG_RC4030
|
||||
if (s->isr_jazz != 0) {
|
||||
uint32_t irq = 0;
|
||||
DPRINTF("pending irqs:");
|
||||
for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) {
|
||||
if (s->isr_jazz & (1 << irq)) {
|
||||
printf(" %s", irq_names[irq]);
|
||||
if (!(s->imr_jazz & (1 << irq))) {
|
||||
printf("(ignored)");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pending != 0)
|
||||
qemu_irq_raise(s->jazz_bus_irq);
|
||||
else
|
||||
|
@ -479,7 +514,7 @@ static void rc4030_periodic_timer(void *opaque)
|
|||
qemu_irq_raise(s->timer_irq);
|
||||
}
|
||||
|
||||
static uint32_t jazzio_readw(void *opaque, hwaddr addr)
|
||||
static uint64_t jazzio_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
rc4030State *s = opaque;
|
||||
uint32_t val;
|
||||
|
@ -494,7 +529,6 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr)
|
|||
irq = 0;
|
||||
while (pending) {
|
||||
if (pending & 1) {
|
||||
DPRINTF("returning irq %s\n", irq_names[irq]);
|
||||
val = (irq + 1) << 2;
|
||||
break;
|
||||
}
|
||||
|
@ -508,36 +542,25 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr)
|
|||
val = s->imr_jazz;
|
||||
break;
|
||||
default:
|
||||
RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx "]\n", addr);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"rc4030/jazzio: invalid read at 0x%x", (int)addr);
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr);
|
||||
trace_jazzio_read(addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t jazzio_readb(void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t v;
|
||||
v = jazzio_readw(opaque, addr & ~0x1);
|
||||
return (v >> (8 * (addr & 0x1))) & 0xff;
|
||||
}
|
||||
|
||||
static uint32_t jazzio_readl(void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t v;
|
||||
v = jazzio_readw(opaque, addr);
|
||||
v |= jazzio_readw(opaque, addr + 2) << 16;
|
||||
return v;
|
||||
}
|
||||
|
||||
static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val)
|
||||
static void jazzio_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
rc4030State *s = opaque;
|
||||
uint32_t val = data;
|
||||
addr &= 0xfff;
|
||||
|
||||
DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr);
|
||||
trace_jazzio_write(addr, val);
|
||||
|
||||
switch (addr) {
|
||||
/* Local bus int enable mask */
|
||||
|
@ -546,43 +569,24 @@ static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val)
|
|||
update_jazz_irq(s);
|
||||
break;
|
||||
default:
|
||||
RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx "]\n", val, addr);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"rc4030/jazzio: invalid write of 0x%02x at 0x%x",
|
||||
val, (int)addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void jazzio_writeb(void *opaque, hwaddr addr, uint32_t val)
|
||||
{
|
||||
uint32_t old_val = jazzio_readw(opaque, addr & ~0x1);
|
||||
|
||||
switch (addr & 1) {
|
||||
case 0:
|
||||
val = val | (old_val & 0xff00);
|
||||
break;
|
||||
case 1:
|
||||
val = (val << 8) | (old_val & 0x00ff);
|
||||
break;
|
||||
}
|
||||
jazzio_writew(opaque, addr & ~0x1, val);
|
||||
}
|
||||
|
||||
static void jazzio_writel(void *opaque, hwaddr addr, uint32_t val)
|
||||
{
|
||||
jazzio_writew(opaque, addr, val & 0xffff);
|
||||
jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps jazzio_ops = {
|
||||
.old_mmio = {
|
||||
.read = { jazzio_readb, jazzio_readw, jazzio_readl, },
|
||||
.write = { jazzio_writeb, jazzio_writew, jazzio_writel, },
|
||||
},
|
||||
.read = jazzio_read,
|
||||
.write = jazzio_write,
|
||||
.impl.min_access_size = 2,
|
||||
.impl.max_access_size = 2,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void rc4030_reset(void *opaque)
|
||||
static void rc4030_reset(DeviceState *dev)
|
||||
{
|
||||
rc4030State *s = opaque;
|
||||
rc4030State *s = RC4030(dev);
|
||||
int i;
|
||||
|
||||
s->config = 0x410; /* some boards seem to accept 0x104 too */
|
||||
|
@ -590,14 +594,14 @@ static void rc4030_reset(void *opaque)
|
|||
s->invalid_address_register = 0;
|
||||
|
||||
memset(s->dma_regs, 0, sizeof(s->dma_regs));
|
||||
s->dma_tl_base = s->dma_tl_limit = 0;
|
||||
rc4030_dma_tt_update(s, 0, 0);
|
||||
|
||||
s->remote_failed_address = s->memory_failed_address = 0;
|
||||
s->cache_maint = 0;
|
||||
s->cache_ptag = s->cache_ltag = 0;
|
||||
s->cache_bmask = 0;
|
||||
|
||||
s->offset210 = 0x18186;
|
||||
s->memory_refresh_rate = 0x18186;
|
||||
s->nvram_protect = 7;
|
||||
for (i = 0; i < 15; i++)
|
||||
s->rem_speed[i] = 7;
|
||||
|
@ -631,7 +635,7 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
|
|||
s->cache_ptag = qemu_get_be32(f);
|
||||
s->cache_ltag = qemu_get_be32(f);
|
||||
s->cache_bmask = qemu_get_be32(f);
|
||||
s->offset210 = qemu_get_be32(f);
|
||||
s->memory_refresh_rate = qemu_get_be32(f);
|
||||
s->nvram_protect = qemu_get_be32(f);
|
||||
for (i = 0; i < 15; i++)
|
||||
s->rem_speed[i] = qemu_get_be32(f);
|
||||
|
@ -663,7 +667,7 @@ static void rc4030_save(QEMUFile *f, void *opaque)
|
|||
qemu_put_be32(f, s->cache_ptag);
|
||||
qemu_put_be32(f, s->cache_ltag);
|
||||
qemu_put_be32(f, s->cache_bmask);
|
||||
qemu_put_be32(f, s->offset210);
|
||||
qemu_put_be32(f, s->memory_refresh_rate);
|
||||
qemu_put_be32(f, s->nvram_protect);
|
||||
for (i = 0; i < 15; i++)
|
||||
qemu_put_be32(f, s->rem_speed[i]);
|
||||
|
@ -672,44 +676,6 @@ static void rc4030_save(QEMUFile *f, void *opaque)
|
|||
qemu_put_be32(f, s->itr);
|
||||
}
|
||||
|
||||
void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)
|
||||
{
|
||||
rc4030State *s = opaque;
|
||||
hwaddr entry_addr;
|
||||
hwaddr phys_addr;
|
||||
dma_pagetable_entry entry;
|
||||
int index;
|
||||
int ncpy, i;
|
||||
|
||||
i = 0;
|
||||
for (;;) {
|
||||
if (i == len) {
|
||||
break;
|
||||
}
|
||||
|
||||
ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1));
|
||||
if (ncpy > len - i)
|
||||
ncpy = len - i;
|
||||
|
||||
/* Get DMA translation table entry */
|
||||
index = addr / DMA_PAGESIZE;
|
||||
if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) {
|
||||
break;
|
||||
}
|
||||
entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
|
||||
/* XXX: not sure. should we really use only lowest bits? */
|
||||
entry_addr &= 0x7fffffff;
|
||||
cpu_physical_memory_read(entry_addr, &entry, sizeof(entry));
|
||||
|
||||
/* Read/write data at right place */
|
||||
phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1));
|
||||
cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write);
|
||||
|
||||
i += ncpy;
|
||||
addr += ncpy;
|
||||
}
|
||||
}
|
||||
|
||||
static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
|
||||
{
|
||||
rc4030State *s = opaque;
|
||||
|
@ -733,32 +699,11 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri
|
|||
dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
|
||||
|
||||
/* Read/write data at right place */
|
||||
rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write);
|
||||
address_space_rw(&s->dma_as, dma_addr, MEMTXATTRS_UNSPECIFIED,
|
||||
buf, len, is_write);
|
||||
|
||||
s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
|
||||
s->dma_regs[n][DMA_REG_COUNT] -= len;
|
||||
|
||||
#ifdef DEBUG_RC4030_DMA
|
||||
{
|
||||
int i, j;
|
||||
printf("rc4030 dma: Copying %d bytes %s host %p\n",
|
||||
len, is_write ? "from" : "to", buf);
|
||||
for (i = 0; i < len; i += 16) {
|
||||
int n = 16;
|
||||
if (n > len - i) {
|
||||
n = len - i;
|
||||
}
|
||||
for (j = 0; j < n; j++)
|
||||
printf("%02x ", buf[i + j]);
|
||||
while (j++ < 16)
|
||||
printf(" ");
|
||||
printf("| ");
|
||||
for (j = 0; j < n; j++)
|
||||
printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct rc4030DMAState {
|
||||
|
@ -795,31 +740,102 @@ static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
|
|||
return s;
|
||||
}
|
||||
|
||||
void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
|
||||
qemu_irq **irqs, rc4030_dma **dmas,
|
||||
MemoryRegion *sysmem)
|
||||
static void rc4030_initfn(Object *obj)
|
||||
{
|
||||
rc4030State *s;
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
rc4030State *s = RC4030(obj);
|
||||
SysBusDevice *sysbus = SYS_BUS_DEVICE(obj);
|
||||
|
||||
s = g_malloc0(sizeof(rc4030State));
|
||||
qdev_init_gpio_in(dev, rc4030_irq_jazz_request, 16);
|
||||
|
||||
*irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
|
||||
*dmas = rc4030_allocate_dmas(s, 4);
|
||||
sysbus_init_irq(sysbus, &s->timer_irq);
|
||||
sysbus_init_irq(sysbus, &s->jazz_bus_irq);
|
||||
|
||||
s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rc4030_periodic_timer, s);
|
||||
s->timer_irq = timer;
|
||||
s->jazz_bus_irq = jazz_bus;
|
||||
|
||||
qemu_register_reset(rc4030_reset, s);
|
||||
register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
|
||||
rc4030_reset(s);
|
||||
|
||||
sysbus_init_mmio(sysbus, &s->iomem_chipset);
|
||||
sysbus_init_mmio(sysbus, &s->iomem_jazzio);
|
||||
}
|
||||
|
||||
static void rc4030_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
rc4030State *s = RC4030(dev);
|
||||
Object *o = OBJECT(dev);
|
||||
int i;
|
||||
|
||||
s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
rc4030_periodic_timer, s);
|
||||
|
||||
memory_region_init_io(&s->iomem_chipset, NULL, &rc4030_ops, s,
|
||||
"rc4030.chipset", 0x300);
|
||||
memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset);
|
||||
memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s,
|
||||
"rc4030.jazzio", 0x00001000);
|
||||
memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio);
|
||||
|
||||
return s;
|
||||
memory_region_init_rom_device(&s->dma_tt, o,
|
||||
&rc4030_dma_tt_ops, s, "dma-table",
|
||||
MAX_TL_ENTRIES * sizeof(dma_pagetable_entry),
|
||||
NULL);
|
||||
memory_region_init(&s->dma_tt_alias, o, "dma-table-alias", 0);
|
||||
memory_region_init(&s->dma_mr, o, "dma", INT32_MAX);
|
||||
for (i = 0; i < MAX_TL_ENTRIES; ++i) {
|
||||
memory_region_init_alias(&s->dma_mrs[i], o, "dma-alias",
|
||||
get_system_memory(), 0, DMA_PAGESIZE);
|
||||
memory_region_set_enabled(&s->dma_mrs[i], false);
|
||||
memory_region_add_subregion(&s->dma_mr, i * DMA_PAGESIZE,
|
||||
&s->dma_mrs[i]);
|
||||
}
|
||||
address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma");
|
||||
}
|
||||
|
||||
static void rc4030_unrealize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
rc4030State *s = RC4030(dev);
|
||||
int i;
|
||||
|
||||
timer_free(s->periodic_timer);
|
||||
|
||||
address_space_destroy(&s->dma_as);
|
||||
object_unparent(OBJECT(&s->dma_tt));
|
||||
object_unparent(OBJECT(&s->dma_tt_alias));
|
||||
object_unparent(OBJECT(&s->dma_mr));
|
||||
for (i = 0; i < MAX_TL_ENTRIES; ++i) {
|
||||
memory_region_del_subregion(&s->dma_mr, &s->dma_mrs[i]);
|
||||
object_unparent(OBJECT(&s->dma_mrs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
static void rc4030_class_init(ObjectClass *klass, void *class_data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = rc4030_realize;
|
||||
dc->unrealize = rc4030_unrealize;
|
||||
dc->reset = rc4030_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo rc4030_info = {
|
||||
.name = TYPE_RC4030,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(rc4030State),
|
||||
.instance_init = rc4030_initfn,
|
||||
.class_init = rc4030_class_init,
|
||||
};
|
||||
|
||||
static void rc4030_register_types(void)
|
||||
{
|
||||
type_register_static(&rc4030_info);
|
||||
}
|
||||
|
||||
type_init(rc4030_register_types)
|
||||
|
||||
DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_RC4030);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
*dmas = rc4030_allocate_dmas(dev, 4);
|
||||
*dma_mr = &RC4030(dev)->dma_mr;
|
||||
return dev;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
|
||||
obj-y += mips_r4k.o mips_malta.o mips_mipssim.o
|
||||
obj-y += addr.o cputimer.o mips_int.o
|
||||
obj-$(CONFIG_JAZZ) += mips_jazz.o
|
||||
obj-$(CONFIG_FULONG) += mips_fulong2e.o
|
||||
obj-y += gt64xxx_pci.o
|
||||
|
|
|
@ -135,16 +135,16 @@ static void mips_jazz_init(MachineState *machine,
|
|||
MIPSCPU *cpu;
|
||||
CPUClass *cc;
|
||||
CPUMIPSState *env;
|
||||
qemu_irq *rc4030, *i8259;
|
||||
qemu_irq *i8259;
|
||||
rc4030_dma *dmas;
|
||||
void* rc4030_opaque;
|
||||
MemoryRegion *rc4030_dma_mr;
|
||||
MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *isa_io = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *rtc = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *i8042 = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
|
||||
NICInfo *nd;
|
||||
DeviceState *dev;
|
||||
DeviceState *dev, *rc4030;
|
||||
SysBusDevice *sysbus;
|
||||
ISABus *isa_bus;
|
||||
ISADevice *pit;
|
||||
|
@ -157,12 +157,7 @@ static void mips_jazz_init(MachineState *machine,
|
|||
|
||||
/* init CPUs */
|
||||
if (cpu_model == NULL) {
|
||||
#ifdef TARGET_MIPS64
|
||||
cpu_model = "R4000";
|
||||
#else
|
||||
/* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */
|
||||
cpu_model = "24Kf";
|
||||
#endif
|
||||
}
|
||||
cpu = cpu_mips_init(cpu_model);
|
||||
if (cpu == NULL) {
|
||||
|
@ -218,8 +213,14 @@ static void mips_jazz_init(MachineState *machine,
|
|||
cpu_mips_clock_init(env);
|
||||
|
||||
/* Chipset */
|
||||
rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas,
|
||||
address_space);
|
||||
rc4030 = rc4030_init(&dmas, &rc4030_dma_mr);
|
||||
sysbus = SYS_BUS_DEVICE(rc4030);
|
||||
sysbus_connect_irq(sysbus, 0, env->irq[6]);
|
||||
sysbus_connect_irq(sysbus, 1, env->irq[3]);
|
||||
memory_region_add_subregion(address_space, 0x80000000,
|
||||
sysbus_mmio_get_region(sysbus, 0));
|
||||
memory_region_add_subregion(address_space, 0xf0000000,
|
||||
sysbus_mmio_get_region(sysbus, 1));
|
||||
memory_region_init_io(dma_dummy, NULL, &dma_dummy_ops, NULL, "dummy_dma", 0x1000);
|
||||
memory_region_add_subregion(address_space, 0x8000d000, dma_dummy);
|
||||
|
||||
|
@ -246,7 +247,7 @@ static void mips_jazz_init(MachineState *machine,
|
|||
sysbus = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(sysbus, 0, 0x60080000);
|
||||
sysbus_mmio_map(sysbus, 1, 0x40000000);
|
||||
sysbus_connect_irq(sysbus, 0, rc4030[3]);
|
||||
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 3));
|
||||
{
|
||||
/* Simple ROM, so user doesn't have to provide one */
|
||||
MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
|
||||
|
@ -272,8 +273,17 @@ static void mips_jazz_init(MachineState *machine,
|
|||
if (!nd->model)
|
||||
nd->model = g_strdup("dp83932");
|
||||
if (strcmp(nd->model, "dp83932") == 0) {
|
||||
dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4],
|
||||
rc4030_opaque, rc4030_dma_memory_rw);
|
||||
qemu_check_nic_model(nd, "dp83932");
|
||||
|
||||
dev = qdev_create(NULL, "dp8393x");
|
||||
qdev_set_nic_properties(dev, nd);
|
||||
qdev_prop_set_uint8(dev, "it_shift", 2);
|
||||
qdev_prop_set_ptr(dev, "dma_mr", rc4030_dma_mr);
|
||||
qdev_init_nofail(dev);
|
||||
sysbus = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(sysbus, 0, 0x80001000);
|
||||
sysbus_mmio_map(sysbus, 1, 0x8000b000);
|
||||
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4));
|
||||
break;
|
||||
} else if (is_help_option(nd->model)) {
|
||||
fprintf(stderr, "qemu: Supported NICs: dp83932\n");
|
||||
|
@ -287,7 +297,7 @@ static void mips_jazz_init(MachineState *machine,
|
|||
/* SCSI adapter */
|
||||
esp_init(0x80002000, 0,
|
||||
rc4030_dma_read, rc4030_dma_write, dmas[0],
|
||||
rc4030[5], &esp_reset, &dma_enable);
|
||||
qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable);
|
||||
|
||||
/* Floppy */
|
||||
if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
|
||||
|
@ -297,7 +307,7 @@ static void mips_jazz_init(MachineState *machine,
|
|||
for (n = 0; n < MAX_FD; n++) {
|
||||
fds[n] = drive_get(IF_FLOPPY, 0, n);
|
||||
}
|
||||
fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
|
||||
fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), 0, 0x80003000, fds);
|
||||
|
||||
/* Real time clock */
|
||||
rtc_init(isa_bus, 1980, NULL);
|
||||
|
@ -305,23 +315,26 @@ static void mips_jazz_init(MachineState *machine,
|
|||
memory_region_add_subregion(address_space, 0x80004000, rtc);
|
||||
|
||||
/* Keyboard (i8042) */
|
||||
i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1);
|
||||
i8042_mm_init(qdev_get_gpio_in(rc4030, 6), qdev_get_gpio_in(rc4030, 7),
|
||||
i8042, 0x1000, 0x1);
|
||||
memory_region_add_subregion(address_space, 0x80005000, i8042);
|
||||
|
||||
/* Serial ports */
|
||||
if (serial_hds[0]) {
|
||||
serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16,
|
||||
serial_mm_init(address_space, 0x80006000, 0,
|
||||
qdev_get_gpio_in(rc4030, 8), 8000000/16,
|
||||
serial_hds[0], DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
if (serial_hds[1]) {
|
||||
serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16,
|
||||
serial_mm_init(address_space, 0x80007000, 0,
|
||||
qdev_get_gpio_in(rc4030, 9), 8000000/16,
|
||||
serial_hds[1], DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
/* Parallel port */
|
||||
if (parallel_hds[0])
|
||||
parallel_mm_init(address_space, 0x80008000, 0, rc4030[0],
|
||||
parallel_hds[0]);
|
||||
parallel_mm_init(address_space, 0x80008000, 0,
|
||||
qdev_get_gpio_in(rc4030, 0), parallel_hds[0]);
|
||||
|
||||
/* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ typedef struct {
|
|||
static ISADevice *pit;
|
||||
|
||||
static struct _loaderparams {
|
||||
int ram_size;
|
||||
int ram_size, ram_low_size;
|
||||
const char *kernel_filename;
|
||||
const char *kernel_cmdline;
|
||||
const char *initrd_filename;
|
||||
|
@ -641,8 +641,8 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
|
|||
stl_p(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */
|
||||
stl_p(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
|
||||
stl_p(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
|
||||
stl_p(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */
|
||||
stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */
|
||||
stl_p(p++, 0x3c070000 | (loaderparams.ram_low_size >> 16)); /* lui a3, high(ram_low_size) */
|
||||
stl_p(p++, 0x34e70000 | (loaderparams.ram_low_size & 0xffff)); /* ori a3, a3, low(ram_low_size) */
|
||||
|
||||
/* Load BAR registers as done by YAMON */
|
||||
stl_p(p++, 0x3c09b400); /* lui t1, 0xb400 */
|
||||
|
@ -851,8 +851,10 @@ static int64_t load_kernel (void)
|
|||
}
|
||||
|
||||
prom_set(prom_buf, prom_index++, "memsize");
|
||||
prom_set(prom_buf, prom_index++, "%i",
|
||||
MIN(loaderparams.ram_size, 256 << 20));
|
||||
prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_low_size);
|
||||
|
||||
prom_set(prom_buf, prom_index++, "ememsize");
|
||||
prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_size);
|
||||
|
||||
prom_set(prom_buf, prom_index++, "modetty0");
|
||||
prom_set(prom_buf, prom_index++, "38400n8r");
|
||||
|
@ -1054,7 +1056,8 @@ void mips_malta_init(MachineState *machine)
|
|||
}
|
||||
|
||||
/* Write a small bootloader to the flash location. */
|
||||
loaderparams.ram_size = ram_low_size;
|
||||
loaderparams.ram_size = ram_size;
|
||||
loaderparams.ram_low_size = ram_low_size;
|
||||
loaderparams.kernel_filename = kernel_filename;
|
||||
loaderparams.kernel_cmdline = kernel_cmdline;
|
||||
loaderparams.initrd_filename = initrd_filename;
|
||||
|
|
375
hw/net/dp8393x.c
375
hw/net/dp8393x.c
|
@ -17,20 +17,15 @@
|
|||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/devices.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/mips/mips.h"
|
||||
#include "qemu/timer.h"
|
||||
#include <zlib.h>
|
||||
|
||||
//#define DEBUG_SONIC
|
||||
|
||||
/* Calculate CRCs properly on Rx packets */
|
||||
#define SONIC_CALCULATE_RXCRC
|
||||
|
||||
#if defined(SONIC_CALCULATE_RXCRC)
|
||||
/* For crc32 */
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
#define SONIC_PROM_SIZE 0x1000
|
||||
|
||||
#ifdef DEBUG_SONIC
|
||||
#define DPRINTF(fmt, ...) \
|
||||
|
@ -145,9 +140,14 @@ do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
|
|||
#define SONIC_ISR_PINT 0x0800
|
||||
#define SONIC_ISR_LCD 0x1000
|
||||
|
||||
#define TYPE_DP8393X "dp8393x"
|
||||
#define DP8393X(obj) OBJECT_CHECK(dp8393xState, (obj), TYPE_DP8393X)
|
||||
|
||||
typedef struct dp8393xState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/* Hardware */
|
||||
int it_shift;
|
||||
uint8_t it_shift;
|
||||
qemu_irq irq;
|
||||
#ifdef DEBUG_SONIC
|
||||
int irq_level;
|
||||
|
@ -156,8 +156,8 @@ typedef struct dp8393xState {
|
|||
int64_t wt_last_update;
|
||||
NICConf conf;
|
||||
NICState *nic;
|
||||
MemoryRegion *address_space;
|
||||
MemoryRegion mmio;
|
||||
MemoryRegion prom;
|
||||
|
||||
/* Registers */
|
||||
uint8_t cam[16][6];
|
||||
|
@ -168,8 +168,8 @@ typedef struct dp8393xState {
|
|||
int loopback_packet;
|
||||
|
||||
/* Memory access */
|
||||
void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write);
|
||||
void* mem_opaque;
|
||||
void *dma_mr;
|
||||
AddressSpace as;
|
||||
} dp8393xState;
|
||||
|
||||
static void dp8393x_update_irq(dp8393xState *s)
|
||||
|
@ -190,7 +190,7 @@ static void dp8393x_update_irq(dp8393xState *s)
|
|||
qemu_set_irq(s->irq, level);
|
||||
}
|
||||
|
||||
static void do_load_cam(dp8393xState *s)
|
||||
static void dp8393x_do_load_cam(dp8393xState *s)
|
||||
{
|
||||
uint16_t data[8];
|
||||
int width, size;
|
||||
|
@ -201,9 +201,9 @@ static void do_load_cam(dp8393xState *s)
|
|||
|
||||
while (s->regs[SONIC_CDC] & 0x1f) {
|
||||
/* Fill current entry */
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
|
||||
(uint8_t *)data, size, 0);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->cam[index][0] = data[1 * width] & 0xff;
|
||||
s->cam[index][1] = data[1 * width] >> 8;
|
||||
s->cam[index][2] = data[2 * width] & 0xff;
|
||||
|
@ -220,9 +220,9 @@ static void do_load_cam(dp8393xState *s)
|
|||
}
|
||||
|
||||
/* Read CAM enable */
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
|
||||
(uint8_t *)data, size, 0);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->regs[SONIC_CE] = data[0 * width];
|
||||
DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
|
||||
|
||||
|
@ -232,7 +232,7 @@ static void do_load_cam(dp8393xState *s)
|
|||
dp8393x_update_irq(s);
|
||||
}
|
||||
|
||||
static void do_read_rra(dp8393xState *s)
|
||||
static void dp8393x_do_read_rra(dp8393xState *s)
|
||||
{
|
||||
uint16_t data[8];
|
||||
int width, size;
|
||||
|
@ -240,9 +240,9 @@ static void do_read_rra(dp8393xState *s)
|
|||
/* Read memory */
|
||||
width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
|
||||
size = sizeof(uint16_t) * 4 * width;
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
|
||||
(uint8_t *)data, size, 0);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
|
||||
/* Update SONIC registers */
|
||||
s->regs[SONIC_CRBA0] = data[0 * width];
|
||||
|
@ -272,7 +272,7 @@ static void do_read_rra(dp8393xState *s)
|
|||
s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
|
||||
}
|
||||
|
||||
static void do_software_reset(dp8393xState *s)
|
||||
static void dp8393x_do_software_reset(dp8393xState *s)
|
||||
{
|
||||
timer_del(s->watchdog);
|
||||
|
||||
|
@ -280,7 +280,7 @@ static void do_software_reset(dp8393xState *s)
|
|||
s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
|
||||
}
|
||||
|
||||
static void set_next_tick(dp8393xState *s)
|
||||
static void dp8393x_set_next_tick(dp8393xState *s)
|
||||
{
|
||||
uint32_t ticks;
|
||||
int64_t delay;
|
||||
|
@ -296,7 +296,7 @@ static void set_next_tick(dp8393xState *s)
|
|||
timer_mod(s->watchdog, s->wt_last_update + delay);
|
||||
}
|
||||
|
||||
static void update_wt_regs(dp8393xState *s)
|
||||
static void dp8393x_update_wt_regs(dp8393xState *s)
|
||||
{
|
||||
int64_t elapsed;
|
||||
uint32_t val;
|
||||
|
@ -311,33 +311,33 @@ static void update_wt_regs(dp8393xState *s)
|
|||
val -= elapsed / 5000000;
|
||||
s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
|
||||
s->regs[SONIC_WT0] = (val >> 0) & 0xffff;
|
||||
set_next_tick(s);
|
||||
dp8393x_set_next_tick(s);
|
||||
|
||||
}
|
||||
|
||||
static void do_start_timer(dp8393xState *s)
|
||||
static void dp8393x_do_start_timer(dp8393xState *s)
|
||||
{
|
||||
s->regs[SONIC_CR] &= ~SONIC_CR_STP;
|
||||
set_next_tick(s);
|
||||
dp8393x_set_next_tick(s);
|
||||
}
|
||||
|
||||
static void do_stop_timer(dp8393xState *s)
|
||||
static void dp8393x_do_stop_timer(dp8393xState *s)
|
||||
{
|
||||
s->regs[SONIC_CR] &= ~SONIC_CR_ST;
|
||||
update_wt_regs(s);
|
||||
dp8393x_update_wt_regs(s);
|
||||
}
|
||||
|
||||
static void do_receiver_enable(dp8393xState *s)
|
||||
static void dp8393x_do_receiver_enable(dp8393xState *s)
|
||||
{
|
||||
s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
|
||||
}
|
||||
|
||||
static void do_receiver_disable(dp8393xState *s)
|
||||
static void dp8393x_do_receiver_disable(dp8393xState *s)
|
||||
{
|
||||
s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
|
||||
}
|
||||
|
||||
static void do_transmit_packets(dp8393xState *s)
|
||||
static void dp8393x_do_transmit_packets(dp8393xState *s)
|
||||
{
|
||||
NetClientState *nc = qemu_get_queue(s->nic);
|
||||
uint16_t data[12];
|
||||
|
@ -353,9 +353,9 @@ static void do_transmit_packets(dp8393xState *s)
|
|||
(s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
|
||||
size = sizeof(uint16_t) * 6 * width;
|
||||
s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
|
||||
(uint8_t *)data, size, 0);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
tx_len = 0;
|
||||
|
||||
/* Update registers */
|
||||
|
@ -379,18 +379,18 @@ static void do_transmit_packets(dp8393xState *s)
|
|||
if (tx_len + len > sizeof(s->tx_buffer)) {
|
||||
len = sizeof(s->tx_buffer) - tx_len;
|
||||
}
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
(s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
|
||||
&s->tx_buffer[tx_len], len, 0);
|
||||
MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0);
|
||||
tx_len += len;
|
||||
|
||||
i++;
|
||||
if (i != s->regs[SONIC_TFC]) {
|
||||
/* Read next fragment details */
|
||||
size = sizeof(uint16_t) * 3 * width;
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
|
||||
(uint8_t *)data, size, 0);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->regs[SONIC_TSA0] = data[0 * width];
|
||||
s->regs[SONIC_TSA1] = data[1 * width];
|
||||
s->regs[SONIC_TFS] = data[2 * width];
|
||||
|
@ -422,16 +422,16 @@ static void do_transmit_packets(dp8393xState *s)
|
|||
/* Write status */
|
||||
data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
|
||||
size = sizeof(uint16_t) * width;
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
(s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
|
||||
(uint8_t *)data, size, 1);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
|
||||
|
||||
if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
|
||||
/* Read footer of packet */
|
||||
size = sizeof(uint16_t) * width;
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
|
||||
(uint8_t *)data, size, 0);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
|
||||
if (data[0 * width] & 0x1) {
|
||||
/* EOL detected */
|
||||
|
@ -446,12 +446,12 @@ static void do_transmit_packets(dp8393xState *s)
|
|||
dp8393x_update_irq(s);
|
||||
}
|
||||
|
||||
static void do_halt_transmission(dp8393xState *s)
|
||||
static void dp8393x_do_halt_transmission(dp8393xState *s)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
static void do_command(dp8393xState *s, uint16_t command)
|
||||
static void dp8393x_do_command(dp8393xState *s, uint16_t command)
|
||||
{
|
||||
if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
|
||||
s->regs[SONIC_CR] &= ~SONIC_CR_RST;
|
||||
|
@ -461,34 +461,36 @@ static void do_command(dp8393xState *s, uint16_t command)
|
|||
s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
|
||||
|
||||
if (command & SONIC_CR_HTX)
|
||||
do_halt_transmission(s);
|
||||
dp8393x_do_halt_transmission(s);
|
||||
if (command & SONIC_CR_TXP)
|
||||
do_transmit_packets(s);
|
||||
dp8393x_do_transmit_packets(s);
|
||||
if (command & SONIC_CR_RXDIS)
|
||||
do_receiver_disable(s);
|
||||
dp8393x_do_receiver_disable(s);
|
||||
if (command & SONIC_CR_RXEN)
|
||||
do_receiver_enable(s);
|
||||
dp8393x_do_receiver_enable(s);
|
||||
if (command & SONIC_CR_STP)
|
||||
do_stop_timer(s);
|
||||
dp8393x_do_stop_timer(s);
|
||||
if (command & SONIC_CR_ST)
|
||||
do_start_timer(s);
|
||||
dp8393x_do_start_timer(s);
|
||||
if (command & SONIC_CR_RST)
|
||||
do_software_reset(s);
|
||||
dp8393x_do_software_reset(s);
|
||||
if (command & SONIC_CR_RRRA)
|
||||
do_read_rra(s);
|
||||
dp8393x_do_read_rra(s);
|
||||
if (command & SONIC_CR_LCAM)
|
||||
do_load_cam(s);
|
||||
dp8393x_do_load_cam(s);
|
||||
}
|
||||
|
||||
static uint16_t read_register(dp8393xState *s, int reg)
|
||||
static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
dp8393xState *s = opaque;
|
||||
int reg = addr >> s->it_shift;
|
||||
uint16_t val = 0;
|
||||
|
||||
switch (reg) {
|
||||
/* Update data before reading it */
|
||||
case SONIC_WT0:
|
||||
case SONIC_WT1:
|
||||
update_wt_regs(s);
|
||||
dp8393x_update_wt_regs(s);
|
||||
val = s->regs[reg];
|
||||
break;
|
||||
/* Accept read to some registers only when in reset mode */
|
||||
|
@ -510,14 +512,18 @@ static uint16_t read_register(dp8393xState *s, int reg)
|
|||
return val;
|
||||
}
|
||||
|
||||
static void write_register(dp8393xState *s, int reg, uint16_t val)
|
||||
static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
|
||||
dp8393xState *s = opaque;
|
||||
int reg = addr >> s->it_shift;
|
||||
|
||||
DPRINTF("write 0x%04x to reg %s\n", (uint16_t)data, reg_names[reg]);
|
||||
|
||||
switch (reg) {
|
||||
/* Command register */
|
||||
case SONIC_CR:
|
||||
do_command(s, val);
|
||||
dp8393x_do_command(s, data);
|
||||
break;
|
||||
/* Prevent write to read-only registers */
|
||||
case SONIC_CAP2:
|
||||
|
@ -530,37 +536,37 @@ static void write_register(dp8393xState *s, int reg, uint16_t val)
|
|||
/* Accept write to some registers only when in reset mode */
|
||||
case SONIC_DCR:
|
||||
if (s->regs[SONIC_CR] & SONIC_CR_RST) {
|
||||
s->regs[reg] = val & 0xbfff;
|
||||
s->regs[reg] = data & 0xbfff;
|
||||
} else {
|
||||
DPRINTF("writing to DCR invalid\n");
|
||||
}
|
||||
break;
|
||||
case SONIC_DCR2:
|
||||
if (s->regs[SONIC_CR] & SONIC_CR_RST) {
|
||||
s->regs[reg] = val & 0xf017;
|
||||
s->regs[reg] = data & 0xf017;
|
||||
} else {
|
||||
DPRINTF("writing to DCR2 invalid\n");
|
||||
}
|
||||
break;
|
||||
/* 12 lower bytes are Read Only */
|
||||
case SONIC_TCR:
|
||||
s->regs[reg] = val & 0xf000;
|
||||
s->regs[reg] = data & 0xf000;
|
||||
break;
|
||||
/* 9 lower bytes are Read Only */
|
||||
case SONIC_RCR:
|
||||
s->regs[reg] = val & 0xffe0;
|
||||
s->regs[reg] = data & 0xffe0;
|
||||
break;
|
||||
/* Ignore most significant bit */
|
||||
case SONIC_IMR:
|
||||
s->regs[reg] = val & 0x7fff;
|
||||
s->regs[reg] = data & 0x7fff;
|
||||
dp8393x_update_irq(s);
|
||||
break;
|
||||
/* Clear bits by writing 1 to them */
|
||||
case SONIC_ISR:
|
||||
val &= s->regs[reg];
|
||||
s->regs[reg] &= ~val;
|
||||
if (val & SONIC_ISR_RBE) {
|
||||
do_read_rra(s);
|
||||
data &= s->regs[reg];
|
||||
s->regs[reg] &= ~data;
|
||||
if (data & SONIC_ISR_RBE) {
|
||||
dp8393x_do_read_rra(s);
|
||||
}
|
||||
dp8393x_update_irq(s);
|
||||
break;
|
||||
|
@ -569,24 +575,32 @@ static void write_register(dp8393xState *s, int reg, uint16_t val)
|
|||
case SONIC_REA:
|
||||
case SONIC_RRP:
|
||||
case SONIC_RWP:
|
||||
s->regs[reg] = val & 0xfffe;
|
||||
s->regs[reg] = data & 0xfffe;
|
||||
break;
|
||||
/* Invert written value for some registers */
|
||||
case SONIC_CRCT:
|
||||
case SONIC_FAET:
|
||||
case SONIC_MPT:
|
||||
s->regs[reg] = val ^ 0xffff;
|
||||
s->regs[reg] = data ^ 0xffff;
|
||||
break;
|
||||
/* All other registers have no special contrainst */
|
||||
default:
|
||||
s->regs[reg] = val;
|
||||
s->regs[reg] = data;
|
||||
}
|
||||
|
||||
if (reg == SONIC_WT0 || reg == SONIC_WT1) {
|
||||
set_next_tick(s);
|
||||
dp8393x_set_next_tick(s);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps dp8393x_ops = {
|
||||
.read = dp8393x_read,
|
||||
.write = dp8393x_write,
|
||||
.impl.min_access_size = 2,
|
||||
.impl.max_access_size = 2,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void dp8393x_watchdog(void *opaque)
|
||||
{
|
||||
dp8393xState *s = opaque;
|
||||
|
@ -597,84 +611,14 @@ static void dp8393x_watchdog(void *opaque)
|
|||
|
||||
s->regs[SONIC_WT1] = 0xffff;
|
||||
s->regs[SONIC_WT0] = 0xffff;
|
||||
set_next_tick(s);
|
||||
dp8393x_set_next_tick(s);
|
||||
|
||||
/* Signal underflow */
|
||||
s->regs[SONIC_ISR] |= SONIC_ISR_TC;
|
||||
dp8393x_update_irq(s);
|
||||
}
|
||||
|
||||
static uint32_t dp8393x_readw(void *opaque, hwaddr addr)
|
||||
{
|
||||
dp8393xState *s = opaque;
|
||||
int reg;
|
||||
|
||||
if ((addr & ((1 << s->it_shift) - 1)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
reg = addr >> s->it_shift;
|
||||
return read_register(s, reg);
|
||||
}
|
||||
|
||||
static uint32_t dp8393x_readb(void *opaque, hwaddr addr)
|
||||
{
|
||||
uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
|
||||
return (v >> (8 * (addr & 0x1))) & 0xff;
|
||||
}
|
||||
|
||||
static uint32_t dp8393x_readl(void *opaque, hwaddr addr)
|
||||
{
|
||||
uint32_t v;
|
||||
v = dp8393x_readw(opaque, addr);
|
||||
v |= dp8393x_readw(opaque, addr + 2) << 16;
|
||||
return v;
|
||||
}
|
||||
|
||||
static void dp8393x_writew(void *opaque, hwaddr addr, uint32_t val)
|
||||
{
|
||||
dp8393xState *s = opaque;
|
||||
int reg;
|
||||
|
||||
if ((addr & ((1 << s->it_shift) - 1)) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
reg = addr >> s->it_shift;
|
||||
|
||||
write_register(s, reg, (uint16_t)val);
|
||||
}
|
||||
|
||||
static void dp8393x_writeb(void *opaque, hwaddr addr, uint32_t val)
|
||||
{
|
||||
uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
|
||||
|
||||
switch (addr & 3) {
|
||||
case 0:
|
||||
val = val | (old_val & 0xff00);
|
||||
break;
|
||||
case 1:
|
||||
val = (val << 8) | (old_val & 0x00ff);
|
||||
break;
|
||||
}
|
||||
dp8393x_writew(opaque, addr & ~0x1, val);
|
||||
}
|
||||
|
||||
static void dp8393x_writel(void *opaque, hwaddr addr, uint32_t val)
|
||||
{
|
||||
dp8393x_writew(opaque, addr, val & 0xffff);
|
||||
dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps dp8393x_ops = {
|
||||
.old_mmio = {
|
||||
.read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, },
|
||||
.write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, },
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int nic_can_receive(NetClientState *nc)
|
||||
static int dp8393x_can_receive(NetClientState *nc)
|
||||
{
|
||||
dp8393xState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
|
@ -685,7 +629,8 @@ static int nic_can_receive(NetClientState *nc)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
|
||||
static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf,
|
||||
int size)
|
||||
{
|
||||
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
int i;
|
||||
|
@ -723,7 +668,8 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
||||
static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
||||
size_t size)
|
||||
{
|
||||
dp8393xState *s = qemu_get_nic_opaque(nc);
|
||||
uint16_t data[10];
|
||||
|
@ -737,7 +683,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
|||
s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
|
||||
SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
|
||||
|
||||
packet_type = receive_filter(s, buf, size);
|
||||
packet_type = dp8393x_receive_filter(s, buf, size);
|
||||
if (packet_type < 0) {
|
||||
DPRINTF("packet not for netcard\n");
|
||||
return -1;
|
||||
|
@ -750,7 +696,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
|||
/* Are we still in resource exhaustion? */
|
||||
size = sizeof(uint16_t) * 1 * width;
|
||||
address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
|
||||
s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
|
||||
address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
|
||||
(uint8_t *)data, size, 0);
|
||||
if (data[0 * width] & 0x1) {
|
||||
/* Still EOL ; stop reception */
|
||||
return -1;
|
||||
|
@ -764,18 +711,16 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
|||
s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
|
||||
|
||||
/* Calculate the ethernet checksum */
|
||||
#ifdef SONIC_CALCULATE_RXCRC
|
||||
checksum = cpu_to_le32(crc32(0, buf, rx_len));
|
||||
#else
|
||||
checksum = 0;
|
||||
#endif
|
||||
|
||||
/* Put packet into RBA */
|
||||
DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
|
||||
address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
|
||||
s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
|
||||
address_space_rw(&s->as, address,
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1);
|
||||
address += rx_len;
|
||||
s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
|
||||
address_space_rw(&s->as, address,
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)&checksum, 4, 1);
|
||||
rx_len += 4;
|
||||
s->regs[SONIC_CRBA1] = address >> 16;
|
||||
s->regs[SONIC_CRBA0] = address & 0xffff;
|
||||
|
@ -803,29 +748,30 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
|||
data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
|
||||
data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
|
||||
size = sizeof(uint16_t) * 5 * width;
|
||||
s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
|
||||
address_space_rw(&s->as, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA],
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
|
||||
|
||||
/* Move to next descriptor */
|
||||
size = sizeof(uint16_t) * width;
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
|
||||
(uint8_t *)data, size, 0);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||
s->regs[SONIC_LLFA] = data[0 * width];
|
||||
if (s->regs[SONIC_LLFA] & 0x1) {
|
||||
/* EOL detected */
|
||||
s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
|
||||
} else {
|
||||
data[0 * width] = 0; /* in_use */
|
||||
s->memory_rw(s->mem_opaque,
|
||||
address_space_rw(&s->as,
|
||||
((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
|
||||
(uint8_t *)data, size, 1);
|
||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1);
|
||||
s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
|
||||
s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
|
||||
s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
|
||||
|
||||
if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
|
||||
/* Read next RRA */
|
||||
do_read_rra(s);
|
||||
dp8393x_do_read_rra(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -835,11 +781,12 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
|||
return size;
|
||||
}
|
||||
|
||||
static void nic_reset(void *opaque)
|
||||
static void dp8393x_reset(DeviceState *dev)
|
||||
{
|
||||
dp8393xState *s = opaque;
|
||||
dp8393xState *s = DP8393X(dev);
|
||||
timer_del(s->watchdog);
|
||||
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
|
||||
s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
|
||||
s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
|
||||
|
@ -862,39 +809,91 @@ static void nic_reset(void *opaque)
|
|||
static NetClientInfo net_dp83932_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = nic_can_receive,
|
||||
.receive = nic_receive,
|
||||
.can_receive = dp8393x_can_receive,
|
||||
.receive = dp8393x_receive,
|
||||
};
|
||||
|
||||
void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
|
||||
MemoryRegion *address_space,
|
||||
qemu_irq irq, void* mem_opaque,
|
||||
void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write))
|
||||
static void dp8393x_instance_init(Object *obj)
|
||||
{
|
||||
dp8393xState *s;
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
dp8393xState *s = DP8393X(obj);
|
||||
|
||||
qemu_check_nic_model(nd, "dp83932");
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
sysbus_init_mmio(sbd, &s->prom);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
}
|
||||
|
||||
s = g_malloc0(sizeof(dp8393xState));
|
||||
static void dp8393x_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
dp8393xState *s = DP8393X(dev);
|
||||
int i, checksum;
|
||||
uint8_t *prom;
|
||||
|
||||
address_space_init(&s->as, s->dma_mr, "dp8393x");
|
||||
memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s,
|
||||
"dp8393x-regs", 0x40 << s->it_shift);
|
||||
|
||||
s->nic = qemu_new_nic(&net_dp83932_info, &s->conf,
|
||||
object_get_typename(OBJECT(dev)), dev->id, s);
|
||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||
|
||||
s->address_space = address_space;
|
||||
s->mem_opaque = mem_opaque;
|
||||
s->memory_rw = memory_rw;
|
||||
s->it_shift = it_shift;
|
||||
s->irq = irq;
|
||||
s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s);
|
||||
s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
|
||||
|
||||
s->conf.macaddr = nd->macaddr;
|
||||
s->conf.peers.ncs[0] = nd->netdev;
|
||||
|
||||
s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
|
||||
|
||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||
qemu_register_reset(nic_reset, s);
|
||||
nic_reset(s);
|
||||
|
||||
memory_region_init_io(&s->mmio, NULL, &dp8393x_ops, s,
|
||||
"dp8393x", 0x40 << it_shift);
|
||||
memory_region_add_subregion(address_space, base, &s->mmio);
|
||||
memory_region_init_rom_device(&s->prom, OBJECT(dev), NULL, NULL,
|
||||
"dp8393x-prom", SONIC_PROM_SIZE, NULL);
|
||||
prom = memory_region_get_ram_ptr(&s->prom);
|
||||
checksum = 0;
|
||||
for (i = 0; i < 6; i++) {
|
||||
prom[i] = s->conf.macaddr.a[i];
|
||||
checksum += prom[i];
|
||||
if (checksum > 0xff) {
|
||||
checksum = (checksum + 1) & 0xff;
|
||||
}
|
||||
}
|
||||
prom[7] = 0xff - checksum;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_dp8393x = {
|
||||
.name = "dp8393x",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_BUFFER_UNSAFE(cam, dp8393xState, 0, 16 * 6),
|
||||
VMSTATE_UINT16_ARRAY(regs, dp8393xState, 0x40),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property dp8393x_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(dp8393xState, conf),
|
||||
DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr),
|
||||
DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void dp8393x_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
|
||||
dc->realize = dp8393x_realize;
|
||||
dc->reset = dp8393x_reset;
|
||||
dc->vmsd = &vmstate_dp8393x;
|
||||
dc->props = dp8393x_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo dp8393x_info = {
|
||||
.name = TYPE_DP8393X,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(dp8393xState),
|
||||
.instance_init = dp8393x_instance_init,
|
||||
.class_init = dp8393x_class_init,
|
||||
};
|
||||
|
||||
static void dp8393x_register_types(void)
|
||||
{
|
||||
type_register_static(&dp8393x_info);
|
||||
}
|
||||
|
||||
type_init(dp8393x_register_types)
|
||||
|
|
|
@ -105,6 +105,8 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
|
|||
hwaddr paddr, MemTxAttrs attrs,
|
||||
int prot, int mmu_idx, target_ulong size);
|
||||
void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
|
||||
void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||
uintptr_t retaddr);
|
||||
#else
|
||||
static inline void tlb_flush_page(CPUState *cpu, target_ulong addr)
|
||||
{
|
||||
|
|
|
@ -15,18 +15,9 @@ PCIBus *bonito_init(qemu_irq *pic);
|
|||
|
||||
/* rc4030.c */
|
||||
typedef struct rc4030DMAState *rc4030_dma;
|
||||
void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write);
|
||||
void rc4030_dma_read(void *dma, uint8_t *buf, int len);
|
||||
void rc4030_dma_write(void *dma, uint8_t *buf, int len);
|
||||
|
||||
void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
|
||||
qemu_irq **irqs, rc4030_dma **dmas,
|
||||
MemoryRegion *sysmem);
|
||||
|
||||
/* dp8393x.c */
|
||||
void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
|
||||
MemoryRegion *address_space,
|
||||
qemu_irq irq, void* mem_opaque,
|
||||
void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write));
|
||||
DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -548,6 +548,28 @@ glue(glue(helper_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr,
|
|||
helper_te_st_name(env, addr, val, oi, GETRA());
|
||||
}
|
||||
|
||||
#if DATA_SIZE == 1
|
||||
/* Probe for whether the specified guest write access is permitted.
|
||||
* If it is not permitted then an exception will be taken in the same
|
||||
* way as if this were a real write access (and we will not return).
|
||||
* Otherwise the function will return, and there will be a valid
|
||||
* entry in the TLB for this access.
|
||||
*/
|
||||
void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
|
||||
|
||||
if ((addr & TARGET_PAGE_MASK)
|
||||
!= (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
/* TLB entry is for a different page */
|
||||
if (!VICTIM_TLB_HIT(addr_write)) {
|
||||
tlb_fill(ENV_GET_CPU(env), addr, MMU_DATA_STORE, mmu_idx, retaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* !defined(SOFTMMU_CODE_ACCESS) */
|
||||
|
||||
#undef READ_ACCESS_TYPE
|
||||
|
|
|
@ -34,7 +34,7 @@ struct r4k_tlb_t {
|
|||
uint_fast16_t RI0:1;
|
||||
uint_fast16_t RI1:1;
|
||||
uint_fast16_t EHINV:1;
|
||||
target_ulong PFN[2];
|
||||
uint64_t PFN[2];
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
@ -100,6 +100,7 @@ struct CPUMIPSFPUContext {
|
|||
float_status fp_status;
|
||||
/* fpu implementation/revision register (fir) */
|
||||
uint32_t fcr0;
|
||||
#define FCR0_FREP 29
|
||||
#define FCR0_UFRP 28
|
||||
#define FCR0_F64 22
|
||||
#define FCR0_L 21
|
||||
|
@ -223,8 +224,14 @@ struct CPUMIPSState {
|
|||
|
||||
uint32_t SEGBITS;
|
||||
uint32_t PABITS;
|
||||
#if defined(TARGET_MIPS64)
|
||||
# define PABITS_BASE 36
|
||||
#else
|
||||
# define PABITS_BASE 32
|
||||
#endif
|
||||
target_ulong SEGMask;
|
||||
target_ulong PAMask;
|
||||
uint64_t PAMask;
|
||||
#define PAMASK_BASE ((1ULL << PABITS_BASE) - 1)
|
||||
|
||||
int32_t msair;
|
||||
#define MSAIR_ProcID 8
|
||||
|
@ -272,8 +279,8 @@ struct CPUMIPSState {
|
|||
#define CP0VPEOpt_DWX2 2
|
||||
#define CP0VPEOpt_DWX1 1
|
||||
#define CP0VPEOpt_DWX0 0
|
||||
target_ulong CP0_EntryLo0;
|
||||
target_ulong CP0_EntryLo1;
|
||||
uint64_t CP0_EntryLo0;
|
||||
uint64_t CP0_EntryLo1;
|
||||
#if defined(TARGET_MIPS64)
|
||||
# define CP0EnLo_RI 63
|
||||
# define CP0EnLo_XI 62
|
||||
|
@ -288,6 +295,7 @@ struct CPUMIPSState {
|
|||
int32_t CP0_PageGrain;
|
||||
#define CP0PG_RIE 31
|
||||
#define CP0PG_XIE 30
|
||||
#define CP0PG_ELPA 29
|
||||
#define CP0PG_IEC 27
|
||||
int32_t CP0_Wired;
|
||||
int32_t CP0_SRSConf0_rw_bitmask;
|
||||
|
@ -462,17 +470,21 @@ struct CPUMIPSState {
|
|||
#define CP0C5_CV 29
|
||||
#define CP0C5_EVA 28
|
||||
#define CP0C5_MSAEn 27
|
||||
#define CP0C5_UFE 9
|
||||
#define CP0C5_FRE 8
|
||||
#define CP0C5_SBRI 6
|
||||
#define CP0C5_MVH 5
|
||||
#define CP0C5_LLB 4
|
||||
#define CP0C5_UFR 2
|
||||
#define CP0C5_NFExists 0
|
||||
int32_t CP0_Config6;
|
||||
int32_t CP0_Config7;
|
||||
/* XXX: Maybe make LLAddr per-TC? */
|
||||
target_ulong lladdr;
|
||||
uint64_t lladdr;
|
||||
target_ulong llval;
|
||||
target_ulong llnewval;
|
||||
target_ulong llreg;
|
||||
target_ulong CP0_LLAddr_rw_bitmask;
|
||||
uint64_t CP0_LLAddr_rw_bitmask;
|
||||
int CP0_LLAddr_shift;
|
||||
target_ulong CP0_WatchLo[8];
|
||||
int32_t CP0_WatchHi[8];
|
||||
|
@ -499,7 +511,7 @@ struct CPUMIPSState {
|
|||
#define CP0DB_DSS 0
|
||||
target_ulong CP0_DEPC;
|
||||
int32_t CP0_Performance0;
|
||||
int32_t CP0_TagLo;
|
||||
uint64_t CP0_TagLo;
|
||||
int32_t CP0_DataLo;
|
||||
int32_t CP0_TagHi;
|
||||
int32_t CP0_DataHi;
|
||||
|
@ -514,7 +526,7 @@ struct CPUMIPSState {
|
|||
#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */
|
||||
uint32_t hflags; /* CPU State */
|
||||
/* TMASK defines different execution modes */
|
||||
#define MIPS_HFLAG_TMASK 0x15807FF
|
||||
#define MIPS_HFLAG_TMASK 0x75807FF
|
||||
#define MIPS_HFLAG_MODE 0x00007 /* execution modes */
|
||||
/* The KSU flags must be the lowest bits in hflags. The flag order
|
||||
must be the same as defined for CP0 Status. This allows to use
|
||||
|
@ -561,6 +573,8 @@ struct CPUMIPSState {
|
|||
#define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */
|
||||
#define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */
|
||||
#define MIPS_HFLAG_MSA 0x1000000
|
||||
#define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */
|
||||
#define MIPS_HFLAG_ELPA 0x4000000
|
||||
target_ulong btarget; /* Jump / branch target */
|
||||
target_ulong bcond; /* Branch condition (if needed) */
|
||||
|
||||
|
@ -796,6 +810,15 @@ static inline void restore_msa_fp_status(CPUMIPSState *env)
|
|||
set_flush_inputs_to_zero(flush_to_zero, status);
|
||||
}
|
||||
|
||||
static inline void restore_pamask(CPUMIPSState *env)
|
||||
{
|
||||
if (env->hflags & MIPS_HFLAG_ELPA) {
|
||||
env->PAMask = (1ULL << env->PABITS) - 1;
|
||||
} else {
|
||||
env->PAMask = PAMASK_BASE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, int *flags)
|
||||
{
|
||||
|
@ -843,7 +866,8 @@ static inline void compute_hflags(CPUMIPSState *env)
|
|||
env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
|
||||
MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
|
||||
MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 |
|
||||
MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA);
|
||||
MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE |
|
||||
MIPS_HFLAG_ELPA);
|
||||
if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_ERL)) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM)) {
|
||||
|
@ -924,6 +948,16 @@ static inline void compute_hflags(CPUMIPSState *env)
|
|||
env->hflags |= MIPS_HFLAG_MSA;
|
||||
}
|
||||
}
|
||||
if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
|
||||
if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
|
||||
env->hflags |= MIPS_HFLAG_FRE;
|
||||
}
|
||||
}
|
||||
if (env->CP0_Config3 & (1 << CP0C3_LPA)) {
|
||||
if (env->CP0_PageGrain & (1 << CP0PG_ELPA)) {
|
||||
env->hflags |= MIPS_HFLAG_ELPA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
|
|
@ -348,6 +348,7 @@ DEF_HELPER_1(tlbinvf, void, env)
|
|||
DEF_HELPER_1(di, tl, env)
|
||||
DEF_HELPER_1(ei, tl, env)
|
||||
DEF_HELPER_1(eret, void, env)
|
||||
DEF_HELPER_1(eretnc, void, env)
|
||||
DEF_HELPER_1(deret, void, env)
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
DEF_HELPER_1(rdhwr_cpunum, tl, env)
|
||||
|
@ -931,5 +932,11 @@ DEF_HELPER_4(msa_ftint_u_df, void, env, i32, i32, i32)
|
|||
DEF_HELPER_4(msa_ffint_s_df, void, env, i32, i32, i32)
|
||||
DEF_HELPER_4(msa_ffint_u_df, void, env, i32, i32, i32)
|
||||
|
||||
DEF_HELPER_5(msa_ld_df, void, env, i32, i32, i32, s32)
|
||||
DEF_HELPER_5(msa_st_df, void, env, i32, i32, i32, s32)
|
||||
#define MSALDST_PROTO(type) \
|
||||
DEF_HELPER_3(msa_ld_ ## type, void, env, i32, tl) \
|
||||
DEF_HELPER_3(msa_st_ ## type, void, env, i32, tl)
|
||||
MSALDST_PROTO(b)
|
||||
MSALDST_PROTO(h)
|
||||
MSALDST_PROTO(w)
|
||||
MSALDST_PROTO(d)
|
||||
#undef MSALDST_PROTO
|
||||
|
|
|
@ -10,6 +10,7 @@ static int cpu_post_load(void *opaque, int version_id)
|
|||
restore_fp_status(env);
|
||||
restore_msa_fp_status(env);
|
||||
compute_hflags(env);
|
||||
restore_pamask(env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -142,8 +143,8 @@ static int get_tlb(QEMUFile *f, void *pv, size_t size)
|
|||
v->RI0 = (flags >> 13) & 1;
|
||||
v->XI1 = (flags >> 12) & 1;
|
||||
v->XI0 = (flags >> 11) & 1;
|
||||
qemu_get_betls(f, &v->PFN[0]);
|
||||
qemu_get_betls(f, &v->PFN[1]);
|
||||
qemu_get_be64s(f, &v->PFN[0]);
|
||||
qemu_get_be64s(f, &v->PFN[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -169,8 +170,8 @@ static void put_tlb(QEMUFile *f, void *pv, size_t size)
|
|||
qemu_put_be32s(f, &v->PageMask);
|
||||
qemu_put_8s(f, &v->ASID);
|
||||
qemu_put_be16s(f, &flags);
|
||||
qemu_put_betls(f, &v->PFN[0]);
|
||||
qemu_put_betls(f, &v->PFN[1]);
|
||||
qemu_put_be64s(f, &v->PFN[0]);
|
||||
qemu_put_be64s(f, &v->PFN[1]);
|
||||
}
|
||||
|
||||
const VMStateInfo vmstate_info_tlb = {
|
||||
|
@ -201,8 +202,8 @@ const VMStateDescription vmstate_tlb = {
|
|||
|
||||
const VMStateDescription vmstate_mips_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 6,
|
||||
.minimum_version_id = 6,
|
||||
.version_id = 7,
|
||||
.minimum_version_id = 7,
|
||||
.post_load = cpu_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
/* Active TC */
|
||||
|
@ -237,8 +238,8 @@ const VMStateDescription vmstate_mips_cpu = {
|
|||
VMSTATE_UINTTL(env.CP0_VPESchedule, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_VPEScheFBack, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_VPEOpt, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_EntryLo0, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_EntryLo1, MIPSCPU),
|
||||
VMSTATE_UINT64(env.CP0_EntryLo0, MIPSCPU),
|
||||
VMSTATE_UINT64(env.CP0_EntryLo1, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_Context, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_PageMask, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_PageGrain, MIPSCPU),
|
||||
|
@ -269,7 +270,7 @@ const VMStateDescription vmstate_mips_cpu = {
|
|||
VMSTATE_INT32(env.CP0_Config3, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_Config6, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_Config7, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.lladdr, MIPSCPU),
|
||||
VMSTATE_UINT64(env.lladdr, MIPSCPU),
|
||||
VMSTATE_UINTTL_ARRAY(env.CP0_WatchLo, MIPSCPU, 8),
|
||||
VMSTATE_INT32_ARRAY(env.CP0_WatchHi, MIPSCPU, 8),
|
||||
VMSTATE_UINTTL(env.CP0_XContext, MIPSCPU),
|
||||
|
@ -277,7 +278,7 @@ const VMStateDescription vmstate_mips_cpu = {
|
|||
VMSTATE_INT32(env.CP0_Debug, MIPSCPU),
|
||||
VMSTATE_UINTTL(env.CP0_DEPC, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_Performance0, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_TagLo, MIPSCPU),
|
||||
VMSTATE_UINT64(env.CP0_TagLo, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_DataLo, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_TagHi, MIPSCPU),
|
||||
VMSTATE_INT32(env.CP0_DataHi, MIPSCPU),
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
#if defined(TARGET_MIPS64)
|
||||
#define TARGET_LONG_BITS 64
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 36
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 48
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 42
|
||||
#else
|
||||
#define TARGET_LONG_BITS 32
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 36
|
||||
#define TARGET_PHYS_ADDR_SPACE_BITS 40
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
#endif
|
||||
|
||||
|
|
|
@ -90,10 +90,10 @@ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
|
|||
} \
|
||||
}
|
||||
#endif
|
||||
HELPER_LD(lbu, ldub, uint8_t)
|
||||
HELPER_LD(lhu, lduw, uint16_t)
|
||||
HELPER_LD(lw, ldl, int32_t)
|
||||
#if defined(TARGET_MIPS64)
|
||||
HELPER_LD(ld, ldq, int64_t)
|
||||
#endif
|
||||
#undef HELPER_LD
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
@ -118,9 +118,10 @@ static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
|
|||
}
|
||||
#endif
|
||||
HELPER_ST(sb, stb, uint8_t)
|
||||
HELPER_ST(sh, stw, uint16_t)
|
||||
HELPER_ST(sw, stl, uint32_t)
|
||||
#if defined(TARGET_MIPS64)
|
||||
HELPER_ST(sd, stq, uint64_t)
|
||||
#endif
|
||||
#undef HELPER_ST
|
||||
|
||||
target_ulong helper_clo (target_ulong arg1)
|
||||
|
@ -1067,19 +1068,23 @@ void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
|
|||
env->CP0_VPEOpt = arg1 & 0x0000ffff;
|
||||
}
|
||||
|
||||
#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
|
||||
|
||||
void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
/* Large physaddr (PABITS) not implemented */
|
||||
/* 1k pages not implemented */
|
||||
target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
|
||||
env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30));
|
||||
env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
|
||||
| (rxi << (CP0EnLo_XI - 30));
|
||||
}
|
||||
|
||||
#if defined(TARGET_MIPS64)
|
||||
#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
|
||||
|
||||
void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
|
||||
{
|
||||
uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
|
||||
env->CP0_EntryLo0 = (arg1 & 0x3FFFFFFF) | rxi;
|
||||
env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1245,17 +1250,17 @@ void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
|
|||
|
||||
void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
/* Large physaddr (PABITS) not implemented */
|
||||
/* 1k pages not implemented */
|
||||
target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
|
||||
env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | (rxi << (CP0EnLo_XI - 30));
|
||||
env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
|
||||
| (rxi << (CP0EnLo_XI - 30));
|
||||
}
|
||||
|
||||
#if defined(TARGET_MIPS64)
|
||||
void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
|
||||
{
|
||||
uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
|
||||
env->CP0_EntryLo1 = (arg1 & 0x3FFFFFFF) | rxi;
|
||||
env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1278,10 +1283,11 @@ void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
|
|||
void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
/* SmartMIPS not implemented */
|
||||
/* Large physaddr (PABITS) not implemented */
|
||||
/* 1k pages not implemented */
|
||||
env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
|
||||
(env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
|
||||
compute_hflags(env);
|
||||
restore_pamask(env);
|
||||
}
|
||||
|
||||
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
|
||||
|
@ -1825,6 +1831,16 @@ static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
|
||||
{
|
||||
#if defined(TARGET_MIPS64)
|
||||
return extract64(entrylo, 6, 54);
|
||||
#else
|
||||
return extract64(entrylo, 6, 24) | /* PFN */
|
||||
(extract64(entrylo, 32, 32) << 24); /* PFNX */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void r4k_fill_tlb(CPUMIPSState *env, int idx)
|
||||
{
|
||||
r4k_tlb_t *tlb;
|
||||
|
@ -1848,13 +1864,13 @@ static void r4k_fill_tlb(CPUMIPSState *env, int idx)
|
|||
tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
|
||||
tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
|
||||
tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
|
||||
tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
|
||||
tlb->PFN[0] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) << 12;
|
||||
tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
|
||||
tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
|
||||
tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
|
||||
tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
|
||||
tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
|
||||
tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
|
||||
tlb->PFN[1] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) << 12;
|
||||
}
|
||||
|
||||
void r4k_helper_tlbinv(CPUMIPSState *env)
|
||||
|
@ -1971,6 +1987,16 @@ void r4k_helper_tlbp(CPUMIPSState *env)
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
|
||||
{
|
||||
#if defined(TARGET_MIPS64)
|
||||
return tlb_pfn << 6;
|
||||
#else
|
||||
return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
|
||||
(extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
|
||||
#endif
|
||||
}
|
||||
|
||||
void r4k_helper_tlbr(CPUMIPSState *env)
|
||||
{
|
||||
r4k_tlb_t *tlb;
|
||||
|
@ -1996,13 +2022,13 @@ void r4k_helper_tlbr(CPUMIPSState *env)
|
|||
env->CP0_EntryHi = tlb->VPN | tlb->ASID;
|
||||
env->CP0_PageMask = tlb->PageMask;
|
||||
env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
|
||||
((target_ulong)tlb->RI0 << CP0EnLo_RI) |
|
||||
((target_ulong)tlb->XI0 << CP0EnLo_XI) |
|
||||
(tlb->C0 << 3) | (tlb->PFN[0] >> 6);
|
||||
((uint64_t)tlb->RI0 << CP0EnLo_RI) |
|
||||
((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
|
||||
get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
|
||||
env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
|
||||
((target_ulong)tlb->RI1 << CP0EnLo_RI) |
|
||||
((target_ulong)tlb->XI1 << CP0EnLo_XI) |
|
||||
(tlb->C1 << 3) | (tlb->PFN[1] >> 6);
|
||||
((uint64_t)tlb->RI1 << CP0EnLo_RI) |
|
||||
((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
|
||||
get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2098,7 +2124,7 @@ static void set_pc(CPUMIPSState *env, target_ulong error_pc)
|
|||
}
|
||||
}
|
||||
|
||||
void helper_eret(CPUMIPSState *env)
|
||||
static inline void exception_return(CPUMIPSState *env)
|
||||
{
|
||||
debug_pre_eret(env);
|
||||
if (env->CP0_Status & (1 << CP0St_ERL)) {
|
||||
|
@ -2110,9 +2136,19 @@ void helper_eret(CPUMIPSState *env)
|
|||
}
|
||||
compute_hflags(env);
|
||||
debug_post_eret(env);
|
||||
}
|
||||
|
||||
void helper_eret(CPUMIPSState *env)
|
||||
{
|
||||
exception_return(env);
|
||||
env->lladdr = 1;
|
||||
}
|
||||
|
||||
void helper_eretnc(CPUMIPSState *env)
|
||||
{
|
||||
exception_return(env);
|
||||
}
|
||||
|
||||
void helper_deret(CPUMIPSState *env)
|
||||
{
|
||||
debug_pre_eret(env);
|
||||
|
@ -2303,6 +2339,16 @@ target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/* FRE Support - read Config5.FRE bit */
|
||||
if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
|
||||
if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
|
||||
arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
|
||||
} else {
|
||||
helper_raise_exception(env, EXCP_RI);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 25:
|
||||
arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
|
||||
break;
|
||||
|
@ -2347,6 +2393,30 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
|
|||
helper_raise_exception(env, EXCP_RI);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/* FRE Support - clear Config5.FRE bit */
|
||||
if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
|
||||
return;
|
||||
}
|
||||
if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
|
||||
env->CP0_Config5 &= ~(1 << CP0C5_FRE);
|
||||
compute_hflags(env);
|
||||
} else {
|
||||
helper_raise_exception(env, EXCP_RI);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
/* FRE Support - set Config5.FRE bit */
|
||||
if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
|
||||
return;
|
||||
}
|
||||
if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
|
||||
env->CP0_Config5 |= (1 << CP0C5_FRE);
|
||||
compute_hflags(env);
|
||||
} else {
|
||||
helper_raise_exception(env, EXCP_RI);
|
||||
}
|
||||
break;
|
||||
case 25:
|
||||
if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
|
||||
return;
|
||||
|
@ -3558,72 +3628,82 @@ FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
|
|||
/* Element-by-element access macros */
|
||||
#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
|
||||
|
||||
void helper_msa_ld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs,
|
||||
int32_t s10)
|
||||
{
|
||||
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
|
||||
target_ulong addr = env->active_tc.gpr[rs] + (s10 << df);
|
||||
int i;
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#define MEMOP_IDX(DF) \
|
||||
TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \
|
||||
cpu_mmu_index(env));
|
||||
#else
|
||||
#define MEMOP_IDX(DF)
|
||||
#endif
|
||||
|
||||
switch (df) {
|
||||
case DF_BYTE:
|
||||
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) {
|
||||
pwd->b[i] = do_lbu(env, addr + (i << DF_BYTE),
|
||||
env->hflags & MIPS_HFLAG_KSU);
|
||||
}
|
||||
break;
|
||||
case DF_HALF:
|
||||
for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) {
|
||||
pwd->h[i] = do_lhu(env, addr + (i << DF_HALF),
|
||||
env->hflags & MIPS_HFLAG_KSU);
|
||||
}
|
||||
break;
|
||||
case DF_WORD:
|
||||
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
|
||||
pwd->w[i] = do_lw(env, addr + (i << DF_WORD),
|
||||
env->hflags & MIPS_HFLAG_KSU);
|
||||
}
|
||||
break;
|
||||
case DF_DOUBLE:
|
||||
for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
|
||||
pwd->d[i] = do_ld(env, addr + (i << DF_DOUBLE),
|
||||
env->hflags & MIPS_HFLAG_KSU);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#define MSA_LD_DF(DF, TYPE, LD_INSN, ...) \
|
||||
void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
|
||||
target_ulong addr) \
|
||||
{ \
|
||||
wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
|
||||
wr_t wx; \
|
||||
int i; \
|
||||
MEMOP_IDX(DF) \
|
||||
for (i = 0; i < DF_ELEMENTS(DF); i++) { \
|
||||
wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__); \
|
||||
} \
|
||||
memcpy(pwd, &wx, sizeof(wr_t)); \
|
||||
}
|
||||
|
||||
void helper_msa_st_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs,
|
||||
int32_t s10)
|
||||
{
|
||||
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
|
||||
target_ulong addr = env->active_tc.gpr[rs] + (s10 << df);
|
||||
int i;
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETRA())
|
||||
MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETRA())
|
||||
MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETRA())
|
||||
MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETRA())
|
||||
#else
|
||||
MSA_LD_DF(DF_BYTE, b, cpu_ldub_data)
|
||||
MSA_LD_DF(DF_HALF, h, cpu_lduw_data)
|
||||
MSA_LD_DF(DF_WORD, w, cpu_ldl_data)
|
||||
MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
|
||||
#endif
|
||||
|
||||
switch (df) {
|
||||
case DF_BYTE:
|
||||
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) {
|
||||
do_sb(env, addr + (i << DF_BYTE), pwd->b[i],
|
||||
env->hflags & MIPS_HFLAG_KSU);
|
||||
}
|
||||
break;
|
||||
case DF_HALF:
|
||||
for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) {
|
||||
do_sh(env, addr + (i << DF_HALF), pwd->h[i],
|
||||
env->hflags & MIPS_HFLAG_KSU);
|
||||
}
|
||||
break;
|
||||
case DF_WORD:
|
||||
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
|
||||
do_sw(env, addr + (i << DF_WORD), pwd->w[i],
|
||||
env->hflags & MIPS_HFLAG_KSU);
|
||||
}
|
||||
break;
|
||||
case DF_DOUBLE:
|
||||
for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
|
||||
do_sd(env, addr + (i << DF_DOUBLE), pwd->d[i],
|
||||
env->hflags & MIPS_HFLAG_KSU);
|
||||
}
|
||||
break;
|
||||
#define MSA_PAGESPAN(x) \
|
||||
((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
|
||||
|
||||
static inline void ensure_writable_pages(CPUMIPSState *env,
|
||||
target_ulong addr,
|
||||
int mmu_idx,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
target_ulong page_addr;
|
||||
if (unlikely(MSA_PAGESPAN(addr))) {
|
||||
/* first page */
|
||||
probe_write(env, addr, mmu_idx, retaddr);
|
||||
/* second page */
|
||||
page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||
probe_write(env, page_addr, mmu_idx, retaddr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define MSA_ST_DF(DF, TYPE, ST_INSN, ...) \
|
||||
void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
|
||||
target_ulong addr) \
|
||||
{ \
|
||||
wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
|
||||
int mmu_idx = cpu_mmu_index(env); \
|
||||
int i; \
|
||||
MEMOP_IDX(DF) \
|
||||
ensure_writable_pages(env, addr, mmu_idx, GETRA()); \
|
||||
for (i = 0; i < DF_ELEMENTS(DF); i++) { \
|
||||
ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETRA())
|
||||
MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETRA())
|
||||
MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETRA())
|
||||
MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETRA())
|
||||
#else
|
||||
MSA_ST_DF(DF_BYTE, b, cpu_stb_data)
|
||||
MSA_ST_DF(DF_HALF, h, cpu_stw_data)
|
||||
MSA_ST_DF(DF_WORD, w, cpu_stl_data)
|
||||
MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -400,10 +400,12 @@ static const mips_def_t mips_defs[] =
|
|||
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
|
||||
(1 << CP0C1_CA),
|
||||
.CP0_Config2 = MIPS_CONFIG2,
|
||||
.CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP),
|
||||
.CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) |
|
||||
(1 << CP0C3_LPA),
|
||||
.CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M),
|
||||
.CP0_Config4_rw_bitmask = 0,
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_UFR),
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_UFR) | (1 << CP0C5_LLB) |
|
||||
(1 << CP0C5_MVH),
|
||||
.CP0_Config5_rw_bitmask = (0 << CP0C5_M) | (1 << CP0C5_K) |
|
||||
(1 << CP0C5_CV) | (0 << CP0C5_EVA) |
|
||||
(1 << CP0C5_MSAEn) | (1 << CP0C5_UFR) |
|
||||
|
@ -413,11 +415,12 @@ static const mips_def_t mips_defs[] =
|
|||
.SYNCI_Step = 32,
|
||||
.CCRes = 2,
|
||||
.CP0_Status_rw_bitmask = 0x3778FF1F,
|
||||
.CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
|
||||
.CP1_fcr0 = (1 << FCR0_UFRP) | (1 << FCR0_F64) | (1 << FCR0_L) |
|
||||
(1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
|
||||
(0x93 << FCR0_PRID),
|
||||
.SEGBITS = 32,
|
||||
.PABITS = 32,
|
||||
.PABITS = 40,
|
||||
.insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_MSA,
|
||||
.mmu_type = MMU_TYPE_R4000,
|
||||
},
|
||||
|
@ -553,9 +556,6 @@ static const mips_def_t mips_defs[] =
|
|||
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
|
||||
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
|
||||
.SEGBITS = 42,
|
||||
/* The architectural limit is 59, but we have hardcoded 36 bit
|
||||
in some places...
|
||||
.PABITS = 59, */ /* the architectural limit */
|
||||
.PABITS = 36,
|
||||
.insn_flags = CPU_MIPS64R2 | ASE_MIPS3D,
|
||||
.mmu_type = MMU_TYPE_R4000,
|
||||
|
@ -607,7 +607,7 @@ static const mips_def_t mips_defs[] =
|
|||
},
|
||||
{
|
||||
/* A generic CPU supporting MIPS64 Release 6 ISA.
|
||||
FIXME: Support IEEE 754-2008 FP and misaligned memory accesses.
|
||||
FIXME: Support IEEE 754-2008 FP.
|
||||
Eventually this should be replaced by a real CPU model. */
|
||||
.name = "MIPS64R6-generic",
|
||||
.CP0_PRid = 0x00010000,
|
||||
|
@ -619,10 +619,13 @@ static const mips_def_t mips_defs[] =
|
|||
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
|
||||
.CP0_Config2 = MIPS_CONFIG2,
|
||||
.CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_RXI) | (1 << CP0C3_BP) |
|
||||
(1 << CP0C3_BI) | (1 << CP0C3_ULRI) | (1U << CP0C3_M),
|
||||
(1 << CP0C3_BI) | (1 << CP0C3_ULRI) | (1 << CP0C3_LPA) |
|
||||
(1U << CP0C3_M),
|
||||
.CP0_Config4 = MIPS_CONFIG4 | (0xfc << CP0C4_KScrExist) |
|
||||
(3 << CP0C4_IE) | (1 << CP0C4_M),
|
||||
.CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI),
|
||||
.CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_LLB),
|
||||
.CP0_Config5_rw_bitmask = (1 << CP0C5_SBRI) | (1 << CP0C5_FRE) |
|
||||
(1 << CP0C5_UFE),
|
||||
.CP0_LLAddr_rw_bitmask = 0,
|
||||
.CP0_LLAddr_shift = 0,
|
||||
.SYNCI_Step = 32,
|
||||
|
@ -630,15 +633,12 @@ static const mips_def_t mips_defs[] =
|
|||
.CP0_Status_rw_bitmask = 0x30D8FFFF,
|
||||
.CP0_PageGrain = (1 << CP0PG_IEC) | (1 << CP0PG_XIE) |
|
||||
(1U << CP0PG_RIE),
|
||||
.CP0_PageGrain_rw_bitmask = 0,
|
||||
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
|
||||
(1 << FCR0_D) | (1 << FCR0_S) | (0x00 << FCR0_PRID) |
|
||||
(0x0 << FCR0_REV),
|
||||
.CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
|
||||
.CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_F64) | (1 << FCR0_L) |
|
||||
(1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) |
|
||||
(0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
|
||||
.SEGBITS = 42,
|
||||
/* The architectural limit is 59, but we have hardcoded 36 bit
|
||||
in some places...
|
||||
.PABITS = 59, */ /* the architectural limit */
|
||||
.PABITS = 36,
|
||||
.PABITS = 48,
|
||||
.insn_flags = CPU_MIPS64R6,
|
||||
.mmu_type = MMU_TYPE_R4000,
|
||||
},
|
||||
|
@ -701,9 +701,6 @@ static const mips_def_t mips_defs[] =
|
|||
(1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
|
||||
(1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
|
||||
.SEGBITS = 42,
|
||||
/* The architectural limit is 59, but we have hardcoded 36 bit
|
||||
in some places...
|
||||
.PABITS = 59, */ /* the architectural limit */
|
||||
.PABITS = 36,
|
||||
.insn_flags = CPU_MIPS64R2 | ASE_DSP | ASE_DSPR2,
|
||||
.mmu_type = MMU_TYPE_R4000,
|
||||
|
|
|
@ -31,8 +31,6 @@ struct TestCase {
|
|||
|
||||
static const TestCase test_cases[] = {
|
||||
{ "i386", "pc", -1 },
|
||||
{ "mips", "magnum", 0x90000000, .bswap = true },
|
||||
{ "mips", "pica61", 0x90000000, .bswap = true },
|
||||
{ "mips", "mips", 0x14000000, .bswap = true },
|
||||
{ "mips", "malta", 0x10000000, .bswap = true },
|
||||
{ "mips64", "magnum", 0x90000000, .bswap = true },
|
||||
|
|
|
@ -280,6 +280,12 @@ slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d cha
|
|||
slavio_timer_mem_writel_mode_invalid(void) "not system timer"
|
||||
slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64
|
||||
|
||||
# hw/dma/rc4030.c
|
||||
jazzio_read(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x"
|
||||
jazzio_write(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x"
|
||||
rc4030_read(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x"
|
||||
rc4030_write(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x"
|
||||
|
||||
# hw/dma/sparc32_dma.c
|
||||
ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64
|
||||
ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64
|
||||
|
|
Loading…
Reference in New Issue