SPARC: Emulation of Leon3
Leon3 is an open-source VHDL System-On-Chip, well known in space industry (more information on http://www.gaisler.com). Leon3 is made of multiple components available in the GrLib VHDL library. Three devices are implemented: uart, timers and IRQ manager. You can find code for these peripherals in the grlib_* files. Signed-off-by: Fabien Chouteau <chouteau@adacore.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
8b1e132074
commit
b04d989054
@ -286,7 +286,10 @@ obj-sparc-y += cirrus_vga.o
|
||||
else
|
||||
obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
|
||||
obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
|
||||
obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
|
||||
obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o
|
||||
|
||||
# GRLIB
|
||||
obj-sparc-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
|
||||
endif
|
||||
|
||||
obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
|
||||
|
218
hw/leon3.c
Normal file
218
hw/leon3.c
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* QEMU Leon3 System Emulator
|
||||
*
|
||||
* Copyright (c) 2010-2011 AdaCore
|
||||
*
|
||||
* 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.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "qemu-char.h"
|
||||
#include "sysemu.h"
|
||||
#include "boards.h"
|
||||
#include "loader.h"
|
||||
#include "elf.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include "grlib.h"
|
||||
|
||||
/* Default system clock. */
|
||||
#define CPU_CLK (40 * 1000 * 1000)
|
||||
|
||||
#define PROM_FILENAME "u-boot.bin"
|
||||
|
||||
#define MAX_PILS 16
|
||||
|
||||
typedef struct ResetData {
|
||||
CPUState *env;
|
||||
uint32_t entry; /* save kernel entry in case of reset */
|
||||
} ResetData;
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
ResetData *s = (ResetData *)opaque;
|
||||
CPUState *env = s->env;
|
||||
|
||||
cpu_reset(env);
|
||||
|
||||
env->halted = 0;
|
||||
env->pc = s->entry;
|
||||
env->npc = s->entry + 4;
|
||||
}
|
||||
|
||||
static void leon3_irq_ack(void *irq_manager, int intno)
|
||||
{
|
||||
grlib_irqmp_ack((DeviceState *)irq_manager, intno);
|
||||
leon3_cache_control_int();
|
||||
}
|
||||
|
||||
static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
|
||||
{
|
||||
CPUState *env = (CPUState *)opaque;
|
||||
|
||||
assert(env != NULL);
|
||||
|
||||
env->pil_in = pil_in;
|
||||
|
||||
if (env->pil_in && (env->interrupt_index == 0 ||
|
||||
(env->interrupt_index & ~15) == TT_EXTINT)) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 15; i > 0; i--) {
|
||||
if (env->pil_in & (1 << i)) {
|
||||
int old_interrupt = env->interrupt_index;
|
||||
|
||||
env->interrupt_index = TT_EXTINT | i;
|
||||
if (old_interrupt != env->interrupt_index) {
|
||||
trace_leon3_set_irq(i);
|
||||
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
|
||||
trace_leon3_reset_irq(env->interrupt_index & 15);
|
||||
env->interrupt_index = 0;
|
||||
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
static void leon3_generic_hw_init(ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
const char *cpu_model)
|
||||
{
|
||||
CPUState *env;
|
||||
ram_addr_t ram_offset, prom_offset;
|
||||
int ret;
|
||||
char *filename;
|
||||
qemu_irq *cpu_irqs = NULL;
|
||||
int bios_size;
|
||||
int prom_size;
|
||||
ResetData *reset_info;
|
||||
|
||||
/* Init CPU */
|
||||
if (!cpu_model) {
|
||||
cpu_model = "LEON3";
|
||||
}
|
||||
|
||||
env = cpu_init(cpu_model);
|
||||
if (!env) {
|
||||
fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpu_sparc_set_id(env, 0);
|
||||
|
||||
/* Reset data */
|
||||
reset_info = qemu_mallocz(sizeof(ResetData));
|
||||
reset_info->env = env;
|
||||
qemu_register_reset(main_cpu_reset, reset_info);
|
||||
|
||||
/* Allocate IRQ manager */
|
||||
grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
|
||||
|
||||
env->qemu_irq_ack = leon3_irq_ack;
|
||||
|
||||
/* Allocate RAM */
|
||||
if ((uint64_t)ram_size > (1UL << 30)) {
|
||||
fprintf(stderr,
|
||||
"qemu: Too much memory for this machine: %d, maximum 1G\n",
|
||||
(unsigned int)(ram_size / (1024 * 1024)));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
|
||||
cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
|
||||
|
||||
/* Allocate BIOS */
|
||||
prom_size = 8 * 1024 * 1024; /* 8Mb */
|
||||
prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
|
||||
cpu_register_physical_memory(0x00000000, prom_size,
|
||||
prom_offset | IO_MEM_ROM);
|
||||
|
||||
/* Load boot prom */
|
||||
if (bios_name == NULL) {
|
||||
bios_name = PROM_FILENAME;
|
||||
}
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
|
||||
bios_size = get_image_size(filename);
|
||||
|
||||
if (bios_size > prom_size) {
|
||||
fprintf(stderr, "qemu: could not load prom '%s': file too big\n",
|
||||
filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (bios_size > 0) {
|
||||
ret = load_image_targphys(filename, 0x00000000, bios_size);
|
||||
if (ret < 0 || ret > prom_size) {
|
||||
fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
} else if (kernel_filename == NULL) {
|
||||
fprintf(stderr, "Can't read bios image %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Can directly load an application. */
|
||||
if (kernel_filename != NULL) {
|
||||
long kernel_size;
|
||||
uint64_t entry;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
|
||||
1 /* big endian */, ELF_MACHINE, 0);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
if (bios_size <= 0) {
|
||||
/* If there is no bios/monitor, start the application. */
|
||||
env->pc = entry;
|
||||
env->npc = entry + 4;
|
||||
reset_info->entry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate timers */
|
||||
grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
|
||||
|
||||
/* Allocate uart */
|
||||
if (serial_hds[0]) {
|
||||
grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
|
||||
}
|
||||
}
|
||||
|
||||
QEMUMachine leon3_generic_machine = {
|
||||
.name = "leon3_generic",
|
||||
.desc = "Leon-3 generic",
|
||||
.init = leon3_generic_hw_init,
|
||||
.use_scsi = 0,
|
||||
};
|
||||
|
||||
static void leon3_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&leon3_generic_machine);
|
||||
}
|
||||
|
||||
machine_init(leon3_machine_init);
|
@ -252,20 +252,21 @@ typedef struct sparc_def_t {
|
||||
uint32_t maxtl;
|
||||
} sparc_def_t;
|
||||
|
||||
#define CPU_FEATURE_FLOAT (1 << 0)
|
||||
#define CPU_FEATURE_FLOAT128 (1 << 1)
|
||||
#define CPU_FEATURE_SWAP (1 << 2)
|
||||
#define CPU_FEATURE_MUL (1 << 3)
|
||||
#define CPU_FEATURE_DIV (1 << 4)
|
||||
#define CPU_FEATURE_FLUSH (1 << 5)
|
||||
#define CPU_FEATURE_FSQRT (1 << 6)
|
||||
#define CPU_FEATURE_FMUL (1 << 7)
|
||||
#define CPU_FEATURE_VIS1 (1 << 8)
|
||||
#define CPU_FEATURE_VIS2 (1 << 9)
|
||||
#define CPU_FEATURE_FSMULD (1 << 10)
|
||||
#define CPU_FEATURE_HYPV (1 << 11)
|
||||
#define CPU_FEATURE_CMT (1 << 12)
|
||||
#define CPU_FEATURE_GL (1 << 13)
|
||||
#define CPU_FEATURE_FLOAT (1 << 0)
|
||||
#define CPU_FEATURE_FLOAT128 (1 << 1)
|
||||
#define CPU_FEATURE_SWAP (1 << 2)
|
||||
#define CPU_FEATURE_MUL (1 << 3)
|
||||
#define CPU_FEATURE_DIV (1 << 4)
|
||||
#define CPU_FEATURE_FLUSH (1 << 5)
|
||||
#define CPU_FEATURE_FSQRT (1 << 6)
|
||||
#define CPU_FEATURE_FMUL (1 << 7)
|
||||
#define CPU_FEATURE_VIS1 (1 << 8)
|
||||
#define CPU_FEATURE_VIS2 (1 << 9)
|
||||
#define CPU_FEATURE_FSMULD (1 << 10)
|
||||
#define CPU_FEATURE_HYPV (1 << 11)
|
||||
#define CPU_FEATURE_CMT (1 << 12)
|
||||
#define CPU_FEATURE_GL (1 << 13)
|
||||
#define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */
|
||||
#ifndef TARGET_SPARC64
|
||||
#define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \
|
||||
CPU_FEATURE_MUL | CPU_FEATURE_DIV | \
|
||||
@ -437,6 +438,12 @@ typedef struct CPUSPARCState {
|
||||
#define SOFTINT_REG_MASK (SOFTINT_STIMER|SOFTINT_INTRMASK|SOFTINT_TIMER)
|
||||
#endif
|
||||
sparc_def_t *def;
|
||||
|
||||
void *irq_manager;
|
||||
void (*qemu_irq_ack) (void *irq_manager, int intno);
|
||||
|
||||
/* Leon3 cache control */
|
||||
uint32_t cache_control;
|
||||
} CPUSPARCState;
|
||||
|
||||
#ifndef NO_CPU_IO_DEFS
|
||||
@ -469,6 +476,8 @@ int cpu_cwp_inc(CPUState *env1, int cwp);
|
||||
int cpu_cwp_dec(CPUState *env1, int cwp);
|
||||
void cpu_set_cwp(CPUState *env1, int new_cwp);
|
||||
|
||||
void leon3_cache_control_int(void);
|
||||
|
||||
/* sun4m.c, sun4u.c */
|
||||
void cpu_check_irqs(CPUSPARCState *env);
|
||||
|
||||
|
@ -770,6 +770,7 @@ void cpu_reset(CPUSPARCState *env)
|
||||
env->pc = 0;
|
||||
env->npc = env->pc + 4;
|
||||
#endif
|
||||
env->cache_control = 0;
|
||||
}
|
||||
|
||||
static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
|
||||
@ -1274,20 +1275,20 @@ static const sparc_def_t sparc_defs[] = {
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
|
||||
},
|
||||
{
|
||||
.name = "LEON3",
|
||||
.iu_version = 0xf3000000,
|
||||
.fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
|
||||
.mmu_version = 0xf3000000,
|
||||
.mmu_bm = 0x00004000,
|
||||
.mmu_bm = 0x00000000,
|
||||
.mmu_ctpr_mask = 0x007ffff0,
|
||||
.mmu_cxr_mask = 0x0000003f,
|
||||
.mmu_sfsr_mask = 0xffffffff,
|
||||
.mmu_trcr_mask = 0xffffffff,
|
||||
.nwindows = 8,
|
||||
.features = CPU_DEFAULT_FEATURES,
|
||||
.features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
@ -85,6 +85,7 @@ DEF_HELPER_0(fcmpeq_fcc2, void)
|
||||
DEF_HELPER_0(fcmpeq_fcc3, void)
|
||||
#endif
|
||||
DEF_HELPER_1(raise_exception, void, int)
|
||||
DEF_HELPER_0(shutdown, void)
|
||||
#define F_HELPER_0_0(name) DEF_HELPER_0(f ## name, void)
|
||||
#define F_HELPER_DQ_0_0(name) \
|
||||
F_HELPER_0_0(name ## d); \
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "exec.h"
|
||||
#include "host-utils.h"
|
||||
#include "helper.h"
|
||||
#include "sysemu.h"
|
||||
|
||||
//#define DEBUG_MMU
|
||||
//#define DEBUG_MXCC
|
||||
@ -9,6 +10,7 @@
|
||||
//#define DEBUG_ASI
|
||||
//#define DEBUG_PCALL
|
||||
//#define DEBUG_PSTATE
|
||||
//#define DEBUG_CACHE_CONTROL
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
#define DPRINTF_MMU(fmt, ...) \
|
||||
@ -36,6 +38,13 @@
|
||||
#define DPRINTF_PSTATE(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CACHE_CONTROL
|
||||
#define DPRINTF_CACHE_CONTROL(fmt, ...) \
|
||||
do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
#ifndef TARGET_ABI32
|
||||
#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
|
||||
@ -49,6 +58,27 @@
|
||||
#define QT0 (env->qt0)
|
||||
#define QT1 (env->qt1)
|
||||
|
||||
/* Leon3 cache control */
|
||||
|
||||
/* Cache control: emulate the behavior of cache control registers but without
|
||||
any effect on the emulated */
|
||||
|
||||
#define CACHE_STATE_MASK 0x3
|
||||
#define CACHE_DISABLED 0x0
|
||||
#define CACHE_FROZEN 0x1
|
||||
#define CACHE_ENABLED 0x3
|
||||
|
||||
/* Cache Control register fields */
|
||||
|
||||
#define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */
|
||||
#define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */
|
||||
#define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */
|
||||
#define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */
|
||||
#define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */
|
||||
#define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */
|
||||
#define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */
|
||||
#define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
|
||||
static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
|
||||
int is_asi, int size);
|
||||
@ -294,6 +324,13 @@ void HELPER(raise_exception)(int tt)
|
||||
raise_exception(tt);
|
||||
}
|
||||
|
||||
void helper_shutdown(void)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
qemu_system_shutdown_request();
|
||||
#endif
|
||||
}
|
||||
|
||||
void helper_check_align(target_ulong addr, uint32_t align)
|
||||
{
|
||||
if (addr & align) {
|
||||
@ -1612,6 +1649,103 @@ static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
|
||||
/* Leon3 cache control */
|
||||
|
||||
void leon3_cache_control_int(void)
|
||||
{
|
||||
uint32_t state = 0;
|
||||
|
||||
if (env->cache_control & CACHE_CTRL_IF) {
|
||||
/* Instruction cache state */
|
||||
state = env->cache_control & CACHE_STATE_MASK;
|
||||
if (state == CACHE_ENABLED) {
|
||||
state = CACHE_FROZEN;
|
||||
DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n");
|
||||
}
|
||||
|
||||
env->cache_control &= ~CACHE_STATE_MASK;
|
||||
env->cache_control |= state;
|
||||
}
|
||||
|
||||
if (env->cache_control & CACHE_CTRL_DF) {
|
||||
/* Data cache state */
|
||||
state = (env->cache_control >> 2) & CACHE_STATE_MASK;
|
||||
if (state == CACHE_ENABLED) {
|
||||
state = CACHE_FROZEN;
|
||||
DPRINTF_CACHE_CONTROL("Data cache: freeze\n");
|
||||
}
|
||||
|
||||
env->cache_control &= ~(CACHE_STATE_MASK << 2);
|
||||
env->cache_control |= (state << 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size)
|
||||
{
|
||||
DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n",
|
||||
addr, val, size);
|
||||
|
||||
if (size != 4) {
|
||||
DPRINTF_CACHE_CONTROL("32bits only\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* Cache control */
|
||||
|
||||
/* These values must always be read as zeros */
|
||||
val &= ~CACHE_CTRL_FD;
|
||||
val &= ~CACHE_CTRL_FI;
|
||||
val &= ~CACHE_CTRL_IB;
|
||||
val &= ~CACHE_CTRL_IP;
|
||||
val &= ~CACHE_CTRL_DP;
|
||||
|
||||
env->cache_control = val;
|
||||
break;
|
||||
case 0x04: /* Instruction cache configuration */
|
||||
case 0x08: /* Data cache configuration */
|
||||
/* Read Only */
|
||||
break;
|
||||
default:
|
||||
DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static uint64_t leon3_cache_control_ld(target_ulong addr, int size)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
|
||||
if (size != 4) {
|
||||
DPRINTF_CACHE_CONTROL("32bits only\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case 0x00: /* Cache control */
|
||||
ret = env->cache_control;
|
||||
break;
|
||||
|
||||
/* Configuration registers are read and only always keep those
|
||||
predefined values */
|
||||
|
||||
case 0x04: /* Instruction cache configuration */
|
||||
ret = 0x10220000;
|
||||
break;
|
||||
case 0x08: /* Data cache configuration */
|
||||
ret = 0x18220000;
|
||||
break;
|
||||
default:
|
||||
DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr);
|
||||
break;
|
||||
};
|
||||
DPRINTF_CACHE_CONTROL("st addr:%08x, ret:%" PRIx64 ", size:%d\n",
|
||||
addr, ret, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
@ -1621,8 +1755,13 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
|
||||
|
||||
helper_check_align(addr, size - 1);
|
||||
switch (asi) {
|
||||
case 2: /* SuperSparc MXCC registers */
|
||||
case 2: /* SuperSparc MXCC registers and Leon3 cache control */
|
||||
switch (addr) {
|
||||
case 0x00: /* Leon3 Cache Control */
|
||||
case 0x08: /* Leon3 Instruction Cache config */
|
||||
case 0x0C: /* Leon3 Date Cache config */
|
||||
ret = leon3_cache_control_ld(addr, size);
|
||||
break;
|
||||
case 0x01c00a00: /* MXCC control register */
|
||||
if (size == 8)
|
||||
ret = env->mxccregs[3];
|
||||
@ -1850,8 +1989,14 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
|
||||
{
|
||||
helper_check_align(addr, size - 1);
|
||||
switch(asi) {
|
||||
case 2: /* SuperSparc MXCC registers */
|
||||
case 2: /* SuperSparc MXCC registers and Leon3 cache control */
|
||||
switch (addr) {
|
||||
case 0x00: /* Leon3 Cache Control */
|
||||
case 0x08: /* Leon3 Instruction Cache config */
|
||||
case 0x0C: /* Leon3 Date Cache config */
|
||||
leon3_cache_control_st(addr, val, size);
|
||||
break;
|
||||
|
||||
case 0x01c00000: /* MXCC stream data register 0 */
|
||||
if (size == 8)
|
||||
env->mxccdata[0] = val;
|
||||
@ -4177,6 +4322,13 @@ void do_interrupt(CPUState *env)
|
||||
env->pc = env->tbr;
|
||||
env->npc = env->pc + 4;
|
||||
env->exception_index = -1;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* IRQ acknowledgment */
|
||||
if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
|
||||
env->qemu_irq_ack(env->irq_manager, intno);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1997,8 +1997,9 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
} else
|
||||
tcg_gen_mov_tl(cpu_dst, cpu_src1);
|
||||
}
|
||||
|
||||
cond = GET_FIELD(insn, 3, 6);
|
||||
if (cond == 0x8) {
|
||||
if (cond == 0x8) { /* Trap Always */
|
||||
save_state(dc, cpu_cond);
|
||||
if ((dc->def->features & CPU_FEATURE_HYPV) &&
|
||||
supervisor(dc))
|
||||
@ -2007,7 +2008,15 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK);
|
||||
tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP);
|
||||
tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst);
|
||||
gen_helper_raise_exception(cpu_tmp32);
|
||||
|
||||
if (rs2 == 0 &&
|
||||
dc->def->features & CPU_FEATURE_TA0_SHUTDOWN) {
|
||||
|
||||
gen_helper_shutdown();
|
||||
|
||||
} else {
|
||||
gen_helper_raise_exception(cpu_tmp32);
|
||||
}
|
||||
} else if (cond != 0) {
|
||||
TCGv r_cond = tcg_temp_new();
|
||||
int l1;
|
||||
|
@ -244,3 +244,7 @@ disable grlib_irqmp_unknown_register(const char *op, uint64_t val) "%s unknown r
|
||||
# hw/grlib_apbuart.c
|
||||
disable grlib_apbuart_event(int event) "event:%d"
|
||||
disable grlib_apbuart_unknown_register(const char *op, uint64_t val) "%s unknown register 0x%"PRIx64""
|
||||
|
||||
# hw/leon3.c
|
||||
disable leon3_set_irq(int intno) "Set CPU IRQ %d"
|
||||
disable leon3_reset_irq(int intno) "Reset CPU IRQ %d"
|
||||
|
Loading…
Reference in New Issue
Block a user