mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+9
-16
@@ -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;
|
||||
|
||||
+17
-4
@@ -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;
|
||||
|
||||
+10
-8
@@ -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);
|
||||
}
|
||||
|
||||
+17
-6
@@ -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);
|
||||
}
|
||||
|
||||
+34
-25
@@ -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)
|
||||
|
||||
+15
-15
@@ -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. */
|
||||
|
||||
+8
-8
@@ -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)
|
||||
{
|
||||
|
||||
+13
-38
@@ -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)
|
||||
|
||||
+54
-1
@@ -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 */
|
||||
|
||||
+163
-57
@@ -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) \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user