SPARC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1179 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
9772c73bbc
commit
e80cfcfc88
4
Makefile
4
Makefile
|
@ -50,7 +50,7 @@ install: all
|
||||||
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
|
install -m 644 pc-bios/bios.bin pc-bios/vgabios.bin \
|
||||||
pc-bios/vgabios-cirrus.bin \
|
pc-bios/vgabios-cirrus.bin \
|
||||||
pc-bios/ppc_rom.bin \
|
pc-bios/ppc_rom.bin \
|
||||||
pc-bios/proll.bin \
|
pc-bios/proll.elf \
|
||||||
pc-bios/linux_boot.bin "$(datadir)"
|
pc-bios/linux_boot.bin "$(datadir)"
|
||||||
mkdir -p "$(docdir)"
|
mkdir -p "$(docdir)"
|
||||||
install -m 644 qemu-doc.html qemu-tech.html "$(docdir)"
|
install -m 644 qemu-doc.html qemu-tech.html "$(docdir)"
|
||||||
|
@ -107,7 +107,7 @@ tarbin:
|
||||||
$(datadir)/vgabios.bin \
|
$(datadir)/vgabios.bin \
|
||||||
$(datadir)/vgabios-cirrus.bin \
|
$(datadir)/vgabios-cirrus.bin \
|
||||||
$(datadir)/ppc_rom.bin \
|
$(datadir)/ppc_rom.bin \
|
||||||
$(datadir)/proll.bin \
|
$(datadir)/proll.elf \
|
||||||
$(datadir)/linux_boot.bin \
|
$(datadir)/linux_boot.bin \
|
||||||
$(docdir)/qemu-doc.html \
|
$(docdir)/qemu-doc.html \
|
||||||
$(docdir)/qemu-tech.html \
|
$(docdir)/qemu-tech.html \
|
||||||
|
|
|
@ -175,6 +175,7 @@ endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_DARWIN),yes)
|
ifeq ($(CONFIG_DARWIN),yes)
|
||||||
OP_CFLAGS+= -mdynamic-no-pic
|
OP_CFLAGS+= -mdynamic-no-pic
|
||||||
|
LIBS+=-lmx
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#########################################################
|
#########################################################
|
||||||
|
@ -300,7 +301,7 @@ VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
|
||||||
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o
|
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o
|
||||||
endif
|
endif
|
||||||
ifeq ($(TARGET_ARCH), sparc)
|
ifeq ($(TARGET_ARCH), sparc)
|
||||||
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o
|
VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o fdc.o
|
||||||
endif
|
endif
|
||||||
ifdef CONFIG_GDBSTUB
|
ifdef CONFIG_GDBSTUB
|
||||||
VL_OBJS+=gdbstub.o
|
VL_OBJS+=gdbstub.o
|
||||||
|
|
|
@ -261,7 +261,7 @@ int cpu_exec(CPUState *env1)
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
||||||
do_interrupt(0, 0, 0, 0, 0);
|
do_interrupt(env->interrupt_index, 0, 0, 0, 0);
|
||||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||||
} else if (interrupt_request & CPU_INTERRUPT_TIMER) {
|
} else if (interrupt_request & CPU_INTERRUPT_TIMER) {
|
||||||
//do_interrupt(0, 0, 0, 0, 0);
|
//do_interrupt(0, 0, 0, 0, 0);
|
||||||
|
|
28
disas.c
28
disas.c
|
@ -9,9 +9,7 @@
|
||||||
#include "disas.h"
|
#include "disas.h"
|
||||||
|
|
||||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||||
unsigned int disas_num_syms;
|
struct syminfo *syminfos = NULL;
|
||||||
void *disas_symtab;
|
|
||||||
const char *disas_strtab;
|
|
||||||
|
|
||||||
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
/* Get LENGTH bytes from info's buffer, at target address memaddr.
|
||||||
Transfer them to myaddr. */
|
Transfer them to myaddr. */
|
||||||
|
@ -203,19 +201,23 @@ const char *lookup_symbol(void *orig_addr)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
/* Hack, because we know this is x86. */
|
/* Hack, because we know this is x86. */
|
||||||
Elf32_Sym *sym = disas_symtab;
|
Elf32_Sym *sym;
|
||||||
|
struct syminfo *s;
|
||||||
|
|
||||||
for (i = 0; i < disas_num_syms; i++) {
|
for (s = syminfos; s; s = s->next) {
|
||||||
if (sym[i].st_shndx == SHN_UNDEF
|
sym = s->disas_symtab;
|
||||||
|| sym[i].st_shndx >= SHN_LORESERVE)
|
for (i = 0; i < s->disas_num_syms; i++) {
|
||||||
continue;
|
if (sym[i].st_shndx == SHN_UNDEF
|
||||||
|
|| sym[i].st_shndx >= SHN_LORESERVE)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
|
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((long)orig_addr >= sym[i].st_value
|
if ((long)orig_addr >= sym[i].st_value
|
||||||
&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
|
&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
|
||||||
return disas_strtab + sym[i].st_name;
|
return s->disas_strtab + sym[i].st_name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
10
disas.h
10
disas.h
|
@ -9,7 +9,11 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags);
|
||||||
const char *lookup_symbol(void *orig_addr);
|
const char *lookup_symbol(void *orig_addr);
|
||||||
|
|
||||||
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
/* Filled in by elfload.c. Simplistic, but will do for now. */
|
||||||
extern unsigned int disas_num_syms;
|
extern struct syminfo {
|
||||||
extern void *disas_symtab; /* FIXME: includes are a mess --RR */
|
unsigned int disas_num_syms;
|
||||||
extern const char *disas_strtab;
|
void *disas_symtab;
|
||||||
|
const char *disas_strtab;
|
||||||
|
struct syminfo *next;
|
||||||
|
} *syminfos;
|
||||||
|
|
||||||
#endif /* _QEMU_DISAS_H */
|
#endif /* _QEMU_DISAS_H */
|
||||||
|
|
19
gdbstub.c
19
gdbstub.c
|
@ -298,11 +298,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||||
}
|
}
|
||||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||||
registers[64] = tswapl(env->y);
|
registers[64] = tswapl(env->y);
|
||||||
tmp = (0<<28) | (4<<24) | env->psr \
|
tmp = GET_PSR(env);
|
||||||
| (env->psrs? PSR_S : 0) \
|
|
||||||
| (env->psrs? PSR_PS : 0) \
|
|
||||||
| (env->psret? PSR_ET : 0) \
|
|
||||||
| env->cwp;
|
|
||||||
registers[65] = tswapl(tmp);
|
registers[65] = tswapl(tmp);
|
||||||
registers[66] = tswapl(env->wim);
|
registers[66] = tswapl(env->wim);
|
||||||
registers[67] = tswapl(env->tbr);
|
registers[67] = tswapl(env->tbr);
|
||||||
|
@ -317,7 +313,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||||
|
|
||||||
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||||
{
|
{
|
||||||
uint32_t *registers = (uint32_t *)mem_buf, tmp;
|
uint32_t *registers = (uint32_t *)mem_buf;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* fill in g0..g7 */
|
/* fill in g0..g7 */
|
||||||
|
@ -334,12 +330,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||||
}
|
}
|
||||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||||
env->y = tswapl(registers[64]);
|
env->y = tswapl(registers[64]);
|
||||||
tmp = tswapl(registers[65]);
|
PUT_PSR(env, tswapl(registers[65]));
|
||||||
env->psr = tmp & ~PSR_ICC;
|
|
||||||
env->psrs = (tmp & PSR_S)? 1 : 0;
|
|
||||||
env->psrps = (tmp & PSR_PS)? 1 : 0;
|
|
||||||
env->psret = (tmp & PSR_ET)? 1 : 0;
|
|
||||||
env->cwp = (tmp & PSR_CWP);
|
|
||||||
env->wim = tswapl(registers[66]);
|
env->wim = tswapl(registers[66]);
|
||||||
env->tbr = tswapl(registers[67]);
|
env->tbr = tswapl(registers[67]);
|
||||||
env->pc = tswapl(registers[68]);
|
env->pc = tswapl(registers[68]);
|
||||||
|
@ -495,8 +486,10 @@ static void gdb_vm_stopped(void *opaque, int reason)
|
||||||
/* disable single step if it was enable */
|
/* disable single step if it was enable */
|
||||||
cpu_single_step(cpu_single_env, 0);
|
cpu_single_step(cpu_single_env, 0);
|
||||||
|
|
||||||
if (reason == EXCP_DEBUG)
|
if (reason == EXCP_DEBUG) {
|
||||||
|
tb_flush(cpu_single_env);
|
||||||
ret = SIGTRAP;
|
ret = SIGTRAP;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ret = 0;
|
ret = 0;
|
||||||
snprintf(buf, sizeof(buf), "S%02x", ret);
|
snprintf(buf, sizeof(buf), "S%02x", ret);
|
||||||
|
|
35
hw/fdc.c
35
hw/fdc.c
|
@ -21,6 +21,10 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* The controller is used in Sun4m systems in a slightly different
|
||||||
|
* way. There are changes in DOR register and DMA is not available.
|
||||||
|
*/
|
||||||
#include "vl.h"
|
#include "vl.h"
|
||||||
|
|
||||||
/********************************************************/
|
/********************************************************/
|
||||||
|
@ -90,6 +94,16 @@ typedef struct fdrive_t {
|
||||||
uint8_t ro; /* Is read-only */
|
uint8_t ro; /* Is read-only */
|
||||||
} fdrive_t;
|
} fdrive_t;
|
||||||
|
|
||||||
|
#ifdef TARGET_SPARC
|
||||||
|
#define DMA_read_memory(a,b,c,d)
|
||||||
|
#define DMA_write_memory(a,b,c,d)
|
||||||
|
#define DMA_register_channel(a,b,c)
|
||||||
|
#define DMA_hold_DREQ(a)
|
||||||
|
#define DMA_release_DREQ(a)
|
||||||
|
#define DMA_get_channel_mode(a) (0)
|
||||||
|
#define DMA_schedule(a)
|
||||||
|
#endif
|
||||||
|
|
||||||
static void fd_init (fdrive_t *drv, BlockDriverState *bs)
|
static void fd_init (fdrive_t *drv, BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
/* Drive */
|
/* Drive */
|
||||||
|
@ -455,6 +469,18 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
|
||||||
|
fdctrl_read,
|
||||||
|
fdctrl_read,
|
||||||
|
fdctrl_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
|
||||||
|
fdctrl_write,
|
||||||
|
fdctrl_write,
|
||||||
|
fdctrl_write,
|
||||||
|
};
|
||||||
|
|
||||||
static void fd_change_cb (void *opaque)
|
static void fd_change_cb (void *opaque)
|
||||||
{
|
{
|
||||||
fdrive_t *drv = opaque;
|
fdrive_t *drv = opaque;
|
||||||
|
@ -473,7 +499,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
|
||||||
BlockDriverState **fds)
|
BlockDriverState **fds)
|
||||||
{
|
{
|
||||||
fdctrl_t *fdctrl;
|
fdctrl_t *fdctrl;
|
||||||
// int io_mem;
|
int io_mem;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
FLOPPY_DPRINTF("init controller\n");
|
FLOPPY_DPRINTF("init controller\n");
|
||||||
|
@ -504,11 +530,8 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
|
||||||
fdctrl_reset(fdctrl, 0);
|
fdctrl_reset(fdctrl, 0);
|
||||||
fdctrl->state = FD_CTRL_ACTIVE;
|
fdctrl->state = FD_CTRL_ACTIVE;
|
||||||
if (mem_mapped) {
|
if (mem_mapped) {
|
||||||
FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
|
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl);
|
||||||
#if 0
|
cpu_register_physical_memory(io_base, 0x08, io_mem);
|
||||||
io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
|
|
||||||
cpu_register_physical_memory(base, 0x08, io_mem);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
|
register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
|
||||||
register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
|
register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
|
||||||
|
|
54
hw/iommu.c
54
hw/iommu.c
|
@ -117,8 +117,6 @@ typedef struct IOMMUState {
|
||||||
uint32_t iostart;
|
uint32_t iostart;
|
||||||
} IOMMUState;
|
} IOMMUState;
|
||||||
|
|
||||||
static IOMMUState *ps;
|
|
||||||
|
|
||||||
static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
|
static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
|
||||||
{
|
{
|
||||||
IOMMUState *s = opaque;
|
IOMMUState *s = opaque;
|
||||||
|
@ -187,25 +185,61 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = {
|
||||||
iommu_mem_writew,
|
iommu_mem_writew,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t iommu_translate(uint32_t addr)
|
uint32_t iommu_translate_local(void *opaque, uint32_t addr)
|
||||||
{
|
{
|
||||||
uint32_t *iopte = (void *)(ps->regs[1] << 4), pa;
|
IOMMUState *s = opaque;
|
||||||
|
uint32_t *iopte = (void *)(s->regs[1] << 4), pa;
|
||||||
|
|
||||||
iopte += ((addr - ps->iostart) >> PAGE_SHIFT);
|
iopte += ((addr - s->iostart) >> PAGE_SHIFT);
|
||||||
cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0);
|
cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4);
|
||||||
bswap32s(&pa);
|
bswap32s(&pa);
|
||||||
pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */
|
pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */
|
||||||
return pa + (addr & PAGE_MASK);
|
return pa + (addr & PAGE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void iommu_init(uint32_t addr)
|
static void iommu_save(QEMUFile *f, void *opaque)
|
||||||
|
{
|
||||||
|
IOMMUState *s = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
qemu_put_be32s(f, &s->addr);
|
||||||
|
for (i = 0; i < sizeof(struct iommu_regs); i += 4)
|
||||||
|
qemu_put_be32s(f, &s->regs[i]);
|
||||||
|
qemu_put_be32s(f, &s->iostart);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iommu_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
IOMMUState *s = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (version_id != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qemu_get_be32s(f, &s->addr);
|
||||||
|
for (i = 0; i < sizeof(struct iommu_regs); i += 4)
|
||||||
|
qemu_put_be32s(f, &s->regs[i]);
|
||||||
|
qemu_get_be32s(f, &s->iostart);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iommu_reset(void *opaque)
|
||||||
|
{
|
||||||
|
IOMMUState *s = opaque;
|
||||||
|
|
||||||
|
memset(s->regs, 0, sizeof(struct iommu_regs));
|
||||||
|
s->iostart = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *iommu_init(uint32_t addr)
|
||||||
{
|
{
|
||||||
IOMMUState *s;
|
IOMMUState *s;
|
||||||
int iommu_io_memory;
|
int iommu_io_memory;
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(IOMMUState));
|
s = qemu_mallocz(sizeof(IOMMUState));
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return NULL;
|
||||||
|
|
||||||
s->addr = addr;
|
s->addr = addr;
|
||||||
|
|
||||||
|
@ -213,6 +247,8 @@ void iommu_init(uint32_t addr)
|
||||||
cpu_register_physical_memory(addr, sizeof(struct iommu_regs),
|
cpu_register_physical_memory(addr, sizeof(struct iommu_regs),
|
||||||
iommu_io_memory);
|
iommu_io_memory);
|
||||||
|
|
||||||
ps = s;
|
register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
|
||||||
|
qemu_register_reset(iommu_reset, s);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
127
hw/lance.c
127
hw/lance.c
|
@ -147,6 +147,7 @@ struct lance_init_block {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LEDMA_REGS 4
|
#define LEDMA_REGS 4
|
||||||
|
#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
|
||||||
#if 0
|
#if 0
|
||||||
/* Structure to describe the current status of DMA registers on the Sparc */
|
/* Structure to describe the current status of DMA registers on the Sparc */
|
||||||
struct sparc_dma_registers {
|
struct sparc_dma_registers {
|
||||||
|
@ -157,32 +158,28 @@ struct sparc_dma_registers {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct LEDMAState {
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t regs[LEDMA_REGS];
|
|
||||||
} LEDMAState;
|
|
||||||
|
|
||||||
typedef struct LANCEState {
|
typedef struct LANCEState {
|
||||||
uint32_t paddr;
|
|
||||||
NetDriverState *nd;
|
NetDriverState *nd;
|
||||||
uint32_t leptr;
|
uint32_t leptr;
|
||||||
uint16_t addr;
|
uint16_t addr;
|
||||||
uint16_t regs[LE_MAXREG];
|
uint16_t regs[LE_MAXREG];
|
||||||
uint8_t phys[6]; /* mac address */
|
uint8_t phys[6]; /* mac address */
|
||||||
int irq;
|
int irq;
|
||||||
LEDMAState *ledma;
|
unsigned int rxptr, txptr;
|
||||||
|
uint32_t ledmaregs[LEDMA_REGS];
|
||||||
} LANCEState;
|
} LANCEState;
|
||||||
|
|
||||||
static unsigned int rxptr, txptr;
|
|
||||||
|
|
||||||
static void lance_send(void *opaque);
|
static void lance_send(void *opaque);
|
||||||
|
|
||||||
static void lance_reset(LANCEState *s)
|
static void lance_reset(void *opaque)
|
||||||
{
|
{
|
||||||
|
LANCEState *s = opaque;
|
||||||
memcpy(s->phys, s->nd->macaddr, 6);
|
memcpy(s->phys, s->nd->macaddr, 6);
|
||||||
rxptr = 0;
|
s->rxptr = 0;
|
||||||
txptr = 0;
|
s->txptr = 0;
|
||||||
|
memset(s->regs, 0, LE_MAXREG * 2);
|
||||||
s->regs[LE_CSR0] = LE_C0_STOP;
|
s->regs[LE_CSR0] = LE_C0_STOP;
|
||||||
|
memset(s->ledmaregs, 0, LEDMA_REGS * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
|
static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
|
||||||
|
@ -190,7 +187,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
|
||||||
LANCEState *s = opaque;
|
LANCEState *s = opaque;
|
||||||
uint32_t saddr;
|
uint32_t saddr;
|
||||||
|
|
||||||
saddr = addr - s->paddr;
|
saddr = addr & LE_MAXREG;
|
||||||
switch (saddr >> 1) {
|
switch (saddr >> 1) {
|
||||||
case LE_RDP:
|
case LE_RDP:
|
||||||
return s->regs[s->addr];
|
return s->regs[s->addr];
|
||||||
|
@ -208,7 +205,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
|
||||||
uint32_t saddr;
|
uint32_t saddr;
|
||||||
uint16_t reg;
|
uint16_t reg;
|
||||||
|
|
||||||
saddr = addr - s->paddr;
|
saddr = addr & LE_MAXREG;
|
||||||
switch (saddr >> 1) {
|
switch (saddr >> 1) {
|
||||||
case LE_RDP:
|
case LE_RDP:
|
||||||
switch(s->addr) {
|
switch(s->addr) {
|
||||||
|
@ -292,7 +289,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = {
|
||||||
static int lance_can_receive(void *opaque)
|
static int lance_can_receive(void *opaque)
|
||||||
{
|
{
|
||||||
LANCEState *s = opaque;
|
LANCEState *s = opaque;
|
||||||
void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
|
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
||||||
struct lance_init_block *ib;
|
struct lance_init_block *ib;
|
||||||
int i;
|
int i;
|
||||||
uint16_t temp;
|
uint16_t temp;
|
||||||
|
@ -303,7 +300,7 @@ static int lance_can_receive(void *opaque)
|
||||||
ib = (void *) iommu_translate(dmaptr);
|
ib = (void *) iommu_translate(dmaptr);
|
||||||
|
|
||||||
for (i = 0; i < RX_RING_SIZE; i++) {
|
for (i = 0; i < RX_RING_SIZE; i++) {
|
||||||
cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
|
cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
|
||||||
temp &= 0xff;
|
temp &= 0xff;
|
||||||
if (temp == (LE_R1_OWN)) {
|
if (temp == (LE_R1_OWN)) {
|
||||||
#ifdef DEBUG_LANCE
|
#ifdef DEBUG_LANCE
|
||||||
|
@ -323,7 +320,7 @@ static int lance_can_receive(void *opaque)
|
||||||
static void lance_receive(void *opaque, const uint8_t *buf, int size)
|
static void lance_receive(void *opaque, const uint8_t *buf, int size)
|
||||||
{
|
{
|
||||||
LANCEState *s = opaque;
|
LANCEState *s = opaque;
|
||||||
void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
|
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
||||||
struct lance_init_block *ib;
|
struct lance_init_block *ib;
|
||||||
unsigned int i, old_rxptr, j;
|
unsigned int i, old_rxptr, j;
|
||||||
uint16_t temp;
|
uint16_t temp;
|
||||||
|
@ -333,23 +330,23 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size)
|
||||||
|
|
||||||
ib = (void *) iommu_translate(dmaptr);
|
ib = (void *) iommu_translate(dmaptr);
|
||||||
|
|
||||||
old_rxptr = rxptr;
|
old_rxptr = s->rxptr;
|
||||||
for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
|
for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
|
||||||
cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
|
cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
|
||||||
if (temp == (LE_R1_OWN)) {
|
if (temp == (LE_R1_OWN)) {
|
||||||
rxptr = (rxptr + 1) & RX_RING_MOD_MASK;
|
s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
|
||||||
temp = size;
|
temp = size;
|
||||||
bswap16s(&temp);
|
bswap16s(&temp);
|
||||||
cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2);
|
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp, 2);
|
||||||
#if 0
|
#if 0
|
||||||
cpu_physical_memory_write(&ib->rx_buf[i], buf, size);
|
cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size);
|
||||||
#else
|
#else
|
||||||
for (j = 0; j < size; j++) {
|
for (j = 0; j < size; j++) {
|
||||||
cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1);
|
cpu_physical_memory_write(((uint32_t)&ib->rx_buf[i]) + j, &buf[j], 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
temp = LE_R1_POK;
|
temp = LE_R1_POK;
|
||||||
cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
|
cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
|
||||||
s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
|
s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
|
||||||
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
|
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
|
||||||
pic_set_irq(s->irq, 1);
|
pic_set_irq(s->irq, 1);
|
||||||
|
@ -364,7 +361,7 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size)
|
||||||
static void lance_send(void *opaque)
|
static void lance_send(void *opaque)
|
||||||
{
|
{
|
||||||
LANCEState *s = opaque;
|
LANCEState *s = opaque;
|
||||||
void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
|
uint32_t dmaptr = s->leptr + s->ledmaregs[3];
|
||||||
struct lance_init_block *ib;
|
struct lance_init_block *ib;
|
||||||
unsigned int i, old_txptr, j;
|
unsigned int i, old_txptr, j;
|
||||||
uint16_t temp;
|
uint16_t temp;
|
||||||
|
@ -375,18 +372,18 @@ static void lance_send(void *opaque)
|
||||||
|
|
||||||
ib = (void *) iommu_translate(dmaptr);
|
ib = (void *) iommu_translate(dmaptr);
|
||||||
|
|
||||||
old_txptr = txptr;
|
old_txptr = s->txptr;
|
||||||
for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
|
for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
|
||||||
cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
|
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
|
||||||
if (temp == (LE_T1_POK|LE_T1_OWN)) {
|
if (temp == (LE_T1_POK|LE_T1_OWN)) {
|
||||||
cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2);
|
cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp, 2);
|
||||||
bswap16s(&temp);
|
bswap16s(&temp);
|
||||||
temp = (~temp) + 1;
|
temp = (~temp) + 1;
|
||||||
#if 0
|
#if 0
|
||||||
cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp);
|
cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp);
|
||||||
#else
|
#else
|
||||||
for (j = 0; j < temp; j++) {
|
for (j = 0; j < temp; j++) {
|
||||||
cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1);
|
cpu_physical_memory_read((uint32_t)&ib->tx_buf[i] + j, &pkt_buf[j], 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -395,8 +392,8 @@ static void lance_send(void *opaque)
|
||||||
#endif
|
#endif
|
||||||
qemu_send_packet(s->nd, pkt_buf, temp);
|
qemu_send_packet(s->nd, pkt_buf, temp);
|
||||||
temp = LE_T1_POK;
|
temp = LE_T1_POK;
|
||||||
cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
|
cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
|
||||||
txptr = (txptr + 1) & TX_RING_MOD_MASK;
|
s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
|
||||||
s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
|
s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,24 +401,20 @@ static void lance_send(void *opaque)
|
||||||
|
|
||||||
static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
|
static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||||
{
|
{
|
||||||
LEDMAState *s = opaque;
|
LANCEState *s = opaque;
|
||||||
uint32_t saddr;
|
uint32_t saddr;
|
||||||
|
|
||||||
saddr = (addr - s->addr) >> 2;
|
saddr = (addr & LEDMA_MAXADDR) >> 2;
|
||||||
if (saddr < LEDMA_REGS)
|
return s->ledmaregs[saddr];
|
||||||
return s->regs[saddr];
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||||
{
|
{
|
||||||
LEDMAState *s = opaque;
|
LANCEState *s = opaque;
|
||||||
uint32_t saddr;
|
uint32_t saddr;
|
||||||
|
|
||||||
saddr = (addr - s->addr) >> 2;
|
saddr = (addr & LEDMA_MAXADDR) >> 2;
|
||||||
if (saddr < LEDMA_REGS)
|
s->ledmaregs[saddr] = val;
|
||||||
s->regs[saddr] = val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static CPUReadMemoryFunc *ledma_mem_read[3] = {
|
static CPUReadMemoryFunc *ledma_mem_read[3] = {
|
||||||
|
@ -436,33 +429,61 @@ static CPUWriteMemoryFunc *ledma_mem_write[3] = {
|
||||||
ledma_mem_writel,
|
ledma_mem_writel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void lance_save(QEMUFile *f, void *opaque)
|
||||||
|
{
|
||||||
|
LANCEState *s = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
qemu_put_be32s(f, &s->leptr);
|
||||||
|
qemu_put_be16s(f, &s->addr);
|
||||||
|
for (i = 0; i < LE_MAXREG; i ++)
|
||||||
|
qemu_put_be16s(f, &s->regs[i]);
|
||||||
|
qemu_put_buffer(f, s->phys, 6);
|
||||||
|
qemu_put_be32s(f, &s->irq);
|
||||||
|
for (i = 0; i < LEDMA_REGS; i ++)
|
||||||
|
qemu_put_be32s(f, &s->ledmaregs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lance_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
LANCEState *s = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (version_id != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qemu_get_be32s(f, &s->leptr);
|
||||||
|
qemu_get_be16s(f, &s->addr);
|
||||||
|
for (i = 0; i < LE_MAXREG; i ++)
|
||||||
|
qemu_get_be16s(f, &s->regs[i]);
|
||||||
|
qemu_get_buffer(f, s->phys, 6);
|
||||||
|
qemu_get_be32s(f, &s->irq);
|
||||||
|
for (i = 0; i < LEDMA_REGS; i ++)
|
||||||
|
qemu_get_be32s(f, &s->ledmaregs[i]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
|
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
|
||||||
{
|
{
|
||||||
LANCEState *s;
|
LANCEState *s;
|
||||||
LEDMAState *led;
|
|
||||||
int lance_io_memory, ledma_io_memory;
|
int lance_io_memory, ledma_io_memory;
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(LANCEState));
|
s = qemu_mallocz(sizeof(LANCEState));
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
s->paddr = leaddr;
|
|
||||||
s->nd = nd;
|
s->nd = nd;
|
||||||
s->irq = irq;
|
s->irq = irq;
|
||||||
|
|
||||||
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
|
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
|
||||||
cpu_register_physical_memory(leaddr, 8, lance_io_memory);
|
cpu_register_physical_memory(leaddr, 8, lance_io_memory);
|
||||||
|
|
||||||
led = qemu_mallocz(sizeof(LEDMAState));
|
ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
|
||||||
if (!led)
|
|
||||||
return;
|
|
||||||
|
|
||||||
s->ledma = led;
|
|
||||||
led->addr = ledaddr;
|
|
||||||
ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led);
|
|
||||||
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
|
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
|
||||||
|
|
||||||
lance_reset(s);
|
lance_reset(s);
|
||||||
qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
|
qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
|
||||||
|
register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
|
||||||
|
qemu_register_reset(lance_reset, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
161
hw/m48t08.c
161
hw/m48t08.c
|
@ -32,19 +32,14 @@
|
||||||
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
|
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NVRAM_MAX_MEM 0xfff0
|
#define NVRAM_MAX_MEM 0x1ff0
|
||||||
|
#define NVRAM_MAXADDR 0x1fff
|
||||||
|
|
||||||
struct m48t08_t {
|
struct m48t08_t {
|
||||||
/* Hardware parameters */
|
|
||||||
int mem_index;
|
|
||||||
uint32_t mem_base;
|
|
||||||
uint16_t size;
|
|
||||||
/* RTC management */
|
/* RTC management */
|
||||||
time_t time_offset;
|
time_t time_offset;
|
||||||
time_t stop_time;
|
time_t stop_time;
|
||||||
/* NVRAM storage */
|
/* NVRAM storage */
|
||||||
uint8_t lock;
|
|
||||||
uint16_t addr;
|
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,14 +78,13 @@ static void set_time (m48t08_t *NVRAM, struct tm *tm)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Direct access to NVRAM */
|
/* Direct access to NVRAM */
|
||||||
void m48t08_write (m48t08_t *NVRAM, uint32_t val)
|
void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val)
|
||||||
{
|
{
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
int tmp;
|
int tmp;
|
||||||
|
|
||||||
if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000)
|
addr &= NVRAM_MAXADDR;
|
||||||
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
|
switch (addr) {
|
||||||
switch (NVRAM->addr) {
|
|
||||||
case 0x1FF8:
|
case 0x1FF8:
|
||||||
/* control */
|
/* control */
|
||||||
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
|
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
|
||||||
|
@ -167,25 +161,18 @@ void m48t08_write (m48t08_t *NVRAM, uint32_t val)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Check lock registers state */
|
NVRAM->buffer[addr] = val & 0xFF;
|
||||||
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
|
|
||||||
break;
|
|
||||||
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
|
|
||||||
break;
|
|
||||||
if (NVRAM->addr < NVRAM_MAX_MEM ||
|
|
||||||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
|
|
||||||
NVRAM->buffer[NVRAM->addr] = val & 0xFF;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t m48t08_read (m48t08_t *NVRAM)
|
uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr)
|
||||||
{
|
{
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
uint32_t retval = 0xFF;
|
uint8_t retval = 0xFF;
|
||||||
|
|
||||||
switch (NVRAM->addr) {
|
addr &= NVRAM_MAXADDR;
|
||||||
|
switch (addr) {
|
||||||
case 0x1FF8:
|
case 0x1FF8:
|
||||||
/* control */
|
/* control */
|
||||||
goto do_read;
|
goto do_read;
|
||||||
|
@ -225,65 +212,36 @@ uint32_t m48t08_read (m48t08_t *NVRAM)
|
||||||
retval = toBCD(tm.tm_year);
|
retval = toBCD(tm.tm_year);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Check lock registers state */
|
do_read:
|
||||||
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
|
retval = NVRAM->buffer[addr];
|
||||||
break;
|
|
||||||
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
|
|
||||||
break;
|
|
||||||
if (NVRAM->addr < NVRAM_MAX_MEM ||
|
|
||||||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
|
|
||||||
do_read:
|
|
||||||
retval = NVRAM->buffer[NVRAM->addr];
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000)
|
|
||||||
NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr)
|
|
||||||
{
|
|
||||||
NVRAM->addr = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void m48t08_toggle_lock (m48t08_t *NVRAM, int lock)
|
|
||||||
{
|
|
||||||
NVRAM->lock ^= 1 << lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
|
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
m48t08_t *NVRAM = opaque;
|
m48t08_t *NVRAM = opaque;
|
||||||
|
|
||||||
addr -= NVRAM->mem_base;
|
m48t08_write(NVRAM, addr, value);
|
||||||
if (addr < NVRAM_MAX_MEM)
|
|
||||||
NVRAM->buffer[addr] = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
|
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
m48t08_t *NVRAM = opaque;
|
m48t08_t *NVRAM = opaque;
|
||||||
|
|
||||||
addr -= NVRAM->mem_base;
|
m48t08_write(NVRAM, addr, value);
|
||||||
if (addr < NVRAM_MAX_MEM) {
|
m48t08_write(NVRAM, addr + 1, value >> 8);
|
||||||
NVRAM->buffer[addr] = value >> 8;
|
|
||||||
NVRAM->buffer[addr + 1] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||||
{
|
{
|
||||||
m48t08_t *NVRAM = opaque;
|
m48t08_t *NVRAM = opaque;
|
||||||
|
|
||||||
addr -= NVRAM->mem_base;
|
m48t08_write(NVRAM, addr, value);
|
||||||
if (addr < NVRAM_MAX_MEM) {
|
m48t08_write(NVRAM, addr + 1, value >> 8);
|
||||||
NVRAM->buffer[addr] = value >> 24;
|
m48t08_write(NVRAM, addr + 2, value >> 16);
|
||||||
NVRAM->buffer[addr + 1] = value >> 16;
|
m48t08_write(NVRAM, addr + 3, value >> 24);
|
||||||
NVRAM->buffer[addr + 2] = value >> 8;
|
|
||||||
NVRAM->buffer[addr + 3] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
|
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
|
||||||
|
@ -291,10 +249,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
|
||||||
m48t08_t *NVRAM = opaque;
|
m48t08_t *NVRAM = opaque;
|
||||||
uint32_t retval = 0;
|
uint32_t retval = 0;
|
||||||
|
|
||||||
addr -= NVRAM->mem_base;
|
retval = m48t08_read(NVRAM, addr);
|
||||||
if (addr < NVRAM_MAX_MEM)
|
|
||||||
retval = NVRAM->buffer[addr];
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,12 +258,8 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
|
||||||
m48t08_t *NVRAM = opaque;
|
m48t08_t *NVRAM = opaque;
|
||||||
uint32_t retval = 0;
|
uint32_t retval = 0;
|
||||||
|
|
||||||
addr -= NVRAM->mem_base;
|
retval = m48t08_read(NVRAM, addr) << 8;
|
||||||
if (addr < NVRAM_MAX_MEM) {
|
retval |= m48t08_read(NVRAM, addr + 1);
|
||||||
retval = NVRAM->buffer[addr] << 8;
|
|
||||||
retval |= NVRAM->buffer[addr + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,14 +268,10 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
|
||||||
m48t08_t *NVRAM = opaque;
|
m48t08_t *NVRAM = opaque;
|
||||||
uint32_t retval = 0;
|
uint32_t retval = 0;
|
||||||
|
|
||||||
addr -= NVRAM->mem_base;
|
retval = m48t08_read(NVRAM, addr) << 24;
|
||||||
if (addr < NVRAM_MAX_MEM) {
|
retval |= m48t08_read(NVRAM, addr + 1) << 16;
|
||||||
retval = NVRAM->buffer[addr] << 24;
|
retval |= m48t08_read(NVRAM, addr + 2) << 8;
|
||||||
retval |= NVRAM->buffer[addr + 1] << 16;
|
retval |= m48t08_read(NVRAM, addr + 3);
|
||||||
retval |= NVRAM->buffer[addr + 2] << 8;
|
|
||||||
retval |= NVRAM->buffer[addr + 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,12 +287,42 @@ static CPUReadMemoryFunc *nvram_read[] = {
|
||||||
&nvram_readl,
|
&nvram_readl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void nvram_save(QEMUFile *f, void *opaque)
|
||||||
|
{
|
||||||
|
m48t08_t *s = opaque;
|
||||||
|
|
||||||
|
qemu_put_be32s(f, (uint32_t *)&s->time_offset);
|
||||||
|
qemu_put_be32s(f, (uint32_t *)&s->stop_time);
|
||||||
|
qemu_put_buffer(f, s->buffer, 0x2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvram_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
m48t08_t *s = opaque;
|
||||||
|
|
||||||
|
if (version_id != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qemu_get_be32s(f, (uint32_t *)&s->time_offset);
|
||||||
|
qemu_get_be32s(f, (uint32_t *)&s->stop_time);
|
||||||
|
qemu_get_buffer(f, s->buffer, 0x2000);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void m48t08_reset(void *opaque)
|
||||||
|
{
|
||||||
|
m48t08_t *s = opaque;
|
||||||
|
|
||||||
|
s->time_offset = 0;
|
||||||
|
s->stop_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Initialisation routine */
|
/* Initialisation routine */
|
||||||
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr)
|
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size)
|
||||||
{
|
{
|
||||||
m48t08_t *s;
|
m48t08_t *s;
|
||||||
int i;
|
int mem_index;
|
||||||
unsigned char tmp = 0;
|
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(m48t08_t));
|
s = qemu_mallocz(sizeof(m48t08_t));
|
||||||
if (!s)
|
if (!s)
|
||||||
|
@ -355,25 +332,13 @@ m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr)
|
||||||
qemu_free(s);
|
qemu_free(s);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
s->size = size;
|
|
||||||
s->mem_base = mem_base;
|
|
||||||
s->addr = 0;
|
|
||||||
if (mem_base != 0) {
|
if (mem_base != 0) {
|
||||||
s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
|
mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
|
||||||
cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
|
cpu_register_physical_memory(mem_base, 0x2000, mem_index);
|
||||||
}
|
}
|
||||||
s->lock = 0;
|
|
||||||
|
|
||||||
i = 0x1fd8;
|
register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s);
|
||||||
s->buffer[i++] = 0x01;
|
qemu_register_reset(m48t08_reset, s);
|
||||||
s->buffer[i++] = 0x80; /* Sun4m OBP */
|
|
||||||
memcpy(&s->buffer[i], macaddr, 6);
|
|
||||||
|
|
||||||
/* Calculate checksum */
|
|
||||||
for (i = 0x1fd8; i < 0x1fe7; i++) {
|
|
||||||
tmp ^= s->buffer[i];
|
|
||||||
}
|
|
||||||
s->buffer[0x1fe7] = tmp;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,8 @@
|
||||||
|
|
||||||
typedef struct m48t08_t m48t08_t;
|
typedef struct m48t08_t m48t08_t;
|
||||||
|
|
||||||
void m48t08_write (m48t08_t *NVRAM, uint32_t val);
|
void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val);
|
||||||
uint32_t m48t08_read (m48t08_t *NVRAM);
|
uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr);
|
||||||
void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr);
|
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size);
|
||||||
void m48t08_toggle_lock (m48t08_t *NVRAM, int lock);
|
|
||||||
m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr);
|
|
||||||
|
|
||||||
#endif /* !defined (__M48T08_H__) */
|
#endif /* !defined (__M48T08_H__) */
|
||||||
|
|
179
hw/magic-load.c
179
hw/magic-load.c
|
@ -1,5 +1,54 @@
|
||||||
#include "vl.h"
|
#include "vl.h"
|
||||||
#include "disas.h"
|
#include "disas.h"
|
||||||
|
#include "exec-all.h"
|
||||||
|
|
||||||
|
struct exec
|
||||||
|
{
|
||||||
|
uint32_t a_info; /* Use macros N_MAGIC, etc for access */
|
||||||
|
uint32_t a_text; /* length of text, in bytes */
|
||||||
|
uint32_t a_data; /* length of data, in bytes */
|
||||||
|
uint32_t a_bss; /* length of uninitialized data area, in bytes */
|
||||||
|
uint32_t a_syms; /* length of symbol table data in file, in bytes */
|
||||||
|
uint32_t a_entry; /* start address */
|
||||||
|
uint32_t a_trsize; /* length of relocation info for text, in bytes */
|
||||||
|
uint32_t a_drsize; /* length of relocation info for data, in bytes */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef BSWAP_NEEDED
|
||||||
|
static void bswap_ahdr(struct exec *e)
|
||||||
|
{
|
||||||
|
bswap32s(&e->a_info);
|
||||||
|
bswap32s(&e->a_text);
|
||||||
|
bswap32s(&e->a_data);
|
||||||
|
bswap32s(&e->a_bss);
|
||||||
|
bswap32s(&e->a_syms);
|
||||||
|
bswap32s(&e->a_entry);
|
||||||
|
bswap32s(&e->a_trsize);
|
||||||
|
bswap32s(&e->a_drsize);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define bswap_ahdr(x) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
|
||||||
|
#define OMAGIC 0407
|
||||||
|
#define NMAGIC 0410
|
||||||
|
#define ZMAGIC 0413
|
||||||
|
#define QMAGIC 0314
|
||||||
|
#define _N_HDROFF(x) (1024 - sizeof (struct exec))
|
||||||
|
#define N_TXTOFF(x) \
|
||||||
|
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
|
||||||
|
(N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
|
||||||
|
#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
|
||||||
|
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
|
||||||
|
#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1))
|
||||||
|
|
||||||
|
#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
|
||||||
|
|
||||||
|
#define N_DATADDR(x) \
|
||||||
|
(N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
|
||||||
|
: (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
|
||||||
|
|
||||||
|
|
||||||
#define ELF_CLASS ELFCLASS32
|
#define ELF_CLASS ELFCLASS32
|
||||||
#define ELF_DATA ELFDATA2MSB
|
#define ELF_DATA ELFDATA2MSB
|
||||||
|
@ -103,27 +152,27 @@ static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint3
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
|
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
return -1;
|
return NULL;
|
||||||
|
|
||||||
retval = read(fd, shdr, sizeof(*shdr));
|
retval = read(fd, shdr, sizeof(*shdr));
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
return -1;
|
return NULL;
|
||||||
bswap_shdr(shdr);
|
bswap_shdr(shdr);
|
||||||
if (shdr->sh_type == SHT_STRTAB)
|
if (shdr->sh_type == SHT_STRTAB)
|
||||||
return qemu_malloc(shdr->sh_size);;
|
return qemu_malloc(shdr->sh_size);;
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_program(int fd, struct elf_phdr *phdr, void *dst)
|
static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
retval = lseek(fd, 0x4000, SEEK_SET);
|
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return read(fd, dst, phdr->p_filesz);
|
return read(fd, dst, phdr->p_filesz);
|
||||||
|
@ -178,6 +227,7 @@ static void load_symbols(struct elfhdr *ehdr, int fd)
|
||||||
{
|
{
|
||||||
struct elf_shdr symtab, strtab;
|
struct elf_shdr symtab, strtab;
|
||||||
struct elf_sym *syms;
|
struct elf_sym *syms;
|
||||||
|
struct syminfo *s;
|
||||||
int nsyms, i;
|
int nsyms, i;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
|
@ -196,20 +246,19 @@ static void load_symbols(struct elfhdr *ehdr, int fd)
|
||||||
goto error_freesyms;
|
goto error_freesyms;
|
||||||
|
|
||||||
/* Commit */
|
/* Commit */
|
||||||
if (disas_symtab)
|
s = qemu_mallocz(sizeof(*s));
|
||||||
qemu_free(disas_symtab); /* XXX Merge with old symbols? */
|
s->disas_symtab = syms;
|
||||||
if (disas_strtab)
|
s->disas_num_syms = nsyms;
|
||||||
qemu_free(disas_strtab);
|
s->disas_strtab = str;
|
||||||
disas_symtab = syms;
|
s->next = syminfos;
|
||||||
disas_num_syms = nsyms;
|
syminfos = s;
|
||||||
disas_strtab = str;
|
|
||||||
return;
|
return;
|
||||||
error_freesyms:
|
error_freesyms:
|
||||||
qemu_free(syms);
|
qemu_free(syms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_elf(const char * filename, uint8_t *addr)
|
int load_elf(const char *filename, uint8_t *addr)
|
||||||
{
|
{
|
||||||
struct elfhdr ehdr;
|
struct elfhdr ehdr;
|
||||||
struct elf_phdr phdr;
|
struct elf_phdr phdr;
|
||||||
|
@ -227,12 +276,13 @@ int load_elf(const char * filename, uint8_t *addr)
|
||||||
|
|
||||||
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|
||||||
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
|
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
|
||||||
|| ehdr.e_machine != EM_SPARC)
|
|| (ehdr.e_machine != EM_SPARC
|
||||||
|
&& ehdr.e_machine != EM_SPARC32PLUS))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
|
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
|
||||||
goto error;
|
goto error;
|
||||||
retval = read_program(fd, &phdr, addr);
|
retval = read_program(fd, &phdr, addr, ehdr.e_entry);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -245,17 +295,45 @@ int load_elf(const char * filename, uint8_t *addr)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_kernel(const char *filename, uint8_t *addr)
|
int load_aout(const char *filename, uint8_t *addr)
|
||||||
{
|
{
|
||||||
int fd, size;
|
int fd, size, ret;
|
||||||
|
struct exec e;
|
||||||
|
uint32_t magic;
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY | O_BINARY);
|
fd = open(filename, O_RDONLY | O_BINARY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
/* load 32 bit code */
|
|
||||||
size = read(fd, addr, 16 * 1024 * 1024);
|
size = read(fd, &e, sizeof(e));
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
bswap_ahdr(&e);
|
||||||
|
|
||||||
|
magic = N_MAGIC(e);
|
||||||
|
switch (magic) {
|
||||||
|
case ZMAGIC:
|
||||||
|
case QMAGIC:
|
||||||
|
case OMAGIC:
|
||||||
|
lseek(fd, N_TXTOFF(e), SEEK_SET);
|
||||||
|
size = read(fd, addr, e.a_text + e.a_data);
|
||||||
|
if (size < 0)
|
||||||
|
goto fail;
|
||||||
|
break;
|
||||||
|
case NMAGIC:
|
||||||
|
lseek(fd, N_TXTOFF(e), SEEK_SET);
|
||||||
|
size = read(fd, addr, e.a_text);
|
||||||
|
if (size < 0)
|
||||||
|
goto fail;
|
||||||
|
ret = read(fd, addr + N_DATADDR(e), e.a_data);
|
||||||
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
|
size += ret;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
return size;
|
return size;
|
||||||
fail:
|
fail:
|
||||||
|
@ -263,64 +341,3 @@ int load_kernel(const char *filename, uint8_t *addr)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct MAGICState {
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t saved_addr;
|
|
||||||
int magic_state;
|
|
||||||
char saved_kfn[1024];
|
|
||||||
} MAGICState;
|
|
||||||
|
|
||||||
static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
MAGICState *s = opaque;
|
|
||||||
|
|
||||||
if (s->magic_state == 0) {
|
|
||||||
ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr);
|
|
||||||
if (ret < 0)
|
|
||||||
ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr);
|
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
|
||||||
s->saved_kfn);
|
|
||||||
}
|
|
||||||
s->magic_state = 1; /* No more magic */
|
|
||||||
tb_flush();
|
|
||||||
return bswap32(ret);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static CPUReadMemoryFunc *magic_mem_read[3] = {
|
|
||||||
magic_mem_readl,
|
|
||||||
magic_mem_readl,
|
|
||||||
magic_mem_readl,
|
|
||||||
};
|
|
||||||
|
|
||||||
static CPUWriteMemoryFunc *magic_mem_write[3] = {
|
|
||||||
magic_mem_writel,
|
|
||||||
magic_mem_writel,
|
|
||||||
magic_mem_writel,
|
|
||||||
};
|
|
||||||
|
|
||||||
void magic_init(const char *kfn, int kloadaddr, uint32_t addr)
|
|
||||||
{
|
|
||||||
int magic_io_memory;
|
|
||||||
MAGICState *s;
|
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(MAGICState));
|
|
||||||
if (!s)
|
|
||||||
return;
|
|
||||||
|
|
||||||
strcpy(s->saved_kfn, kfn);
|
|
||||||
s->saved_addr = kloadaddr;
|
|
||||||
s->magic_state = 0;
|
|
||||||
s->addr = addr;
|
|
||||||
magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s);
|
|
||||||
cpu_register_physical_memory(addr, 4, magic_io_memory);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
268
hw/sched.c
268
hw/sched.c
|
@ -1,268 +0,0 @@
|
||||||
/*
|
|
||||||
* QEMU interrupt controller emulation
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003-2004 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* 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 "vl.h"
|
|
||||||
//#define DEBUG_IRQ_COUNT
|
|
||||||
|
|
||||||
/* These registers are used for sending/receiving irqs from/to
|
|
||||||
* different cpu's.
|
|
||||||
*/
|
|
||||||
struct sun4m_intreg_percpu {
|
|
||||||
unsigned int tbt; /* Intrs pending for this cpu, by PIL. */
|
|
||||||
/* These next two registers are WRITE-ONLY and are only
|
|
||||||
* "on bit" sensitive, "off bits" written have NO affect.
|
|
||||||
*/
|
|
||||||
unsigned int clear; /* Clear this cpus irqs here. */
|
|
||||||
unsigned int set; /* Set this cpus irqs here. */
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
* djhr
|
|
||||||
* Actually the clear and set fields in this struct are misleading..
|
|
||||||
* according to the SLAVIO manual (and the same applies for the SEC)
|
|
||||||
* the clear field clears bits in the mask which will ENABLE that IRQ
|
|
||||||
* the set field sets bits in the mask to DISABLE the IRQ.
|
|
||||||
*
|
|
||||||
* Also the undirected_xx address in the SLAVIO is defined as
|
|
||||||
* RESERVED and write only..
|
|
||||||
*
|
|
||||||
* DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
|
|
||||||
* sun4m machines, for MP the layout makes more sense.
|
|
||||||
*/
|
|
||||||
struct sun4m_intreg_master {
|
|
||||||
unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */
|
|
||||||
unsigned int irqs; /* Master IRQ bits. */
|
|
||||||
|
|
||||||
/* Again, like the above, two these registers are WRITE-ONLY. */
|
|
||||||
unsigned int clear; /* Clear master IRQ's by setting bits here. */
|
|
||||||
unsigned int set; /* Set master IRQ's by setting bits here. */
|
|
||||||
|
|
||||||
/* This register is both READ and WRITE. */
|
|
||||||
unsigned int undirected_target; /* Which cpu gets undirected irqs. */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SUN4M_INT_ENABLE 0x80000000
|
|
||||||
#define SUN4M_INT_E14 0x00000080
|
|
||||||
#define SUN4M_INT_E10 0x00080000
|
|
||||||
|
|
||||||
#define SUN4M_HARD_INT(x) (0x000000001 << (x))
|
|
||||||
#define SUN4M_SOFT_INT(x) (0x000010000 << (x))
|
|
||||||
|
|
||||||
#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
|
|
||||||
#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
|
|
||||||
#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
|
|
||||||
#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
|
|
||||||
#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
|
|
||||||
#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
|
|
||||||
#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
|
|
||||||
#define SUN4M_INT_REALTIME 0x00080000 /* system timer */
|
|
||||||
#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */
|
|
||||||
#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */
|
|
||||||
#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */
|
|
||||||
#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
|
|
||||||
#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
|
|
||||||
|
|
||||||
#define SUN4M_INT_SBUS(x) (1 << (x+7))
|
|
||||||
#define SUN4M_INT_VME(x) (1 << (x))
|
|
||||||
|
|
||||||
typedef struct SCHEDState {
|
|
||||||
uint32_t addr, addrg;
|
|
||||||
uint32_t intreg_pending;
|
|
||||||
uint32_t intreg_enabled;
|
|
||||||
uint32_t intregm_pending;
|
|
||||||
uint32_t intregm_enabled;
|
|
||||||
} SCHEDState;
|
|
||||||
|
|
||||||
static SCHEDState *ps;
|
|
||||||
|
|
||||||
#ifdef DEBUG_IRQ_COUNT
|
|
||||||
static uint64_t irq_count[32];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
SCHEDState *s = opaque;
|
|
||||||
uint32_t saddr;
|
|
||||||
|
|
||||||
saddr = (addr - s->addr) >> 2;
|
|
||||||
switch (saddr) {
|
|
||||||
case 0:
|
|
||||||
return s->intreg_pending;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
SCHEDState *s = opaque;
|
|
||||||
uint32_t saddr;
|
|
||||||
|
|
||||||
saddr = (addr - s->addr) >> 2;
|
|
||||||
switch (saddr) {
|
|
||||||
case 0:
|
|
||||||
s->intreg_pending = val;
|
|
||||||
break;
|
|
||||||
case 1: // clear
|
|
||||||
s->intreg_enabled &= ~val;
|
|
||||||
break;
|
|
||||||
case 2: // set
|
|
||||||
s->intreg_enabled |= val;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CPUReadMemoryFunc *intreg_mem_read[3] = {
|
|
||||||
intreg_mem_readl,
|
|
||||||
intreg_mem_readl,
|
|
||||||
intreg_mem_readl,
|
|
||||||
};
|
|
||||||
|
|
||||||
static CPUWriteMemoryFunc *intreg_mem_write[3] = {
|
|
||||||
intreg_mem_writel,
|
|
||||||
intreg_mem_writel,
|
|
||||||
intreg_mem_writel,
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
SCHEDState *s = opaque;
|
|
||||||
uint32_t saddr;
|
|
||||||
|
|
||||||
saddr = (addr - s->addrg) >> 2;
|
|
||||||
switch (saddr) {
|
|
||||||
case 0:
|
|
||||||
return s->intregm_pending;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
return s->intregm_enabled;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
SCHEDState *s = opaque;
|
|
||||||
uint32_t saddr;
|
|
||||||
|
|
||||||
saddr = (addr - s->addrg) >> 2;
|
|
||||||
switch (saddr) {
|
|
||||||
case 0:
|
|
||||||
s->intregm_pending = val;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
s->intregm_enabled = val;
|
|
||||||
break;
|
|
||||||
case 2: // clear
|
|
||||||
s->intregm_enabled &= ~val;
|
|
||||||
break;
|
|
||||||
case 3: // set
|
|
||||||
s->intregm_enabled |= val;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CPUReadMemoryFunc *intregm_mem_read[3] = {
|
|
||||||
intregm_mem_readl,
|
|
||||||
intregm_mem_readl,
|
|
||||||
intregm_mem_readl,
|
|
||||||
};
|
|
||||||
|
|
||||||
static CPUWriteMemoryFunc *intregm_mem_write[3] = {
|
|
||||||
intregm_mem_writel,
|
|
||||||
intregm_mem_writel,
|
|
||||||
intregm_mem_writel,
|
|
||||||
};
|
|
||||||
|
|
||||||
void pic_info(void)
|
|
||||||
{
|
|
||||||
term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled);
|
|
||||||
term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void irq_info(void)
|
|
||||||
{
|
|
||||||
#ifndef DEBUG_IRQ_COUNT
|
|
||||||
term_printf("irq statistic code not compiled.\n");
|
|
||||||
#else
|
|
||||||
int i;
|
|
||||||
int64_t count;
|
|
||||||
|
|
||||||
term_printf("IRQ statistics:\n");
|
|
||||||
for (i = 0; i < 32; i++) {
|
|
||||||
count = irq_count[i];
|
|
||||||
if (count > 0)
|
|
||||||
term_printf("%2d: %lld\n", i, count);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static const unsigned int intr_to_mask[16] = {
|
|
||||||
0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
void pic_set_irq(int irq, int level)
|
|
||||||
{
|
|
||||||
if (irq < 16) {
|
|
||||||
unsigned int mask = intr_to_mask[irq];
|
|
||||||
ps->intreg_pending |= 1 << irq;
|
|
||||||
if (ps->intregm_enabled & mask) {
|
|
||||||
cpu_single_env->interrupt_index = irq;
|
|
||||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_IRQ_COUNT
|
|
||||||
if (level == 1)
|
|
||||||
irq_count[irq]++;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void sched_init(uint32_t addr, uint32_t addrg)
|
|
||||||
{
|
|
||||||
int intreg_io_memory, intregm_io_memory;
|
|
||||||
SCHEDState *s;
|
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(SCHEDState));
|
|
||||||
if (!s)
|
|
||||||
return;
|
|
||||||
s->addr = addr;
|
|
||||||
s->addrg = addrg;
|
|
||||||
|
|
||||||
intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s);
|
|
||||||
cpu_register_physical_memory(addr, 3, intreg_io_memory);
|
|
||||||
|
|
||||||
intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s);
|
|
||||||
cpu_register_physical_memory(addrg, 5, intregm_io_memory);
|
|
||||||
|
|
||||||
ps = s;
|
|
||||||
}
|
|
||||||
|
|
299
hw/slavio_intctl.c
Normal file
299
hw/slavio_intctl.c
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
/*
|
||||||
|
* QEMU Sparc SLAVIO interrupt controller emulation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2004 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* 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 "vl.h"
|
||||||
|
//#define DEBUG_IRQ_COUNT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Registers of interrupt controller in sun4m.
|
||||||
|
*
|
||||||
|
* This is the interrupt controller part of chip STP2001 (Slave I/O), also
|
||||||
|
* produced as NCR89C105. See
|
||||||
|
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
|
||||||
|
*
|
||||||
|
* There is a system master controller and one for each cpu.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_CPUS 16
|
||||||
|
|
||||||
|
typedef struct SLAVIO_INTCTLState {
|
||||||
|
uint32_t intreg_pending[MAX_CPUS];
|
||||||
|
uint32_t intregm_pending;
|
||||||
|
uint32_t intregm_disabled;
|
||||||
|
uint32_t target_cpu;
|
||||||
|
#ifdef DEBUG_IRQ_COUNT
|
||||||
|
uint64_t irq_count[32];
|
||||||
|
#endif
|
||||||
|
} SLAVIO_INTCTLState;
|
||||||
|
|
||||||
|
#define INTCTL_MAXADDR 0xf
|
||||||
|
#define INTCTLM_MAXADDR 0xf
|
||||||
|
|
||||||
|
// per-cpu interrupt controller
|
||||||
|
static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
uint32_t saddr;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
|
||||||
|
saddr = (addr & INTCTL_MAXADDR) >> 2;
|
||||||
|
switch (saddr) {
|
||||||
|
case 0:
|
||||||
|
return s->intreg_pending[cpu];
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
uint32_t saddr;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
|
||||||
|
saddr = (addr & INTCTL_MAXADDR) >> 2;
|
||||||
|
switch (saddr) {
|
||||||
|
case 1: // clear pending softints
|
||||||
|
if (val & 0x4000)
|
||||||
|
val |= 80000000;
|
||||||
|
val &= 0xfffe0000;
|
||||||
|
s->intreg_pending[cpu] &= ~val;
|
||||||
|
break;
|
||||||
|
case 2: // set softint
|
||||||
|
val &= 0xfffe0000;
|
||||||
|
s->intreg_pending[cpu] |= val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
|
||||||
|
slavio_intctl_mem_readl,
|
||||||
|
slavio_intctl_mem_readl,
|
||||||
|
slavio_intctl_mem_readl,
|
||||||
|
};
|
||||||
|
|
||||||
|
static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
|
||||||
|
slavio_intctl_mem_writel,
|
||||||
|
slavio_intctl_mem_writel,
|
||||||
|
slavio_intctl_mem_writel,
|
||||||
|
};
|
||||||
|
|
||||||
|
// master system interrupt controller
|
||||||
|
static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
uint32_t saddr;
|
||||||
|
|
||||||
|
saddr = (addr & INTCTLM_MAXADDR) >> 2;
|
||||||
|
switch (saddr) {
|
||||||
|
case 0:
|
||||||
|
return s->intregm_pending;
|
||||||
|
case 1:
|
||||||
|
return s->intregm_disabled;
|
||||||
|
case 4:
|
||||||
|
return s->target_cpu;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
uint32_t saddr;
|
||||||
|
|
||||||
|
saddr = (addr & INTCTLM_MAXADDR) >> 2;
|
||||||
|
switch (saddr) {
|
||||||
|
case 2: // clear (enable)
|
||||||
|
// Force unused bits
|
||||||
|
val |= 0x7fb2007f;
|
||||||
|
s->intregm_disabled &= ~val;
|
||||||
|
break;
|
||||||
|
case 3: // set (disable, clear pending)
|
||||||
|
// Force unused bits
|
||||||
|
val &= ~0x7fb2007f;
|
||||||
|
s->intregm_disabled |= val;
|
||||||
|
s->intregm_pending &= ~val;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
s->target_cpu = val & (MAX_CPUS - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
|
||||||
|
slavio_intctlm_mem_readl,
|
||||||
|
slavio_intctlm_mem_readl,
|
||||||
|
slavio_intctlm_mem_readl,
|
||||||
|
};
|
||||||
|
|
||||||
|
static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
|
||||||
|
slavio_intctlm_mem_writel,
|
||||||
|
slavio_intctlm_mem_writel,
|
||||||
|
slavio_intctlm_mem_writel,
|
||||||
|
};
|
||||||
|
|
||||||
|
void slavio_pic_info(void *opaque)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CPUS; i++) {
|
||||||
|
term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
|
||||||
|
}
|
||||||
|
term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void slavio_irq_info(void *opaque)
|
||||||
|
{
|
||||||
|
#ifndef DEBUG_IRQ_COUNT
|
||||||
|
term_printf("irq statistic code not compiled.\n");
|
||||||
|
#else
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
int i;
|
||||||
|
int64_t count;
|
||||||
|
|
||||||
|
term_printf("IRQ statistics:\n");
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
count = s->irq_count[i];
|
||||||
|
if (count > 0)
|
||||||
|
term_printf("%2d: %lld\n", i, count);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t intbit_to_level[32] = {
|
||||||
|
2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
|
||||||
|
6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "irq" here is the bit number in the system interrupt register to
|
||||||
|
* separate serial and keyboard interrupts sharing a level.
|
||||||
|
*/
|
||||||
|
void slavio_pic_set_irq(void *opaque, int irq, int level)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
|
||||||
|
if (irq < 32) {
|
||||||
|
uint32_t mask = 1 << irq;
|
||||||
|
uint32_t pil = intbit_to_level[irq];
|
||||||
|
if (pil > 0) {
|
||||||
|
if (level) {
|
||||||
|
s->intregm_pending |= mask;
|
||||||
|
s->intreg_pending[s->target_cpu] |= 1 << pil;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s->intregm_pending &= ~mask;
|
||||||
|
s->intreg_pending[s->target_cpu] &= ~(1 << pil);
|
||||||
|
}
|
||||||
|
if (level &&
|
||||||
|
!(s->intregm_disabled & mask) &&
|
||||||
|
!(s->intregm_disabled & 0x80000000) &&
|
||||||
|
(pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) {
|
||||||
|
#ifdef DEBUG_IRQ_COUNT
|
||||||
|
if (level == 1)
|
||||||
|
s->irq_count[pil]++;
|
||||||
|
#endif
|
||||||
|
cpu_single_env->interrupt_index = TT_EXTINT | pil;
|
||||||
|
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_intctl_save(QEMUFile *f, void *opaque)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CPUS; i++) {
|
||||||
|
qemu_put_be32s(f, &s->intreg_pending[i]);
|
||||||
|
}
|
||||||
|
qemu_put_be32s(f, &s->intregm_pending);
|
||||||
|
qemu_put_be32s(f, &s->intregm_disabled);
|
||||||
|
qemu_put_be32s(f, &s->target_cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (version_id != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CPUS; i++) {
|
||||||
|
qemu_get_be32s(f, &s->intreg_pending[i]);
|
||||||
|
}
|
||||||
|
qemu_get_be32s(f, &s->intregm_pending);
|
||||||
|
qemu_get_be32s(f, &s->intregm_disabled);
|
||||||
|
qemu_get_be32s(f, &s->target_cpu);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_intctl_reset(void *opaque)
|
||||||
|
{
|
||||||
|
SLAVIO_INTCTLState *s = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CPUS; i++) {
|
||||||
|
s->intreg_pending[i] = 0;
|
||||||
|
}
|
||||||
|
s->intregm_disabled = 0xffffffff;
|
||||||
|
s->intregm_pending = 0;
|
||||||
|
s->target_cpu = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
|
||||||
|
{
|
||||||
|
int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
|
||||||
|
SLAVIO_INTCTLState *s;
|
||||||
|
|
||||||
|
s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CPUS; i++) {
|
||||||
|
slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
|
||||||
|
cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
|
||||||
|
cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
|
||||||
|
|
||||||
|
register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
|
||||||
|
qemu_register_reset(slavio_intctl_reset, s);
|
||||||
|
slavio_intctl_reset(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
364
hw/slavio_serial.c
Normal file
364
hw/slavio_serial.c
Normal file
|
@ -0,0 +1,364 @@
|
||||||
|
/*
|
||||||
|
* QEMU Sparc SLAVIO serial port emulation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2004 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* 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 "vl.h"
|
||||||
|
|
||||||
|
//#define DEBUG_SERIAL
|
||||||
|
|
||||||
|
/* debug keyboard */
|
||||||
|
//#define DEBUG_KBD
|
||||||
|
|
||||||
|
/* debug keyboard : only mouse */
|
||||||
|
//#define DEBUG_MOUSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the serial port, mouse and keyboard part of chip STP2001
|
||||||
|
* (Slave I/O), also produced as NCR89C105. See
|
||||||
|
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
|
||||||
|
*
|
||||||
|
* The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
|
||||||
|
* mouse and keyboard ports don't implement all functions and they are
|
||||||
|
* only asynchronous. There is no DMA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct ChannelState {
|
||||||
|
int irq;
|
||||||
|
int reg;
|
||||||
|
int rxint, txint;
|
||||||
|
uint8_t rx, tx, wregs[16], rregs[16];
|
||||||
|
CharDriverState *chr;
|
||||||
|
} ChannelState;
|
||||||
|
|
||||||
|
struct SerialState {
|
||||||
|
struct ChannelState chn[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SERIAL_MAXADDR 7
|
||||||
|
|
||||||
|
static void slavio_serial_update_irq(ChannelState *s)
|
||||||
|
{
|
||||||
|
if ((s->wregs[1] & 1) && // interrupts enabled
|
||||||
|
(((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
|
||||||
|
((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
|
||||||
|
s->rxint == 1) || // rx ints enabled, pending
|
||||||
|
((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
|
||||||
|
pic_set_irq(s->irq, 1);
|
||||||
|
} else {
|
||||||
|
pic_set_irq(s->irq, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_serial_reset_chn(ChannelState *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
s->reg = 0;
|
||||||
|
for (i = 0; i < SERIAL_MAXADDR; i++) {
|
||||||
|
s->rregs[i] = 0;
|
||||||
|
s->wregs[i] = 0;
|
||||||
|
}
|
||||||
|
s->wregs[4] = 4;
|
||||||
|
s->wregs[9] = 0xc0;
|
||||||
|
s->wregs[11] = 8;
|
||||||
|
s->wregs[14] = 0x30;
|
||||||
|
s->wregs[15] = 0xf8;
|
||||||
|
s->rregs[0] = 0x44;
|
||||||
|
s->rregs[1] = 6;
|
||||||
|
|
||||||
|
s->rx = s->tx = 0;
|
||||||
|
s->rxint = s->txint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_serial_reset(void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = opaque;
|
||||||
|
slavio_serial_reset_chn(&s->chn[0]);
|
||||||
|
slavio_serial_reset_chn(&s->chn[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_serial_mem_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||||
|
{
|
||||||
|
SerialState *ser = opaque;
|
||||||
|
ChannelState *s;
|
||||||
|
uint32_t saddr;
|
||||||
|
int newreg, channel;
|
||||||
|
|
||||||
|
val &= 0xff;
|
||||||
|
saddr = (addr & 3) >> 1;
|
||||||
|
channel = (addr & SERIAL_MAXADDR) >> 2;
|
||||||
|
s = &ser->chn[channel];
|
||||||
|
switch (saddr) {
|
||||||
|
case 0:
|
||||||
|
newreg = 0;
|
||||||
|
switch (s->reg) {
|
||||||
|
case 0:
|
||||||
|
newreg = val & 7;
|
||||||
|
val &= 0x38;
|
||||||
|
switch (val) {
|
||||||
|
case 8:
|
||||||
|
s->reg |= 0x8;
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
s->rxint = 0;
|
||||||
|
break;
|
||||||
|
case 0x28:
|
||||||
|
s->txint = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1 ... 8:
|
||||||
|
case 10 ... 15:
|
||||||
|
s->wregs[s->reg] = val;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
switch (val & 0xc0) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
slavio_serial_reset_chn(&ser->chn[1]);
|
||||||
|
return;
|
||||||
|
case 0x80:
|
||||||
|
slavio_serial_reset_chn(&ser->chn[0]);
|
||||||
|
return;
|
||||||
|
case 0xc0:
|
||||||
|
slavio_serial_reset(ser);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (s->reg == 0)
|
||||||
|
s->reg = newreg;
|
||||||
|
else
|
||||||
|
s->reg = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (s->wregs[5] & 8) { // tx enabled
|
||||||
|
s->tx = val;
|
||||||
|
if (s->chr)
|
||||||
|
qemu_chr_write(s->chr, &s->tx, 1);
|
||||||
|
s->txint = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t slavio_serial_mem_readb(void *opaque, uint32_t addr)
|
||||||
|
{
|
||||||
|
SerialState *ser = opaque;
|
||||||
|
ChannelState *s;
|
||||||
|
uint32_t saddr;
|
||||||
|
uint32_t ret;
|
||||||
|
int channel;
|
||||||
|
|
||||||
|
saddr = (addr & 3) >> 1;
|
||||||
|
channel = (addr & SERIAL_MAXADDR) >> 2;
|
||||||
|
s = &ser->chn[channel];
|
||||||
|
switch (saddr) {
|
||||||
|
case 0:
|
||||||
|
ret = s->rregs[s->reg];
|
||||||
|
s->reg = 0;
|
||||||
|
return ret;
|
||||||
|
case 1:
|
||||||
|
s->rregs[0] &= ~1;
|
||||||
|
return s->rx;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serial_can_receive(void *opaque)
|
||||||
|
{
|
||||||
|
ChannelState *s = opaque;
|
||||||
|
if (((s->wregs[3] & 1) == 0) // Rx not enabled
|
||||||
|
|| ((s->rregs[0] & 1) == 1)) // char already available
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_receive_byte(ChannelState *s, int ch)
|
||||||
|
{
|
||||||
|
s->rregs[0] |= 1;
|
||||||
|
s->rx = ch;
|
||||||
|
s->rxint = 1;
|
||||||
|
slavio_serial_update_irq(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_receive_break(ChannelState *s)
|
||||||
|
{
|
||||||
|
s->rregs[0] |= 0x80;
|
||||||
|
slavio_serial_update_irq(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_receive1(void *opaque, const uint8_t *buf, int size)
|
||||||
|
{
|
||||||
|
ChannelState *s = opaque;
|
||||||
|
serial_receive_byte(s, buf[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_event(void *opaque, int event)
|
||||||
|
{
|
||||||
|
ChannelState *s = opaque;
|
||||||
|
if (event == CHR_EVENT_BREAK)
|
||||||
|
serial_receive_break(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
|
||||||
|
slavio_serial_mem_readb,
|
||||||
|
slavio_serial_mem_readb,
|
||||||
|
slavio_serial_mem_readb,
|
||||||
|
};
|
||||||
|
|
||||||
|
static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
|
||||||
|
slavio_serial_mem_writeb,
|
||||||
|
slavio_serial_mem_writeb,
|
||||||
|
slavio_serial_mem_writeb,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
|
||||||
|
{
|
||||||
|
qemu_put_be32s(f, &s->irq);
|
||||||
|
qemu_put_be32s(f, &s->reg);
|
||||||
|
qemu_put_be32s(f, &s->rxint);
|
||||||
|
qemu_put_be32s(f, &s->txint);
|
||||||
|
qemu_put_8s(f, &s->rx);
|
||||||
|
qemu_put_8s(f, &s->tx);
|
||||||
|
qemu_put_buffer(f, s->wregs, 16);
|
||||||
|
qemu_put_buffer(f, s->rregs, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_serial_save(QEMUFile *f, void *opaque)
|
||||||
|
{
|
||||||
|
SerialState *s = opaque;
|
||||||
|
|
||||||
|
slavio_serial_save_chn(f, &s->chn[0]);
|
||||||
|
slavio_serial_save_chn(f, &s->chn[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
|
||||||
|
{
|
||||||
|
if (version_id != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qemu_get_be32s(f, &s->irq);
|
||||||
|
qemu_get_be32s(f, &s->reg);
|
||||||
|
qemu_get_be32s(f, &s->rxint);
|
||||||
|
qemu_get_be32s(f, &s->txint);
|
||||||
|
qemu_get_8s(f, &s->rx);
|
||||||
|
qemu_get_8s(f, &s->tx);
|
||||||
|
qemu_get_buffer(f, s->wregs, 16);
|
||||||
|
qemu_get_buffer(f, s->rregs, 16);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
SerialState *s = opaque;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
|
||||||
|
{
|
||||||
|
int slavio_serial_io_memory;
|
||||||
|
SerialState *s;
|
||||||
|
|
||||||
|
s = qemu_mallocz(sizeof(SerialState));
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
s->chn[0].irq = irq;
|
||||||
|
s->chn[1].irq = irq;
|
||||||
|
s->chn[0].chr = chr1;
|
||||||
|
s->chn[1].chr = chr2;
|
||||||
|
|
||||||
|
slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
|
||||||
|
cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
|
||||||
|
|
||||||
|
if (chr1) {
|
||||||
|
qemu_chr_add_read_handler(chr1, serial_can_receive, serial_receive1, &s->chn[0]);
|
||||||
|
qemu_chr_add_event_handler(chr1, serial_event);
|
||||||
|
}
|
||||||
|
if (chr2) {
|
||||||
|
qemu_chr_add_read_handler(chr2, serial_can_receive, serial_receive1, &s->chn[1]);
|
||||||
|
qemu_chr_add_event_handler(chr2, serial_event);
|
||||||
|
}
|
||||||
|
register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s);
|
||||||
|
qemu_register_reset(slavio_serial_reset, s);
|
||||||
|
slavio_serial_reset(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sunkbd_event(void *opaque, int ch)
|
||||||
|
{
|
||||||
|
ChannelState *s = opaque;
|
||||||
|
// XXX: PC -> Sun Type 5 translation?
|
||||||
|
serial_receive_byte(s, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sunmouse_event(void *opaque,
|
||||||
|
int dx, int dy, int dz, int buttons_state)
|
||||||
|
{
|
||||||
|
ChannelState *s = opaque;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
ch = 0x42;
|
||||||
|
serial_receive_byte(s, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void slavio_serial_ms_kbd_init(int base, int irq)
|
||||||
|
{
|
||||||
|
int slavio_serial_io_memory;
|
||||||
|
SerialState *s;
|
||||||
|
|
||||||
|
s = qemu_mallocz(sizeof(SerialState));
|
||||||
|
if (!s)
|
||||||
|
return;
|
||||||
|
s->chn[0].irq = irq;
|
||||||
|
s->chn[1].irq = irq;
|
||||||
|
s->chn[0].chr = NULL;
|
||||||
|
s->chn[1].chr = NULL;
|
||||||
|
|
||||||
|
slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
|
||||||
|
cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
|
||||||
|
|
||||||
|
qemu_add_kbd_event_handler(sunkbd_event, &s->chn[0]);
|
||||||
|
qemu_add_mouse_event_handler(sunmouse_event, &s->chn[1]);
|
||||||
|
qemu_register_reset(slavio_serial_reset, s);
|
||||||
|
slavio_serial_reset(s);
|
||||||
|
}
|
289
hw/slavio_timer.c
Normal file
289
hw/slavio_timer.c
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
/*
|
||||||
|
* QEMU Sparc SLAVIO timer controller emulation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2004 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* 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 "vl.h"
|
||||||
|
|
||||||
|
//#define DEBUG_TIMER
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Registers of hardware timer in sun4m.
|
||||||
|
*
|
||||||
|
* This is the timer/counter part of chip STP2001 (Slave I/O), also
|
||||||
|
* produced as NCR89C105. See
|
||||||
|
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
|
||||||
|
*
|
||||||
|
* The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
|
||||||
|
* are zero. Bit 31 is 1 when count has been reached.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct SLAVIO_TIMERState {
|
||||||
|
uint32_t limit, count, counthigh;
|
||||||
|
int64_t count_load_time;
|
||||||
|
int64_t expire_time;
|
||||||
|
int64_t stop_time, tick_offset;
|
||||||
|
QEMUTimer *irq_timer;
|
||||||
|
int irq;
|
||||||
|
int reached, stopped;
|
||||||
|
int mode; // 0 = processor, 1 = user, 2 = system
|
||||||
|
} SLAVIO_TIMERState;
|
||||||
|
|
||||||
|
#define TIMER_MAXADDR 0x1f
|
||||||
|
#define CNT_FREQ 2000000
|
||||||
|
#define MAX_CPUS 16
|
||||||
|
|
||||||
|
// Update count, set irq, update expire_time
|
||||||
|
static void slavio_timer_get_out(SLAVIO_TIMERState *s)
|
||||||
|
{
|
||||||
|
int out;
|
||||||
|
int64_t diff, ticks, count;
|
||||||
|
uint32_t limit;
|
||||||
|
|
||||||
|
// There are three clock tick units: CPU ticks, register units
|
||||||
|
// (nanoseconds), and counter ticks (500 ns).
|
||||||
|
if (s->mode == 1 && s->stopped)
|
||||||
|
ticks = s->stop_time;
|
||||||
|
else
|
||||||
|
ticks = qemu_get_clock(vm_clock) - s->tick_offset;
|
||||||
|
|
||||||
|
out = (ticks >= s->expire_time);
|
||||||
|
if (out)
|
||||||
|
s->reached = 0x80000000;
|
||||||
|
if (!s->limit)
|
||||||
|
limit = 0x7fffffff;
|
||||||
|
else
|
||||||
|
limit = s->limit;
|
||||||
|
|
||||||
|
// Convert register units to counter ticks
|
||||||
|
limit = limit >> 9;
|
||||||
|
|
||||||
|
// Convert cpu ticks to counter ticks
|
||||||
|
diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
|
||||||
|
|
||||||
|
// Calculate what the counter should be, convert to register
|
||||||
|
// units
|
||||||
|
count = diff % limit;
|
||||||
|
s->count = count << 9;
|
||||||
|
s->counthigh = count >> 22;
|
||||||
|
|
||||||
|
// Expire time: CPU ticks left to next interrupt
|
||||||
|
// Convert remaining counter ticks to CPU ticks
|
||||||
|
s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
|
||||||
|
|
||||||
|
#ifdef DEBUG_TIMER
|
||||||
|
term_printf("timer: irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
|
||||||
|
#endif
|
||||||
|
if (s->mode != 1)
|
||||||
|
pic_set_irq(s->irq, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// timer callback
|
||||||
|
static void slavio_timer_irq(void *opaque)
|
||||||
|
{
|
||||||
|
SLAVIO_TIMERState *s = opaque;
|
||||||
|
|
||||||
|
if (!s->irq_timer)
|
||||||
|
return;
|
||||||
|
slavio_timer_get_out(s);
|
||||||
|
if (s->mode != 1)
|
||||||
|
qemu_mod_timer(s->irq_timer, s->expire_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||||
|
{
|
||||||
|
SLAVIO_TIMERState *s = opaque;
|
||||||
|
uint32_t saddr;
|
||||||
|
|
||||||
|
saddr = (addr & TIMER_MAXADDR) >> 2;
|
||||||
|
switch (saddr) {
|
||||||
|
case 0:
|
||||||
|
// read limit (system counter mode) or read most signifying
|
||||||
|
// part of counter (user mode)
|
||||||
|
if (s->mode != 1) {
|
||||||
|
// clear irq
|
||||||
|
pic_set_irq(s->irq, 0);
|
||||||
|
s->count_load_time = qemu_get_clock(vm_clock);
|
||||||
|
s->reached = 0;
|
||||||
|
return s->limit;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
slavio_timer_get_out(s);
|
||||||
|
return s->counthigh & 0x7fffffff;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
// read counter and reached bit (system mode) or read lsbits
|
||||||
|
// of counter (user mode)
|
||||||
|
slavio_timer_get_out(s);
|
||||||
|
if (s->mode != 1)
|
||||||
|
return (s->count & 0x7fffffff) | s->reached;
|
||||||
|
else
|
||||||
|
return s->count;
|
||||||
|
case 3:
|
||||||
|
// read start/stop status
|
||||||
|
return s->stopped;
|
||||||
|
case 4:
|
||||||
|
// read user/system mode
|
||||||
|
return s->mode & 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||||
|
{
|
||||||
|
SLAVIO_TIMERState *s = opaque;
|
||||||
|
uint32_t saddr;
|
||||||
|
|
||||||
|
saddr = (addr & TIMER_MAXADDR) >> 2;
|
||||||
|
switch (saddr) {
|
||||||
|
case 0:
|
||||||
|
// set limit, reset counter
|
||||||
|
s->count_load_time = qemu_get_clock(vm_clock);
|
||||||
|
// fall through
|
||||||
|
case 2:
|
||||||
|
// set limit without resetting counter
|
||||||
|
if (!val)
|
||||||
|
s->limit = 0x7fffffff;
|
||||||
|
else
|
||||||
|
s->limit = val & 0x7fffffff;
|
||||||
|
slavio_timer_irq(s);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// start/stop user counter
|
||||||
|
if (s->mode == 1) {
|
||||||
|
if (val & 1) {
|
||||||
|
s->stop_time = qemu_get_clock(vm_clock);
|
||||||
|
s->stopped = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (s->stopped)
|
||||||
|
s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time;
|
||||||
|
s->stopped = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
// bit 0: user (1) or system (0) counter mode
|
||||||
|
if (s->mode == 0 || s->mode == 1)
|
||||||
|
s->mode = val & 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
|
||||||
|
slavio_timer_mem_readl,
|
||||||
|
slavio_timer_mem_readl,
|
||||||
|
slavio_timer_mem_readl,
|
||||||
|
};
|
||||||
|
|
||||||
|
static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
|
||||||
|
slavio_timer_mem_writel,
|
||||||
|
slavio_timer_mem_writel,
|
||||||
|
slavio_timer_mem_writel,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void slavio_timer_save(QEMUFile *f, void *opaque)
|
||||||
|
{
|
||||||
|
SLAVIO_TIMERState *s = opaque;
|
||||||
|
|
||||||
|
qemu_put_be32s(f, &s->limit);
|
||||||
|
qemu_put_be32s(f, &s->count);
|
||||||
|
qemu_put_be32s(f, &s->counthigh);
|
||||||
|
qemu_put_be64s(f, &s->count_load_time);
|
||||||
|
qemu_put_be64s(f, &s->expire_time);
|
||||||
|
qemu_put_be64s(f, &s->stop_time);
|
||||||
|
qemu_put_be64s(f, &s->tick_offset);
|
||||||
|
qemu_put_be32s(f, &s->irq);
|
||||||
|
qemu_put_be32s(f, &s->reached);
|
||||||
|
qemu_put_be32s(f, &s->stopped);
|
||||||
|
qemu_put_be32s(f, &s->mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
SLAVIO_TIMERState *s = opaque;
|
||||||
|
|
||||||
|
if (version_id != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qemu_get_be32s(f, &s->limit);
|
||||||
|
qemu_get_be32s(f, &s->count);
|
||||||
|
qemu_get_be32s(f, &s->counthigh);
|
||||||
|
qemu_get_be64s(f, &s->count_load_time);
|
||||||
|
qemu_get_be64s(f, &s->expire_time);
|
||||||
|
qemu_get_be64s(f, &s->stop_time);
|
||||||
|
qemu_get_be64s(f, &s->tick_offset);
|
||||||
|
qemu_get_be32s(f, &s->irq);
|
||||||
|
qemu_get_be32s(f, &s->reached);
|
||||||
|
qemu_get_be32s(f, &s->stopped);
|
||||||
|
qemu_get_be32s(f, &s->mode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_timer_reset(void *opaque)
|
||||||
|
{
|
||||||
|
SLAVIO_TIMERState *s = opaque;
|
||||||
|
|
||||||
|
s->limit = 0;
|
||||||
|
s->count = 0;
|
||||||
|
s->count_load_time = qemu_get_clock(vm_clock);;
|
||||||
|
s->stop_time = s->count_load_time;
|
||||||
|
s->tick_offset = 0;
|
||||||
|
s->reached = 0;
|
||||||
|
s->mode &= 2;
|
||||||
|
s->stopped = 1;
|
||||||
|
slavio_timer_get_out(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
|
||||||
|
{
|
||||||
|
int slavio_timer_io_memory;
|
||||||
|
SLAVIO_TIMERState *s;
|
||||||
|
|
||||||
|
s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
|
||||||
|
if (!s)
|
||||||
|
return;
|
||||||
|
s->irq = irq;
|
||||||
|
s->mode = mode;
|
||||||
|
s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
|
||||||
|
|
||||||
|
slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
|
||||||
|
slavio_timer_mem_write, s);
|
||||||
|
cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory);
|
||||||
|
register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s);
|
||||||
|
qemu_register_reset(slavio_timer_reset, s);
|
||||||
|
slavio_timer_reset(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_CPUS; i++) {
|
||||||
|
slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
slavio_timer_init_internal(addr2, irq2, 2);
|
||||||
|
}
|
163
hw/sun4m.c
163
hw/sun4m.c
|
@ -25,29 +25,32 @@
|
||||||
#include "m48t08.h"
|
#include "m48t08.h"
|
||||||
|
|
||||||
#define KERNEL_LOAD_ADDR 0x00004000
|
#define KERNEL_LOAD_ADDR 0x00004000
|
||||||
#define MMU_CONTEXT_TBL 0x00003000
|
#define PROM_ADDR 0xffd00000
|
||||||
#define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400)
|
|
||||||
#define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800)
|
|
||||||
#define PROM_ADDR 0xffd04000
|
|
||||||
#define PROM_FILENAMEB "proll.bin"
|
#define PROM_FILENAMEB "proll.bin"
|
||||||
#define PROM_FILENAMEE "proll.elf"
|
#define PROM_FILENAMEE "proll.elf"
|
||||||
#define PROLL_MAGIC_ADDR 0x20000000
|
#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */
|
||||||
#define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */
|
|
||||||
#define PHYS_JJ_IDPROM_OFF 0x1FD8
|
#define PHYS_JJ_IDPROM_OFF 0x1FD8
|
||||||
#define PHYS_JJ_EEPROM_SIZE 0x2000
|
#define PHYS_JJ_EEPROM_SIZE 0x2000
|
||||||
#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */
|
// IRQs are not PIL ones, but master interrupt controller register
|
||||||
|
// bits
|
||||||
|
#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */
|
||||||
#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */
|
#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */
|
||||||
#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */
|
#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */
|
||||||
#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */
|
#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */
|
||||||
#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */
|
#define PHYS_JJ_LE_IRQ 16
|
||||||
#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */
|
#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */
|
||||||
#define PHYS_JJ_LE_IRQ 6
|
#define PHYS_JJ_CLOCK_IRQ 7
|
||||||
#define PHYS_JJ_CLOCK 0x71D00000
|
#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */
|
||||||
#define PHYS_JJ_CLOCK_IRQ 10
|
#define PHYS_JJ_CLOCK1_IRQ 19
|
||||||
#define PHYS_JJ_CLOCK1 0x71D10000
|
#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */
|
||||||
#define PHYS_JJ_CLOCK1_IRQ 14
|
|
||||||
#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */
|
|
||||||
#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */
|
#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */
|
||||||
|
#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */
|
||||||
|
#define PHYS_JJ_MS_KBD_IRQ 14
|
||||||
|
#define PHYS_JJ_SER 0x71100000 /* Serial */
|
||||||
|
#define PHYS_JJ_SER_IRQ 15
|
||||||
|
#define PHYS_JJ_SCSI_IRQ 18
|
||||||
|
#define PHYS_JJ_FDC 0x71400000 /* Floppy */
|
||||||
|
#define PHYS_JJ_FLOPPY_IRQ 22
|
||||||
|
|
||||||
/* TSC handling */
|
/* TSC handling */
|
||||||
|
|
||||||
|
@ -57,13 +60,73 @@ uint64_t cpu_get_tsc()
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA_run() {}
|
void DMA_run() {}
|
||||||
void SB16_run() {}
|
|
||||||
int serial_can_receive(SerialState *s) { return 0; }
|
|
||||||
void serial_receive_byte(SerialState *s, int ch) {}
|
|
||||||
void serial_receive_break(SerialState *s) {}
|
|
||||||
|
|
||||||
static m48t08_t *nvram;
|
static m48t08_t *nvram;
|
||||||
|
|
||||||
|
static void nvram_init(m48t08_t *nvram, uint8_t *macaddr)
|
||||||
|
{
|
||||||
|
unsigned char tmp = 0;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
i = 0x1fd8;
|
||||||
|
m48t08_write(nvram, i++, 0x01);
|
||||||
|
m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */
|
||||||
|
j = 0;
|
||||||
|
m48t08_write(nvram, i++, macaddr[j++]);
|
||||||
|
m48t08_write(nvram, i++, macaddr[j++]);
|
||||||
|
m48t08_write(nvram, i++, macaddr[j++]);
|
||||||
|
m48t08_write(nvram, i++, macaddr[j++]);
|
||||||
|
m48t08_write(nvram, i++, macaddr[j++]);
|
||||||
|
m48t08_write(nvram, i, macaddr[j]);
|
||||||
|
|
||||||
|
/* Calculate checksum */
|
||||||
|
for (i = 0x1fd8; i < 0x1fe7; i++) {
|
||||||
|
tmp ^= m48t08_read(nvram, i);
|
||||||
|
}
|
||||||
|
m48t08_write(nvram, 0x1fe7, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *slavio_intctl;
|
||||||
|
|
||||||
|
void pic_info()
|
||||||
|
{
|
||||||
|
slavio_pic_info(slavio_intctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void irq_info()
|
||||||
|
{
|
||||||
|
slavio_irq_info(slavio_intctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pic_set_irq(int irq, int level)
|
||||||
|
{
|
||||||
|
slavio_pic_set_irq(slavio_intctl, irq, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *tcx;
|
||||||
|
|
||||||
|
void vga_update_display()
|
||||||
|
{
|
||||||
|
tcx_update_display(tcx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_invalidate_display()
|
||||||
|
{
|
||||||
|
tcx_invalidate_display(tcx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_screen_dump(const char *filename)
|
||||||
|
{
|
||||||
|
tcx_screen_dump(tcx, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *iommu;
|
||||||
|
|
||||||
|
uint32_t iommu_translate(uint32_t addr)
|
||||||
|
{
|
||||||
|
return iommu_translate_local(iommu, addr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Sun4m hardware initialisation */
|
/* Sun4m hardware initialisation */
|
||||||
void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
||||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||||
|
@ -72,42 +135,50 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int ret, linux_boot;
|
int ret, linux_boot;
|
||||||
unsigned long bios_offset;
|
unsigned long vram_size = 0x100000, prom_offset;
|
||||||
|
|
||||||
linux_boot = (kernel_filename != NULL);
|
linux_boot = (kernel_filename != NULL);
|
||||||
|
|
||||||
/* allocate RAM */
|
/* allocate RAM */
|
||||||
cpu_register_physical_memory(0, ram_size, 0);
|
cpu_register_physical_memory(0, ram_size, 0);
|
||||||
bios_offset = ram_size;
|
|
||||||
|
|
||||||
iommu_init(PHYS_JJ_IOMMU);
|
iommu = iommu_init(PHYS_JJ_IOMMU);
|
||||||
sched_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
|
slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
|
||||||
tcx_init(ds, PHYS_JJ_TCX_FB);
|
tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size);
|
||||||
lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
|
lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
|
||||||
nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE, &nd_table[0].macaddr);
|
nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE);
|
||||||
timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ);
|
nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr);
|
||||||
timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
|
slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
|
||||||
magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR, PROLL_MAGIC_ADDR);
|
slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ);
|
||||||
|
slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]);
|
||||||
|
fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
|
||||||
|
|
||||||
/* We load Proll as the kernel and start it. It will issue a magic
|
prom_offset = ram_size + vram_size;
|
||||||
IO to load the real kernel */
|
|
||||||
if (linux_boot) {
|
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
|
||||||
|
ret = load_elf(buf, phys_ram_base + prom_offset);
|
||||||
|
if (ret < 0) {
|
||||||
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
|
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
|
||||||
ret = load_kernel(buf,
|
ret = load_image(buf, phys_ram_base + prom_offset);
|
||||||
phys_ram_base + KERNEL_LOAD_ADDR);
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "qemu: could not load prom '%s'\n",
|
||||||
|
buf);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
|
||||||
|
prom_offset | IO_MEM_ROM);
|
||||||
|
|
||||||
|
if (linux_boot) {
|
||||||
|
ret = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
|
||||||
|
if (ret < 0)
|
||||||
|
ret = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
|
||||||
|
if (ret < 0)
|
||||||
|
ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||||
buf);
|
kernel_filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Setup a MMU entry for entire address space */
|
|
||||||
stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1);
|
|
||||||
stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1);
|
|
||||||
stl_raw(phys_ram_base + MMU_L1PTP + (0x01 << 2), (MMU_L2PTP >> 4) | 1); // 01.. == 00..
|
|
||||||
stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00..
|
|
||||||
stl_raw(phys_ram_base + MMU_L1PTP + (0xf0 << 2), (MMU_L2PTP >> 4) | 1); // f0.. == 00..
|
|
||||||
/* 3 = U:RWX S:RWX */
|
|
||||||
stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2);
|
|
||||||
stl_raw(phys_ram_base + MMU_L2PTP, ((0x01 << PTE_PPN_SHIFT) >> 4 ) | (3 << PTE_ACCESS_SHIFT) | 2);
|
|
||||||
}
|
}
|
||||||
|
|
321
hw/tcx.c
321
hw/tcx.c
|
@ -25,179 +25,254 @@
|
||||||
|
|
||||||
#define MAXX 1024
|
#define MAXX 1024
|
||||||
#define MAXY 768
|
#define MAXY 768
|
||||||
|
/*
|
||||||
|
* Proll uses only small part of display, we need to switch to full
|
||||||
|
* display when we get linux framebuffer console or X11 running. For
|
||||||
|
* now it's just slower and awkward.
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
#define XSZ (8*80)
|
#define XSZ (8*80)
|
||||||
#define YSZ (24*11)
|
#define YSZ (24*11)
|
||||||
#define XOFF (MAXX-XSZ)
|
#define XOFF (MAXX-XSZ)
|
||||||
#define YOFF (MAXY-YSZ)
|
#define YOFF (MAXY-YSZ)
|
||||||
|
#else
|
||||||
|
#define XSZ MAXX
|
||||||
|
#define YSZ MAXY
|
||||||
|
#define XOFF 0
|
||||||
|
#define YOFF 0
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct TCXState {
|
typedef struct TCXState {
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
DisplayState *ds;
|
DisplayState *ds;
|
||||||
uint8_t *vram;
|
uint8_t *vram;
|
||||||
|
unsigned long vram_offset;
|
||||||
|
uint8_t r[256], g[256], b[256];
|
||||||
} TCXState;
|
} TCXState;
|
||||||
|
|
||||||
static TCXState *ts;
|
static void tcx_draw_line32(TCXState *s1, uint8_t *d,
|
||||||
|
const uint8_t *s, int width)
|
||||||
void vga_update_display()
|
|
||||||
{
|
{
|
||||||
dpy_update(ts->ds, 0, 0, XSZ, YSZ);
|
int x;
|
||||||
|
uint8_t val;
|
||||||
|
|
||||||
|
for(x = 0; x < width; x++) {
|
||||||
|
val = *s++;
|
||||||
|
*d++ = s1->r[val];
|
||||||
|
*d++ = s1->g[val];
|
||||||
|
*d++ = s1->b[val];
|
||||||
|
d++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_invalidate_display() {}
|
static void tcx_draw_line24(TCXState *s1, uint8_t *d,
|
||||||
|
const uint8_t *s, int width)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
uint8_t val;
|
||||||
|
|
||||||
static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr)
|
for(x = 0; x < width; x++) {
|
||||||
|
val = *s++;
|
||||||
|
*d++ = s1->r[val];
|
||||||
|
*d++ = s1->g[val];
|
||||||
|
*d++ = s1->b[val];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcx_draw_line8(TCXState *s1, uint8_t *d,
|
||||||
|
const uint8_t *s, int width)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
uint8_t val;
|
||||||
|
|
||||||
|
for(x = 0; x < width; x++) {
|
||||||
|
val = *s++;
|
||||||
|
/* XXX translate between palettes? */
|
||||||
|
*d++ = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fixed line length 1024 allows us to do nice tricks not possible on
|
||||||
|
VGA... */
|
||||||
|
void tcx_update_display(void *opaque)
|
||||||
|
{
|
||||||
|
TCXState *ts = opaque;
|
||||||
|
uint32_t page;
|
||||||
|
int y, page_min, page_max, y_start, dd, ds;
|
||||||
|
uint8_t *d, *s;
|
||||||
|
void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
|
||||||
|
|
||||||
|
if (ts->ds->depth == 0)
|
||||||
|
return;
|
||||||
|
#ifdef LD_BYPASS_OK
|
||||||
|
page = ts->vram_offset + YOFF*MAXX;
|
||||||
|
#else
|
||||||
|
page = ts->addr + YOFF*MAXX;
|
||||||
|
#endif
|
||||||
|
y_start = -1;
|
||||||
|
page_min = 0x7fffffff;
|
||||||
|
page_max = -1;
|
||||||
|
d = ts->ds->data;
|
||||||
|
s = ts->vram + YOFF*MAXX + XOFF;
|
||||||
|
dd = ts->ds->linesize;
|
||||||
|
ds = 1024;
|
||||||
|
|
||||||
|
switch (ts->ds->depth) {
|
||||||
|
case 32:
|
||||||
|
f = tcx_draw_line32;
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
f = tcx_draw_line24;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case 8:
|
||||||
|
f = tcx_draw_line8;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) {
|
||||||
|
if (cpu_physical_memory_is_dirty(page)) {
|
||||||
|
if (y_start < 0)
|
||||||
|
y_start = y;
|
||||||
|
if (page < page_min)
|
||||||
|
page_min = page;
|
||||||
|
if (page > page_max)
|
||||||
|
page_max = page;
|
||||||
|
f(ts, d, s, XSZ);
|
||||||
|
d += dd;
|
||||||
|
s += ds;
|
||||||
|
f(ts, d, s, XSZ);
|
||||||
|
d += dd;
|
||||||
|
s += ds;
|
||||||
|
f(ts, d, s, XSZ);
|
||||||
|
d += dd;
|
||||||
|
s += ds;
|
||||||
|
f(ts, d, s, XSZ);
|
||||||
|
d += dd;
|
||||||
|
s += ds;
|
||||||
|
} else {
|
||||||
|
if (y_start >= 0) {
|
||||||
|
/* flush to display */
|
||||||
|
dpy_update(ts->ds, 0, y_start,
|
||||||
|
XSZ, y - y_start);
|
||||||
|
y_start = -1;
|
||||||
|
}
|
||||||
|
d += dd * 4;
|
||||||
|
s += ds * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y_start >= 0) {
|
||||||
|
/* flush to display */
|
||||||
|
dpy_update(ts->ds, 0, y_start,
|
||||||
|
XSZ, y - y_start);
|
||||||
|
}
|
||||||
|
/* reset modified pages */
|
||||||
|
if (page_max != -1) {
|
||||||
|
cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcx_invalidate_display(void *opaque)
|
||||||
{
|
{
|
||||||
TCXState *s = opaque;
|
TCXState *s = opaque;
|
||||||
uint32_t saddr;
|
int i;
|
||||||
unsigned int x, y;
|
|
||||||
|
|
||||||
saddr = addr - s->addr - YOFF*MAXX - XOFF;
|
for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
|
||||||
y = saddr / MAXX;
|
#ifdef LD_BYPASS_OK
|
||||||
x = saddr - y * MAXX;
|
cpu_physical_memory_set_dirty(s->vram_offset + i);
|
||||||
if (x < XSZ && y < YSZ) {
|
#else
|
||||||
return s->vram[y * XSZ + x];
|
cpu_physical_memory_set_dirty(s->addr + i);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcx_save(QEMUFile *f, void *opaque)
|
||||||
|
{
|
||||||
|
TCXState *s = opaque;
|
||||||
|
|
||||||
|
qemu_put_be32s(f, (uint32_t *)&s->addr);
|
||||||
|
qemu_put_be32s(f, (uint32_t *)&s->vram);
|
||||||
|
qemu_put_buffer(f, s->r, 256);
|
||||||
|
qemu_put_buffer(f, s->g, 256);
|
||||||
|
qemu_put_buffer(f, s->b, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcx_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
TCXState *s = opaque;
|
||||||
|
|
||||||
|
if (version_id != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
qemu_get_be32s(f, (uint32_t *)&s->addr);
|
||||||
|
qemu_get_be32s(f, (uint32_t *)&s->vram);
|
||||||
|
qemu_get_buffer(f, s->r, 256);
|
||||||
|
qemu_get_buffer(f, s->g, 256);
|
||||||
|
qemu_get_buffer(f, s->b, 256);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr)
|
static void tcx_reset(void *opaque)
|
||||||
{
|
|
||||||
uint32_t v;
|
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
|
||||||
v = tcx_mem_readb(opaque, addr) << 8;
|
|
||||||
v |= tcx_mem_readb(opaque, addr + 1);
|
|
||||||
#else
|
|
||||||
v = tcx_mem_readb(opaque, addr);
|
|
||||||
v |= tcx_mem_readb(opaque, addr + 1) << 8;
|
|
||||||
#endif
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
uint32_t v;
|
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
|
||||||
v = tcx_mem_readb(opaque, addr) << 24;
|
|
||||||
v |= tcx_mem_readb(opaque, addr + 1) << 16;
|
|
||||||
v |= tcx_mem_readb(opaque, addr + 2) << 8;
|
|
||||||
v |= tcx_mem_readb(opaque, addr + 3);
|
|
||||||
#else
|
|
||||||
v = tcx_mem_readb(opaque, addr);
|
|
||||||
v |= tcx_mem_readb(opaque, addr + 1) << 8;
|
|
||||||
v |= tcx_mem_readb(opaque, addr + 2) << 16;
|
|
||||||
v |= tcx_mem_readb(opaque, addr + 3) << 24;
|
|
||||||
#endif
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
{
|
||||||
TCXState *s = opaque;
|
TCXState *s = opaque;
|
||||||
uint32_t saddr;
|
|
||||||
unsigned int x, y;
|
|
||||||
char *sptr;
|
|
||||||
|
|
||||||
saddr = addr - s->addr - YOFF*MAXX - XOFF;
|
/* Initialize palette */
|
||||||
y = saddr / MAXX;
|
memset(s->r, 0, 256);
|
||||||
x = saddr - y * MAXX;
|
memset(s->g, 0, 256);
|
||||||
if (x < XSZ && y < YSZ) {
|
memset(s->b, 0, 256);
|
||||||
sptr = s->ds->data;
|
s->r[255] = s->g[255] = s->b[255] = 255;
|
||||||
if (sptr) {
|
memset(s->vram, 0, MAXX*MAXY);
|
||||||
if (s->ds->depth == 24 || s->ds->depth == 32) {
|
#ifdef LD_BYPASS_OK
|
||||||
/* XXX need to do CLUT translation */
|
cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY - 1);
|
||||||
sptr[y * s->ds->linesize + x*4] = val & 0xff;
|
|
||||||
sptr[y * s->ds->linesize + x*4+1] = val & 0xff;
|
|
||||||
sptr[y * s->ds->linesize + x*4+2] = val & 0xff;
|
|
||||||
}
|
|
||||||
else if (s->ds->depth == 8) {
|
|
||||||
sptr[y * s->ds->linesize + x] = val & 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cpu_physical_memory_set_dirty(addr);
|
|
||||||
s->vram[y * XSZ + x] = val & 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
|
||||||
tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff);
|
|
||||||
tcx_mem_writeb(opaque, addr + 1, val & 0xff);
|
|
||||||
#else
|
|
||||||
tcx_mem_writeb(opaque, addr, val & 0xff);
|
|
||||||
tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
|
||||||
{
|
unsigned long vram_offset, int vram_size)
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
|
||||||
tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff);
|
|
||||||
tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
|
|
||||||
tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
|
|
||||||
tcx_mem_writeb(opaque, addr + 3, val & 0xff);
|
|
||||||
#else
|
|
||||||
tcx_mem_writeb(opaque, addr, val & 0xff);
|
|
||||||
tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
|
||||||
tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
|
|
||||||
tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static CPUReadMemoryFunc *tcx_mem_read[3] = {
|
|
||||||
tcx_mem_readb,
|
|
||||||
tcx_mem_readw,
|
|
||||||
tcx_mem_readl,
|
|
||||||
};
|
|
||||||
|
|
||||||
static CPUWriteMemoryFunc *tcx_mem_write[3] = {
|
|
||||||
tcx_mem_writeb,
|
|
||||||
tcx_mem_writew,
|
|
||||||
tcx_mem_writel,
|
|
||||||
};
|
|
||||||
|
|
||||||
void tcx_init(DisplayState *ds, uint32_t addr)
|
|
||||||
{
|
{
|
||||||
TCXState *s;
|
TCXState *s;
|
||||||
int tcx_io_memory;
|
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(TCXState));
|
s = qemu_mallocz(sizeof(TCXState));
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return NULL;
|
||||||
s->ds = ds;
|
s->ds = ds;
|
||||||
s->addr = addr;
|
s->addr = addr;
|
||||||
ts = s;
|
s->vram = vram_base;
|
||||||
tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s);
|
s->vram_offset = vram_offset;
|
||||||
cpu_register_physical_memory(addr, 0x100000,
|
|
||||||
tcx_io_memory);
|
cpu_register_physical_memory(addr, vram_size, vram_offset);
|
||||||
s->vram = qemu_mallocz(XSZ*YSZ);
|
|
||||||
|
register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
|
||||||
|
qemu_register_reset(tcx_reset, s);
|
||||||
|
tcx_reset(s);
|
||||||
dpy_resize(s->ds, XSZ, YSZ);
|
dpy_resize(s->ds, XSZ, YSZ);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_screen_dump(const char *filename)
|
void tcx_screen_dump(void *opaque, const char *filename)
|
||||||
{
|
{
|
||||||
TCXState *s = ts;
|
TCXState *s = opaque;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
uint8_t *d, *d1;
|
uint8_t *d, *d1, v;
|
||||||
unsigned int v;
|
|
||||||
int y, x;
|
int y, x;
|
||||||
|
|
||||||
f = fopen(filename, "wb");
|
f = fopen(filename, "wb");
|
||||||
if (!f)
|
if (!f)
|
||||||
return -1;
|
return;
|
||||||
fprintf(f, "P6\n%d %d\n%d\n",
|
fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255);
|
||||||
XSZ, YSZ, 255);
|
d1 = s->vram + YOFF*MAXX + XOFF;
|
||||||
d1 = s->vram;
|
|
||||||
for(y = 0; y < YSZ; y++) {
|
for(y = 0; y < YSZ; y++) {
|
||||||
d = d1;
|
d = d1;
|
||||||
for(x = 0; x < XSZ; x++) {
|
for(x = 0; x < XSZ; x++) {
|
||||||
v = *d;
|
v = *d;
|
||||||
fputc((v) & 0xff, f);
|
fputc(s->r[v], f);
|
||||||
fputc((v) & 0xff, f);
|
fputc(s->g[v], f);
|
||||||
fputc((v) & 0xff, f);
|
fputc(s->b[v], f);
|
||||||
d++;
|
d++;
|
||||||
}
|
}
|
||||||
d1 += XSZ;
|
d1 += MAXX;
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return;
|
return;
|
||||||
|
|
97
hw/timer.c
97
hw/timer.c
|
@ -1,97 +0,0 @@
|
||||||
/*
|
|
||||||
* QEMU Sparc timer controller emulation
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003-2004 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* 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 "vl.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Registers of hardware timer in sun4m.
|
|
||||||
*/
|
|
||||||
struct sun4m_timer_percpu {
|
|
||||||
volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
|
|
||||||
volatile unsigned int l14_cur_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sun4m_timer_global {
|
|
||||||
volatile unsigned int l10_timer_limit;
|
|
||||||
volatile unsigned int l10_cur_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TIMERState {
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t timer_regs[2];
|
|
||||||
int irq;
|
|
||||||
} TIMERState;
|
|
||||||
|
|
||||||
static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr)
|
|
||||||
{
|
|
||||||
TIMERState *s = opaque;
|
|
||||||
uint32_t saddr;
|
|
||||||
|
|
||||||
saddr = (addr - s->addr) >> 2;
|
|
||||||
switch (saddr) {
|
|
||||||
default:
|
|
||||||
return s->timer_regs[saddr];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|
||||||
{
|
|
||||||
TIMERState *s = opaque;
|
|
||||||
uint32_t saddr;
|
|
||||||
|
|
||||||
saddr = (addr - s->addr) >> 2;
|
|
||||||
switch (saddr) {
|
|
||||||
default:
|
|
||||||
s->timer_regs[saddr] = val;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CPUReadMemoryFunc *timer_mem_read[3] = {
|
|
||||||
timer_mem_readl,
|
|
||||||
timer_mem_readl,
|
|
||||||
timer_mem_readl,
|
|
||||||
};
|
|
||||||
|
|
||||||
static CPUWriteMemoryFunc *timer_mem_write[3] = {
|
|
||||||
timer_mem_writel,
|
|
||||||
timer_mem_writel,
|
|
||||||
timer_mem_writel,
|
|
||||||
};
|
|
||||||
|
|
||||||
void timer_init(uint32_t addr, int irq)
|
|
||||||
{
|
|
||||||
int timer_io_memory;
|
|
||||||
TIMERState *s;
|
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(TIMERState));
|
|
||||||
if (!s)
|
|
||||||
return;
|
|
||||||
s->addr = addr;
|
|
||||||
s->irq = irq;
|
|
||||||
|
|
||||||
timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s);
|
|
||||||
cpu_register_physical_memory(addr, 2, timer_io_memory);
|
|
||||||
}
|
|
|
@ -841,6 +841,7 @@ static void load_symbols(struct elfhdr *hdr, int fd)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct elf_shdr sechdr, symtab, strtab;
|
struct elf_shdr sechdr, symtab, strtab;
|
||||||
char *strings;
|
char *strings;
|
||||||
|
struct syminfo *s;
|
||||||
|
|
||||||
lseek(fd, hdr->e_shoff, SEEK_SET);
|
lseek(fd, hdr->e_shoff, SEEK_SET);
|
||||||
for (i = 0; i < hdr->e_shnum; i++) {
|
for (i = 0; i < hdr->e_shnum; i++) {
|
||||||
|
@ -866,24 +867,27 @@ static void load_symbols(struct elfhdr *hdr, int fd)
|
||||||
|
|
||||||
found:
|
found:
|
||||||
/* Now know where the strtab and symtab are. Snarf them. */
|
/* Now know where the strtab and symtab are. Snarf them. */
|
||||||
disas_symtab = malloc(symtab.sh_size);
|
s = malloc(sizeof(*s));
|
||||||
disas_strtab = strings = malloc(strtab.sh_size);
|
s->disas_symtab = malloc(symtab.sh_size);
|
||||||
if (!disas_symtab || !disas_strtab)
|
s->disas_strtab = strings = malloc(strtab.sh_size);
|
||||||
|
if (!s->disas_symtab || !s->disas_strtab)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lseek(fd, symtab.sh_offset, SEEK_SET);
|
lseek(fd, symtab.sh_offset, SEEK_SET);
|
||||||
if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
|
if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef BSWAP_NEEDED
|
#ifdef BSWAP_NEEDED
|
||||||
for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
|
for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
|
||||||
bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
|
bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lseek(fd, strtab.sh_offset, SEEK_SET);
|
lseek(fd, strtab.sh_offset, SEEK_SET);
|
||||||
if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
|
if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
|
||||||
return;
|
return;
|
||||||
disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
|
s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
|
||||||
|
s->next = syminfos;
|
||||||
|
syminfos = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||||
|
|
|
@ -497,6 +497,8 @@ void cpu_loop (CPUSPARCState *env)
|
||||||
case TT_WIN_UNF: /* window underflow */
|
case TT_WIN_UNF: /* window underflow */
|
||||||
restore_window(env);
|
restore_window(env);
|
||||||
break;
|
break;
|
||||||
|
case 0x100: // XXX, why do we get these?
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||||
cpu_dump_state(env, stderr, fprintf, 0);
|
cpu_dump_state(env, stderr, fprintf, 0);
|
||||||
|
|
|
@ -1354,13 +1354,14 @@ struct target_rt_signal_frame {
|
||||||
__siginfo_fpu_t fpu_state;
|
__siginfo_fpu_t fpu_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UREG_O0 0
|
#define UREG_O0 16
|
||||||
#define UREG_O6 6
|
#define UREG_O6 22
|
||||||
#define UREG_I0 16
|
#define UREG_I0 0
|
||||||
#define UREG_I1 17
|
#define UREG_I1 1
|
||||||
#define UREG_I2 18
|
#define UREG_I2 2
|
||||||
#define UREG_I6 22
|
#define UREG_I6 6
|
||||||
#define UREG_I7 23
|
#define UREG_I7 7
|
||||||
|
#define UREG_L0 8
|
||||||
#define UREG_FP UREG_I6
|
#define UREG_FP UREG_I6
|
||||||
#define UREG_SP UREG_O6
|
#define UREG_SP UREG_O6
|
||||||
|
|
||||||
|
@ -1385,23 +1386,20 @@ setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask)
|
||||||
{
|
{
|
||||||
int err = 0, i;
|
int err = 0, i;
|
||||||
|
|
||||||
fprintf(stderr, "2.a %lx psr: %lx regs: %lx\n", si, env->psr, si->si_regs.psr);
|
|
||||||
err |= __put_user(env->psr, &si->si_regs.psr);
|
err |= __put_user(env->psr, &si->si_regs.psr);
|
||||||
fprintf(stderr, "2.a1 pc:%lx\n", si->si_regs.pc);
|
|
||||||
err |= __put_user(env->pc, &si->si_regs.pc);
|
err |= __put_user(env->pc, &si->si_regs.pc);
|
||||||
err |= __put_user(env->npc, &si->si_regs.npc);
|
err |= __put_user(env->npc, &si->si_regs.npc);
|
||||||
err |= __put_user(env->y, &si->si_regs.y);
|
err |= __put_user(env->y, &si->si_regs.y);
|
||||||
fprintf(stderr, "2.b\n");
|
|
||||||
for (i=0; i < 7; i++) {
|
for (i=0; i < 7; i++) {
|
||||||
err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
|
err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
|
||||||
}
|
}
|
||||||
for (i=0; i < 7; i++) {
|
for (i=0; i < 7; i++) {
|
||||||
err |= __put_user(env->regwptr[i+16], &si->si_regs.u_regs[i+8]);
|
err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "2.c\n");
|
|
||||||
err |= __put_user(mask, &si->si_mask);
|
err |= __put_user(mask, &si->si_mask);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
|
setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
|
||||||
CPUState *env, unsigned long mask)
|
CPUState *env, unsigned long mask)
|
||||||
|
@ -1434,6 +1432,7 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||||
sf = (struct target_signal_frame *)
|
sf = (struct target_signal_frame *)
|
||||||
get_sigframe(ka, env, sigframe_size);
|
get_sigframe(ka, env, sigframe_size);
|
||||||
|
|
||||||
|
//fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
|
||||||
#if 0
|
#if 0
|
||||||
if (invalid_frame_pointer(sf, sigframe_size))
|
if (invalid_frame_pointer(sf, sigframe_size))
|
||||||
goto sigill_and_return;
|
goto sigill_and_return;
|
||||||
|
@ -1451,13 +1450,11 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
err |= __put_user(env->regwptr[i + 8], &sf->ss.locals[i]);
|
err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
err |= __put_user(env->regwptr[i + 16], &sf->ss.ins[i]);
|
err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
|
||||||
}
|
}
|
||||||
//err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
|
||||||
// sizeof(struct reg_window));
|
|
||||||
if (err)
|
if (err)
|
||||||
goto sigsegv;
|
goto sigsegv;
|
||||||
|
|
||||||
|
@ -1486,13 +1483,15 @@ static void setup_frame(int sig, struct emulated_sigaction *ka,
|
||||||
|
|
||||||
/* Flush instruction space. */
|
/* Flush instruction space. */
|
||||||
//flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
|
//flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
|
||||||
//tb_flush(env);
|
tb_flush(env);
|
||||||
}
|
}
|
||||||
|
//cpu_dump_state(env, stderr, fprintf, 0);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sigill_and_return:
|
sigill_and_return:
|
||||||
force_sig(TARGET_SIGILL);
|
force_sig(TARGET_SIGILL);
|
||||||
sigsegv:
|
sigsegv:
|
||||||
|
//fprintf(stderr, "force_sig\n");
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
}
|
}
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -1542,13 +1541,16 @@ static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
||||||
long do_sigreturn(CPUState *env)
|
long do_sigreturn(CPUState *env)
|
||||||
{
|
{
|
||||||
struct target_signal_frame *sf;
|
struct target_signal_frame *sf;
|
||||||
unsigned long up_psr, pc, npc;
|
uint32_t up_psr, pc, npc;
|
||||||
target_sigset_t set;
|
target_sigset_t set;
|
||||||
|
sigset_t host_set;
|
||||||
__siginfo_fpu_t *fpu_save;
|
__siginfo_fpu_t *fpu_save;
|
||||||
int err;
|
int err, i;
|
||||||
|
|
||||||
sf = (struct new_signal_frame *) env->regwptr[UREG_FP];
|
sf = (struct target_signal_frame *) env->regwptr[UREG_FP];
|
||||||
fprintf(stderr, "sigreturn sf: %lx\n", &sf);
|
fprintf(stderr, "sigreturn\n");
|
||||||
|
fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
|
||||||
|
//cpu_dump_state(env, stderr, fprintf, 0);
|
||||||
|
|
||||||
/* 1. Make sure we are not getting garbage from the user */
|
/* 1. Make sure we are not getting garbage from the user */
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1567,36 +1569,41 @@ long do_sigreturn(CPUState *env)
|
||||||
goto segv_and_exit;
|
goto segv_and_exit;
|
||||||
|
|
||||||
/* 2. Restore the state */
|
/* 2. Restore the state */
|
||||||
up_psr = env->psr;
|
err |= __get_user(up_psr, &sf->info.si_regs.psr);
|
||||||
//err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)
|
|
||||||
//);
|
|
||||||
/* User can only change condition codes and FPU enabling in %psr. */
|
/* User can only change condition codes and FPU enabling in %psr. */
|
||||||
env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */))
|
env->psr = (up_psr & ~(PSR_ICC /* | PSR_EF */))
|
||||||
| (env->psr & (PSR_ICC /* | PSR_EF */));
|
| (env->psr & (PSR_ICC /* | PSR_EF */));
|
||||||
fprintf(stderr, "psr: %lx\n", env->psr);
|
fprintf(stderr, "psr: %x\n", env->psr);
|
||||||
|
env->pc = pc-4;
|
||||||
|
env->npc = pc;
|
||||||
|
err |= __get_user(env->y, &sf->info.si_regs.y);
|
||||||
|
for (i=0; i < 7; i++) {
|
||||||
|
err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
|
||||||
|
}
|
||||||
|
for (i=0; i < 7; i++) {
|
||||||
|
err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
|
||||||
|
}
|
||||||
|
|
||||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||||
|
|
||||||
if (fpu_save)
|
//if (fpu_save)
|
||||||
err |= restore_fpu_state(env, fpu_save);
|
// err |= restore_fpu_state(env, fpu_save);
|
||||||
|
|
||||||
/* This is pretty much atomic, no amount locking would prevent
|
/* This is pretty much atomic, no amount locking would prevent
|
||||||
* the races which exist anyways.
|
* the races which exist anyways.
|
||||||
*/
|
*/
|
||||||
err |= __get_user(set.sig[0], &sf->info.si_mask);
|
err |= __get_user(set.sig[0], &sf->info.si_mask);
|
||||||
//err |= __copy_from_user(&set.sig[1], &sf->extramask,
|
for(i = 1; i < TARGET_NSIG_WORDS; i++) {
|
||||||
// (_NSIG_WORDS-1) * sizeof(unsigned int));
|
err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
target_to_host_sigset_internal(&host_set, &set);
|
||||||
|
sigprocmask(SIG_SETMASK, &host_set, NULL);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto segv_and_exit;
|
goto segv_and_exit;
|
||||||
|
|
||||||
#if 0
|
|
||||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
|
||||||
spin_lock_irq(¤t->sigmask_lock);
|
|
||||||
current->blocked = set;
|
|
||||||
recalc_sigpending(current);
|
|
||||||
spin_unlock_irq(¤t->sigmask_lock);
|
|
||||||
#endif
|
|
||||||
fprintf(stderr, "returning %lx\n", env->regwptr[0]);
|
fprintf(stderr, "returning %lx\n", env->regwptr[0]);
|
||||||
return env->regwptr[0];
|
return env->regwptr[0];
|
||||||
|
|
||||||
|
|
Binary file not shown.
BIN
pc-bios/proll.elf
Normal file
BIN
pc-bios/proll.elf
Normal file
Binary file not shown.
2098
pc-bios/proll.patch
2098
pc-bios/proll.patch
File diff suppressed because it is too large
Load diff
|
@ -1099,6 +1099,29 @@ Set the initial VGA graphic mode. The default is 800x600x15.
|
||||||
More information is available at
|
More information is available at
|
||||||
@url{http://jocelyn.mayer.free.fr/qemu-ppc/}.
|
@url{http://jocelyn.mayer.free.fr/qemu-ppc/}.
|
||||||
|
|
||||||
|
@chapter Sparc System emulator invocation
|
||||||
|
|
||||||
|
Use the executable @file{qemu-system-sparc} to simulate a JavaStation
|
||||||
|
(sun4m architecture). The emulation is far from complete.
|
||||||
|
|
||||||
|
QEMU emulates the following sun4m peripherials:
|
||||||
|
|
||||||
|
@itemize @minus
|
||||||
|
@item
|
||||||
|
IOMMU
|
||||||
|
@item
|
||||||
|
TCX Frame buffer
|
||||||
|
@item
|
||||||
|
Lance (Am7990) Ethernet
|
||||||
|
@item
|
||||||
|
Non Volatile RAM M48T08
|
||||||
|
@item
|
||||||
|
Slave I/O: timers, interrupt controllers, Zilog serial ports
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
QEMU uses the Proll, a PROM replacement available at
|
||||||
|
@url{http://people.redhat.com/zaitcev/linux/}.
|
||||||
|
|
||||||
@chapter QEMU User space emulator invocation
|
@chapter QEMU User space emulator invocation
|
||||||
|
|
||||||
@section Quick Start
|
@section Quick Start
|
||||||
|
|
|
@ -126,7 +126,7 @@ maximum performances.
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
|
|
||||||
@item Full PowerPC 32 bit emulation, including priviledged instructions,
|
@item Full PowerPC 32 bit emulation, including privileged instructions,
|
||||||
FPU and MMU.
|
FPU and MMU.
|
||||||
|
|
||||||
@item Can run most PowerPC Linux binaries.
|
@item Can run most PowerPC Linux binaries.
|
||||||
|
@ -137,7 +137,8 @@ FPU and MMU.
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
|
|
||||||
@item SPARC V8 user support, except FPU instructions.
|
@item Somewhat complete SPARC V8 emulation, including privileged
|
||||||
|
instructions, FPU and MMU.
|
||||||
|
|
||||||
@item Can run some SPARC Linux binaries.
|
@item Can run some SPARC Linux binaries.
|
||||||
|
|
||||||
|
|
|
@ -10,23 +10,42 @@
|
||||||
/* trap definitions */
|
/* trap definitions */
|
||||||
#define TT_ILL_INSN 0x02
|
#define TT_ILL_INSN 0x02
|
||||||
#define TT_PRIV_INSN 0x03
|
#define TT_PRIV_INSN 0x03
|
||||||
|
#define TT_NFPU_INSN 0x04
|
||||||
#define TT_WIN_OVF 0x05
|
#define TT_WIN_OVF 0x05
|
||||||
#define TT_WIN_UNF 0x06
|
#define TT_WIN_UNF 0x06
|
||||||
#define TT_FP_EXCP 0x08
|
#define TT_FP_EXCP 0x08
|
||||||
#define TT_DIV_ZERO 0x2a
|
#define TT_DIV_ZERO 0x2a
|
||||||
#define TT_TRAP 0x80
|
#define TT_TRAP 0x80
|
||||||
|
#define TT_EXTINT 0x10
|
||||||
|
|
||||||
#define PSR_NEG (1<<23)
|
#define PSR_NEG (1<<23)
|
||||||
#define PSR_ZERO (1<<22)
|
#define PSR_ZERO (1<<22)
|
||||||
#define PSR_OVF (1<<21)
|
#define PSR_OVF (1<<21)
|
||||||
#define PSR_CARRY (1<<20)
|
#define PSR_CARRY (1<<20)
|
||||||
#define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
|
#define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
|
||||||
|
#define PSR_EF (1<<12)
|
||||||
|
#define PSR_PIL 0xf00
|
||||||
#define PSR_S (1<<7)
|
#define PSR_S (1<<7)
|
||||||
#define PSR_PS (1<<6)
|
#define PSR_PS (1<<6)
|
||||||
#define PSR_ET (1<<5)
|
#define PSR_ET (1<<5)
|
||||||
#define PSR_CWP 0x1f
|
#define PSR_CWP 0x1f
|
||||||
/* Fake impl 0, version 4 */
|
/* Fake impl 0, version 4 */
|
||||||
#define GET_PSR(env) ((0<<28) | (4<<24) | env->psr | (env->psrs? PSR_S : 0) | (env->psrs? PSR_PS : 0) |(env->psret? PSR_ET : 0) | env->cwp)
|
#define GET_PSR(env) ((0 << 28) | (4 << 24) | env->psr | \
|
||||||
|
(env->psref? PSR_EF : 0) | \
|
||||||
|
(env->psrpil << 8) | \
|
||||||
|
(env->psrs? PSR_S : 0) | \
|
||||||
|
(env->psrs? PSR_PS : 0) | \
|
||||||
|
(env->psret? PSR_ET : 0) | env->cwp)
|
||||||
|
|
||||||
|
#define PUT_PSR(env, val) do { int _tmp = val; \
|
||||||
|
env->psr = _tmp & ~PSR_ICC; \
|
||||||
|
env->psref = (_tmp & PSR_EF)? 1 : 0; \
|
||||||
|
env->psrpil = (_tmp & PSR_PIL) >> 8; \
|
||||||
|
env->psrs = (_tmp & PSR_S)? 1 : 0; \
|
||||||
|
env->psrps = (_tmp & PSR_PS)? 1 : 0; \
|
||||||
|
env->psret = (_tmp & PSR_ET)? 1 : 0; \
|
||||||
|
set_cwp(_tmp & PSR_CWP & (NWINDOWS - 1)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* Trap base register */
|
/* Trap base register */
|
||||||
#define TBR_BASE_MASK 0xfffff000
|
#define TBR_BASE_MASK 0xfffff000
|
||||||
|
@ -65,6 +84,9 @@
|
||||||
#define FSR_FTT1 (1<<15)
|
#define FSR_FTT1 (1<<15)
|
||||||
#define FSR_FTT0 (1<<14)
|
#define FSR_FTT0 (1<<14)
|
||||||
#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
|
#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
|
||||||
|
#define FSR_FTT_IEEE_EXCP (1 << 14)
|
||||||
|
#define FSR_FTT_UNIMPFPOP (3 << 14)
|
||||||
|
#define FSR_FTT_INVAL_FPR (6 << 14)
|
||||||
|
|
||||||
#define FSR_FCC1 (1<<11)
|
#define FSR_FCC1 (1<<11)
|
||||||
#define FSR_FCC0 (1<<10)
|
#define FSR_FCC0 (1<<10)
|
||||||
|
@ -106,6 +128,8 @@ typedef struct CPUSPARCState {
|
||||||
int psrs; /* supervisor mode (extracted from PSR) */
|
int psrs; /* supervisor mode (extracted from PSR) */
|
||||||
int psrps; /* previous supervisor mode */
|
int psrps; /* previous supervisor mode */
|
||||||
int psret; /* enable traps */
|
int psret; /* enable traps */
|
||||||
|
int psrpil; /* interrupt level */
|
||||||
|
int psref; /* enable fpu */
|
||||||
jmp_buf jmp_env;
|
jmp_buf jmp_env;
|
||||||
int user_mode_only;
|
int user_mode_only;
|
||||||
int exception_index;
|
int exception_index;
|
||||||
|
@ -144,6 +168,8 @@ typedef struct CPUSPARCState {
|
||||||
CPUSPARCState *cpu_sparc_init(void);
|
CPUSPARCState *cpu_sparc_init(void);
|
||||||
int cpu_sparc_exec(CPUSPARCState *s);
|
int cpu_sparc_exec(CPUSPARCState *s);
|
||||||
int cpu_sparc_close(CPUSPARCState *s);
|
int cpu_sparc_close(CPUSPARCState *s);
|
||||||
|
void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f);
|
||||||
|
double cpu_put_fp64(uint64_t mant, uint16_t exp);
|
||||||
|
|
||||||
struct siginfo;
|
struct siginfo;
|
||||||
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
|
int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
|
||||||
|
|
|
@ -40,6 +40,9 @@ void do_interrupt(int intno, int is_int, int error_code,
|
||||||
void raise_exception_err(int exception_index, int error_code);
|
void raise_exception_err(int exception_index, int error_code);
|
||||||
void raise_exception(int tt);
|
void raise_exception(int tt);
|
||||||
void memcpy32(uint32_t *dst, const uint32_t *src);
|
void memcpy32(uint32_t *dst, const uint32_t *src);
|
||||||
|
uint32_t mmu_probe(uint32_t address, int mmulev);
|
||||||
|
void dump_mmu(void);
|
||||||
|
void helper_debug();
|
||||||
|
|
||||||
/* XXX: move that to a generic header */
|
/* XXX: move that to a generic header */
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
|
|
@ -51,18 +51,6 @@ void OPPROTO glue(op_store_FT2_fpr_fpr, REGNAME)(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* double floating point registers moves */
|
/* double floating point registers moves */
|
||||||
#if 0
|
|
||||||
#define CPU_DOUBLE_U_DEF
|
|
||||||
typedef union {
|
|
||||||
double d;
|
|
||||||
struct {
|
|
||||||
uint32_t lower;
|
|
||||||
uint32_t upper;
|
|
||||||
} l;
|
|
||||||
uint64_t ll;
|
|
||||||
} CPU_DoubleU;
|
|
||||||
#endif /* CPU_DOUBLE_U_DEF */
|
|
||||||
|
|
||||||
void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void)
|
void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void)
|
||||||
{
|
{
|
||||||
CPU_DoubleU u;
|
CPU_DoubleU u;
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
*/
|
*/
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
|
|
||||||
#define DEBUG_PCALL
|
//#define DEBUG_PCALL
|
||||||
|
//#define DEBUG_MMU
|
||||||
|
|
||||||
/* Sparc MMU emulation */
|
/* Sparc MMU emulation */
|
||||||
int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||||
|
@ -108,80 +109,71 @@ static const int rw_table[2][8] = {
|
||||||
{ 0, 1, 0, 1, 0, 0, 0, 0 }
|
{ 0, 1, 0, 1, 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
|
||||||
/* Perform address translation */
|
int *access_index, uint32_t address, int rw,
|
||||||
int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
int is_user)
|
||||||
int is_user, int is_softmmu)
|
|
||||||
{
|
{
|
||||||
int exception = 0;
|
int access_perms = 0;
|
||||||
int access_perms = 0, access_index = 0;
|
target_phys_addr_t pde_ptr;
|
||||||
uint8_t *pde_ptr;
|
|
||||||
uint32_t pde, virt_addr;
|
uint32_t pde, virt_addr;
|
||||||
int error_code = 0, is_dirty, prot, ret = 0;
|
int error_code = 0, is_dirty;
|
||||||
unsigned long paddr, vaddr, page_offset;
|
unsigned long page_offset;
|
||||||
|
|
||||||
if (env->user_mode_only) {
|
|
||||||
/* user mode only emulation */
|
|
||||||
ret = -2;
|
|
||||||
goto do_fault;
|
|
||||||
}
|
|
||||||
|
|
||||||
virt_addr = address & TARGET_PAGE_MASK;
|
virt_addr = address & TARGET_PAGE_MASK;
|
||||||
if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
|
if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
|
||||||
paddr = address;
|
*physical = address;
|
||||||
page_offset = address & (TARGET_PAGE_SIZE - 1);
|
*prot = PAGE_READ | PAGE_WRITE;
|
||||||
prot = PAGE_READ | PAGE_WRITE;
|
return 0;
|
||||||
goto do_mapping;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SPARC reference MMU table walk: Context table->L1->L2->PTE */
|
/* SPARC reference MMU table walk: Context table->L1->L2->PTE */
|
||||||
/* Context base + context number */
|
/* Context base + context number */
|
||||||
pde_ptr = phys_ram_base + (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
|
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
|
||||||
pde = ldl_raw(pde_ptr);
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
|
bswap32s(&pde);
|
||||||
|
|
||||||
/* Ctx pde */
|
/* Ctx pde */
|
||||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||||
|
default:
|
||||||
case 0: /* Invalid */
|
case 0: /* Invalid */
|
||||||
error_code = 1;
|
return 1;
|
||||||
goto do_fault;
|
case 2: /* L0 PTE, maybe should not happen? */
|
||||||
case 2: /* PTE, maybe should not happen? */
|
|
||||||
case 3: /* Reserved */
|
case 3: /* Reserved */
|
||||||
error_code = 4;
|
return 4;
|
||||||
goto do_fault;
|
case 1: /* L0 PDE */
|
||||||
case 1: /* L1 PDE */
|
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
|
||||||
pde_ptr = phys_ram_base + ((address >> 22) & ~3) + ((pde & ~3) << 4);
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
pde = ldl_raw(pde_ptr);
|
bswap32s(&pde);
|
||||||
|
|
||||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||||
|
default:
|
||||||
case 0: /* Invalid */
|
case 0: /* Invalid */
|
||||||
error_code = 1;
|
return 1;
|
||||||
goto do_fault;
|
|
||||||
case 3: /* Reserved */
|
case 3: /* Reserved */
|
||||||
error_code = 4;
|
return 4;
|
||||||
goto do_fault;
|
case 1: /* L1 PDE */
|
||||||
case 1: /* L2 PDE */
|
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
|
||||||
pde_ptr = phys_ram_base + ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
pde = ldl_raw(pde_ptr);
|
bswap32s(&pde);
|
||||||
|
|
||||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||||
|
default:
|
||||||
case 0: /* Invalid */
|
case 0: /* Invalid */
|
||||||
error_code = 1;
|
return 1;
|
||||||
goto do_fault;
|
|
||||||
case 3: /* Reserved */
|
case 3: /* Reserved */
|
||||||
error_code = 4;
|
return 4;
|
||||||
goto do_fault;
|
case 1: /* L2 PDE */
|
||||||
case 1: /* L3 PDE */
|
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
|
||||||
pde_ptr = phys_ram_base + ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
pde = ldl_raw(pde_ptr);
|
bswap32s(&pde);
|
||||||
|
|
||||||
switch (pde & PTE_ENTRYTYPE_MASK) {
|
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||||
|
default:
|
||||||
case 0: /* Invalid */
|
case 0: /* Invalid */
|
||||||
error_code = 1;
|
return 1;
|
||||||
goto do_fault;
|
|
||||||
case 1: /* PDE, should not happen */
|
case 1: /* PDE, should not happen */
|
||||||
case 3: /* Reserved */
|
case 3: /* Reserved */
|
||||||
error_code = 4;
|
return 4;
|
||||||
goto do_fault;
|
|
||||||
case 2: /* L3 PTE */
|
case 2: /* L3 PTE */
|
||||||
virt_addr = address & TARGET_PAGE_MASK;
|
virt_addr = address & TARGET_PAGE_MASK;
|
||||||
page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
|
page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
|
||||||
|
@ -201,40 +193,58 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||||
/* update page modified and dirty bits */
|
/* update page modified and dirty bits */
|
||||||
is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
|
is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
|
||||||
if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
|
if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
|
||||||
|
uint32_t tmppde;
|
||||||
pde |= PG_ACCESSED_MASK;
|
pde |= PG_ACCESSED_MASK;
|
||||||
if (is_dirty)
|
if (is_dirty)
|
||||||
pde |= PG_MODIFIED_MASK;
|
pde |= PG_MODIFIED_MASK;
|
||||||
stl_raw(pde_ptr, pde);
|
tmppde = bswap32(pde);
|
||||||
|
cpu_physical_memory_write(pde_ptr, (uint8_t *)&tmppde, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check access */
|
/* check access */
|
||||||
access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
|
*access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
|
||||||
access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
|
access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
|
||||||
error_code = access_table[access_index][access_perms];
|
error_code = access_table[*access_index][access_perms];
|
||||||
if (error_code)
|
if (error_code)
|
||||||
goto do_fault;
|
return error_code;
|
||||||
|
|
||||||
/* the page can be put in the TLB */
|
/* the page can be put in the TLB */
|
||||||
prot = PAGE_READ;
|
*prot = PAGE_READ;
|
||||||
if (pde & PG_MODIFIED_MASK) {
|
if (pde & PG_MODIFIED_MASK) {
|
||||||
/* only set write access if already dirty... otherwise wait
|
/* only set write access if already dirty... otherwise wait
|
||||||
for dirty access */
|
for dirty access */
|
||||||
if (rw_table[is_user][access_perms])
|
if (rw_table[is_user][access_perms])
|
||||||
prot |= PAGE_WRITE;
|
*prot |= PAGE_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Even if large ptes, we map only one 4KB page in the cache to
|
/* Even if large ptes, we map only one 4KB page in the cache to
|
||||||
avoid filling it too fast */
|
avoid filling it too fast */
|
||||||
virt_addr = address & TARGET_PAGE_MASK;
|
*physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
|
||||||
paddr = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
do_mapping:
|
/* Perform address translation */
|
||||||
vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
|
int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||||
|
int is_user, int is_softmmu)
|
||||||
|
{
|
||||||
|
int exception = 0;
|
||||||
|
uint32_t virt_addr, paddr;
|
||||||
|
unsigned long vaddr;
|
||||||
|
int error_code = 0, prot, ret = 0, access_index;
|
||||||
|
|
||||||
ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
|
if (env->user_mode_only) {
|
||||||
return ret;
|
/* user mode only emulation */
|
||||||
|
error_code = -2;
|
||||||
|
goto do_fault_user;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
|
||||||
|
if (error_code == 0) {
|
||||||
|
virt_addr = address & TARGET_PAGE_MASK;
|
||||||
|
vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
|
||||||
|
ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
do_fault:
|
|
||||||
if (env->mmuregs[3]) /* Fault status register */
|
if (env->mmuregs[3]) /* Fault status register */
|
||||||
env->mmuregs[3] = 1; /* overflow (not read before another fault) */
|
env->mmuregs[3] = 1; /* overflow (not read before another fault) */
|
||||||
env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2;
|
env->mmuregs[3] |= (access_index << 5) | (error_code << 2) | 2;
|
||||||
|
@ -242,7 +252,7 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
||||||
|
|
||||||
if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault
|
if (env->mmuregs[0] & MMU_NF || env->psret == 0) // No fault
|
||||||
return 0;
|
return 0;
|
||||||
|
do_fault_user:
|
||||||
env->exception_index = exception;
|
env->exception_index = exception;
|
||||||
env->error_code = error_code;
|
env->error_code = error_code;
|
||||||
return error_code;
|
return error_code;
|
||||||
|
@ -289,13 +299,14 @@ void do_interrupt(int intno, int is_int, int error_code,
|
||||||
count, intno, error_code, is_int,
|
count, intno, error_code, is_int,
|
||||||
env->pc,
|
env->pc,
|
||||||
env->npc, env->regwptr[6]);
|
env->npc, env->regwptr[6]);
|
||||||
#if 0
|
#if 1
|
||||||
cpu_dump_state(env, logfile, fprintf, 0);
|
cpu_dump_state(env, logfile, fprintf, 0);
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
|
|
||||||
fprintf(logfile, " code=");
|
fprintf(logfile, " code=");
|
||||||
ptr = env->pc;
|
ptr = (uint8_t *)env->pc;
|
||||||
for(i = 0; i < 16; i++) {
|
for(i = 0; i < 16; i++) {
|
||||||
fprintf(logfile, " %02x", ldub(ptr + i));
|
fprintf(logfile, " %02x", ldub(ptr + i));
|
||||||
}
|
}
|
||||||
|
@ -304,12 +315,19 @@ void do_interrupt(int intno, int is_int, int error_code,
|
||||||
#endif
|
#endif
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
if (env->psret == 0) {
|
||||||
|
fprintf(logfile, "Trap while interrupts disabled, Error state!\n");
|
||||||
|
qemu_system_shutdown_request();
|
||||||
|
return;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
env->psret = 0;
|
env->psret = 0;
|
||||||
cwp = (env->cwp - 1) & (NWINDOWS - 1);
|
cwp = (env->cwp - 1) & (NWINDOWS - 1);
|
||||||
set_cwp(cwp);
|
set_cwp(cwp);
|
||||||
env->regwptr[9] = env->pc;
|
env->regwptr[9] = env->pc - 4; // XXX?
|
||||||
env->regwptr[10] = env->npc;
|
env->regwptr[10] = env->pc;
|
||||||
env->psrps = env->psrs;
|
env->psrps = env->psrs;
|
||||||
env->psrs = 1;
|
env->psrs = 1;
|
||||||
env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
|
env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
|
||||||
|
@ -322,3 +340,106 @@ void raise_exception_err(int exception_index, int error_code)
|
||||||
{
|
{
|
||||||
raise_exception(exception_index);
|
raise_exception(exception_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t mmu_probe(uint32_t address, int mmulev)
|
||||||
|
{
|
||||||
|
target_phys_addr_t pde_ptr;
|
||||||
|
uint32_t pde;
|
||||||
|
|
||||||
|
/* Context base + context number */
|
||||||
|
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
|
||||||
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
|
bswap32s(&pde);
|
||||||
|
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||||
|
default:
|
||||||
|
case 0: /* Invalid */
|
||||||
|
case 2: /* PTE, maybe should not happen? */
|
||||||
|
case 3: /* Reserved */
|
||||||
|
return 0;
|
||||||
|
case 1: /* L1 PDE */
|
||||||
|
if (mmulev == 3)
|
||||||
|
return pde;
|
||||||
|
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
|
||||||
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
|
bswap32s(&pde);
|
||||||
|
|
||||||
|
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||||
|
default:
|
||||||
|
case 0: /* Invalid */
|
||||||
|
case 3: /* Reserved */
|
||||||
|
return 0;
|
||||||
|
case 2: /* L1 PTE */
|
||||||
|
return pde;
|
||||||
|
case 1: /* L2 PDE */
|
||||||
|
if (mmulev == 2)
|
||||||
|
return pde;
|
||||||
|
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
|
||||||
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
|
bswap32s(&pde);
|
||||||
|
|
||||||
|
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||||
|
default:
|
||||||
|
case 0: /* Invalid */
|
||||||
|
case 3: /* Reserved */
|
||||||
|
return 0;
|
||||||
|
case 2: /* L2 PTE */
|
||||||
|
return pde;
|
||||||
|
case 1: /* L3 PDE */
|
||||||
|
if (mmulev == 1)
|
||||||
|
return pde;
|
||||||
|
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
|
||||||
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
|
bswap32s(&pde);
|
||||||
|
|
||||||
|
switch (pde & PTE_ENTRYTYPE_MASK) {
|
||||||
|
default:
|
||||||
|
case 0: /* Invalid */
|
||||||
|
case 1: /* PDE, should not happen */
|
||||||
|
case 3: /* Reserved */
|
||||||
|
return 0;
|
||||||
|
case 2: /* L3 PTE */
|
||||||
|
return pde;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_mmu(void)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
uint32_t pa, va, va1, va2;
|
||||||
|
int n, m, o;
|
||||||
|
target_phys_addr_t pde_ptr;
|
||||||
|
uint32_t pde;
|
||||||
|
|
||||||
|
printf("MMU dump:\n");
|
||||||
|
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 4);
|
||||||
|
cpu_physical_memory_read(pde_ptr, (uint8_t *)&pde, 4);
|
||||||
|
bswap32s(&pde);
|
||||||
|
printf("Root ptr: 0x%08x, ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
|
||||||
|
for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
|
||||||
|
pde_ptr = mmu_probe(va, 2);
|
||||||
|
if (pde_ptr) {
|
||||||
|
pa = cpu_get_phys_page_debug(env, va);
|
||||||
|
printf("VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va, pa, pde_ptr);
|
||||||
|
for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
|
||||||
|
pde_ptr = mmu_probe(va1, 1);
|
||||||
|
if (pde_ptr) {
|
||||||
|
pa = cpu_get_phys_page_debug(env, va1);
|
||||||
|
printf(" VA: 0x%08x, PA: 0x%08x PDE: 0x%08x\n", va1, pa, pde_ptr);
|
||||||
|
for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
|
||||||
|
pde_ptr = mmu_probe(va2, 0);
|
||||||
|
if (pde_ptr) {
|
||||||
|
pa = cpu_get_phys_page_debug(env, va2);
|
||||||
|
printf(" VA: 0x%08x, PA: 0x%08x PTE: 0x%08x\n", va2, pa, pde_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("MMU dump ends\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -524,13 +524,7 @@ void OPPROTO op_rdpsr(void)
|
||||||
|
|
||||||
void OPPROTO op_wrpsr(void)
|
void OPPROTO op_wrpsr(void)
|
||||||
{
|
{
|
||||||
int cwp;
|
PUT_PSR(env,T0);
|
||||||
env->psr = T0 & ~PSR_ICC;
|
|
||||||
env->psrs = (T0 & PSR_S)? 1 : 0;
|
|
||||||
env->psrps = (T0 & PSR_PS)? 1 : 0;
|
|
||||||
env->psret = (T0 & PSR_ET)? 1 : 0;
|
|
||||||
cwp = (T0 & PSR_CWP) & (NWINDOWS - 1);
|
|
||||||
set_cwp(cwp);
|
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,10 +596,27 @@ void OPPROTO op_trapcc_T0(void)
|
||||||
FORCE_RET();
|
FORCE_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_trap_ifnofpu(void)
|
||||||
|
{
|
||||||
|
if (!env->psref) {
|
||||||
|
env->exception_index = TT_NFPU_INSN;
|
||||||
|
cpu_loop_exit();
|
||||||
|
}
|
||||||
|
FORCE_RET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OPPROTO op_fpexception_im(void)
|
||||||
|
{
|
||||||
|
env->exception_index = TT_FP_EXCP;
|
||||||
|
env->fsr &= ~FSR_FTT_MASK;
|
||||||
|
env->fsr |= PARAM1;
|
||||||
|
cpu_loop_exit();
|
||||||
|
FORCE_RET();
|
||||||
|
}
|
||||||
|
|
||||||
void OPPROTO op_debug(void)
|
void OPPROTO op_debug(void)
|
||||||
{
|
{
|
||||||
env->exception_index = EXCP_DEBUG;
|
helper_debug();
|
||||||
cpu_loop_exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OPPROTO op_exit_tb(void)
|
void OPPROTO op_exit_tb(void)
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include <fenv.h>
|
#include <fenv.h>
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
|
|
||||||
|
//#define DEBUG_MMU
|
||||||
|
|
||||||
#ifdef USE_INT_TO_FLOAT_HELPERS
|
#ifdef USE_INT_TO_FLOAT_HELPERS
|
||||||
void do_fitos(void)
|
void do_fitos(void)
|
||||||
{
|
{
|
||||||
|
@ -33,6 +35,13 @@ void do_fcmps (void)
|
||||||
{
|
{
|
||||||
if (isnan(FT0) || isnan(FT1)) {
|
if (isnan(FT0) || isnan(FT1)) {
|
||||||
T0 = FSR_FCC1 | FSR_FCC0;
|
T0 = FSR_FCC1 | FSR_FCC0;
|
||||||
|
env->fsr &= ~(FSR_FCC1 | FSR_FCC0);
|
||||||
|
env->fsr |= T0;
|
||||||
|
if (env->fsr & FSR_NVM) {
|
||||||
|
raise_exception(TT_FP_EXCP);
|
||||||
|
} else {
|
||||||
|
env->fsr |= FSR_NVA;
|
||||||
|
}
|
||||||
} else if (FT0 < FT1) {
|
} else if (FT0 < FT1) {
|
||||||
T0 = FSR_FCC0;
|
T0 = FSR_FCC0;
|
||||||
} else if (FT0 > FT1) {
|
} else if (FT0 > FT1) {
|
||||||
|
@ -47,6 +56,13 @@ void do_fcmpd (void)
|
||||||
{
|
{
|
||||||
if (isnan(DT0) || isnan(DT1)) {
|
if (isnan(DT0) || isnan(DT1)) {
|
||||||
T0 = FSR_FCC1 | FSR_FCC0;
|
T0 = FSR_FCC1 | FSR_FCC0;
|
||||||
|
env->fsr &= ~(FSR_FCC1 | FSR_FCC0);
|
||||||
|
env->fsr |= T0;
|
||||||
|
if (env->fsr & FSR_NVM) {
|
||||||
|
raise_exception(TT_FP_EXCP);
|
||||||
|
} else {
|
||||||
|
env->fsr |= FSR_NVA;
|
||||||
|
}
|
||||||
} else if (DT0 < DT1) {
|
} else if (DT0 < DT1) {
|
||||||
T0 = FSR_FCC0;
|
T0 = FSR_FCC0;
|
||||||
} else if (DT0 > DT1) {
|
} else if (DT0 > DT1) {
|
||||||
|
@ -59,55 +75,131 @@ void do_fcmpd (void)
|
||||||
|
|
||||||
void helper_ld_asi(int asi, int size, int sign)
|
void helper_ld_asi(int asi, int size, int sign)
|
||||||
{
|
{
|
||||||
switch(asi) {
|
uint32_t ret;
|
||||||
|
|
||||||
|
switch (asi) {
|
||||||
case 3: /* MMU probe */
|
case 3: /* MMU probe */
|
||||||
T1 = 0;
|
{
|
||||||
return;
|
int mmulev;
|
||||||
|
|
||||||
|
mmulev = (T0 >> 8) & 15;
|
||||||
|
if (mmulev > 4)
|
||||||
|
ret = 0;
|
||||||
|
else {
|
||||||
|
ret = mmu_probe(T0, mmulev);
|
||||||
|
//bswap32s(&ret);
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 4: /* read MMU regs */
|
case 4: /* read MMU regs */
|
||||||
{
|
{
|
||||||
int temp, reg = (T0 >> 8) & 0xf;
|
int reg = (T0 >> 8) & 0xf;
|
||||||
|
|
||||||
temp = env->mmuregs[reg];
|
ret = env->mmuregs[reg];
|
||||||
if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/
|
if (reg == 3 || reg == 4) /* Fault status, addr cleared on read*/
|
||||||
env->mmuregs[reg] = 0;
|
env->mmuregs[4] = 0;
|
||||||
T1 = temp;
|
|
||||||
}
|
}
|
||||||
return;
|
break;
|
||||||
case 0x20 ... 0x2f: /* MMU passthrough */
|
case 0x20 ... 0x2f: /* MMU passthrough */
|
||||||
{
|
cpu_physical_memory_read(T0, (void *) &ret, size);
|
||||||
int temp;
|
if (size == 4)
|
||||||
|
bswap32s(&ret);
|
||||||
cpu_physical_memory_read(T0, (void *) &temp, size);
|
else if (size == 2)
|
||||||
bswap32s(&temp);
|
bswap16s(&ret);
|
||||||
T1 = temp;
|
break;
|
||||||
}
|
|
||||||
return;
|
|
||||||
default:
|
default:
|
||||||
T1 = 0;
|
ret = 0;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
T1 = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_st_asi(int asi, int size, int sign)
|
void helper_st_asi(int asi, int size, int sign)
|
||||||
{
|
{
|
||||||
switch(asi) {
|
switch(asi) {
|
||||||
case 3: /* MMU flush */
|
case 3: /* MMU flush */
|
||||||
return;
|
{
|
||||||
|
int mmulev;
|
||||||
|
|
||||||
|
mmulev = (T0 >> 8) & 15;
|
||||||
|
switch (mmulev) {
|
||||||
|
case 0: // flush page
|
||||||
|
tlb_flush_page(cpu_single_env, T0 & 0xfffff000);
|
||||||
|
break;
|
||||||
|
case 1: // flush segment (256k)
|
||||||
|
case 2: // flush region (16M)
|
||||||
|
case 3: // flush context (4G)
|
||||||
|
case 4: // flush entire
|
||||||
|
tlb_flush(cpu_single_env, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dump_mmu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
case 4: /* write MMU regs */
|
case 4: /* write MMU regs */
|
||||||
{
|
{
|
||||||
int reg = (T0 >> 8) & 0xf;
|
int reg = (T0 >> 8) & 0xf, oldreg;
|
||||||
|
|
||||||
|
oldreg = env->mmuregs[reg];
|
||||||
if (reg == 0) {
|
if (reg == 0) {
|
||||||
env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
|
env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
|
||||||
env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
|
env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
|
||||||
} else
|
} else
|
||||||
env->mmuregs[reg] = T1;
|
env->mmuregs[reg] = T1;
|
||||||
|
if (oldreg != env->mmuregs[reg]) {
|
||||||
|
#if 0
|
||||||
|
// XXX: Only if MMU mapping change, we may need to flush?
|
||||||
|
tlb_flush(cpu_single_env, 1);
|
||||||
|
cpu_loop_exit();
|
||||||
|
FORCE_RET();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
dump_mmu();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case 0x17: /* Block copy, sta access */
|
||||||
|
{
|
||||||
|
// value (T1) = src
|
||||||
|
// address (T0) = dst
|
||||||
|
// copy 32 bytes
|
||||||
|
int src = T1, dst = T0;
|
||||||
|
uint8_t temp[32];
|
||||||
|
|
||||||
|
bswap32s(&src);
|
||||||
|
|
||||||
|
cpu_physical_memory_read(src, (void *) &temp, 32);
|
||||||
|
cpu_physical_memory_write(dst, (void *) &temp, 32);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 0x1f: /* Block fill, stda access */
|
||||||
|
{
|
||||||
|
// value (T1, T2)
|
||||||
|
// address (T0) = dst
|
||||||
|
// fill 32 bytes
|
||||||
|
int i, dst = T0;
|
||||||
|
uint64_t val;
|
||||||
|
|
||||||
|
val = (((uint64_t)T1) << 32) | T2;
|
||||||
|
bswap64s(&val);
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i += 8, dst += 8) {
|
||||||
|
cpu_physical_memory_write(dst, (void *) &val, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
case 0x20 ... 0x2f: /* MMU passthrough */
|
case 0x20 ... 0x2f: /* MMU passthrough */
|
||||||
{
|
{
|
||||||
int temp = T1;
|
int temp = T1;
|
||||||
|
if (size == 4)
|
||||||
|
bswap32s(&temp);
|
||||||
|
else if (size == 2)
|
||||||
|
bswap16s(&temp);
|
||||||
|
|
||||||
bswap32s(&temp);
|
|
||||||
cpu_physical_memory_write(T0, (void *) &temp, size);
|
cpu_physical_memory_write(T0, (void *) &temp, size);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -116,27 +208,6 @@ void helper_st_asi(int asi, int size, int sign)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
void do_ldd_raw(uint32_t addr)
|
|
||||||
{
|
|
||||||
T1 = ldl_raw((void *) addr);
|
|
||||||
T0 = ldl_raw((void *) (addr + 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
void do_ldd_user(uint32_t addr)
|
|
||||||
{
|
|
||||||
T1 = ldl_user((void *) addr);
|
|
||||||
T0 = ldl_user((void *) (addr + 4));
|
|
||||||
}
|
|
||||||
void do_ldd_kernel(uint32_t addr)
|
|
||||||
{
|
|
||||||
T1 = ldl_kernel((void *) addr);
|
|
||||||
T0 = ldl_kernel((void *) (addr + 4));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void helper_rett()
|
void helper_rett()
|
||||||
{
|
{
|
||||||
int cwp;
|
int cwp;
|
||||||
|
@ -166,3 +237,22 @@ void helper_ldfsr(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f)
|
||||||
|
{
|
||||||
|
int exptemp;
|
||||||
|
|
||||||
|
*pmant = ldexp(frexp(f, &exptemp), 53);
|
||||||
|
*pexp = exptemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
double cpu_put_fp64(uint64_t mant, uint16_t exp)
|
||||||
|
{
|
||||||
|
return ldexp((double) mant, exp - 53);
|
||||||
|
}
|
||||||
|
|
||||||
|
void helper_debug()
|
||||||
|
{
|
||||||
|
env->exception_index = EXCP_DEBUG;
|
||||||
|
cpu_loop_exit();
|
||||||
|
}
|
||||||
|
|
|
@ -43,12 +43,8 @@ void OPPROTO glue(op_swap, MEMSUFFIX)(void)
|
||||||
|
|
||||||
void OPPROTO glue(op_ldd, MEMSUFFIX)(void)
|
void OPPROTO glue(op_ldd, MEMSUFFIX)(void)
|
||||||
{
|
{
|
||||||
#if 1
|
|
||||||
T1 = glue(ldl, MEMSUFFIX)((void *) T0);
|
T1 = glue(ldl, MEMSUFFIX)((void *) T0);
|
||||||
T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4));
|
T0 = glue(ldl, MEMSUFFIX)((void *) (T0 + 4));
|
||||||
#else
|
|
||||||
glue(do_ldd, MEMSUFFIX)(T0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** Floating-point store ***/
|
/*** Floating-point store ***/
|
||||||
|
|
|
@ -646,6 +646,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
switch (xop) {
|
switch (xop) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
case 0x1: /* UNIMPL */
|
case 0x1: /* UNIMPL */
|
||||||
|
case 0x5: /*CBN+x */
|
||||||
default:
|
default:
|
||||||
goto illegal_insn;
|
goto illegal_insn;
|
||||||
case 0x2: /* BN+x */
|
case 0x2: /* BN+x */
|
||||||
|
@ -657,16 +658,24 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
}
|
}
|
||||||
case 0x6: /* FBN+x */
|
case 0x6: /* FBN+x */
|
||||||
{
|
{
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
gen_op_trap_ifnofpu();
|
||||||
|
#endif
|
||||||
target <<= 2;
|
target <<= 2;
|
||||||
target = sign_extend(target, 22);
|
target = sign_extend(target, 22);
|
||||||
do_fbranch(dc, target, insn);
|
do_fbranch(dc, target, insn);
|
||||||
goto jmp_insn;
|
goto jmp_insn;
|
||||||
}
|
}
|
||||||
case 0x4: /* SETHI */
|
case 0x4: /* SETHI */
|
||||||
gen_movl_imm_T0(target << 10);
|
#define OPTIM
|
||||||
gen_movl_T0_reg(rd);
|
#if defined(OPTIM)
|
||||||
break;
|
if (rd) { // nop
|
||||||
case 0x5: /*CBN+x */
|
#endif
|
||||||
|
gen_movl_imm_T0(target << 10);
|
||||||
|
gen_movl_T0_reg(rd);
|
||||||
|
#if defined(OPTIM)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -691,14 +700,24 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_movl_reg_T0(rs1);
|
gen_movl_reg_T0(rs1);
|
||||||
if (IS_IMM) {
|
if (IS_IMM) {
|
||||||
rs2 = GET_FIELD(insn, 25, 31);
|
rs2 = GET_FIELD(insn, 25, 31);
|
||||||
|
#if defined(OPTIM)
|
||||||
if (rs2 != 0) {
|
if (rs2 != 0) {
|
||||||
gen_movl_imm_T1(rs2);
|
#endif
|
||||||
gen_op_add_T1_T0();
|
gen_movl_imm_T1(rs2);
|
||||||
|
gen_op_add_T1_T0();
|
||||||
|
#if defined(OPTIM)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
rs2 = GET_FIELD(insn, 27, 31);
|
rs2 = GET_FIELD(insn, 27, 31);
|
||||||
gen_movl_reg_T1(rs2);
|
#if defined(OPTIM)
|
||||||
gen_op_add_T1_T0();
|
if (rs2 != 0) {
|
||||||
|
#endif
|
||||||
|
gen_movl_reg_T1(rs2);
|
||||||
|
gen_op_add_T1_T0();
|
||||||
|
#if defined(OPTIM)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
save_state(dc);
|
save_state(dc);
|
||||||
cond = GET_FIELD(insn, 3, 6);
|
cond = GET_FIELD(insn, 3, 6);
|
||||||
|
@ -707,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
dc->is_br = 1;
|
dc->is_br = 1;
|
||||||
goto jmp_insn;
|
goto jmp_insn;
|
||||||
} else {
|
} else {
|
||||||
|
gen_cond(cond);
|
||||||
gen_op_trapcc_T0();
|
gen_op_trapcc_T0();
|
||||||
}
|
}
|
||||||
} else if (xop == 0x28) {
|
} else if (xop == 0x28) {
|
||||||
|
@ -741,7 +761,10 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_movl_T0_reg(rd);
|
gen_movl_T0_reg(rd);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
} else if (xop == 0x34 || xop == 0x35) { /* FPU Operations */
|
} else if (xop == 0x34) { /* FPU Operations */
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
gen_op_trap_ifnofpu();
|
||||||
|
#endif
|
||||||
rs1 = GET_FIELD(insn, 13, 17);
|
rs1 = GET_FIELD(insn, 13, 17);
|
||||||
rs2 = GET_FIELD(insn, 27, 31);
|
rs2 = GET_FIELD(insn, 27, 31);
|
||||||
xop = GET_FIELD(insn, 18, 26);
|
xop = GET_FIELD(insn, 18, 26);
|
||||||
|
@ -770,6 +793,8 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_fsqrtd();
|
gen_op_fsqrtd();
|
||||||
gen_op_store_DT0_fpr(rd);
|
gen_op_store_DT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
case 0x2b: /* fsqrtq */
|
||||||
|
goto nfpu_insn;
|
||||||
case 0x41:
|
case 0x41:
|
||||||
gen_op_load_fpr_FT0(rs1);
|
gen_op_load_fpr_FT0(rs1);
|
||||||
gen_op_load_fpr_FT1(rs2);
|
gen_op_load_fpr_FT1(rs2);
|
||||||
|
@ -782,6 +807,8 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_faddd();
|
gen_op_faddd();
|
||||||
gen_op_store_DT0_fpr(rd);
|
gen_op_store_DT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
case 0x43: /* faddq */
|
||||||
|
goto nfpu_insn;
|
||||||
case 0x45:
|
case 0x45:
|
||||||
gen_op_load_fpr_FT0(rs1);
|
gen_op_load_fpr_FT0(rs1);
|
||||||
gen_op_load_fpr_FT1(rs2);
|
gen_op_load_fpr_FT1(rs2);
|
||||||
|
@ -794,6 +821,8 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_fsubd();
|
gen_op_fsubd();
|
||||||
gen_op_store_DT0_fpr(rd);
|
gen_op_store_DT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
case 0x47: /* fsubq */
|
||||||
|
goto nfpu_insn;
|
||||||
case 0x49:
|
case 0x49:
|
||||||
gen_op_load_fpr_FT0(rs1);
|
gen_op_load_fpr_FT0(rs1);
|
||||||
gen_op_load_fpr_FT1(rs2);
|
gen_op_load_fpr_FT1(rs2);
|
||||||
|
@ -806,6 +835,8 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_fmuld();
|
gen_op_fmuld();
|
||||||
gen_op_store_DT0_fpr(rd);
|
gen_op_store_DT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
case 0x4b: /* fmulq */
|
||||||
|
goto nfpu_insn;
|
||||||
case 0x4d:
|
case 0x4d:
|
||||||
gen_op_load_fpr_FT0(rs1);
|
gen_op_load_fpr_FT0(rs1);
|
||||||
gen_op_load_fpr_FT1(rs2);
|
gen_op_load_fpr_FT1(rs2);
|
||||||
|
@ -818,32 +849,16 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_fdivd();
|
gen_op_fdivd();
|
||||||
gen_op_store_DT0_fpr(rd);
|
gen_op_store_DT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
case 0x51:
|
case 0x4f: /* fdivq */
|
||||||
gen_op_load_fpr_FT0(rs1);
|
goto nfpu_insn;
|
||||||
gen_op_load_fpr_FT1(rs2);
|
|
||||||
gen_op_fcmps();
|
|
||||||
break;
|
|
||||||
case 0x52:
|
|
||||||
gen_op_load_fpr_DT0(rs1);
|
|
||||||
gen_op_load_fpr_DT1(rs2);
|
|
||||||
gen_op_fcmpd();
|
|
||||||
break;
|
|
||||||
case 0x55: /* fcmpes */
|
|
||||||
gen_op_load_fpr_FT0(rs1);
|
|
||||||
gen_op_load_fpr_FT1(rs2);
|
|
||||||
gen_op_fcmps(); /* XXX */
|
|
||||||
break;
|
|
||||||
case 0x56: /* fcmped */
|
|
||||||
gen_op_load_fpr_DT0(rs1);
|
|
||||||
gen_op_load_fpr_DT1(rs2);
|
|
||||||
gen_op_fcmpd(); /* XXX */
|
|
||||||
break;
|
|
||||||
case 0x69:
|
case 0x69:
|
||||||
gen_op_load_fpr_FT0(rs1);
|
gen_op_load_fpr_FT0(rs1);
|
||||||
gen_op_load_fpr_FT1(rs2);
|
gen_op_load_fpr_FT1(rs2);
|
||||||
gen_op_fsmuld();
|
gen_op_fsmuld();
|
||||||
gen_op_store_DT0_fpr(rd);
|
gen_op_store_DT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
case 0x6e: /* fdmulq */
|
||||||
|
goto nfpu_insn;
|
||||||
case 0xc4:
|
case 0xc4:
|
||||||
gen_op_load_fpr_FT1(rs2);
|
gen_op_load_fpr_FT1(rs2);
|
||||||
gen_op_fitos();
|
gen_op_fitos();
|
||||||
|
@ -854,6 +869,8 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_fdtos();
|
gen_op_fdtos();
|
||||||
gen_op_store_FT0_fpr(rd);
|
gen_op_store_FT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
case 0xc7: /* fqtos */
|
||||||
|
goto nfpu_insn;
|
||||||
case 0xc8:
|
case 0xc8:
|
||||||
gen_op_load_fpr_FT1(rs2);
|
gen_op_load_fpr_FT1(rs2);
|
||||||
gen_op_fitod();
|
gen_op_fitod();
|
||||||
|
@ -864,6 +881,14 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_fstod();
|
gen_op_fstod();
|
||||||
gen_op_store_DT0_fpr(rd);
|
gen_op_store_DT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
case 0xcb: /* fqtod */
|
||||||
|
goto nfpu_insn;
|
||||||
|
case 0xcc: /* fitoq */
|
||||||
|
goto nfpu_insn;
|
||||||
|
case 0xcd: /* fstoq */
|
||||||
|
goto nfpu_insn;
|
||||||
|
case 0xce: /* fdtoq */
|
||||||
|
goto nfpu_insn;
|
||||||
case 0xd1:
|
case 0xd1:
|
||||||
gen_op_load_fpr_FT1(rs2);
|
gen_op_load_fpr_FT1(rs2);
|
||||||
gen_op_fstoi();
|
gen_op_fstoi();
|
||||||
|
@ -874,13 +899,85 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_fdtoi();
|
gen_op_fdtoi();
|
||||||
gen_op_store_FT0_fpr(rd);
|
gen_op_store_FT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
case 0xd3: /* fqtoi */
|
||||||
|
goto nfpu_insn;
|
||||||
default:
|
default:
|
||||||
goto illegal_insn;
|
goto illegal_insn;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (xop == 0x35) { /* FPU Operations */
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
gen_op_trap_ifnofpu();
|
||||||
|
#endif
|
||||||
rs1 = GET_FIELD(insn, 13, 17);
|
rs1 = GET_FIELD(insn, 13, 17);
|
||||||
gen_movl_reg_T0(rs1);
|
rs2 = GET_FIELD(insn, 27, 31);
|
||||||
if (IS_IMM) { /* immediate */
|
xop = GET_FIELD(insn, 18, 26);
|
||||||
|
switch (xop) {
|
||||||
|
case 0x51:
|
||||||
|
gen_op_load_fpr_FT0(rs1);
|
||||||
|
gen_op_load_fpr_FT1(rs2);
|
||||||
|
gen_op_fcmps();
|
||||||
|
break;
|
||||||
|
case 0x52:
|
||||||
|
gen_op_load_fpr_DT0(rs1);
|
||||||
|
gen_op_load_fpr_DT1(rs2);
|
||||||
|
gen_op_fcmpd();
|
||||||
|
break;
|
||||||
|
case 0x53: /* fcmpq */
|
||||||
|
goto nfpu_insn;
|
||||||
|
case 0x55: /* fcmpes */
|
||||||
|
gen_op_load_fpr_FT0(rs1);
|
||||||
|
gen_op_load_fpr_FT1(rs2);
|
||||||
|
gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */
|
||||||
|
break;
|
||||||
|
case 0x56: /* fcmped */
|
||||||
|
gen_op_load_fpr_DT0(rs1);
|
||||||
|
gen_op_load_fpr_DT1(rs2);
|
||||||
|
gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */
|
||||||
|
break;
|
||||||
|
case 0x57: /* fcmpeq */
|
||||||
|
goto nfpu_insn;
|
||||||
|
default:
|
||||||
|
goto illegal_insn;
|
||||||
|
}
|
||||||
|
#if defined(OPTIM)
|
||||||
|
} else if (xop == 0x2) {
|
||||||
|
// clr/mov shortcut
|
||||||
|
|
||||||
|
rs1 = GET_FIELD(insn, 13, 17);
|
||||||
|
if (rs1 == 0) {
|
||||||
|
// or %g0, x, y -> mov T1, x; mov y, T1
|
||||||
|
if (IS_IMM) { /* immediate */
|
||||||
|
rs2 = GET_FIELDs(insn, 19, 31);
|
||||||
|
gen_movl_imm_T1(rs2);
|
||||||
|
} else { /* register */
|
||||||
|
rs2 = GET_FIELD(insn, 27, 31);
|
||||||
|
gen_movl_reg_T1(rs2);
|
||||||
|
}
|
||||||
|
gen_movl_T1_reg(rd);
|
||||||
|
} else {
|
||||||
|
gen_movl_reg_T0(rs1);
|
||||||
|
if (IS_IMM) { /* immediate */
|
||||||
|
// or x, #0, y -> mov T1, x; mov y, T1
|
||||||
|
rs2 = GET_FIELDs(insn, 19, 31);
|
||||||
|
if (rs2 != 0) {
|
||||||
|
gen_movl_imm_T1(rs2);
|
||||||
|
gen_op_or_T1_T0();
|
||||||
|
}
|
||||||
|
} else { /* register */
|
||||||
|
// or x, %g0, y -> mov T1, x; mov y, T1
|
||||||
|
rs2 = GET_FIELD(insn, 27, 31);
|
||||||
|
if (rs2 != 0) {
|
||||||
|
gen_movl_reg_T1(rs2);
|
||||||
|
gen_op_or_T1_T0();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gen_movl_T0_reg(rd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (xop < 0x38) {
|
||||||
|
rs1 = GET_FIELD(insn, 13, 17);
|
||||||
|
gen_movl_reg_T0(rs1);
|
||||||
|
if (IS_IMM) { /* immediate */
|
||||||
rs2 = GET_FIELDs(insn, 19, 31);
|
rs2 = GET_FIELDs(insn, 19, 31);
|
||||||
gen_movl_imm_T1(rs2);
|
gen_movl_imm_T1(rs2);
|
||||||
} else { /* register */
|
} else { /* register */
|
||||||
|
@ -901,10 +998,10 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_logic_T0_cc();
|
gen_op_logic_T0_cc();
|
||||||
break;
|
break;
|
||||||
case 0x2:
|
case 0x2:
|
||||||
gen_op_or_T1_T0();
|
gen_op_or_T1_T0();
|
||||||
if (xop & 0x10)
|
if (xop & 0x10)
|
||||||
gen_op_logic_T0_cc();
|
gen_op_logic_T0_cc();
|
||||||
break;
|
break;
|
||||||
case 0x3:
|
case 0x3:
|
||||||
gen_op_xor_T1_T0();
|
gen_op_xor_T1_T0();
|
||||||
if (xop & 0x10)
|
if (xop & 0x10)
|
||||||
|
@ -964,9 +1061,14 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
default:
|
default:
|
||||||
goto illegal_insn;
|
goto illegal_insn;
|
||||||
}
|
}
|
||||||
gen_movl_T0_reg(rd);
|
gen_movl_T0_reg(rd);
|
||||||
} else {
|
} else {
|
||||||
switch (xop) {
|
switch (xop) {
|
||||||
|
case 0x20: /* taddcc */
|
||||||
|
case 0x21: /* tsubcc */
|
||||||
|
case 0x22: /* taddcctv */
|
||||||
|
case 0x23: /* tsubcctv */
|
||||||
|
goto illegal_insn;
|
||||||
case 0x24: /* mulscc */
|
case 0x24: /* mulscc */
|
||||||
gen_op_mulscc_T1_T0();
|
gen_op_mulscc_T1_T0();
|
||||||
gen_movl_T0_reg(rd);
|
gen_movl_T0_reg(rd);
|
||||||
|
@ -1021,56 +1123,72 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 0x38: /* jmpl */
|
default:
|
||||||
{
|
goto illegal_insn;
|
||||||
gen_op_add_T1_T0();
|
}
|
||||||
gen_op_movl_npc_T0();
|
}
|
||||||
if (rd != 0) {
|
} else {
|
||||||
gen_op_movl_T0_im((long) (dc->pc));
|
rs1 = GET_FIELD(insn, 13, 17);
|
||||||
gen_movl_T0_reg(rd);
|
gen_movl_reg_T0(rs1);
|
||||||
}
|
if (IS_IMM) { /* immediate */
|
||||||
dc->pc = dc->npc;
|
rs2 = GET_FIELDs(insn, 19, 31);
|
||||||
dc->npc = DYNAMIC_PC;
|
#if defined(OPTIM)
|
||||||
}
|
if (rs2) {
|
||||||
goto jmp_insn;
|
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
|
||||||
case 0x39: /* rett */
|
|
||||||
{
|
|
||||||
if (!supervisor(dc))
|
|
||||||
goto priv_insn;
|
|
||||||
gen_op_add_T1_T0();
|
|
||||||
gen_op_movl_npc_T0();
|
|
||||||
gen_op_rett();
|
|
||||||
#if 0
|
|
||||||
dc->pc = dc->npc;
|
|
||||||
dc->npc = DYNAMIC_PC;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
gen_movl_imm_T1(rs2);
|
||||||
#if 0
|
gen_op_add_T1_T0();
|
||||||
goto jmp_insn;
|
#if defined(OPTIM)
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
} else { /* register */
|
||||||
|
rs2 = GET_FIELD(insn, 27, 31);
|
||||||
|
#if defined(OPTIM)
|
||||||
|
if (rs2) {
|
||||||
|
#endif
|
||||||
|
gen_movl_reg_T1(rs2);
|
||||||
|
gen_op_add_T1_T0();
|
||||||
|
#if defined(OPTIM)
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
case 0x3b: /* flush */
|
|
||||||
gen_op_add_T1_T0();
|
|
||||||
gen_op_flush_T0();
|
|
||||||
break;
|
|
||||||
case 0x3c: /* save */
|
|
||||||
save_state(dc);
|
|
||||||
gen_op_add_T1_T0();
|
|
||||||
gen_op_save();
|
|
||||||
gen_movl_T0_reg(rd);
|
|
||||||
break;
|
|
||||||
case 0x3d: /* restore */
|
|
||||||
save_state(dc);
|
|
||||||
gen_op_add_T1_T0();
|
|
||||||
gen_op_restore();
|
|
||||||
gen_movl_T0_reg(rd);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto illegal_insn;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
switch (xop) {
|
||||||
|
case 0x38: /* jmpl */
|
||||||
|
{
|
||||||
|
gen_op_movl_npc_T0();
|
||||||
|
if (rd != 0) {
|
||||||
|
gen_op_movl_T0_im((long) (dc->pc));
|
||||||
|
gen_movl_T0_reg(rd);
|
||||||
|
}
|
||||||
|
dc->pc = dc->npc;
|
||||||
|
dc->npc = DYNAMIC_PC;
|
||||||
|
}
|
||||||
|
goto jmp_insn;
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
case 0x39: /* rett */
|
||||||
|
{
|
||||||
|
if (!supervisor(dc))
|
||||||
|
goto priv_insn;
|
||||||
|
gen_op_movl_npc_T0();
|
||||||
|
gen_op_rett();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 0x3b: /* flush */
|
||||||
|
gen_op_flush_T0();
|
||||||
|
break;
|
||||||
|
case 0x3c: /* save */
|
||||||
|
save_state(dc);
|
||||||
|
gen_op_save();
|
||||||
|
gen_movl_T0_reg(rd);
|
||||||
|
break;
|
||||||
|
case 0x3d: /* restore */
|
||||||
|
save_state(dc);
|
||||||
|
gen_op_restore();
|
||||||
|
gen_movl_T0_reg(rd);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto illegal_insn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1081,14 +1199,24 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_movl_reg_T0(rs1);
|
gen_movl_reg_T0(rs1);
|
||||||
if (IS_IMM) { /* immediate */
|
if (IS_IMM) { /* immediate */
|
||||||
rs2 = GET_FIELDs(insn, 19, 31);
|
rs2 = GET_FIELDs(insn, 19, 31);
|
||||||
|
#if defined(OPTIM)
|
||||||
if (rs2 != 0) {
|
if (rs2 != 0) {
|
||||||
|
#endif
|
||||||
gen_movl_imm_T1(rs2);
|
gen_movl_imm_T1(rs2);
|
||||||
gen_op_add_T1_T0();
|
gen_op_add_T1_T0();
|
||||||
|
#if defined(OPTIM)
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else { /* register */
|
} else { /* register */
|
||||||
rs2 = GET_FIELD(insn, 27, 31);
|
rs2 = GET_FIELD(insn, 27, 31);
|
||||||
gen_movl_reg_T1(rs2);
|
#if defined(OPTIM)
|
||||||
gen_op_add_T1_T0();
|
if (rs2 != 0) {
|
||||||
|
#endif
|
||||||
|
gen_movl_reg_T1(rs2);
|
||||||
|
gen_op_add_T1_T0();
|
||||||
|
#if defined(OPTIM)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (xop < 4 || (xop > 7 && xop < 0x14) || \
|
if (xop < 4 || (xop > 7 && xop < 0x14) || \
|
||||||
(xop > 0x17 && xop < 0x20)) {
|
(xop > 0x17 && xop < 0x20)) {
|
||||||
|
@ -1116,8 +1244,10 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_op_ldst(ldstub);
|
gen_op_ldst(ldstub);
|
||||||
break;
|
break;
|
||||||
case 0x0f: /* swap register with memory. Also atomically */
|
case 0x0f: /* swap register with memory. Also atomically */
|
||||||
|
gen_movl_reg_T1(rd);
|
||||||
gen_op_ldst(swap);
|
gen_op_ldst(swap);
|
||||||
break;
|
break;
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
case 0x10: /* load word alternate */
|
case 0x10: /* load word alternate */
|
||||||
if (!supervisor(dc))
|
if (!supervisor(dc))
|
||||||
goto priv_insn;
|
goto priv_insn;
|
||||||
|
@ -1157,11 +1287,18 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
case 0x1f: /* swap reg with alt. memory. Also atomically */
|
case 0x1f: /* swap reg with alt. memory. Also atomically */
|
||||||
if (!supervisor(dc))
|
if (!supervisor(dc))
|
||||||
goto priv_insn;
|
goto priv_insn;
|
||||||
|
gen_movl_reg_T1(rd);
|
||||||
gen_op_swapa(insn, 1, 4, 0);
|
gen_op_swapa(insn, 1, 4, 0);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto illegal_insn;
|
||||||
}
|
}
|
||||||
gen_movl_T1_reg(rd);
|
gen_movl_T1_reg(rd);
|
||||||
} else if (xop >= 0x20 && xop < 0x24) {
|
} else if (xop >= 0x20 && xop < 0x24) {
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
gen_op_trap_ifnofpu();
|
||||||
|
#endif
|
||||||
switch (xop) {
|
switch (xop) {
|
||||||
case 0x20: /* load fpreg */
|
case 0x20: /* load fpreg */
|
||||||
gen_op_ldst(ldf);
|
gen_op_ldst(ldf);
|
||||||
|
@ -1169,11 +1306,14 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
break;
|
break;
|
||||||
case 0x21: /* load fsr */
|
case 0x21: /* load fsr */
|
||||||
gen_op_ldfsr();
|
gen_op_ldfsr();
|
||||||
|
gen_op_store_FT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
case 0x23: /* load double fpreg */
|
case 0x23: /* load double fpreg */
|
||||||
gen_op_ldst(lddf);
|
gen_op_ldst(lddf);
|
||||||
gen_op_store_DT0_fpr(rd);
|
gen_op_store_DT0_fpr(rd);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
goto illegal_insn;
|
||||||
}
|
}
|
||||||
} else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) {
|
} else if (xop < 8 || (xop >= 0x14 && xop < 0x18)) {
|
||||||
gen_movl_reg_T1(rd);
|
gen_movl_reg_T1(rd);
|
||||||
|
@ -1192,6 +1332,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_movl_reg_T2(rd + 1);
|
gen_movl_reg_T2(rd + 1);
|
||||||
gen_op_ldst(std);
|
gen_op_ldst(std);
|
||||||
break;
|
break;
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
case 0x14:
|
case 0x14:
|
||||||
if (!supervisor(dc))
|
if (!supervisor(dc))
|
||||||
goto priv_insn;
|
goto priv_insn;
|
||||||
|
@ -1214,24 +1355,37 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
gen_movl_reg_T2(rd + 1);
|
gen_movl_reg_T2(rd + 1);
|
||||||
gen_op_stda(insn, 0, 8, 0);
|
gen_op_stda(insn, 0, 8, 0);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto illegal_insn;
|
||||||
}
|
}
|
||||||
} else if (xop > 0x23 && xop < 0x28) {
|
} else if (xop > 0x23 && xop < 0x28) {
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
|
gen_op_trap_ifnofpu();
|
||||||
|
#endif
|
||||||
switch (xop) {
|
switch (xop) {
|
||||||
case 0x24:
|
case 0x24:
|
||||||
gen_op_load_fpr_FT0(rd);
|
gen_op_load_fpr_FT0(rd);
|
||||||
gen_op_ldst(stf);
|
gen_op_ldst(stf);
|
||||||
break;
|
break;
|
||||||
case 0x25:
|
case 0x25:
|
||||||
|
gen_op_load_fpr_FT0(rd);
|
||||||
gen_op_stfsr();
|
gen_op_stfsr();
|
||||||
break;
|
break;
|
||||||
case 0x27:
|
case 0x27:
|
||||||
gen_op_load_fpr_DT0(rd);
|
gen_op_load_fpr_DT0(rd);
|
||||||
gen_op_ldst(stdf);
|
gen_op_ldst(stdf);
|
||||||
break;
|
break;
|
||||||
|
case 0x26: /* stdfq */
|
||||||
|
default:
|
||||||
|
goto illegal_insn;
|
||||||
}
|
}
|
||||||
} else if (xop > 0x33 && xop < 0x38) {
|
} else if (xop > 0x33 && xop < 0x38) {
|
||||||
/* Co-processor */
|
/* Co-processor */
|
||||||
|
goto illegal_insn;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
goto illegal_insn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* default case for non jump instructions */
|
/* default case for non jump instructions */
|
||||||
|
@ -1246,17 +1400,24 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||||
dc->pc = dc->npc;
|
dc->pc = dc->npc;
|
||||||
dc->npc = dc->npc + 4;
|
dc->npc = dc->npc + 4;
|
||||||
}
|
}
|
||||||
jmp_insn:;
|
jmp_insn:
|
||||||
return;
|
return;
|
||||||
illegal_insn:
|
illegal_insn:
|
||||||
save_state(dc);
|
save_state(dc);
|
||||||
gen_op_exception(TT_ILL_INSN);
|
gen_op_exception(TT_ILL_INSN);
|
||||||
dc->is_br = 1;
|
dc->is_br = 1;
|
||||||
return;
|
return;
|
||||||
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
priv_insn:
|
priv_insn:
|
||||||
save_state(dc);
|
save_state(dc);
|
||||||
gen_op_exception(TT_PRIV_INSN);
|
gen_op_exception(TT_PRIV_INSN);
|
||||||
dc->is_br = 1;
|
dc->is_br = 1;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
nfpu_insn:
|
||||||
|
save_state(dc);
|
||||||
|
gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
|
||||||
|
dc->is_br = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||||
|
@ -1271,6 +1432,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||||
dc->tb = tb;
|
dc->tb = tb;
|
||||||
pc_start = tb->pc;
|
pc_start = tb->pc;
|
||||||
dc->pc = pc_start;
|
dc->pc = pc_start;
|
||||||
|
last_pc = dc->pc;
|
||||||
dc->npc = (target_ulong) tb->cs_base;
|
dc->npc = (target_ulong) tb->cs_base;
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
dc->mem_idx = 0;
|
dc->mem_idx = 0;
|
||||||
|
@ -1285,8 +1447,13 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||||
if (env->nb_breakpoints > 0) {
|
if (env->nb_breakpoints > 0) {
|
||||||
for(j = 0; j < env->nb_breakpoints; j++) {
|
for(j = 0; j < env->nb_breakpoints; j++) {
|
||||||
if (env->breakpoints[j] == dc->pc) {
|
if (env->breakpoints[j] == dc->pc) {
|
||||||
gen_debug(dc, dc->pc);
|
if (dc->pc != pc_start)
|
||||||
break;
|
save_state(dc);
|
||||||
|
gen_op_debug();
|
||||||
|
gen_op_movl_T0_0();
|
||||||
|
gen_op_exit_tb();
|
||||||
|
dc->is_br = 1;
|
||||||
|
goto exit_gen_loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1310,8 +1477,18 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||||
/* if the next PC is different, we abort now */
|
/* if the next PC is different, we abort now */
|
||||||
if (dc->pc != (last_pc + 4))
|
if (dc->pc != (last_pc + 4))
|
||||||
break;
|
break;
|
||||||
|
/* if single step mode, we generate only one instruction and
|
||||||
|
generate an exception */
|
||||||
|
if (env->singlestep_enabled) {
|
||||||
|
gen_op_jmp_im(dc->pc);
|
||||||
|
gen_op_movl_T0_0();
|
||||||
|
gen_op_exit_tb();
|
||||||
|
break;
|
||||||
|
}
|
||||||
} while ((gen_opc_ptr < gen_opc_end) &&
|
} while ((gen_opc_ptr < gen_opc_end) &&
|
||||||
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||||
|
|
||||||
|
exit_gen_loop:
|
||||||
if (!dc->is_br) {
|
if (!dc->is_br) {
|
||||||
if (dc->pc != DYNAMIC_PC &&
|
if (dc->pc != DYNAMIC_PC &&
|
||||||
(dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
|
(dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
|
||||||
|
@ -1338,7 +1515,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
tb->size = dc->npc - pc_start;
|
tb->size = last_pc + 4 - pc_start;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_DISAS
|
#ifdef DEBUG_DISAS
|
||||||
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
if (loglevel & CPU_LOG_TB_IN_ASM) {
|
||||||
|
@ -1366,6 +1543,25 @@ int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
|
||||||
return gen_intermediate_code_internal(tb, 1, env);
|
return gen_intermediate_code_internal(tb, 1, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int ram_size;
|
||||||
|
|
||||||
|
void cpu_reset(CPUSPARCState *env)
|
||||||
|
{
|
||||||
|
memset(env, 0, sizeof(*env));
|
||||||
|
env->cwp = 0;
|
||||||
|
env->wim = 1;
|
||||||
|
env->regwptr = env->regbase + (env->cwp * 16);
|
||||||
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
env->user_mode_only = 1;
|
||||||
|
#else
|
||||||
|
env->psrs = 1;
|
||||||
|
env->pc = 0xffd00000;
|
||||||
|
env->gregs[1] = ram_size;
|
||||||
|
env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */
|
||||||
|
env->npc = env->pc + 4;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
CPUSPARCState *cpu_sparc_init(void)
|
CPUSPARCState *cpu_sparc_init(void)
|
||||||
{
|
{
|
||||||
CPUSPARCState *env;
|
CPUSPARCState *env;
|
||||||
|
@ -1374,21 +1570,8 @@ CPUSPARCState *cpu_sparc_init(void)
|
||||||
|
|
||||||
if (!(env = malloc(sizeof(CPUSPARCState))))
|
if (!(env = malloc(sizeof(CPUSPARCState))))
|
||||||
return (NULL);
|
return (NULL);
|
||||||
memset(env, 0, sizeof(*env));
|
|
||||||
env->cwp = 0;
|
|
||||||
env->wim = 1;
|
|
||||||
env->regwptr = env->regbase + (env->cwp * 16);
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
|
||||||
env->user_mode_only = 1;
|
|
||||||
#else
|
|
||||||
/* Emulate Prom */
|
|
||||||
env->psrs = 1;
|
|
||||||
env->pc = 0x4000;
|
|
||||||
env->npc = env->pc + 4;
|
|
||||||
env->mmuregs[0] = (0x10<<24) | MMU_E; /* Impl 1, ver 0, MMU Enabled */
|
|
||||||
env->mmuregs[1] = 0x3000 >> 4; /* MMU Context table */
|
|
||||||
#endif
|
|
||||||
cpu_single_env = env;
|
cpu_single_env = env;
|
||||||
|
cpu_reset(env);
|
||||||
return (env);
|
return (env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1436,11 +1619,24 @@ void cpu_dump_state(CPUState *env, FILE *f,
|
||||||
cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr);
|
cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_USER_ONLY)
|
||||||
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
||||||
{
|
{
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
|
||||||
|
{
|
||||||
|
uint32_t phys_addr;
|
||||||
|
int prot, access_index;
|
||||||
|
|
||||||
|
if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0)
|
||||||
|
return -1;
|
||||||
|
return phys_addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void helper_flush(target_ulong addr)
|
void helper_flush(target_ulong addr)
|
||||||
{
|
{
|
||||||
addr &= ~7;
|
addr &= ~7;
|
||||||
|
|
66
vl.c
66
vl.c
|
@ -2214,10 +2214,74 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
#elif defined(TARGET_SPARC)
|
#elif defined(TARGET_SPARC)
|
||||||
void cpu_save(QEMUFile *f, void *opaque)
|
void cpu_save(QEMUFile *f, void *opaque)
|
||||||
{
|
{
|
||||||
|
CPUState *env = opaque;
|
||||||
|
int i;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
for(i = 1; i < 8; i++)
|
||||||
|
qemu_put_be32s(f, &env->gregs[i]);
|
||||||
|
tmp = env->regwptr - env->regbase;
|
||||||
|
qemu_put_be32s(f, &tmp);
|
||||||
|
for(i = 1; i < NWINDOWS * 16 + 8; i++)
|
||||||
|
qemu_put_be32s(f, &env->regbase[i]);
|
||||||
|
|
||||||
|
/* FPU */
|
||||||
|
for(i = 0; i < 32; i++) {
|
||||||
|
uint64_t mant;
|
||||||
|
uint16_t exp;
|
||||||
|
cpu_get_fp64(&mant, &exp, env->fpr[i]);
|
||||||
|
qemu_put_be64(f, mant);
|
||||||
|
qemu_put_be16(f, exp);
|
||||||
|
}
|
||||||
|
qemu_put_be32s(f, &env->pc);
|
||||||
|
qemu_put_be32s(f, &env->npc);
|
||||||
|
qemu_put_be32s(f, &env->y);
|
||||||
|
tmp = GET_PSR(env);
|
||||||
|
qemu_put_be32s(f, &tmp);
|
||||||
|
qemu_put_be32s(f, &env->fsr);
|
||||||
|
qemu_put_be32s(f, &env->cwp);
|
||||||
|
qemu_put_be32s(f, &env->wim);
|
||||||
|
qemu_put_be32s(f, &env->tbr);
|
||||||
|
/* MMU */
|
||||||
|
for(i = 0; i < 16; i++)
|
||||||
|
qemu_put_be32s(f, &env->mmuregs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
{
|
{
|
||||||
|
CPUState *env = opaque;
|
||||||
|
int i;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
for(i = 1; i < 8; i++)
|
||||||
|
qemu_get_be32s(f, &env->gregs[i]);
|
||||||
|
qemu_get_be32s(f, &tmp);
|
||||||
|
env->regwptr = env->regbase + tmp;
|
||||||
|
for(i = 1; i < NWINDOWS * 16 + 8; i++)
|
||||||
|
qemu_get_be32s(f, &env->regbase[i]);
|
||||||
|
|
||||||
|
/* FPU */
|
||||||
|
for(i = 0; i < 32; i++) {
|
||||||
|
uint64_t mant;
|
||||||
|
uint16_t exp;
|
||||||
|
|
||||||
|
qemu_get_be64s(f, &mant);
|
||||||
|
qemu_get_be16s(f, &exp);
|
||||||
|
env->fpr[i] = cpu_put_fp64(mant, exp);
|
||||||
|
}
|
||||||
|
qemu_get_be32s(f, &env->pc);
|
||||||
|
qemu_get_be32s(f, &env->npc);
|
||||||
|
qemu_get_be32s(f, &env->y);
|
||||||
|
qemu_get_be32s(f, &tmp);
|
||||||
|
PUT_PSR(env, tmp);
|
||||||
|
qemu_get_be32s(f, &env->fsr);
|
||||||
|
qemu_get_be32s(f, &env->cwp);
|
||||||
|
qemu_get_be32s(f, &env->wim);
|
||||||
|
qemu_get_be32s(f, &env->tbr);
|
||||||
|
/* MMU */
|
||||||
|
for(i = 0; i < 16; i++)
|
||||||
|
qemu_get_be32s(f, &env->mmuregs[i]);
|
||||||
|
tlb_flush(env, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -2388,7 +2452,7 @@ void qemu_system_shutdown_request(void)
|
||||||
|
|
||||||
static void main_cpu_reset(void *opaque)
|
static void main_cpu_reset(void *opaque)
|
||||||
{
|
{
|
||||||
#ifdef TARGET_I386
|
#if defined(TARGET_I386) || defined(TARGET_SPARC)
|
||||||
CPUState *env = opaque;
|
CPUState *env = opaque;
|
||||||
cpu_reset(env);
|
cpu_reset(env);
|
||||||
#endif
|
#endif
|
||||||
|
|
31
vl.h
31
vl.h
|
@ -261,7 +261,7 @@ typedef void QEMUTimerCB(void *opaque);
|
||||||
Hz. */
|
Hz. */
|
||||||
extern QEMUClock *rt_clock;
|
extern QEMUClock *rt_clock;
|
||||||
|
|
||||||
/* Rge virtual clock is only run during the emulation. It is stopped
|
/* The virtual clock is only run during the emulation. It is stopped
|
||||||
when the virtual machine is stopped. Virtual timers use a high
|
when the virtual machine is stopped. Virtual timers use a high
|
||||||
precision clock, usually cpu cycles (use ticks_per_sec). */
|
precision clock, usually cpu cycles (use ticks_per_sec). */
|
||||||
extern QEMUClock *vm_clock;
|
extern QEMUClock *vm_clock;
|
||||||
|
@ -672,25 +672,38 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
|
||||||
DisplayState *ds, const char **fd_filename, int snapshot,
|
DisplayState *ds, const char **fd_filename, int snapshot,
|
||||||
const char *kernel_filename, const char *kernel_cmdline,
|
const char *kernel_filename, const char *kernel_cmdline,
|
||||||
const char *initrd_filename);
|
const char *initrd_filename);
|
||||||
|
uint32_t iommu_translate(uint32_t addr);
|
||||||
|
|
||||||
/* iommu.c */
|
/* iommu.c */
|
||||||
void iommu_init(uint32_t addr);
|
void *iommu_init(uint32_t addr);
|
||||||
uint32_t iommu_translate(uint32_t addr);
|
uint32_t iommu_translate_local(void *opaque, uint32_t addr);
|
||||||
|
|
||||||
/* lance.c */
|
/* lance.c */
|
||||||
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr);
|
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr);
|
||||||
|
|
||||||
/* tcx.c */
|
/* tcx.c */
|
||||||
void tcx_init(DisplayState *ds, uint32_t addr);
|
void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
|
||||||
|
unsigned long vram_offset, int vram_size);
|
||||||
|
void tcx_update_display(void *opaque);
|
||||||
|
void tcx_invalidate_display(void *opaque);
|
||||||
|
void tcx_screen_dump(void *opaque, const char *filename);
|
||||||
|
|
||||||
/* sched.c */
|
/* slavio_intctl.c */
|
||||||
void sched_init();
|
void *slavio_intctl_init();
|
||||||
|
void slavio_pic_info(void *opaque);
|
||||||
|
void slavio_irq_info(void *opaque);
|
||||||
|
void slavio_pic_set_irq(void *opaque, int irq, int level);
|
||||||
|
|
||||||
/* magic-load.c */
|
/* magic-load.c */
|
||||||
void magic_init(const char *kfn, int kloadaddr, uint32_t addr);
|
int load_elf(const char *filename, uint8_t *addr);
|
||||||
|
int load_aout(const char *filename, uint8_t *addr);
|
||||||
|
|
||||||
/* timer.c */
|
/* slavio_timer.c */
|
||||||
void timer_init(uint32_t addr, int irq);
|
void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2);
|
||||||
|
|
||||||
|
/* slavio_serial.c */
|
||||||
|
SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2);
|
||||||
|
void slavio_serial_ms_kbd_init(int base, int irq);
|
||||||
|
|
||||||
/* NVRAM helpers */
|
/* NVRAM helpers */
|
||||||
#include "hw/m48t59.h"
|
#include "hw/m48t59.h"
|
||||||
|
|
Loading…
Reference in a new issue