mirror of https://github.com/xemu-project/xemu.git
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>
This commit is contained in:
commit
22d30b340a
25
MAINTAINERS
25
MAINTAINERS
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue