MIPS patches queue

. Fix some comment spelling errors
 . Demacro some TCG helpers
 . Add loongson-ext lswc2/lsdc2 group of instructions
 . Log unimplemented cache opcode
 . Increase number of TLB entries on the 34Kf core
 . Allow the CPU to use dynamic frequencies
 . Calculate the CP0 timer period using the CPU frequency
 . Set CPU frequency for each machine
 . Fix Malta FPGA I/O region size
 . Allow running qtests when ROM is missing
 . Add record/replay acceptance tests
 . Update MIPS CPU documentation
 . MAINTAINERS updates
 
 CI jobs results:
   https://gitlab.com/philmd/qemu/-/pipelines/203931842
   https://travis-ci.org/github/philmd/qemu/builds/736491461
   https://cirrus-ci.com/build/6272264062631936
   https://app.shippable.com/github/philmd/qemu/runs/886/summary/console
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAl+K+NkACgkQ4+MsLN6t
 wN4oPRAArZ5v0fjGrylt9g4xCAygLoSMkH3sZxltB77UVN/dCawSTLK2seKKO5g/
 UtGt/j4/OAt8Ms+nF8FT+UZbknkgq+h7coOorHvz6gDEAx9UIg6/S2TRZJEx28+l
 LbzkqdxvNSoHRrQDpGo43xoaxjzCxSTSOKpPfje6p2YDxWjkxdr/ahcsbKHSKc+x
 uGdVdEAlLiAs/fBhkaJD3yy1VfqJKu8V5JJo1g4gSQOD1worRbZ4Us9QfuYr79Q7
 Kce1Z1MQSf/TceZuDubhzZBep5lF1uW4lTywcaDby0LvGNK4K+RnH+i+t7CNhtKs
 LH5j6iFQY1ecjb1Vh0IgKNAFaM2sTtO7A6fbBSOkVTO60wEp7i9fpbI5TRIjv7z/
 EBkzP3n00hhbFFDci6Lnh/Ko0Xy0ODe3Um5l410sTnJe9+LK0HR5V6WH8PD/wKV2
 nnKzSgb1U51KS6+FzLGLbQzDEvCgRKAJ9mwiQ+dlRfFHj+rEM6a9rlQmtsADBhKi
 sEx62BKe6mM/+qQL9AOwZ5xBmFAn6wquuLYoA2Bwfg0wPIiAiFTwrz/eVSm9qYsw
 O9Fer+1IMmd06T1REUtSDAh8+D2ekknKmFA3AG0818WvluD0Qm3KZp8uLLHJ/XkO
 jiRtmeW+hApeh8hP4E0bzmrfJPKseBCYYP1By7XavIOoCxlqhew=
 =BOxw
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/philmd-gitlab/tags/mips-next-20201017' into staging

MIPS patches queue

. Fix some comment spelling errors
. Demacro some TCG helpers
. Add loongson-ext lswc2/lsdc2 group of instructions
. Log unimplemented cache opcode
. Increase number of TLB entries on the 34Kf core
. Allow the CPU to use dynamic frequencies
. Calculate the CP0 timer period using the CPU frequency
. Set CPU frequency for each machine
. Fix Malta FPGA I/O region size
. Allow running qtests when ROM is missing
. Add record/replay acceptance tests
. Update MIPS CPU documentation
. MAINTAINERS updates

CI jobs results:
  https://gitlab.com/philmd/qemu/-/pipelines/203931842
  https://travis-ci.org/github/philmd/qemu/builds/736491461
  https://cirrus-ci.com/build/6272264062631936
  https://app.shippable.com/github/philmd/qemu/runs/886/summary/console

# gpg: Signature made Sat 17 Oct 2020 14:59:53 BST
# gpg:                using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD  6BB2 E3E3 2C2C DEAD C0DE

* remotes/philmd-gitlab/tags/mips-next-20201017: (44 commits)
  target/mips: Increase number of TLB entries on the 34Kf core (16 -> 64)
  MAINTAINERS: Remove duplicated Malta test entries
  MAINTAINERS: Downgrade MIPS Boston to 'Odd Fixes', fix Paul Burton mail
  MAINTAINERS: Put myself forward for MIPS target
  MAINTAINERS: Remove myself
  docs/system: Update MIPS CPU documentation
  tests/acceptance: Add MIPS record/replay tests
  hw/mips: Remove exit(1) in case of missing ROM
  hw/mips: Rename TYPE_MIPS_BOSTON to TYPE_BOSTON
  hw/mips: Simplify code using ROUND_UP(INITRD_PAGE_SIZE)
  hw/mips: Simplify loading 64-bit ELF kernels
  hw/mips/malta: Use clearer qdev style
  hw/mips/malta: Move gt64120 related code together
  hw/mips/malta: Fix FPGA I/O region size
  target/mips/cpu: Display warning when CPU is used without input clock
  hw/mips/cps: Do not allow use without input clock
  hw/mips/malta: Set CPU frequency to 320 MHz
  hw/mips/boston: Set CPU frequency to 1 GHz
  hw/mips/cps: Expose input clock and connect it to CPU cores
  hw/mips/jazz: Correct CPU frequencies
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2020-10-19 10:52:56 +01:00
commit 22d30b340a
26 changed files with 1119 additions and 195 deletions

View File

@ -220,11 +220,11 @@ F: hw/microblaze/
F: disas/microblaze.c
MIPS TCG CPUs
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
R: Aurelien Jarno <aurelien@aurel32.net>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
S: Odd Fixes
F: target/mips/
F: default-configs/*mips*
F: disas/*mips*
@ -237,8 +237,6 @@ F: include/hw/intc/mips_gic.h
F: include/hw/mips/
F: include/hw/misc/mips_*
F: include/hw/timer/mips_gictimer.h
F: tests/acceptance/linux_ssh_mips_malta.py
F: tests/acceptance/machine_mips_malta.py
F: tests/tcg/mips/
K: ^Subject:.*(?i)mips
@ -386,7 +384,6 @@ F: target/arm/kvm.c
MIPS KVM CPUs
M: Huacai Chen <chenhc@lemote.com>
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
S: Odd Fixes
F: target/mips/kvm.c
@ -1123,10 +1120,9 @@ F: hw/display/jazz_led.c
F: hw/dma/rc4030.c
Malta
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
R: Aurelien Jarno <aurelien@aurel32.net>
S: Maintained
S: Odd Fixes
F: hw/isa/piix4.c
F: hw/acpi/piix4.c
F: hw/mips/malta.c
@ -1136,14 +1132,12 @@ F: tests/acceptance/linux_ssh_mips_malta.py
F: tests/acceptance/machine_mips_malta.py
Mipssim
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Odd Fixes
S: Orphaned
F: hw/mips/mipssim.c
F: hw/net/mipsnet.c
R4000
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Aurelien Jarno <aurelien@aurel32.net>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Obsolete
@ -1152,7 +1146,6 @@ F: hw/mips/r4k.c
Fuloong 2E
M: Huacai Chen <chenhc@lemote.com>
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Odd Fixes
F: hw/mips/fuloong2e.c
@ -1167,9 +1160,9 @@ S: Maintained
F: hw/intc/loongson_liointc.c
Boston
M: Paul Burton <pburton@wavecomp.com>
M: Paul Burton <paulburton@kernel.org>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
S: Odd Fixes
F: hw/core/loader-fit.c
F: hw/mips/boston.c
F: hw/pci-host/xilinx-pcie.c
@ -2823,12 +2816,12 @@ F: tcg/i386/
F: disas/i386.c
MIPS TCG target
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
R: Aurelien Jarno <aurelien@aurel32.net>
R: Huacai Chen <chenhc@lemote.com>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained
S: Odd Fixes
F: tcg/mips/
PPC TCG target
@ -3169,7 +3162,7 @@ S: Odd Fixes
F: scripts/git-submodule.sh
UI translations
M: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
S: Orphaned
F: po/*.po
Sphinx documentation configuration and build machinery

View File

@ -48,11 +48,17 @@ across all desired hosts.
``I6400``
MIPS64 Processor (Release 6, 2014)
``Loongson-2E``
MIPS64 Processor (Loongson 2, 2006)
``Loongson-2F``
MIPS64 Processor (Loongson 2, 2008)
``Loongson-2E``
MIPS64 Processor (Loongson 2, 2006)
``Loongson-3A1000``
MIPS64 Processor (Loongson 3, 2010)
``Loongson-3A4000``
MIPS64 Processor (Loongson 3, 2018)
``mips64dspr2``
MIPS64 Processor (Release 2, 2006)

View File

@ -23,6 +23,21 @@ void clock_setup_canonical_path(Clock *clk)
clk->canonical_path = object_get_canonical_path(OBJECT(clk));
}
Clock *clock_new(Object *parent, const char *name)
{
Object *obj;
Clock *clk;
obj = object_new(TYPE_CLOCK);
object_property_add_child(parent, name, obj);
object_unref(obj);
clk = CLOCK(obj);
clock_setup_canonical_path(clk);
return clk;
}
void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque)
{
clk->callback = cb;

View File

@ -12,6 +12,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/qdev-clock.h"
#include "hw/qdev-core.h"
#include "qapi/error.h"
@ -153,6 +154,11 @@ Clock *qdev_get_clock_in(DeviceState *dev, const char *name)
assert(name);
ncl = qdev_get_clocklist(dev, name);
if (!ncl) {
error_report("Can not find clock-in '%s' for device type '%s'",
name, object_get_typename(OBJECT(dev)));
abort();
}
assert(!ncl->output);
return ncl->clock;
@ -165,6 +171,11 @@ Clock *qdev_get_clock_out(DeviceState *dev, const char *name)
assert(name);
ncl = qdev_get_clocklist(dev, name);
if (!ncl) {
error_report("Can not find clock-out '%s' for device type '%s'",
name, object_get_typename(OBJECT(dev)));
abort();
}
assert(ncl->output);
return ncl->clock;

View File

@ -30,6 +30,7 @@
#include "hw/mips/cps.h"
#include "hw/mips/cpudevs.h"
#include "hw/pci-host/xilinx-pcie.h"
#include "hw/qdev-clock.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@ -43,10 +44,10 @@
#include <libfdt.h>
#include "qom/object.h"
#define TYPE_MIPS_BOSTON "mips-boston"
#define TYPE_BOSTON "mips-boston"
typedef struct BostonState BostonState;
DECLARE_INSTANCE_CHECKER(BostonState, BOSTON,
TYPE_MIPS_BOSTON)
TYPE_BOSTON)
struct BostonState {
SysBusDevice parent_obj;
@ -54,6 +55,7 @@ struct BostonState {
MachineState *mach;
MIPSCPSState cps;
SerialMM *uart;
Clock *cpuclk;
CharBackend lcd_display;
char lcd_content[8];
@ -251,10 +253,19 @@ static const MemoryRegionOps boston_platreg_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void mips_boston_instance_init(Object *obj)
{
BostonState *s = BOSTON(obj);
s->cpuclk = qdev_init_clock_out(DEVICE(obj), "cpu-refclk");
clock_set_hz(s->cpuclk, 1000000000); /* 1 GHz */
}
static const TypeInfo boston_device = {
.name = TYPE_MIPS_BOSTON,
.name = TYPE_BOSTON,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(BostonState),
.instance_init = mips_boston_instance_init,
};
static void boston_register_types(void)
@ -444,7 +455,7 @@ static void boston_mach_init(MachineState *machine)
exit(1);
}
dev = qdev_new(TYPE_MIPS_BOSTON);
dev = qdev_new(TYPE_BOSTON);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
s = BOSTON(dev);
@ -462,6 +473,8 @@ static void boston_mach_init(MachineState *machine)
&error_fatal);
object_property_set_int(OBJECT(&s->cps), "num-vp", machine->smp.cpus,
&error_fatal);
qdev_connect_clock_in(DEVICE(&s->cps), "clk-in",
qdev_get_clock_out(dev, "cpu-refclk"));
sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal);
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1);

View File

@ -22,6 +22,7 @@
#include "qemu/module.h"
#include "hw/mips/cps.h"
#include "hw/mips/mips.h"
#include "hw/qdev-clock.h"
#include "hw/qdev-properties.h"
#include "hw/mips/cpudevs.h"
#include "sysemu/kvm.h"
@ -38,6 +39,7 @@ static void mips_cps_init(Object *obj)
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
MIPSCPSState *s = MIPS_CPS(obj);
s->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, NULL);
/*
* Cover entire address space as there do not seem to be any
* constraints for the base address of CPC and GIC.
@ -72,6 +74,11 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
bool itu_present = false;
bool saar_present = false;
if (!clock_get(s->clock)) {
error_setg(errp, "CPS input clock is not connected to an output clock");
return;
}
for (i = 0; i < s->num_vp; i++) {
cpu = MIPS_CPU(object_new(s->cpu_type));
@ -80,6 +87,8 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
errp)) {
return;
}
/* All cores use the same clock tree */
qdev_connect_clock_in(DEVICE(cpu), "clk-in", s->clock);
if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) {
return;

View File

@ -23,6 +23,7 @@
#include "qemu/units.h"
#include "qapi/error.h"
#include "cpu.h"
#include "hw/clock.h"
#include "hw/intc/i8259.h"
#include "hw/dma/i8257.h"
#include "hw/isa/superio.h"
@ -132,8 +133,7 @@ static int64_t load_kernel(CPUMIPSState *env)
if (loaderparams.initrd_filename) {
initrd_size = get_image_size(loaderparams.initrd_filename);
if (initrd_size > 0) {
initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
INITRD_PAGE_MASK;
initrd_offset = ROUND_UP(kernel_high, INITRD_PAGE_SIZE);
if (initrd_offset + initrd_size > ram_size) {
error_report("memory too small for initial ram disk '%s'",
loaderparams.initrd_filename);
@ -298,12 +298,16 @@ static void mips_fuloong2e_init(MachineState *machine)
PCIBus *pci_bus;
ISABus *isa_bus;
I2CBus *smbus;
Clock *cpuclk;
MIPSCPU *cpu;
CPUMIPSState *env;
DeviceState *dev;
cpuclk = clock_new(OBJECT(machine), "cpu-refclk");
clock_set_hz(cpuclk, 533080000); /* ~533 MHz */
/* init CPUs */
cpu = MIPS_CPU(cpu_create(machine->cpu_type));
cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
env = &cpu->env;
qemu_register_reset(main_cpu_reset, cpu);
@ -333,10 +337,8 @@ static void mips_fuloong2e_init(MachineState *machine)
kernel_entry = load_kernel(env);
write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry);
} else {
if (bios_name == NULL) {
bios_name = FULOONG_BIOSNAME;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
bios_name ?: FULOONG_BIOSNAME);
if (filename) {
bios_size = load_image_targphys(filename, 0x1fc00000LL,
BIOS_SIZE);
@ -346,7 +348,7 @@ static void mips_fuloong2e_init(MachineState *machine)
}
if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
!kernel_filename && !qtest_enabled()) {
bios_name && !qtest_enabled()) {
error_report("Could not load MIPS bios '%s'", bios_name);
exit(1);
}

View File

@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "hw/clock.h"
#include "hw/mips/mips.h"
#include "hw/mips/cpudevs.h"
#include "hw/intc/i8259.h"
@ -142,6 +143,7 @@ static void mips_jazz_init(MachineState *machine,
MemoryRegion *address_space = get_system_memory();
char *filename;
int bios_size, n;
Clock *cpuclk;
MIPSCPU *cpu;
CPUClass *cc;
CPUMIPSState *env;
@ -163,14 +165,25 @@ static void mips_jazz_init(MachineState *machine,
MemoryRegion *bios2 = g_new(MemoryRegion, 1);
SysBusESPState *sysbus_esp;
ESPState *esp;
static const struct {
unsigned freq_hz;
unsigned pll_mult;
} ext_clk[] = {
[JAZZ_MAGNUM] = {50000000, 2},
[JAZZ_PICA61] = {33333333, 4},
};
if (machine->ram_size > 256 * MiB) {
error_report("RAM size more than 256Mb is not supported");
exit(EXIT_FAILURE);
}
cpuclk = clock_new(OBJECT(machine), "cpu-refclk");
clock_set_hz(cpuclk, ext_clk[jazz_model].freq_hz
* ext_clk[jazz_model].pll_mult);
/* init CPUs */
cpu = MIPS_CPU(cpu_create(machine->cpu_type));
cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
env = &cpu->env;
qemu_register_reset(main_cpu_reset, cpu);
@ -205,10 +218,7 @@ static void mips_jazz_init(MachineState *machine,
memory_region_add_subregion(address_space, 0xfff00000LL, bios2);
/* load the BIOS image. */
if (bios_name == NULL) {
bios_name = BIOS_FILENAME;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name ?: BIOS_FILENAME);
if (filename) {
bios_size = load_image_targphys(filename, 0xfff00000LL,
MAGNUM_BIOS_SIZE);
@ -216,7 +226,8 @@ static void mips_jazz_init(MachineState *machine,
} else {
bios_size = -1;
}
if ((bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) && !qtest_enabled()) {
if ((bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE)
&& bios_name && !qtest_enabled()) {
error_report("Could not load MIPS bios '%s'", bios_name);
exit(1);
}

View File

@ -26,6 +26,7 @@
#include "qemu/units.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/clock.h"
#include "hw/southbridge/piix.h"
#include "hw/isa/superio.h"
#include "hw/char/serial.h"
@ -57,6 +58,7 @@
#include "sysemu/kvm.h"
#include "hw/semihosting/semihost.h"
#include "hw/mips/cps.h"
#include "hw/qdev-clock.h"
#define ENVP_ADDR 0x80002000l
#define ENVP_NB_ENTRIES 16
@ -94,6 +96,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(MaltaState, MIPS_MALTA)
struct MaltaState {
SysBusDevice parent_obj;
Clock *cpuclk;
MIPSCPSState cps;
qemu_irq i8259[ISA_NUM_IRQS];
};
@ -575,7 +578,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
memory_region_init_alias(&s->iomem_lo, NULL, "malta-fpga",
&s->iomem, 0, 0x900);
memory_region_init_alias(&s->iomem_hi, NULL, "malta-fpga",
&s->iomem, 0xa00, 0x10000 - 0xa00);
&s->iomem, 0xa00, 0x100000 - 0xa00);
memory_region_add_subregion(address_space, base, &s->iomem_lo);
memory_region_add_subregion(address_space, base + 0xa00, &s->iomem_hi);
@ -1074,9 +1077,9 @@ static int64_t load_kernel(void)
* the initrd. It takes at most 128kiB for 2GB RAM and 4kiB
* pages.
*/
initrd_offset = (loaderparams.ram_low_size - initrd_size
- (128 * KiB)
- ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
initrd_offset = ROUND_UP(loaderparams.ram_low_size
- (initrd_size + 128 * KiB),
INITRD_PAGE_SIZE);
if (kernel_high >= initrd_offset) {
error_report("memory too small for initial ram disk '%s'",
loaderparams.initrd_filename);
@ -1159,7 +1162,7 @@ static void main_cpu_reset(void *opaque)
}
}
static void create_cpu_without_cps(MachineState *ms,
static void create_cpu_without_cps(MachineState *ms, MaltaState *s,
qemu_irq *cbus_irq, qemu_irq *i8259_irq)
{
CPUMIPSState *env;
@ -1167,7 +1170,7 @@ static void create_cpu_without_cps(MachineState *ms,
int i;
for (i = 0; i < ms->smp.cpus; i++) {
cpu = MIPS_CPU(cpu_create(ms->cpu_type));
cpu = mips_cpu_create_with_clock(ms->cpu_type, s->cpuclk);
/* Init internal devices */
cpu_mips_irq_init_cpu(cpu);
@ -1189,6 +1192,7 @@ static void create_cps(MachineState *ms, MaltaState *s,
&error_fatal);
object_property_set_int(OBJECT(&s->cps), "num-vp", ms->smp.cpus,
&error_fatal);
qdev_connect_clock_in(DEVICE(&s->cps), "clk-in", s->cpuclk);
sysbus_realize(SYS_BUS_DEVICE(&s->cps), &error_fatal);
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->cps), 0, 0, 1);
@ -1203,7 +1207,7 @@ static void mips_create_cpu(MachineState *ms, MaltaState *s,
if ((ms->smp.cpus > 1) && cpu_supports_cps_smp(ms->cpu_type)) {
create_cps(ms, s, cbus_irq, i8259_irq);
} else {
create_cpu_without_cps(ms, cbus_irq, i8259_irq);
create_cpu_without_cps(ms, s, cbus_irq, i8259_irq);
}
}
@ -1231,18 +1235,11 @@ void mips_malta_init(MachineState *machine)
DriveInfo *dinfo;
int fl_idx = 0;
int be;
MaltaState *s;
DeviceState *dev;
DeviceState *dev = qdev_new(TYPE_MIPS_MALTA);
MaltaState *s = MIPS_MALTA(dev);
/*
* The whole address space decoded by the GT-64120A doesn't generate
* exception when accessing invalid memory. Create an empty slot to
* emulate this feature.
*/
empty_slot_init("GT64120", 0, 0x20000000);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
s = MIPS_MALTA(qdev_new(TYPE_MIPS_MALTA));
sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal);
/* create CPU */
mips_create_cpu(machine, s, &cbus_irq, &i8259_irq);
@ -1335,10 +1332,8 @@ void mips_malta_init(MachineState *machine)
/* Load firmware from flash. */
if (!dinfo) {
/* Load a BIOS image. */
if (bios_name == NULL) {
bios_name = BIOS_FILENAME;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
bios_name ?: BIOS_FILENAME);
if (filename) {
bios_size = load_image_targphys(filename, FLASH_ADDRESS,
BIOS_SIZE);
@ -1347,9 +1342,8 @@ void mips_malta_init(MachineState *machine)
bios_size = -1;
}
if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
!kernel_filename && !qtest_enabled()) {
error_report("Could not load MIPS bios '%s', and no "
"-kernel argument was specified", bios_name);
bios_name && !qtest_enabled()) {
error_report("Could not load MIPS bios '%s'", bios_name);
exit(1);
}
}
@ -1395,6 +1389,12 @@ void mips_malta_init(MachineState *machine)
/* Northbridge */
pci_bus = gt64120_register(s->i8259);
/*
* The whole address space decoded by the GT-64120A doesn't generate
* exception when accessing invalid memory. Create an empty slot to
* emulate this feature.
*/
empty_slot_init("GT64120", 0, 0x20000000);
/* Southbridge */
dev = piix4_create(pci_bus, &isa_bus, &smbus);
@ -1421,10 +1421,19 @@ void mips_malta_init(MachineState *machine)
pci_vga_init(pci_bus);
}
static void mips_malta_instance_init(Object *obj)
{
MaltaState *s = MIPS_MALTA(obj);
s->cpuclk = qdev_init_clock_out(DEVICE(obj), "cpu-refclk");
clock_set_hz(s->cpuclk, 320000000); /* 320 MHz */
}
static const TypeInfo mips_malta_device = {
.name = TYPE_MIPS_MALTA,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MaltaState),
.instance_init = mips_malta_instance_init,
};
static void mips_malta_machine_init(MachineClass *mc)

View File

@ -29,6 +29,7 @@
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/clock.h"
#include "hw/mips/mips.h"
#include "hw/mips/cpudevs.h"
#include "hw/char/serial.h"
@ -76,11 +77,7 @@ static int64_t load_kernel(void)
(uint64_t *)&entry, NULL,
(uint64_t *)&kernel_high, NULL, big_endian,
EM_MIPS, 1, 0);
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000) {
entry = (int32_t)entry;
}
} else {
if (kernel_size < 0) {
error_report("could not load kernel '%s': %s",
loaderparams.kernel_filename,
load_elf_strerror(kernel_size));
@ -93,8 +90,7 @@ static int64_t load_kernel(void)
if (loaderparams.initrd_filename) {
initrd_size = get_image_size(loaderparams.initrd_filename);
if (initrd_size > 0) {
initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
INITRD_PAGE_MASK;
initrd_offset = ROUND_UP(kernel_high, INITRD_PAGE_SIZE);
if (initrd_offset + initrd_size > loaderparams.ram_size) {
error_report("memory too small for initial ram disk '%s'",
loaderparams.initrd_filename);
@ -150,13 +146,21 @@ mips_mipssim_init(MachineState *machine)
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *bios = g_new(MemoryRegion, 1);
Clock *cpuclk;
MIPSCPU *cpu;
CPUMIPSState *env;
ResetData *reset_info;
int bios_size;
cpuclk = clock_new(OBJECT(machine), "cpu-refclk");
#ifdef TARGET_MIPS64
clock_set_hz(cpuclk, 6000000); /* 6 MHz */
#else
clock_set_hz(cpuclk, 12000000); /* 12 MHz */
#endif
/* Init CPUs. */
cpu = MIPS_CPU(cpu_create(machine->cpu_type));
cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
env = &cpu->env;
reset_info = g_malloc0(sizeof(ResetData));
@ -173,10 +177,7 @@ mips_mipssim_init(MachineState *machine)
/* Map the BIOS / boot exception handler. */
memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
/* Load a BIOS / boot exception handler image. */
if (bios_name == NULL) {
bios_name = BIOS_FILENAME;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name ?: BIOS_FILENAME);
if (filename) {
bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE);
g_free(filename);
@ -184,10 +185,9 @@ mips_mipssim_init(MachineState *machine)
bios_size = -1;
}
if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
!kernel_filename && !qtest_enabled()) {
bios_name && !qtest_enabled()) {
/* Bail out if we have neither a kernel image nor boot vector code. */
error_report("Could not load MIPS bios '%s', and no "
"-kernel argument was specified", bios_name);
error_report("Could not load MIPS bios '%s'", bios_name);
exit(1);
} else {
/* We have a boot vector start address. */

View File

@ -13,6 +13,7 @@
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
#include "hw/clock.h"
#include "hw/mips/mips.h"
#include "hw/mips/cpudevs.h"
#include "hw/intc/i8259.h"
@ -101,11 +102,7 @@ static int64_t load_kernel(void)
(uint64_t *)&entry, NULL,
(uint64_t *)&kernel_high, NULL, big_endian,
EM_MIPS, 1, 0);
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000) {
entry = (int32_t)entry;
}
} else {
if (kernel_size < 0) {
error_report("could not load kernel '%s': %s",
loaderparams.kernel_filename,
load_elf_strerror(kernel_size));
@ -118,8 +115,7 @@ static int64_t load_kernel(void)
if (loaderparams.initrd_filename) {
initrd_size = get_image_size(loaderparams.initrd_filename);
if (initrd_size > 0) {
initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
INITRD_PAGE_MASK;
initrd_offset = ROUND_UP(kernel_high, INITRD_PAGE_SIZE);
if (initrd_offset + initrd_size > ram_size) {
error_report("memory too small for initial ram disk '%s'",
loaderparams.initrd_filename);
@ -182,6 +178,7 @@ void mips_r4k_init(MachineState *machine)
MemoryRegion *isa_io = g_new(MemoryRegion, 1);
MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
int bios_size;
Clock *cpuclk;
MIPSCPU *cpu;
CPUMIPSState *env;
ResetData *reset_info;
@ -192,8 +189,11 @@ void mips_r4k_init(MachineState *machine)
DriveInfo *dinfo;
int be;
cpuclk = clock_new(OBJECT(machine), "cpu-refclk");
clock_set_hz(cpuclk, 200000000); /* 200 MHz */
/* init CPUs */
cpu = MIPS_CPU(cpu_create(machine->cpu_type));
cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
env = &cpu->env;
reset_info = g_malloc0(sizeof(ResetData));

View File

@ -90,6 +90,19 @@ extern const VMStateDescription vmstate_clock;
*/
void clock_setup_canonical_path(Clock *clk);
/**
* clock_new:
* @parent: the clock parent
* @name: the clock object name
*
* Helper function to create a new clock and parent it to @parent. There is no
* need to call clock_setup_canonical_path on the returned clock as it is done
* by this function.
*
* @return the newly created clock
*/
Clock *clock_new(Object *parent, const char *name);
/**
* clock_set_callback:
* @clk: the clock to register the callback into

View File

@ -21,6 +21,7 @@
#define MIPS_CPS_H
#include "hw/sysbus.h"
#include "hw/clock.h"
#include "hw/misc/mips_cmgcr.h"
#include "hw/intc/mips_gic.h"
#include "hw/misc/mips_cpc.h"
@ -43,6 +44,7 @@ struct MIPSCPSState {
MIPSGICState gic;
MIPSCPCState cpc;
MIPSITUState itu;
Clock *clock;
};
qemu_irq get_cps_irq(MIPSCPSState *cps, int pin_number);

View File

@ -2,8 +2,10 @@
#define HW_MIPS_H
/* Definitions for mips board emulation. */
#include "qemu/units.h"
/* Kernels can be configured with 64KB pages */
#define INITRD_PAGE_MASK (~((1 << 16) - 1))
#define INITRD_PAGE_SIZE (64 * KiB)
#include "exec/memory.h"

View File

@ -158,6 +158,18 @@ int qemu_strtosz_metric(const char *nptr, const char **end, uint64_t *result);
char *size_to_str(uint64_t val);
/**
* freq_to_str:
* @freq_hz: frequency to stringify
*
* Return human readable string for frequency @freq_hz.
* Use SI units like KHz, MHz, and so forth.
*
* The caller is responsible for releasing the value returned
* with g_free() after use.
*/
char *freq_to_str(uint64_t freq_hz);
/* used to print char* safely */
#define STR_OR_NULL(str) ((str) ? (str) : "null")

View File

@ -203,6 +203,31 @@ static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
*tcst |= asid;
}
/* XXX: do not use a global */
uint32_t cpu_mips_get_random(CPUMIPSState *env)
{
static uint32_t seed = 1;
static uint32_t prev_idx;
uint32_t idx;
uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
if (nb_rand_tlb == 1) {
return env->tlb->nb_tlb - 1;
}
/* Don't return same value twice, so get another value */
do {
/*
* Use a simple algorithm of Linear Congruential Generator
* from ISO/IEC 9899 standard.
*/
seed = 1103515245 * seed + 12345;
idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired;
} while (idx == prev_idx);
prev_idx = idx;
return idx;
}
/* CP0 helpers */
target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
{

View File

@ -27,43 +27,17 @@
#include "sysemu/kvm.h"
#include "internal.h"
#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
/* XXX: do not use a global */
uint32_t cpu_mips_get_random(CPUMIPSState *env)
{
static uint32_t seed = 1;
static uint32_t prev_idx = 0;
uint32_t idx;
uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
if (nb_rand_tlb == 1) {
return env->tlb->nb_tlb - 1;
}
/* Don't return same value twice, so get another value */
do {
/*
* Use a simple algorithm of Linear Congruential Generator
* from ISO/IEC 9899 standard.
*/
seed = 1103515245 * seed + 12345;
idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired;
} while (idx == prev_idx);
prev_idx = idx;
return idx;
}
/* MIPS R4K timer */
static void cpu_mips_timer_update(CPUMIPSState *env)
{
uint64_t now, next;
uint64_t now_ns, next_ns;
uint32_t wait;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
wait = env->CP0_Compare - env->CP0_Count - (uint32_t)(now / TIMER_PERIOD);
next = now + (uint64_t)wait * TIMER_PERIOD;
timer_mod(env->timer, next);
now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
wait = env->CP0_Compare - env->CP0_Count -
(uint32_t)(now_ns / env->cp0_count_ns);
next_ns = now_ns + (uint64_t)wait * env->cp0_count_ns;
timer_mod(env->timer, next_ns);
}
/* Expire the timer. */
@ -81,16 +55,16 @@ uint32_t cpu_mips_get_count(CPUMIPSState *env)
if (env->CP0_Cause & (1 << CP0Ca_DC)) {
return env->CP0_Count;
} else {
uint64_t now;
uint64_t now_ns;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (timer_pending(env->timer)
&& timer_expired(env->timer, now)) {
&& timer_expired(env->timer, now_ns)) {
/* The timer has already expired. */
cpu_mips_timer_expire(env);
}
return env->CP0_Count + (uint32_t)(now / TIMER_PERIOD);
return env->CP0_Count + (uint32_t)(now_ns / env->cp0_count_ns);
}
}
@ -106,7 +80,8 @@ void cpu_mips_store_count(CPUMIPSState *env, uint32_t count)
} else {
/* Store new count register */
env->CP0_Count = count -
(uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
(uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
env->cp0_count_ns);
/* Update timer timer */
cpu_mips_timer_update(env);
}
@ -133,7 +108,7 @@ void cpu_mips_stop_count(CPUMIPSState *env)
{
/* Store the current value */
env->CP0_Count += (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
TIMER_PERIOD);
env->cp0_count_ns);
}
static void mips_timer_cb(void *opaque)

View File

@ -19,14 +19,17 @@
*/
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "cpu.h"
#include "internal.h"
#include "kvm_mips.h"
#include "qemu/module.h"
#include "sysemu/kvm.h"
#include "sysemu/qtest.h"
#include "exec/exec-all.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-clock.h"
static void mips_cpu_set_pc(CPUState *cs, vaddr value)
{
@ -134,6 +137,21 @@ static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info)
}
}
/*
* Since commit 6af0bf9c7c3 this model assumes a CPU clocked at 200MHz.
*/
#define CPU_FREQ_HZ_DEFAULT 200000000
#define CP0_COUNT_RATE_DEFAULT 2
static void mips_cp0_period_set(MIPSCPU *cpu)
{
CPUMIPSState *env = &cpu->env;
env->cp0_count_ns = cpu->cp0_count_rate
* clock_get_ns(MIPS_CPU(cpu)->clock);
assert(env->cp0_count_ns);
}
static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
@ -141,6 +159,20 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev);
Error *local_err = NULL;
if (!clock_get(cpu->clock)) {
#ifndef CONFIG_USER_ONLY
if (!qtest_enabled()) {
g_autofree char *cpu_freq_str = freq_to_str(CPU_FREQ_HZ_DEFAULT);
warn_report("CPU input clock is not connected to any output clock, "
"using default frequency of %s.", cpu_freq_str);
}
#endif
/* Initialize the frequency in case the clock remains unconnected. */
clock_set_hz(cpu->clock, CPU_FREQ_HZ_DEFAULT);
}
mips_cp0_period_set(cpu);
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
@ -162,6 +194,7 @@ static void mips_cpu_initfn(Object *obj)
MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj);
cpu_set_cpustate_pointers(cpu);
cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu);
env->cpu_model = mcc->cpu_def;
}
@ -181,6 +214,13 @@ static ObjectClass *mips_cpu_class_by_name(const char *cpu_model)
return oc;
}
static Property mips_cpu_properties[] = {
/* CP0 timer running at half the clock of the CPU */
DEFINE_PROP_UINT32("cp0-count-rate", MIPSCPU, cp0_count_rate,
CP0_COUNT_RATE_DEFAULT),
DEFINE_PROP_END_OF_LIST()
};
static void mips_cpu_class_init(ObjectClass *c, void *data)
{
MIPSCPUClass *mcc = MIPS_CPU_CLASS(c);
@ -190,6 +230,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
device_class_set_parent_realize(dc, mips_cpu_realizefn,
&mcc->parent_realize);
device_class_set_parent_reset(dc, mips_cpu_reset, &mcc->parent_reset);
device_class_set_props(dc, mips_cpu_properties);
cc->class_by_name = mips_cpu_class_by_name;
cc->has_work = mips_cpu_has_work;
@ -257,3 +298,15 @@ static void mips_cpu_register_types(void)
}
type_init(mips_cpu_register_types)
/* Could be used by generic CPU object */
MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk)
{
DeviceState *cpu;
cpu = DEVICE(object_new(cpu_type));
qdev_connect_clock_in(cpu, "clk-in", cpu_refclk);
qdev_realize(cpu, NULL, &error_abort);
return MIPS_CPU(cpu);
}

View File

@ -4,6 +4,7 @@
#include "cpu-qom.h"
#include "exec/cpu-defs.h"
#include "fpu/softfloat-types.h"
#include "hw/clock.h"
#include "mips-defs.h"
#define TCG_GUEST_DEFAULT_MO (0)
@ -1145,11 +1146,15 @@ struct CPUMIPSState {
struct MIPSITUState *itu;
MemoryRegion *itc_tag; /* ITC Configuration Tags */
target_ulong exception_base; /* ExceptionBase input to the core */
uint64_t cp0_count_ns; /* CP0_Count clock period (in nanoseconds) */
};
/**
* MIPSCPU:
* @env: #CPUMIPSState
* @clock: this CPU input clock (may be connected
* to an output clock from another device).
* @cp0_count_rate: rate at which the coprocessor 0 counter increments
*
* A MIPS CPU.
*/
@ -1158,8 +1163,17 @@ struct MIPSCPU {
CPUState parent_obj;
/*< public >*/
Clock *clock;
CPUNegativeOffsetState neg;
CPUMIPSState env;
/*
* The Count register acts as a timer, incrementing at a constant rate,
* whether or not an instruction is executed, retired, or any forward
* progress is made through the pipeline. The rate at which the counter
* increments is implementation dependent, and is a function of the
* pipeline clock of the processor, not the issue width of the processor.
*/
unsigned cp0_count_rate;
};
@ -1293,4 +1307,16 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
MIPS_HFLAG_HWRENA_ULR);
}
/**
* mips_cpu_create_with_clock:
* @typename: a MIPS CPU type.
* @cpu_refclk: this cpu input clock (an output clock of another device)
*
* Instantiates a MIPS CPU, set the input clock of the CPU to @cpu_refclk,
* then realizes the CPU.
*
* Returns: A #CPUState or %NULL if an error occurred.
*/
MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk);
#endif /* MIPS_CPU_H */

View File

@ -983,27 +983,46 @@ uint32_t helper_float_floor_2008_w_s(CPUMIPSState *env, uint32_t fst0)
}
/* unary operations, not modifying fp status */
#define FLOAT_UNOP(name) \
uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
{ \
return float64_ ## name(fdt0); \
} \
uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
{ \
return float32_ ## name(fst0); \
} \
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
{ \
uint32_t wt0; \
uint32_t wth0; \
\
wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
wth0 = float32_ ## name(fdt0 >> 32); \
return ((uint64_t)wth0 << 32) | wt0; \
uint64_t helper_float_abs_d(uint64_t fdt0)
{
return float64_abs(fdt0);
}
uint32_t helper_float_abs_s(uint32_t fst0)
{
return float32_abs(fst0);
}
uint64_t helper_float_abs_ps(uint64_t fdt0)
{
uint32_t wt0;
uint32_t wth0;
wt0 = float32_abs(fdt0 & 0XFFFFFFFF);
wth0 = float32_abs(fdt0 >> 32);
return ((uint64_t)wth0 << 32) | wt0;
}
uint64_t helper_float_chs_d(uint64_t fdt0)
{
return float64_chs(fdt0);
}
uint32_t helper_float_chs_s(uint32_t fst0)
{
return float32_chs(fst0);
}
uint64_t helper_float_chs_ps(uint64_t fdt0)
{
uint32_t wt0;
uint32_t wth0;
wt0 = float32_chs(fdt0 & 0XFFFFFFFF);
wth0 = float32_chs(fdt0 >> 32);
return ((uint64_t)wth0 << 32) | wt0;
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
#undef FLOAT_UNOP
/* MIPS specific unary operations */
uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
@ -1456,29 +1475,87 @@ uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
return ((uint64_t)fsth2 << 32) | fstl2;
}
#define FLOAT_MINMAX(name, bits, minmaxfunc) \
uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \
uint ## bits ## _t fs, \
uint ## bits ## _t ft) \
{ \
uint ## bits ## _t fdret; \
\
fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \
&env->active_fpu.fp_status); \
update_fcr31(env, GETPC()); \
return fdret; \
uint32_t helper_float_max_s(CPUMIPSState *env, uint32_t fs, uint32_t ft)
{
uint32_t fdret;
fdret = float32_maxnum(fs, ft, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
FLOAT_MINMAX(max_s, 32, maxnum)
FLOAT_MINMAX(max_d, 64, maxnum)
FLOAT_MINMAX(maxa_s, 32, maxnummag)
FLOAT_MINMAX(maxa_d, 64, maxnummag)
uint64_t helper_float_max_d(CPUMIPSState *env, uint64_t fs, uint64_t ft)
{
uint64_t fdret;
fdret = float64_maxnum(fs, ft, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint32_t helper_float_maxa_s(CPUMIPSState *env, uint32_t fs, uint32_t ft)
{
uint32_t fdret;
fdret = float32_maxnummag(fs, ft, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint64_t helper_float_maxa_d(CPUMIPSState *env, uint64_t fs, uint64_t ft)
{
uint64_t fdret;
fdret = float64_maxnummag(fs, ft, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint32_t helper_float_min_s(CPUMIPSState *env, uint32_t fs, uint32_t ft)
{
uint32_t fdret;
fdret = float32_minnum(fs, ft, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint64_t helper_float_min_d(CPUMIPSState *env, uint64_t fs, uint64_t ft)
{
uint64_t fdret;
fdret = float64_minnum(fs, ft, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint32_t helper_float_mina_s(CPUMIPSState *env, uint32_t fs, uint32_t ft)
{
uint32_t fdret;
fdret = float32_minnummag(fs, ft, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint64_t helper_float_mina_d(CPUMIPSState *env, uint64_t fs, uint64_t ft)
{
uint64_t fdret;
fdret = float64_minnummag(fs, ft, &env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
FLOAT_MINMAX(min_s, 32, minnum)
FLOAT_MINMAX(min_d, 64, minnum)
FLOAT_MINMAX(mina_s, 32, minnummag)
FLOAT_MINMAX(mina_d, 64, minnummag)
#undef FLOAT_MINMAX
/* ternary operations */
@ -1647,25 +1724,54 @@ uint64_t helper_float_nmsub_ps(CPUMIPSState *env, uint64_t fdt0,
}
#define FLOAT_FMADDSUB(name, bits, muladd_arg) \
uint ## bits ## _t helper_float_ ## name(CPUMIPSState *env, \
uint ## bits ## _t fs, \
uint ## bits ## _t ft, \
uint ## bits ## _t fd) \
{ \
uint ## bits ## _t fdret; \
\
fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \
&env->active_fpu.fp_status); \
update_fcr31(env, GETPC()); \
return fdret; \
uint32_t helper_float_maddf_s(CPUMIPSState *env, uint32_t fs,
uint32_t ft, uint32_t fd)
{
uint32_t fdret;
fdret = float32_muladd(fs, ft, fd, 0,
&env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint64_t helper_float_maddf_d(CPUMIPSState *env, uint64_t fs,
uint64_t ft, uint64_t fd)
{
uint64_t fdret;
fdret = float64_muladd(fs, ft, fd, 0,
&env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint32_t helper_float_msubf_s(CPUMIPSState *env, uint32_t fs,
uint32_t ft, uint32_t fd)
{
uint32_t fdret;
fdret = float32_muladd(fs, ft, fd, float_muladd_negate_product,
&env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
uint64_t helper_float_msubf_d(CPUMIPSState *env, uint64_t fs,
uint64_t ft, uint64_t fd)
{
uint64_t fdret;
fdret = float64_muladd(fs, ft, fd, float_muladd_negate_product,
&env->active_fpu.fp_status);
update_fcr31(env, GETPC());
return fdret;
}
FLOAT_FMADDSUB(maddf_s, 32, 0)
FLOAT_FMADDSUB(maddf_d, 64, 0)
FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
#undef FLOAT_FMADDSUB
/* compare operations */
#define FOP_COND_D(op, cond) \

View File

@ -144,6 +144,7 @@ void r4k_helper_tlbr(CPUMIPSState *env);
void r4k_helper_tlbinv(CPUMIPSState *env);
void r4k_helper_tlbinvf(CPUMIPSState *env);
void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra);
uint32_t cpu_mips_get_random(CPUMIPSState *env);
void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
vaddr addr, unsigned size,
@ -188,7 +189,7 @@ static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
/*
* A MIPS configured with a vectorizing external interrupt controller
* will feed a vector into the Cause pending lines. The core treats
* the status lines as a vector level, not as indiviual masks.
* the status lines as a vector level, not as individual masks.
*/
r = pending > status;
} else {
@ -209,7 +210,6 @@ void cpu_state_reset(CPUMIPSState *s);
void cpu_mips_realize_env(CPUMIPSState *env);
/* cp0_timer.c */
uint32_t cpu_mips_get_random(CPUMIPSState *env);
uint32_t cpu_mips_get_count(CPUMIPSState *env);
void cpu_mips_store_count(CPUMIPSState *env, uint32_t value);
void cpu_mips_store_compare(CPUMIPSState *env, uint32_t value);

View File

@ -1574,15 +1574,34 @@ void helper_msa_st_d(CPUMIPSState *env, uint32_t wd,
void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
{
#ifndef CONFIG_USER_ONLY
static const char *const type_name[] = {
"Primary Instruction",
"Primary Data or Unified Primary",
"Tertiary",
"Secondary"
};
uint32_t cache_type = extract32(op, 0, 2);
uint32_t cache_operation = extract32(op, 2, 3);
target_ulong index = addr & 0x1fffffff;
if (op == 9) {
/* Index Store Tag */
switch (cache_operation) {
case 0b010: /* Index Store Tag */
memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
MO_64, MEMTXATTRS_UNSPECIFIED);
} else if (op == 5) {
/* Index Load Tag */
break;
case 0b001: /* Index Load Tag */
memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
MO_64, MEMTXATTRS_UNSPECIFIED);
break;
case 0b000: /* Index Invalidate */
case 0b100: /* Hit Invalidate */
case 0b110: /* Hit Writeback */
/* no-op */
break;
default:
qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n",
cache_operation, type_name[cache_type]);
break;
}
#endif
}

View File

@ -460,6 +460,48 @@ enum {
R6_OPC_SCD = 0x27 | OPC_SPECIAL3,
};
/* Loongson EXT load/store quad word opcodes */
#define MASK_LOONGSON_GSLSQ(op) (MASK_OP_MAJOR(op) | (op & 0x8020))
enum {
OPC_GSLQ = 0x0020 | OPC_LWC2,
OPC_GSLQC1 = 0x8020 | OPC_LWC2,
OPC_GSSHFL = OPC_LWC2,
OPC_GSSQ = 0x0020 | OPC_SWC2,
OPC_GSSQC1 = 0x8020 | OPC_SWC2,
OPC_GSSHFS = OPC_SWC2,
};
/* Loongson EXT shifted load/store opcodes */
#define MASK_LOONGSON_GSSHFLS(op) (MASK_OP_MAJOR(op) | (op & 0xc03f))
enum {
OPC_GSLWLC1 = 0x4 | OPC_GSSHFL,
OPC_GSLWRC1 = 0x5 | OPC_GSSHFL,
OPC_GSLDLC1 = 0x6 | OPC_GSSHFL,
OPC_GSLDRC1 = 0x7 | OPC_GSSHFL,
OPC_GSSWLC1 = 0x4 | OPC_GSSHFS,
OPC_GSSWRC1 = 0x5 | OPC_GSSHFS,
OPC_GSSDLC1 = 0x6 | OPC_GSSHFS,
OPC_GSSDRC1 = 0x7 | OPC_GSSHFS,
};
/* Loongson EXT LDC2/SDC2 opcodes */
#define MASK_LOONGSON_LSDC2(op) (MASK_OP_MAJOR(op) | (op & 0x7))
enum {
OPC_GSLBX = 0x0 | OPC_LDC2,
OPC_GSLHX = 0x1 | OPC_LDC2,
OPC_GSLWX = 0x2 | OPC_LDC2,
OPC_GSLDX = 0x3 | OPC_LDC2,
OPC_GSLWXC1 = 0x6 | OPC_LDC2,
OPC_GSLDXC1 = 0x7 | OPC_LDC2,
OPC_GSSBX = 0x0 | OPC_SDC2,
OPC_GSSHX = 0x1 | OPC_SDC2,
OPC_GSSWX = 0x2 | OPC_SDC2,
OPC_GSSDX = 0x3 | OPC_SDC2,
OPC_GSSWXC1 = 0x6 | OPC_SDC2,
OPC_GSSDXC1 = 0x7 | OPC_SDC2,
};
/* BSHFL opcodes */
#define MASK_BSHFL(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
@ -3718,7 +3760,7 @@ static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset,
t0 = tcg_temp_new();
addr = tcg_temp_new();
/* compare the address against that of the preceeding LL */
/* compare the address against that of the preceding LL */
gen_base_offset_addr(ctx, addr, base, offset);
tcg_gen_brcond_tl(TCG_COND_EQ, addr, cpu_lladdr, l1);
tcg_temp_free(addr);
@ -5910,6 +5952,403 @@ no_rd:
tcg_temp_free_i64(t1);
}
static void gen_loongson_lswc2(DisasContext *ctx, int rt,
int rs, int rd)
{
TCGv t0, t1, t2;
TCGv_i32 fp0;
#if defined(TARGET_MIPS64)
int lsq_rt1 = ctx->opcode & 0x1f;
int lsq_offset = sextract32(ctx->opcode, 6, 9) << 4;
#endif
int shf_offset = sextract32(ctx->opcode, 6, 8);
t0 = tcg_temp_new();
switch (MASK_LOONGSON_GSLSQ(ctx->opcode)) {
#if defined(TARGET_MIPS64)
case OPC_GSLQ:
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
gen_store_gpr(t1, rt);
gen_store_gpr(t0, lsq_rt1);
tcg_temp_free(t1);
break;
case OPC_GSLQC1:
check_cp1_enabled(ctx);
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
gen_store_fpr64(ctx, t1, rt);
gen_store_fpr64(ctx, t0, lsq_rt1);
tcg_temp_free(t1);
break;
case OPC_GSSQ:
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
gen_load_gpr(t1, rt);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
gen_load_gpr(t1, lsq_rt1);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
tcg_temp_free(t1);
break;
case OPC_GSSQC1:
check_cp1_enabled(ctx);
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
gen_load_fpr64(ctx, t1, rt);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
gen_load_fpr64(ctx, t1, lsq_rt1);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
tcg_temp_free(t1);
break;
#endif
case OPC_GSSHFL:
switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
case OPC_GSLWLC1:
check_cp1_enabled(ctx);
gen_base_offset_addr(ctx, t0, rs, shf_offset);
t1 = tcg_temp_new();
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
tcg_gen_andi_tl(t1, t0, 3);
#ifndef TARGET_WORDS_BIGENDIAN
tcg_gen_xori_tl(t1, t1, 3);
#endif
tcg_gen_shli_tl(t1, t1, 3);
tcg_gen_andi_tl(t0, t0, ~3);
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
tcg_gen_shl_tl(t0, t0, t1);
t2 = tcg_const_tl(-1);
tcg_gen_shl_tl(t2, t2, t1);
fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, rt);
tcg_gen_ext_i32_tl(t1, fp0);
tcg_gen_andc_tl(t1, t1, t2);
tcg_temp_free(t2);
tcg_gen_or_tl(t0, t0, t1);
tcg_temp_free(t1);
#if defined(TARGET_MIPS64)
tcg_gen_extrl_i64_i32(fp0, t0);
#else
tcg_gen_ext32s_tl(fp0, t0);
#endif
gen_store_fpr32(ctx, fp0, rt);
tcg_temp_free_i32(fp0);
break;
case OPC_GSLWRC1:
check_cp1_enabled(ctx);
gen_base_offset_addr(ctx, t0, rs, shf_offset);
t1 = tcg_temp_new();
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
tcg_gen_andi_tl(t1, t0, 3);
#ifdef TARGET_WORDS_BIGENDIAN
tcg_gen_xori_tl(t1, t1, 3);
#endif
tcg_gen_shli_tl(t1, t1, 3);
tcg_gen_andi_tl(t0, t0, ~3);
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
tcg_gen_shr_tl(t0, t0, t1);
tcg_gen_xori_tl(t1, t1, 31);
t2 = tcg_const_tl(0xfffffffeull);
tcg_gen_shl_tl(t2, t2, t1);
fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, rt);
tcg_gen_ext_i32_tl(t1, fp0);
tcg_gen_and_tl(t1, t1, t2);
tcg_temp_free(t2);
tcg_gen_or_tl(t0, t0, t1);
tcg_temp_free(t1);
#if defined(TARGET_MIPS64)
tcg_gen_extrl_i64_i32(fp0, t0);
#else
tcg_gen_ext32s_tl(fp0, t0);
#endif
gen_store_fpr32(ctx, fp0, rt);
tcg_temp_free_i32(fp0);
break;
#if defined(TARGET_MIPS64)
case OPC_GSLDLC1:
check_cp1_enabled(ctx);
gen_base_offset_addr(ctx, t0, rs, shf_offset);
t1 = tcg_temp_new();
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
tcg_gen_andi_tl(t1, t0, 7);
#ifndef TARGET_WORDS_BIGENDIAN
tcg_gen_xori_tl(t1, t1, 7);
#endif
tcg_gen_shli_tl(t1, t1, 3);
tcg_gen_andi_tl(t0, t0, ~7);
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
tcg_gen_shl_tl(t0, t0, t1);
t2 = tcg_const_tl(-1);
tcg_gen_shl_tl(t2, t2, t1);
gen_load_fpr64(ctx, t1, rt);
tcg_gen_andc_tl(t1, t1, t2);
tcg_temp_free(t2);
tcg_gen_or_tl(t0, t0, t1);
tcg_temp_free(t1);
gen_store_fpr64(ctx, t0, rt);
break;
case OPC_GSLDRC1:
check_cp1_enabled(ctx);
gen_base_offset_addr(ctx, t0, rs, shf_offset);
t1 = tcg_temp_new();
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
tcg_gen_andi_tl(t1, t0, 7);
#ifdef TARGET_WORDS_BIGENDIAN
tcg_gen_xori_tl(t1, t1, 7);
#endif
tcg_gen_shli_tl(t1, t1, 3);
tcg_gen_andi_tl(t0, t0, ~7);
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
tcg_gen_shr_tl(t0, t0, t1);
tcg_gen_xori_tl(t1, t1, 63);
t2 = tcg_const_tl(0xfffffffffffffffeull);
tcg_gen_shl_tl(t2, t2, t1);
gen_load_fpr64(ctx, t1, rt);
tcg_gen_and_tl(t1, t1, t2);
tcg_temp_free(t2);
tcg_gen_or_tl(t0, t0, t1);
tcg_temp_free(t1);
gen_store_fpr64(ctx, t0, rt);
break;
#endif
default:
MIPS_INVAL("loongson_gsshfl");
generate_exception_end(ctx, EXCP_RI);
break;
}
break;
case OPC_GSSHFS:
switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
case OPC_GSSWLC1:
check_cp1_enabled(ctx);
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, shf_offset);
fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, rt);
tcg_gen_ext_i32_tl(t1, fp0);
gen_helper_0e2i(swl, t1, t0, ctx->mem_idx);
tcg_temp_free_i32(fp0);
tcg_temp_free(t1);
break;
case OPC_GSSWRC1:
check_cp1_enabled(ctx);
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, shf_offset);
fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, rt);
tcg_gen_ext_i32_tl(t1, fp0);
gen_helper_0e2i(swr, t1, t0, ctx->mem_idx);
tcg_temp_free_i32(fp0);
tcg_temp_free(t1);
break;
#if defined(TARGET_MIPS64)
case OPC_GSSDLC1:
check_cp1_enabled(ctx);
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, shf_offset);
gen_load_fpr64(ctx, t1, rt);
gen_helper_0e2i(sdl, t1, t0, ctx->mem_idx);
tcg_temp_free(t1);
break;
case OPC_GSSDRC1:
check_cp1_enabled(ctx);
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, shf_offset);
gen_load_fpr64(ctx, t1, rt);
gen_helper_0e2i(sdr, t1, t0, ctx->mem_idx);
tcg_temp_free(t1);
break;
#endif
default:
MIPS_INVAL("loongson_gsshfs");
generate_exception_end(ctx, EXCP_RI);
break;
}
break;
default:
MIPS_INVAL("loongson_gslsq");
generate_exception_end(ctx, EXCP_RI);
break;
}
tcg_temp_free(t0);
}
/* Loongson EXT LDC2/SDC2 */
static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
int rs, int rd)
{
int offset = sextract32(ctx->opcode, 3, 8);
uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
TCGv t0, t1;
TCGv_i32 fp0;
/* Pre-conditions */
switch (opc) {
case OPC_GSLBX:
case OPC_GSLHX:
case OPC_GSLWX:
case OPC_GSLDX:
/* prefetch, implement as NOP */
if (rt == 0) {
return;
}
break;
case OPC_GSSBX:
case OPC_GSSHX:
case OPC_GSSWX:
case OPC_GSSDX:
break;
case OPC_GSLWXC1:
#if defined(TARGET_MIPS64)
case OPC_GSLDXC1:
#endif
check_cp1_enabled(ctx);
/* prefetch, implement as NOP */
if (rt == 0) {
return;
}
break;
case OPC_GSSWXC1:
#if defined(TARGET_MIPS64)
case OPC_GSSDXC1:
#endif
check_cp1_enabled(ctx);
break;
default:
MIPS_INVAL("loongson_lsdc2");
generate_exception_end(ctx, EXCP_RI);
return;
break;
}
t0 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, offset);
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
switch (opc) {
case OPC_GSLBX:
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
gen_store_gpr(t0, rt);
break;
case OPC_GSLHX:
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
case OPC_GSLWX:
gen_base_offset_addr(ctx, t0, rs, offset);
if (rd) {
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
}
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
#if defined(TARGET_MIPS64)
case OPC_GSLDX:
gen_base_offset_addr(ctx, t0, rs, offset);
if (rd) {
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
}
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
#endif
case OPC_GSLWXC1:
check_cp1_enabled(ctx);
gen_base_offset_addr(ctx, t0, rs, offset);
if (rd) {
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
}
fp0 = tcg_temp_new_i32();
tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL |
ctx->default_tcg_memop_mask);
gen_store_fpr32(ctx, fp0, rt);
tcg_temp_free_i32(fp0);
break;
#if defined(TARGET_MIPS64)
case OPC_GSLDXC1:
check_cp1_enabled(ctx);
gen_base_offset_addr(ctx, t0, rs, offset);
if (rd) {
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
}
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
gen_store_fpr64(ctx, t0, rt);
break;
#endif
case OPC_GSSBX:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_SB);
tcg_temp_free(t1);
break;
case OPC_GSSHX:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
ctx->default_tcg_memop_mask);
tcg_temp_free(t1);
break;
case OPC_GSSWX:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
ctx->default_tcg_memop_mask);
tcg_temp_free(t1);
break;
#if defined(TARGET_MIPS64)
case OPC_GSSDX:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
tcg_temp_free(t1);
break;
#endif
case OPC_GSSWXC1:
fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, rt);
tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL |
ctx->default_tcg_memop_mask);
tcg_temp_free_i32(fp0);
break;
#if defined(TARGET_MIPS64)
case OPC_GSSDXC1:
t1 = tcg_temp_new();
gen_load_fpr64(ctx, t1, rt);
tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEQ |
ctx->default_tcg_memop_mask);
tcg_temp_free(t1);
break;
#endif
default:
break;
}
tcg_temp_free(t0);
}
/* Traps */
static void gen_trap(DisasContext *ctx, uint32_t opc,
int rs, int rt, int16_t imm)
@ -25597,7 +26036,7 @@ static void gen_mxu_D16MAX_D16MIN(DisasContext *ctx)
}
/* return resulting half-words to its original position */
tcg_gen_shri_i32(t0, t0, 16);
/* finaly update the destination */
/* finally update the destination */
tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
tcg_temp_free(t1);
@ -25633,7 +26072,7 @@ static void gen_mxu_D16MAX_D16MIN(DisasContext *ctx)
}
/* return resulting half-words to its original position */
tcg_gen_shri_i32(t0, t0, 16);
/* finaly update the destination */
/* finally update the destination */
tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
tcg_temp_free(t1);
@ -25702,7 +26141,7 @@ static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx)
}
/* return resulting byte to its original position */
tcg_gen_shri_i32(t0, t0, 8 * (3 - i));
/* finaly update the destination */
/* finally update the destination */
tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
}
@ -25742,7 +26181,7 @@ static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx)
}
/* return resulting byte to its original position */
tcg_gen_shri_i32(t0, t0, 8 * (3 - i));
/* finaly update the destination */
/* finally update the destination */
tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
}
@ -30774,6 +31213,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
/* OPC_BC, OPC_BALC */
gen_compute_compact_branch(ctx, op, 0, 0,
sextract32(ctx->opcode << 2, 0, 28));
} else if (ctx->insn_flags & ASE_LEXT) {
gen_loongson_lswc2(ctx, rt, rs, rd);
} else {
/* OPC_LWC2, OPC_SWC2 */
/* COP2: Not implemented. */
@ -30791,6 +31232,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
/* OPC_JIC, OPC_JIALC */
gen_compute_compact_branch(ctx, op, 0, rt, imm);
}
} else if (ctx->insn_flags & ASE_LEXT) {
gen_loongson_lsdc2(ctx, rt, rs, rd);
} else {
/* OPC_LWC2, OPC_SWC2 */
/* COP2: Not implemented. */

View File

@ -254,7 +254,7 @@ const mips_def_t mips_defs[] =
.CP0_PRid = 0x00019500,
.CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) |
(MMU_TYPE_R4000 << CP0C0_MT),
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
.CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
(0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
(0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) |
(1 << CP0C1_CA),
@ -995,7 +995,7 @@ static void mvp_init (CPUMIPSState *env, const mips_def_t *def)
/* MVPConf1 implemented, TLB sharable, no gating storage support,
programmable cache partitioning implemented, number of allocatable
and sharable TLB entries, MVP has allocatable TCs, 2 VPEs
and shareable TLB entries, MVP has allocatable TCs, 2 VPEs
implemented, 5 TCs implemented. */
env->mvp->CP0_MVPConf0 = (1U << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) |
(0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) |

View File

@ -9,6 +9,8 @@
# later. See the COPYING file in the top-level directory.
import os
import lzma
import shutil
import logging
import time
@ -19,7 +21,7 @@ from avocado.utils import archive
from avocado.utils import process
from boot_linux_console import LinuxKernelTest
class ReplayKernel(LinuxKernelTest):
class ReplayKernelBase(LinuxKernelTest):
"""
Boots a Linux kernel in record mode and checks that the console
is operational and the kernel command line is properly passed
@ -74,6 +76,7 @@ class ReplayKernel(LinuxKernelTest):
logger = logging.getLogger('replay')
logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
class ReplayKernelNormal(ReplayKernelBase):
@skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
def test_x86_64_pc(self):
"""
@ -91,6 +94,51 @@ class ReplayKernel(LinuxKernelTest):
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
def test_mips_malta(self):
"""
:avocado: tags=arch:mips
:avocado: tags=machine:malta
:avocado: tags=endian:big
"""
deb_url = ('http://snapshot.debian.org/archive/debian/'
'20130217T032700Z/pool/main/l/linux-2.6/'
'linux-image-2.6.32-5-4kc-malta_2.6.32-48_mips.deb')
deb_hash = 'a8cfc28ad8f45f54811fc6cf74fc43ffcfe0ba04'
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
kernel_path = self.extract_from_deb(deb_path,
'/boot/vmlinux-2.6.32-5-4kc-malta')
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
def test_mips64el_malta(self):
"""
This test requires the ar tool to extract "data.tar.gz" from
the Debian package.
The kernel can be rebuilt using this Debian kernel source [1] and
following the instructions on [2].
[1] http://snapshot.debian.org/package/linux-2.6/2.6.32-48/
#linux-source-2.6.32_2.6.32-48
[2] https://kernel-team.pages.debian.net/kernel-handbook/
ch-common-tasks.html#s-common-official
:avocado: tags=arch:mips64el
:avocado: tags=machine:malta
"""
deb_url = ('http://snapshot.debian.org/archive/debian/'
'20130217T032700Z/pool/main/l/linux-2.6/'
'linux-image-2.6.32-5-5kc-malta_2.6.32-48_mipsel.deb')
deb_hash = '1aaec92083bf22fda31e0d27fa8d9a388e5fc3d5'
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
kernel_path = self.extract_from_deb(deb_path,
'/boot/vmlinux-2.6.32-5-5kc-malta')
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
def test_aarch64_virt(self):
"""
:avocado: tags=arch:aarch64
@ -302,3 +350,120 @@ class ReplayKernel(LinuxKernelTest):
file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
self.do_test_advcal_2018(file_path, 'santas-sleigh-ride.elf',
args=('-cpu', 'dc233c'))
@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
class ReplayKernelSlow(ReplayKernelBase):
# Override the timeout, because this kernel includes an inner
# loop which is executed with TB recompilings during replay,
# making it very slow.
timeout = 180
def test_mips_malta_cpio(self):
"""
:avocado: tags=arch:mips
:avocado: tags=machine:malta
:avocado: tags=endian:big
:avocado: tags=slowness:high
"""
deb_url = ('http://snapshot.debian.org/archive/debian/'
'20160601T041800Z/pool/main/l/linux/'
'linux-image-4.5.0-2-4kc-malta_4.5.5-1_mips.deb')
deb_hash = 'a3c84f3e88b54e06107d65a410d1d1e8e0f340f8'
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
kernel_path = self.extract_from_deb(deb_path,
'/boot/vmlinux-4.5.0-2-4kc-malta')
initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
'8584a59ed9e5eb5ee7ca91f6d74bbb06619205b8/rootfs/'
'mips/rootfs.cpio.gz')
initrd_hash = 'bf806e17009360a866bf537f6de66590de349a99'
initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
initrd_path = self.workdir + "rootfs.cpio"
archive.gzip_uncompress(initrd_path_gz, initrd_path)
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyS0 console=tty '
'rdinit=/sbin/init noreboot')
console_pattern = 'Boot successful.'
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5,
args=('-initrd', initrd_path))
@skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
def test_mips64el_malta_5KEc_cpio(self):
"""
:avocado: tags=arch:mips64el
:avocado: tags=machine:malta
:avocado: tags=endian:little
:avocado: tags=slowness:high
"""
kernel_url = ('https://github.com/philmd/qemu-testing-blob/'
'raw/9ad2df38/mips/malta/mips64el/'
'vmlinux-3.19.3.mtoman.20150408')
kernel_hash = '00d1d268fb9f7d8beda1de6bebcc46e884d71754'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
initrd_url = ('https://github.com/groeck/linux-build-test/'
'raw/8584a59e/rootfs/'
'mipsel64/rootfs.mipsel64r1.cpio.gz')
initrd_hash = '1dbb8a396e916847325284dbe2151167'
initrd_path_gz = self.fetch_asset(initrd_url, algorithm='md5',
asset_hash=initrd_hash)
initrd_path = self.workdir + "rootfs.cpio"
archive.gzip_uncompress(initrd_path_gz, initrd_path)
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyS0 console=tty '
'rdinit=/sbin/init noreboot')
console_pattern = 'Boot successful.'
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5,
args=('-initrd', initrd_path, '-cpu', '5KEc'))
def do_test_mips_malta32el_nanomips(self, kernel_path_xz):
kernel_path = self.workdir + "kernel"
with lzma.open(kernel_path_xz, 'rb') as f_in:
with open(kernel_path, 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'mem=256m@@0x0 '
'console=ttyS0')
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5,
args=('-cpu', 'I7200'))
def test_mips_malta32el_nanomips_4k(self):
"""
:avocado: tags=arch:mipsel
:avocado: tags=machine:malta
:avocado: tags=endian:little
"""
kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/'
'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
'generic_nano32r6el_page4k.xz')
kernel_hash = '477456aafd2a0f1ddc9482727f20fe9575565dd6'
kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
self.do_test_mips_malta32el_nanomips(kernel_path_xz)
def test_mips_malta32el_nanomips_16k_up(self):
"""
:avocado: tags=arch:mipsel
:avocado: tags=machine:malta
:avocado: tags=endian:little
"""
kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/'
'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
'generic_nano32r6el_page16k_up.xz')
kernel_hash = 'e882868f944c71c816e832e2303b7874d044a7bc'
kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
self.do_test_mips_malta32el_nanomips(kernel_path_xz)
def test_mips_malta32el_nanomips_64k_dbg(self):
"""
:avocado: tags=arch:mipsel
:avocado: tags=machine:malta
:avocado: tags=endian:little
"""
kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/'
'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
'generic_nano32r6el_page64k_dbg.xz')
kernel_hash = '18d1c68f2e23429e266ca39ba5349ccd0aeb7180'
kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
self.do_test_mips_malta32el_nanomips(kernel_path_xz)

View File

@ -885,6 +885,20 @@ char *size_to_str(uint64_t val)
return g_strdup_printf("%0.3g %sB", (double)val / div, suffixes[i]);
}
char *freq_to_str(uint64_t freq_hz)
{
static const char *const suffixes[] = { "", "K", "M", "G", "T", "P", "E" };
double freq = freq_hz;
size_t idx = 0;
while (freq >= 1000.0 && idx < ARRAY_SIZE(suffixes)) {
freq /= 1000.0;
idx++;
}
return g_strdup_printf("%0.3g %sHz", freq, suffixes[idx]);
}
int qemu_pstrcmp0(const char **str1, const char **str2)
{
return g_strcmp0(*str1, *str2);