import
This commit is contained in:
2
qemu/hw/mips/Makefile.objs
Normal file
2
qemu/hw/mips/Makefile.objs
Normal file
@@ -0,0 +1,2 @@
|
||||
obj-y += mips_r4k.o
|
||||
obj-y += addr.o cputimer.o mips_int.o
|
||||
39
qemu/hw/mips/addr.c
Normal file
39
qemu/hw/mips/addr.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* QEMU MIPS address translation support
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/mips/cpudevs.h"
|
||||
|
||||
uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
|
||||
{
|
||||
return addr & 0x1fffffffll;
|
||||
}
|
||||
|
||||
uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr)
|
||||
{
|
||||
return addr | ~0x7fffffffll;
|
||||
}
|
||||
|
||||
uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr)
|
||||
{
|
||||
return addr | 0x40000000ll;
|
||||
}
|
||||
166
qemu/hw/mips/cputimer.c
Normal file
166
qemu/hw/mips/cputimer.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* QEMU MIPS timer support
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/mips/cpudevs.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
#define TIMER_FREQ 100 * 1000 * 1000
|
||||
|
||||
/* XXX: do not use a global */
|
||||
uint32_t cpu_mips_get_random (CPUMIPSState *env)
|
||||
{
|
||||
static uint32_t lfsr = 1;
|
||||
static uint32_t prev_idx = 0;
|
||||
uint32_t idx;
|
||||
/* Don't return same value twice, so get another value */
|
||||
do {
|
||||
lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
|
||||
idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
|
||||
} while (idx == prev_idx);
|
||||
prev_idx = idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* MIPS R4K timer */
|
||||
static void cpu_mips_timer_update(CPUMIPSState *env)
|
||||
{
|
||||
#if 0
|
||||
uint64_t now, next;
|
||||
uint32_t wait;
|
||||
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
wait = env->CP0_Compare - env->CP0_Count -
|
||||
(uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
|
||||
next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
|
||||
timer_mod(env->timer, next);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Expire the timer. */
|
||||
static void cpu_mips_timer_expire(CPUMIPSState *env)
|
||||
{
|
||||
cpu_mips_timer_update(env);
|
||||
if (env->insn_flags & ISA_MIPS32R2) {
|
||||
env->CP0_Cause |= 1 << CP0Ca_TI;
|
||||
}
|
||||
//qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t cpu_mips_get_count (CPUMIPSState *env)
|
||||
{
|
||||
if (env->CP0_Cause & (1 << CP0Ca_DC)) {
|
||||
return env->CP0_Count;
|
||||
} else {
|
||||
uint64_t now;
|
||||
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
//if (timer_pending(env->timer)
|
||||
// && timer_expired(env->timer, now)) {
|
||||
// /* The timer has already expired. */
|
||||
// cpu_mips_timer_expire(env);
|
||||
//}
|
||||
|
||||
return env->CP0_Count +
|
||||
(uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_mips_store_count (CPUMIPSState *env, uint32_t count)
|
||||
{
|
||||
#if 0
|
||||
/*
|
||||
* This gets called from cpu_state_reset(), potentially before timer init.
|
||||
* So env->timer may be NULL, which is also the case with KVM enabled so
|
||||
* treat timer as disabled in that case.
|
||||
*/
|
||||
if (env->CP0_Cause & (1 << CP0Ca_DC) || !env->timer)
|
||||
env->CP0_Count = count;
|
||||
else {
|
||||
/* Store new count register */
|
||||
env->CP0_Count =
|
||||
count - (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||
TIMER_FREQ, get_ticks_per_sec());
|
||||
/* Update timer timer */
|
||||
cpu_mips_timer_update(env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value)
|
||||
{
|
||||
env->CP0_Compare = value;
|
||||
if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
|
||||
cpu_mips_timer_update(env);
|
||||
if (env->insn_flags & ISA_MIPS32R2)
|
||||
env->CP0_Cause &= ~(1 << CP0Ca_TI);
|
||||
//qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
|
||||
}
|
||||
|
||||
void cpu_mips_start_count(CPUMIPSState *env)
|
||||
{
|
||||
cpu_mips_store_count(env, env->CP0_Count);
|
||||
}
|
||||
|
||||
void cpu_mips_stop_count(CPUMIPSState *env)
|
||||
{
|
||||
/* Store the current value */
|
||||
env->CP0_Count += (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
|
||||
TIMER_FREQ, get_ticks_per_sec());
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void mips_timer_cb (void *opaque)
|
||||
{
|
||||
CPUMIPSState *env;
|
||||
|
||||
env = opaque;
|
||||
#if 0
|
||||
qemu_log("%s\n", __func__);
|
||||
#endif
|
||||
|
||||
if (env->CP0_Cause & (1 << CP0Ca_DC))
|
||||
return;
|
||||
|
||||
/* ??? This callback should occur when the counter is exactly equal to
|
||||
the comparator value. Offset the count by one to avoid immediately
|
||||
retriggering the callback before any virtual time has passed. */
|
||||
env->CP0_Count++;
|
||||
cpu_mips_timer_expire(env);
|
||||
env->CP0_Count--;
|
||||
}
|
||||
#endif
|
||||
|
||||
void cpu_mips_clock_init (CPUMIPSState *env)
|
||||
{
|
||||
#if 0
|
||||
/*
|
||||
* If we're in KVM mode, don't create the periodic timer, that is handled in
|
||||
* kernel.
|
||||
*/
|
||||
if (!kvm_enabled()) {
|
||||
env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &mips_timer_cb, env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
82
qemu/hw/mips/mips_int.c
Normal file
82
qemu/hw/mips/mips_int.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* QEMU MIPS interrupt support
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/mips/cpudevs.h"
|
||||
#include "cpu.h"
|
||||
//#include "kvm_mips.h"
|
||||
|
||||
#if 0
|
||||
static void cpu_mips_irq_request(void *opaque, int irq, int level)
|
||||
{
|
||||
MIPSCPU *cpu = opaque;
|
||||
CPUMIPSState *env = &cpu->env;
|
||||
CPUState *cs = CPU(cpu);
|
||||
|
||||
if (irq < 0 || irq > 7)
|
||||
return;
|
||||
|
||||
if (level) {
|
||||
env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
|
||||
|
||||
if (kvm_enabled() && irq == 2) {
|
||||
kvm_mips_set_interrupt(cpu, irq, level);
|
||||
}
|
||||
|
||||
} else {
|
||||
env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
|
||||
if (kvm_enabled() && irq == 2) {
|
||||
kvm_mips_set_interrupt(cpu, irq, level);
|
||||
}
|
||||
}
|
||||
|
||||
if (env->CP0_Cause & CP0Ca_IP_mask) {
|
||||
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
} else {
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void cpu_mips_irq_init_cpu(CPUMIPSState *env)
|
||||
{
|
||||
#if 0
|
||||
qemu_irq *qi;
|
||||
int i;
|
||||
|
||||
qi = qemu_allocate_irqs(cpu_mips_irq_request, mips_env_get_cpu(env), 8);
|
||||
for (i = 0; i < 8; i++) {
|
||||
env->irq[i] = qi[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level)
|
||||
{
|
||||
#if 0
|
||||
if (irq < 0 || irq > 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_set_irq(env->irq[irq], level);
|
||||
#endif
|
||||
}
|
||||
57
qemu/hw/mips/mips_r4k.c
Normal file
57
qemu/hw/mips/mips_r4k.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* QEMU/MIPS pseudo-board
|
||||
*
|
||||
* emulates a simple machine with ISA-like bus.
|
||||
* ISA IO space mapped to the 0x14000000 (PHYS) and
|
||||
* ISA memory at the 0x10000000 (PHYS, 16Mb in size).
|
||||
* All peripherial devices are attached to this "bus" with
|
||||
* the standard PC ISA addresses.
|
||||
*/
|
||||
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh, 2015 */
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/mips/mips.h"
|
||||
#include "hw/mips/cpudevs.h"
|
||||
#include "hw/mips/bios.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
|
||||
static void mips_r4k_init(struct uc_struct *uc, MachineState *machine)
|
||||
{
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
MIPSCPU *cpu;
|
||||
|
||||
|
||||
/* init CPUs */
|
||||
if (cpu_model == NULL) {
|
||||
#ifdef TARGET_MIPS64
|
||||
cpu_model = "R4000";
|
||||
#else
|
||||
cpu_model = "24Kf";
|
||||
#endif
|
||||
}
|
||||
|
||||
cpu = cpu_mips_init(uc, cpu_model);
|
||||
if (cpu == NULL) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void mips_machine_init(struct uc_struct *uc)
|
||||
{
|
||||
static QEMUMachine mips_machine = {
|
||||
.name = "mips",
|
||||
.init = mips_r4k_init,
|
||||
.is_default = 1,
|
||||
.arch = UC_ARCH_MIPS,
|
||||
};
|
||||
|
||||
printf(">>> mips_machine_init\n");
|
||||
|
||||
qemu_register_machine(uc, &mips_machine, TYPE_MACHINE, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user