@@ -362,7 +362,9 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
-obj-alpha-y = alpha_palcode.o
+obj-alpha-y += i8259.o mc146818rtc.o
+obj-alpha-y += vga.o cirrus_vga.o
+obj-alpha-y += alpha_pci.o alpha_sx164.o alpha_pyxis.o
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
@@ -1011,6 +1011,7 @@ if test -z "$target_list" ; then
target_list="\
i386-softmmu \
x86_64-softmmu \
+alpha-softmmu \
arm-softmmu \
cris-softmmu \
lm32-softmmu \
@@ -529,9 +529,19 @@ int cpu_exec(CPUState *env1)
next_tb = 0;
}
#elif defined(TARGET_ALPHA)
- if (interrupt_request & CPU_INTERRUPT_HARD) {
- do_interrupt(env);
- next_tb = 0;
+ if (env->pal_mode == 0 && (env->ps & 7) == 0) {
+ int idx = -1;
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ idx = EXCP_DEV_INTERRUPT;
+ }
+ if (interrupt_request & CPU_INTERRUPT_TIMER) {
+ idx = EXCP_CLK_INTERRUPT;
+ }
+ if (idx >= 0) {
+ env->exception_index = idx;
+ do_interrupt(env);
+ next_tb = 0;
+ }
}
#elif defined(TARGET_CRIS)
if (interrupt_request & CPU_INTERRUPT_HARD
new file mode 100644
@@ -0,0 +1,9 @@
+# Default configuration for alpha-softmmu
+
+include pci.mak
+CONFIG_SERIAL=y
+CONFIG_I8254=y
+CONFIG_VGA_PCI=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_VMWARE_VGA=y
deleted file mode 100644
@@ -1,1048 +0,0 @@
-/*
- * Alpha emulation - PALcode emulation for qemu.
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
-/* Shared handlers */
-static void pal_reset (CPUState *env);
-/* Console handlers */
-static void pal_console_call (CPUState *env, uint32_t palcode);
-/* OpenVMS handlers */
-static void pal_openvms_call (CPUState *env, uint32_t palcode);
-/* UNIX / Linux handlers */
-static void pal_unix_call (CPUState *env, uint32_t palcode);
-
-pal_handler_t pal_handlers[] = {
- /* Console handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_console_call,
- },
- /* OpenVMS handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_openvms_call,
- },
- /* UNIX / Linux handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_unix_call,
- },
-};
-
-#if 0
-/* One must explicitly check that the TB is valid and the FOE bit is reset */
-static void update_itb (void)
-{
- /* This writes into a temp register, not the actual one */
- mtpr(TB_TAG);
- mtpr(TB_CTL);
- /* This commits the TB update */
- mtpr(ITB_PTE);
-}
-
-static void update_dtb (void);
-{
- mtpr(TB_CTL);
- /* This write into a temp register, not the actual one */
- mtpr(TB_TAG);
- /* This commits the TB update */
- mtpr(DTB_PTE);
-}
-#endif
-
-static void pal_reset (CPUState *env)
-{
-}
-
-static void do_swappal (CPUState *env, uint64_t palid)
-{
- pal_handler_t *pal_handler;
-
- switch (palid) {
- case 0 ... 2:
- pal_handler = &pal_handlers[palid];
- env->pal_handler = pal_handler;
- env->ipr[IPR_PAL_BASE] = -1ULL;
- (*pal_handler->reset)(env);
- break;
- case 3 ... 255:
- /* Unknown identifier */
- env->ir[0] = 1;
- return;
- default:
- /* We were given the entry point address */
- env->pal_handler = NULL;
- env->ipr[IPR_PAL_BASE] = palid;
- env->pc = env->ipr[IPR_PAL_BASE];
- cpu_loop_exit();
- }
-}
-
-static void pal_console_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x0000009E:
- /* RDUNIQUE */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRUNIQUE */
- /* REQUIRED */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- default:
- break;
- }
-}
-
-static void pal_openvms_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid, val, oldval;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000003:
- /* LDQP */
- break;
- case 0x00000004:
- /* STQP */
- break;
- case 0x00000005:
- /* SWPCTX */
- break;
- case 0x00000006:
- /* MFPR_ASN */
- if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000007:
- /* MTPR_ASTEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000008:
- /* MTPR_ASTSR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x0000000B:
- /* MFPR_FEN */
- if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000000C:
- /* MTPR_FEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000000D:
- /* MTPR_IPIR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000000E:
- /* MFPR_IPL */
- if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000000F:
- /* MTPR_IPL */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000010:
- /* MFPR_MCES */
- if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000011:
- /* MTPR_MCES */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000012:
- /* MFPR_PCBB */
- if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000013:
- /* MFPR_PRBR */
- if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000014:
- /* MTPR_PRBR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000015:
- /* MFPR_PTBR */
- if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000016:
- /* MFPR_SCBB */
- if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000017:
- /* MTPR_SCBB */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000018:
- /* MTPR_SIRR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000019:
- /* MFPR_SISR */
- if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001A:
- /* MFPR_TBCHK */
- if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001B:
- /* MTPR_TBIA */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001C:
- /* MTPR_TBIAP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001D:
- /* MTPR_TBIS */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001E:
- /* MFPR_ESP */
- if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001F:
- /* MTPR_ESP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000020:
- /* MFPR_SSP */
- if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000021:
- /* MTPR_SSP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000022:
- /* MFPR_USP */
- if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000023:
- /* MTPR_USP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000024:
- /* MTPR_TBISD */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000025:
- /* MTPR_TBISI */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000026:
- /* MFPR_ASTEN */
- if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000027:
- /* MFPR_ASTSR */
- if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000029:
- /* MFPR_VPTB */
- if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000002A:
- /* MTPR_VPTB */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002B:
- /* MTPR_PERFMON */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002E:
- /* MTPR_DATFX */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000003E:
- /* WTINT */
- break;
- case 0x0000003F:
- /* MFPR_WHAMI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000082:
- /* CHME */
- break;
- case 0x00000083:
- /* CHMK */
- break;
- case 0x00000084:
- /* CHMS */
- break;
- case 0x00000085:
- /* CHMU */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000087:
- /* INSQHIL */
- break;
- case 0x00000088:
- /* INSQTIL */
- break;
- case 0x00000089:
- /* INSQHIQ */
- break;
- case 0x0000008A:
- /* INSQTIQ */
- break;
- case 0x0000008B:
- /* INSQUEL */
- break;
- case 0x0000008C:
- /* INSQUEQ */
- break;
- case 0x0000008D:
- /* INSQUEL/D */
- break;
- case 0x0000008E:
- /* INSQUEQ/D */
- break;
- case 0x0000008F:
- /* PROBER */
- break;
- case 0x00000090:
- /* PROBEW */
- break;
- case 0x00000091:
- /* RD_PS */
- break;
- case 0x00000092:
- /* REI */
- break;
- case 0x00000093:
- /* REMQHIL */
- break;
- case 0x00000094:
- /* REMQTIL */
- break;
- case 0x00000095:
- /* REMQHIQ */
- break;
- case 0x00000096:
- /* REMQTIQ */
- break;
- case 0x00000097:
- /* REMQUEL */
- break;
- case 0x00000098:
- /* REMQUEQ */
- break;
- case 0x00000099:
- /* REMQUEL/D */
- break;
- case 0x0000009A:
- /* REMQUEQ/D */
- break;
- case 0x0000009B:
- /* SWASTEN */
- break;
- case 0x0000009C:
- /* WR_PS_SW */
- break;
- case 0x0000009D:
- /* RSCC */
- break;
- case 0x0000009E:
- /* READ_UNQ */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRITE_UNQ */
- /* REQUIRED */
- break;
- case 0x000000A0:
- /* AMOVRR */
- break;
- case 0x000000A1:
- /* AMOVRM */
- break;
- case 0x000000A2:
- /* INSQHILR */
- break;
- case 0x000000A3:
- /* INSQTILR */
- break;
- case 0x000000A4:
- /* INSQHIQR */
- break;
- case 0x000000A5:
- /* INSQTIQR */
- break;
- case 0x000000A6:
- /* REMQHILR */
- break;
- case 0x000000A7:
- /* REMQTILR */
- break;
- case 0x000000A8:
- /* REMQHIQR */
- break;
- case 0x000000A9:
- /* REMQTIQR */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- case 0x000000AE:
- /* CLRFEN */
- break;
- default:
- break;
- }
-}
-
-static void pal_unix_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid, val, oldval;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x0000000D:
- /* WRIPIR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000010:
- /* RDMCES */
- if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000011:
- /* WRMCES */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002B:
- /* WRFEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002D:
- /* WRVPTPTR */
- break;
- case 0x00000030:
- /* SWPCTX */
- break;
- case 0x00000031:
- /* WRVAL */
- break;
- case 0x00000032:
- /* RDVAL */
- break;
- case 0x00000033:
- /* TBI */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000034:
- /* WRENT */
- break;
- case 0x00000035:
- /* SWPIPL */
- break;
- case 0x00000036:
- /* RDPS */
- break;
- case 0x00000037:
- /* WRKGP */
- break;
- case 0x00000038:
- /* WRUSP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000039:
- /* WRPERFMON */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000003A:
- /* RDUSP */
- if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000003C:
- /* WHAMI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000003D:
- /* RETSYS */
- break;
- case 0x0000003E:
- /* WTINT */
- break;
- case 0x0000003F:
- /* RTI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000083:
- /* CALLSYS */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000092:
- /* URTI */
- break;
- case 0x0000009E:
- /* RDUNIQUE */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRUNIQUE */
- /* REQUIRED */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- case 0x000000AE:
- /* CLRFEN */
- break;
- default:
- break;
- }
-}
-
-void call_pal (CPUState *env)
-{
- pal_handler_t *pal_handler = env->pal_handler;
-
- switch (env->exception_index) {
- case EXCP_RESET:
- (*pal_handler->reset)(env);
- break;
- case EXCP_MCHK:
- (*pal_handler->machine_check)(env);
- break;
- case EXCP_ARITH:
- (*pal_handler->arithmetic)(env);
- break;
- case EXCP_INTERRUPT:
- (*pal_handler->interrupt)(env);
- break;
- case EXCP_DFAULT:
- (*pal_handler->dfault)(env);
- break;
- case EXCP_DTB_MISS_PAL:
- (*pal_handler->dtb_miss_pal)(env);
- break;
- case EXCP_DTB_MISS_NATIVE:
- (*pal_handler->dtb_miss_native)(env);
- break;
- case EXCP_UNALIGN:
- (*pal_handler->unalign)(env);
- break;
- case EXCP_ITB_MISS:
- (*pal_handler->itb_miss)(env);
- break;
- case EXCP_ITB_ACV:
- (*pal_handler->itb_acv)(env);
- break;
- case EXCP_OPCDEC:
- (*pal_handler->opcdec)(env);
- break;
- case EXCP_FEN:
- (*pal_handler->fen)(env);
- break;
- default:
- if (env->exception_index >= EXCP_CALL_PAL &&
- env->exception_index < EXCP_CALL_PALP) {
- /* Unprivileged PAL call */
- (*pal_handler->call_pal)
- (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
- } else if (env->exception_index >= EXCP_CALL_PALP &&
- env->exception_index < EXCP_CALL_PALE) {
- /* Privileged PAL call */
- (*pal_handler->call_pal)
- (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
- } else {
- /* Should never happen */
- }
- break;
- }
- env->ipr[IPR_EXC_ADDR] &= ~1;
-}
-
-void pal_init (CPUState *env)
-{
- do_swappal(env, 0);
-}
-
-#if 0
-static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
-{
- uint64_t virbnd, ptbr;
-
- if ((env->features & FEATURE_VIRBND)) {
- cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
- if (vaddr >= virbnd)
- cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
- else
- cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
- } else {
- cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
- }
-
- return ptbr;
-}
-
-static int get_page_bits (CPUState *env)
-{
- /* XXX */
- return 13;
-}
-
-static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
- uint64_t ptebase, int page_bits, uint64_t level,
- int mmu_idx, int rw)
-{
- uint64_t pteaddr, pte, pfn;
- uint8_t gh;
- int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
-
- /* XXX: TOFIX */
- is_user = mmu_idx == MMU_USER_IDX;
- pteaddr = (ptebase << page_bits) + (8 * level);
- pte = ldq_raw(pteaddr);
- /* Decode all interresting PTE fields */
- pfn = pte >> 32;
- uwe = (pte >> 13) & 1;
- kwe = (pte >> 12) & 1;
- ure = (pte >> 9) & 1;
- kre = (pte >> 8) & 1;
- gh = (pte >> 5) & 3;
- foE = (pte >> 3) & 1;
- foW = (pte >> 2) & 1;
- foR = (pte >> 1) & 1;
- v = pte & 1;
- ret = 0;
- if (!v)
- ret = 0x1;
- /* Check access rights */
- ar = 0;
- if (is_user) {
- if (ure)
- ar |= PAGE_READ;
- if (uwe)
- ar |= PAGE_WRITE;
- if (rw == 1 && !uwe)
- ret |= 0x2;
- if (rw != 1 && !ure)
- ret |= 0x2;
- } else {
- if (kre)
- ar |= PAGE_READ;
- if (kwe)
- ar |= PAGE_WRITE;
- if (rw == 1 && !kwe)
- ret |= 0x2;
- if (rw != 1 && !kre)
- ret |= 0x2;
- }
- if (rw == 0 && foR)
- ret |= 0x4;
- if (rw == 2 && foE)
- ret |= 0x8;
- if (rw == 1 && foW)
- ret |= 0xC;
- *pfnp = pfn;
- if (zbitsp != NULL)
- *zbitsp = page_bits + (3 * gh);
- if (protp != NULL)
- *protp = ar;
-
- return ret;
-}
-
-static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
- uint64_t ptebase, int page_bits,
- uint64_t vaddr, int mmu_idx, int rw)
-{
- uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
- int lvl_bits, ret;
-
- page_mask = (1ULL << page_bits) - 1ULL;
- lvl_bits = page_bits - 3;
- lvl_mask = (1ULL << lvl_bits) - 1ULL;
- level3 = (vaddr >> page_bits) & lvl_mask;
- level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
- level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
- /* Level 1 PTE */
- ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
- switch (ret) {
- case 3:
- /* Access violation */
- return 2;
- case 2:
- /* translation not valid */
- return 1;
- default:
- /* OK */
- break;
- }
- /* Level 2 PTE */
- ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
- switch (ret) {
- case 3:
- /* Access violation */
- return 2;
- case 2:
- /* translation not valid */
- return 1;
- default:
- /* OK */
- break;
- }
- /* Level 3 PTE */
- ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
- if (ret & 0x1) {
- /* Translation not valid */
- ret = 1;
- } else if (ret & 2) {
- /* Access violation */
- ret = 2;
- } else {
- switch (ret & 0xC) {
- case 0:
- /* OK */
- ret = 0;
- break;
- case 0x4:
- /* Fault on read */
- ret = 3;
- break;
- case 0x8:
- /* Fault on execute */
- ret = 4;
- break;
- case 0xC:
- /* Fault on write */
- ret = 5;
- break;
- }
- }
- *paddr = (pfn << page_bits) | (vaddr & page_mask);
-
- return 0;
-}
-
-static int virtual_to_physical (CPUState *env, uint64_t *physp,
- int *zbitsp, int *protp,
- uint64_t virtual, int mmu_idx, int rw)
-{
- uint64_t sva, ptebase;
- int seg, page_bits, ret;
-
- sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
- if (sva != virtual)
- seg = -1;
- else
- seg = sva >> (VA_BITS - 2);
- virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
- ptebase = get_ptebase(env, virtual);
- page_bits = get_page_bits(env);
- ret = 0;
- switch (seg) {
- case 0:
- /* seg1: 3 levels of PTE */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- case 1:
- /* seg1: 2 levels of PTE */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- case 2:
- /* kernel segment */
- if (mmu_idx != 0) {
- ret = 2;
- } else {
- *physp = virtual;
- }
- break;
- case 3:
- /* seg1: TB mapped */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- default:
- ret = 1;
- break;
- }
-
- return ret;
-}
-
-/* XXX: code provision */
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
- int mmu_idx, int is_softmmu)
-{
- uint64_t physical, page_size, end;
- int prot, zbits, ret;
-
- ret = virtual_to_physical(env, &physical, &zbits, &prot,
- address, mmu_idx, rw);
-
- switch (ret) {
- case 0:
- /* No fault */
- page_size = 1ULL << zbits;
- address &= ~(page_size - 1);
- /* FIXME: page_size should probably be passed to tlb_set_page,
- and this loop removed. */
- for (end = physical + page_size; physical < end; physical += 0x1000) {
- tlb_set_page(env, address, physical, prot, mmu_idx,
- TARGET_PAGE_SIZE);
- address += 0x1000;
- }
- ret = 0;
- break;
-#if 0
- case 1:
- env->exception_index = EXCP_DFAULT;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 2:
- env->exception_index = EXCP_ACCESS_VIOLATION;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 3:
- env->exception_index = EXCP_FAULT_ON_READ;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 4:
- env->exception_index = EXCP_FAULT_ON_EXECUTE;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- case 5:
- env->exception_index = EXCP_FAULT_ON_WRITE;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
-#endif
- default:
- /* Should never happen */
- env->exception_index = EXCP_MCHK;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- }
-
- return ret;
-}
-#endif
new file mode 100644
@@ -0,0 +1,327 @@
+/* There's nothing in here that's Alpha specific, really. */
+
+#include "config.h"
+#include "alpha_sys.h"
+#include "qemu-log.h"
+
+
+/* PCI IO reads, to byte-word addressable memory. */
+/* ??? Doesn't handle multiple PCI busses. */
+
+static uint32_t bw_io_readb(void *opaque, target_phys_addr_t addr)
+{
+ return cpu_inb(addr);
+}
+
+static uint32_t bw_io_readw(void *opaque, target_phys_addr_t addr)
+{
+ return cpu_inw(addr);
+}
+
+static uint32_t bw_io_readl(void *opaque, target_phys_addr_t addr)
+{
+ return cpu_inl(addr);
+}
+
+/* PCI IO writes, to byte-word addressable memory. */
+/* ??? Doesn't handle multiple PCI busses. */
+
+static void bw_io_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ cpu_outb(addr, val);
+}
+
+static void bw_io_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ cpu_outw(addr, val);
+}
+
+static void bw_io_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ cpu_outl(addr, val);
+}
+
+CPUReadMemoryFunc * const alpha_pci_bw_io_reads[] = {
+ bw_io_readb,
+ bw_io_readw,
+ bw_io_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_bw_io_writes[] = {
+ bw_io_writeb,
+ bw_io_writew,
+ bw_io_writel,
+};
+
+/* PCI config space reads, to byte-word addressable memory. */
+static uint32_t bw_conf1_readb(void *opaque, target_phys_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ return pci_data_read(s->bus, addr, 1);
+}
+
+static uint32_t bw_conf1_readw(void *opaque, target_phys_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ return pci_data_read(s->bus, addr, 2);
+}
+
+static uint32_t bw_conf1_readl(void *opaque, target_phys_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ return pci_data_read(s->bus, addr, 4);
+}
+
+/* PCI config space writes, to byte-word addressable memory. */
+static void bw_conf1_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+ pci_data_write(s->bus, addr, val, 1);
+}
+
+static void bw_conf1_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+ pci_data_write(s->bus, addr, val, 2);
+}
+
+static void bw_conf1_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+ pci_data_write(s->bus, addr, val, 4);
+}
+
+CPUReadMemoryFunc * const alpha_pci_bw_conf1_reads[] = {
+ bw_conf1_readb,
+ bw_conf1_readw,
+ bw_conf1_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_bw_conf1_writes[] = {
+ bw_conf1_writeb,
+ bw_conf1_writew,
+ bw_conf1_writel,
+};
+
+/* PCI MEM access to dense (but not byte-word addressable) memory. */
+static uint32_t dense_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+ PCIBus *b = opaque;
+ return ldl_phys(pci_to_cpu_addr(b, addr));
+}
+
+static void dense_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t v)
+{
+ PCIBus *b = opaque;
+ stl_phys(pci_to_cpu_addr(b, addr), v);
+}
+
+CPUReadMemoryFunc * const alpha_pci_dense_mem_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ dense_mem_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_dense_mem_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ dense_mem_writel,
+};
+
+/* PCI IO to sparse memory. These are helper routines, which expect that the
+ relevant HAE has already been prepended to ADDR by the core-specific
+ routine that is actually registered with the memory region. */
+
+uint32_t alpha_sparse_io_read(target_phys_addr_t addr)
+{
+ int size = (addr >> 3) & 3;
+ uint32_t val;
+
+ addr >>= 5;
+ switch (size) {
+ case 0:
+ /* byte access */
+ val = cpu_inb(addr);
+ break;
+ case 1:
+ /* word access */
+ val = cpu_inw(addr);
+ break;
+ case 2:
+ /* tri-byte access; apparently possible with real pci lines. */
+ qemu_log("pci: tri-byte io read");
+ return ~0u;
+ default:
+ /* long access */
+ return cpu_inl(addr);
+ }
+
+ val <<= (addr & 3) * 8;
+ return val;
+}
+
+void alpha_sparse_io_write(target_phys_addr_t addr, uint32_t val)
+{
+ int size = (addr >> 3) & 3;
+
+ addr >>= 5;
+ switch (size) {
+ case 0:
+ /* byte access */
+ val >>= (addr & 3) * 8;
+ cpu_outb(addr, val);
+ break;
+ case 1:
+ /* word access */
+ val >>= (addr & 3) * 8;
+ cpu_outw(addr, val);
+ break;
+ case 2:
+ /* tri-byte access; apparently possible with real pci lines. */
+ qemu_log("pci: tri-byte io write");
+ break;
+ default:
+ /* long access */
+ cpu_outl(addr, val);
+ break;
+ }
+}
+
+uint32_t alpha_sparse_mem_read(PCIBus *b, target_phys_addr_t addr)
+{
+ int size = (addr >> 3) & 3;
+ uint32_t val;
+
+ addr = pci_to_cpu_addr(b, addr >> 5);
+ switch (size) {
+ case 0:
+ /* byte access */
+ val = ldub_phys(addr);
+ break;
+ case 1:
+ /* word access */
+ val = lduw_phys(addr);
+ break;
+ case 2:
+ /* tri-byte access; apparently possible with real pci lines. */
+ qemu_log("pci: tri-byte mem read");
+ return ~0u;
+ default:
+ /* long access */
+ return ldl_phys(addr);
+ }
+
+ val <<= (addr & 3) * 8;
+ return val;
+}
+
+void alpha_sparse_mem_write(PCIBus *b, target_phys_addr_t addr, uint32_t val)
+{
+ int size = (addr >> 3) & 3;
+
+ addr = pci_to_cpu_addr(b, addr >> 5);
+ switch (size) {
+ case 0:
+ /* byte access */
+ val >>= (addr & 3) * 8;
+ stb_phys(addr, val);
+ break;
+ case 1:
+ /* word access */
+ val >>= (addr & 3) * 8;
+ stw_phys(addr, val);
+ break;
+ case 2:
+ /* tri-byte access; apparently possible with real pci lines. */
+ qemu_log("pci: tri-byte mem write");
+ break;
+ default:
+ /* long access */
+ stl_phys(addr, val);
+ break;
+ }
+}
+
+uint32_t alpha_sparse_conf1_read(PCIBus *b, target_phys_addr_t addr)
+{
+ int size = ((addr >> 3) & 3) + 1;
+ uint32_t val;
+
+ if (size == 3) {
+ qemu_log("pci: tri-byte configuration read");
+ return ~0u;
+ }
+
+ addr >>= 5;
+ val = pci_data_read(b, addr, size);
+ val <<= (addr & 3) * 8;
+
+ return val;
+}
+
+void alpha_sparse_conf1_write(PCIBus *b, target_phys_addr_t addr, uint32_t val)
+{
+ int size = ((addr >> 3) & 3) + 1;
+
+ if (size == 3) {
+ qemu_log("pci: tri-byte configuration write");
+ return;
+ }
+
+ addr >>= 5;
+ val >>= (addr & 3) * 8;
+ pci_data_write(b, addr, val, size);
+}
+
+/* Configuration space accesses do not normall use an HAE. */
+static uint32_t sparse_conf1_readl(void *opaque, target_phys_addr_t addr)
+{
+ PCIBus *b = opaque;
+ return alpha_sparse_conf1_read(b, addr);
+}
+
+static void sparse_conf1_writel(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ PCIBus *b = opaque;
+ alpha_sparse_conf1_write(b, addr, val);
+}
+
+CPUReadMemoryFunc * const alpha_pci_sparse_conf1_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ sparse_conf1_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_sparse_conf1_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ sparse_conf1_writel,
+};
+
+/* PCI/EISA Interrupt Acknowledge Cycle. */
+
+static uint32_t iack_readl(void *opaque, target_phys_addr_t addr)
+{
+ if (addr & 15) {
+ return unassigned_mem_readl(opaque, addr);
+ }
+ return pic_read_irq(isa_pic);
+}
+
+static void special_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ qemu_log("pci: special write cycle %08x", val);
+}
+
+CPUReadMemoryFunc * const alpha_pci_iack_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ iack_readl,
+};
+
+CPUWriteMemoryFunc * const alpha_pci_special_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ special_writel,
+};
new file mode 100644
@@ -0,0 +1,1057 @@
+/*
+ * Qemu 21174 (PYXIS) chipset emulation.
+ *
+ * Written by Richard Henderson.
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ */
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "hw.h"
+#include "devices.h"
+#include "sysemu.h"
+#include "alpha_sys.h"
+
+/* TODO:
+ ERR_MASK MEM_NEM controls do_unassigned_access behavior.
+
+ RT_COUNT is a 33Mhz free-running counter.
+ INT_TIME should generate interrupt on RT_COUNT match.
+*/
+
+typedef struct PyxisState {
+ PCIHostState host;
+ /* General registers. */
+ uint32_t pyxis_rev;
+ uint32_t pci_lat;
+ uint32_t pyxis_ctrl;
+ uint32_t pyxis_ctrl1;
+ uint32_t flash_ctrl;
+ uint32_t hae_mem;
+ uint32_t hae_io;
+ uint32_t cfg;
+ /* Diagnostic registers. */
+ uint32_t pyxis_diag;
+ uint32_t diag_check;
+ /* Performance monitor registers. */
+ uint32_t perf_monitor;
+ uint32_t perf_control;
+ /* Error registers. */
+ uint32_t pyxis_err;
+ uint32_t pyxis_stat;
+ uint32_t err_mask;
+ uint32_t pyxis_syn;
+ uint32_t pyxis_err_data;
+ uint32_t mear;
+ uint32_t mesr;
+ uint32_t pci_err0;
+ uint32_t pci_err1;
+ uint32_t pci_err2;
+ /* Memory controler registers. */
+ uint32_t mcr;
+ uint32_t mcmr;
+ uint32_t gtr;
+ uint32_t rtr;
+ uint32_t rhpr;
+ uint32_t mdr[2];
+ uint32_t bbar[8];
+ uint32_t bcr[8];
+ uint32_t btr[8];
+ uint32_t cvm;
+ /* PCI window control registers. */
+ uint32_t tbia;
+ uint32_t wbase[4];
+ uint32_t wmask[4];
+ uint32_t tbase[4];
+ uint32_t w_dac;
+ /* Scatter-gather address translation registers. */
+ uint32_t tb_tag[8];
+ uint32_t tb_page[8][4];
+ /* Misc registers. */
+ uint32_t ccr;
+ uint32_t clk_stat;
+ uint32_t reset;
+ /* Interrupt control registers. */
+ uint64_t int_req;
+ uint64_t int_mask;
+ uint32_t int_hilo;
+ uint32_t int_route;
+ uint64_t gpo;
+ uint64_t int_time;
+ uint32_t iic_ctrl;
+ uint32_t int_cnfg;
+ /* QEMU emulation state. */
+ uint32_t latch_tmp;
+ uint64_t ram_size;
+ /* Items with which to raise interrupts. */
+ qemu_irq *irqs;
+} PyxisState;
+
+/* Called when one of INT_REQ or INT_MASK changes,
+ adjust the signalled state of the cpu. */
+static void pyxis_irq_change(PyxisState *s)
+{
+ CPUState *env = first_cpu;
+ uint64_t req;
+
+ req = s->int_req & s->int_mask;
+
+ /* If there are any non-masked interrupts, tell the cpu. */
+ if (req) {
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void invalidate_tag(PyxisState *s, int i)
+{
+ s->tb_tag[i] = 0;
+ memset(s->tb_page[i], 0, sizeof(s->tb_page[i]));
+}
+
+static uint32_t dummy_read(void *opaque, target_phys_addr_t addr)
+{
+ return 0;
+}
+
+static CPUReadMemoryFunc * const dummy_reads[] = {
+ dummy_read,
+ dummy_read,
+ dummy_read,
+};
+
+static CPUWriteMemoryFunc * const dummy_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ unassigned_mem_writel,
+};
+
+static uint32_t sparse0_readl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+ target_phys_addr_t hae;
+
+ hae = (s->hae_mem & 0xe0000000ull) << 5;
+ return alpha_sparse_mem_read(s->host.bus, hae + addr);
+}
+
+static void sparse0_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+ target_phys_addr_t hae;
+
+ hae = (s->hae_mem & 0xe0000000ull) << 5;
+ alpha_sparse_mem_write(s->host.bus, hae + addr, val);
+}
+
+static uint32_t sparse1_readl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+ target_phys_addr_t hae;
+
+ hae = ((s->hae_mem >> 11) & 0x1full) << (27 + 5);
+ return alpha_sparse_mem_read(s->host.bus, hae + addr);
+}
+
+static void sparse1_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+ target_phys_addr_t hae;
+
+ hae = ((s->hae_mem >> 11) & 0x1full) << (27 + 5);
+ alpha_sparse_mem_write(s->host.bus, hae + addr, val);
+}
+
+static uint32_t sparse2_readl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+ target_phys_addr_t hae;
+
+ hae = ((s->hae_mem >> 2) & 0x3full) << (26 + 5);
+ return alpha_sparse_mem_read(s->host.bus, hae + addr);
+}
+
+static void sparse2_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+ target_phys_addr_t hae;
+
+ hae = ((s->hae_mem >> 2) & 0x3full) << (26 + 5);
+ alpha_sparse_mem_write(s->host.bus, hae + addr, val);
+}
+
+static uint32_t sparseA_inl(void *opaque, target_phys_addr_t addr)
+{
+ /* Region A is fixed at the lower 32MB of I/O space. */
+ return alpha_sparse_io_read(addr);
+}
+
+static void sparseA_outl(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ /* Region A is fixed at the lower 32MB of I/O space. */
+ alpha_sparse_io_write(addr, val);
+}
+
+static uint32_t sparseB_inl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+ target_phys_addr_t hae;
+
+ hae = (s->hae_io & 0xfe000000ull) << 5;
+ return alpha_sparse_io_read(hae + addr);
+}
+
+static void sparseB_outl(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+ target_phys_addr_t hae;
+
+ hae = (s->hae_io & 0xfe000000ull) << 5;
+ alpha_sparse_io_write(hae + addr, val);
+}
+
+static uint32_t csr_874_readl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+
+ switch (addr) {
+ /* General Registers. */
+ case 0x0080: return s->pyxis_rev;
+ case 0x00c0: return s->pci_lat;
+ case 0x0100: return s->pyxis_ctrl;
+ case 0x0140: return s->pyxis_ctrl1;
+ case 0x0200: return s->flash_ctrl;
+ case 0x0400: return s->hae_mem;
+ case 0x0440: return s->hae_io;
+ case 0x0480: return s->cfg;
+
+ /* Diagnostic Registers. */
+ case 0x2000: return s->pyxis_diag;
+ case 0x3000: return s->diag_check;
+
+ /* Performance Monitor Registers. */
+ case 0x4000: return s->perf_monitor;
+ case 0x4040: return s->perf_control;
+
+ /* Error Registers. */
+ case 0x8200: return s->pyxis_err;
+ case 0x8240: return s->pyxis_stat;
+ case 0x8280: return s->err_mask;
+ case 0x8300: return s->pyxis_syn;
+ case 0x8308: return s->pyxis_err_data;
+ case 0x8400: return s->mear;
+ case 0x8440: return s->mesr;
+ case 0x8800: return s->pci_err0;
+ case 0x8840: return s->pci_err1;
+ case 0x8880: return s->pci_err2;
+
+ default:
+ do_unassigned_access(addr + 0x8740000000ull, 0, 0, 0, 4);
+ return -1;
+ }
+}
+
+static uint32_t csr_875_readl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+
+ switch (addr) {
+ /* Memory Controller Registers. */
+ case 0x0000: return s->mcr;
+ case 0x0040: return s->mcmr;
+ case 0x0200: return s->gtr;
+ case 0x0300: return s->rtr;
+ case 0x0400: return s->rhpr;
+ case 0x0500: return s->mdr[0];
+ case 0x0540: return s->mdr[1];
+
+ case 0x0600:
+ case 0x0640:
+ case 0x0680:
+ case 0x06c0:
+ case 0x0700:
+ case 0x0740:
+ case 0x0780:
+ case 0x07c0:
+ return s->bbar[(addr - 0x0600) / 0x40];
+
+ case 0x0800:
+ case 0x0840:
+ case 0x0880:
+ case 0x08c0:
+ case 0x0900:
+ case 0x0940:
+ case 0x0980:
+ case 0x09c0:
+ return s->bcr[(addr - 0x0800) / 0x40];
+
+ case 0x0a00:
+ case 0x0a40:
+ case 0x0a80:
+ case 0x0ac0:
+ case 0x0b00:
+ case 0x0b40:
+ case 0x0b80:
+ case 0x0bc0:
+ return s->btr[(addr - 0x0a00) / 0x40];
+
+ case 0x0c00: return s->cvm;
+
+ default:
+ do_unassigned_access(addr + 0x8750000000ull, 0, 0, 0, 4);
+ return -1;
+ }
+}
+
+static uint32_t csr_876_readl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+
+ switch (addr) {
+ /* PCI Window Control Registers. */
+ case 0x0100: return s->tbia;
+
+ case 0x0400:
+ case 0x0500:
+ case 0x0600:
+ case 0x0700:
+ return s->wbase[(addr - 0x0400) / 0x0100];
+
+ case 0x0440:
+ case 0x0540:
+ case 0x0640:
+ case 0x0740:
+ return s->wmask[(addr - 0x0440) / 0x0100];
+
+ case 0x0480:
+ case 0x0580:
+ case 0x0680:
+ case 0x0780:
+ return s->tbase[(addr - 0x0480) / 0x0100];
+
+ case 0x07c0: return s->w_dac;
+
+ /* Scatter-gather Address Translation Registers. */
+ case 0x0800:
+ case 0x0840:
+ case 0x0880:
+ case 0x08c0:
+ case 0x0900:
+ case 0x0940:
+ case 0x0980:
+ case 0x09c0:
+ return s->tb_tag[(addr - 0x0800) / 0x40];
+
+ case 0x1000: case 0x1040: case 0x1080: case 0x10c0:
+ case 0x1100: case 0x1140: case 0x1180: case 0x11c0:
+ case 0x1200: case 0x1240: case 0x1280: case 0x12c0:
+ case 0x1300: case 0x1340: case 0x1380: case 0x13c0:
+ case 0x1400: case 0x1440: case 0x1480: case 0x14c0:
+ case 0x1500: case 0x1540: case 0x1580: case 0x15c0:
+ case 0x1600: case 0x1640: case 0x1680: case 0x16c0:
+ case 0x1700: case 0x1740: case 0x1780: case 0x17c0:
+ return *(&s->tb_page[0][0] + ((addr - 0x1000) / 0x40));
+
+ default:
+ do_unassigned_access(addr + 0x8760000000ull, 0, 0, 0, 4);
+ return -1;
+ }
+}
+
+static uint32_t csr_878_readl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+
+ switch (addr) {
+ /* Miscellaneous Registers. */
+ case 0x0000: return s->ccr;
+ case 0x0100: return s->clk_stat;
+ case 0x0900: return s->reset;
+
+ default:
+ do_unassigned_access(addr + 0x8780000000ull, 0, 0, 0, 4);
+ return -1;
+ }
+}
+
+static uint32_t csr_87a_readl(void *opaque, target_phys_addr_t addr)
+{
+ PyxisState *s = opaque;
+ uint64_t ret;
+
+ switch (addr) {
+ /* Interrupt Control Registers. */
+ case 0x0000:
+ ret = s->int_req;
+ break;
+ case 0x0040:
+ ret = s->int_mask;
+ break;
+ case 0x00c0:
+ ret = s->int_hilo;
+ break;
+ case 0x0140:
+ ret = s->int_route;
+ break;
+ case 0x0180:
+ ret = s->gpo;
+ break;
+ case 0x01c0: return s->int_cnfg;
+ case 0x0200:
+ /* The RT_COUNT clock runs at 66.66MHz. */
+ ret = qemu_get_clock_ns(vm_clock) / 15;
+ break;
+ case 0x0240:
+ ret = s->int_time;
+ break;
+ case 0x02c0:
+ return s->iic_ctrl;
+
+ case 0x0004:
+ case 0x0044:
+ case 0x00c4:
+ case 0x0144:
+ case 0x0184:
+ case 0x0204:
+ case 0x0244:
+ return s->latch_tmp;
+
+ default:
+ do_unassigned_access(addr + 0x87a0000000ull, 0, 0, 0, 4);
+ return -1;
+ }
+
+ s->latch_tmp = ret >> 32;
+ return ret;
+}
+
+static void csr_874_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+
+ switch (addr) {
+ /* General Registers. */
+ case 0x0080:
+ /* pyxis_rev: RO */
+ break;
+ case 0x00c0:
+ s->pci_lat = val & 0xffff;
+ break;
+ case 0x0100:
+ s->pyxis_ctrl = val & 0x77703ffd;
+ break;
+ case 0x0140:
+ s->pyxis_ctrl1 = val & 0xffffff11;
+ break;
+ case 0x0200:
+ s->flash_ctrl = val & 0x3fff;
+ break;
+ case 0x0400:
+ s->hae_mem = val & 0xe000f8fc;
+ break;
+ case 0x0440:
+ s->hae_io = val & 0xfe000000;
+ break;
+ case 0x0480:
+ s->cfg = val & 3;
+ break;
+
+ /* Diagnostic Registers. */
+ case 0x2000:
+ s->pyxis_diag = val & 0xb0000003;
+ break;
+ case 0x3000:
+ s->diag_check = val & 0xff;
+ break;
+
+ /* Performance Monitor Registers. */
+ case 0x4000:
+ /* perf_monitor: RO */
+ break;
+ case 0x4040:
+ /* perf_control: */
+ /* If LOW_COUNT_CLR set, zero the low counter. */
+ if (val & (1 << 13)) {
+ s->perf_monitor &= 0xffff0000;
+ }
+ /* If HIGH_COUNT_CLR set, zero the high counter. */
+ if (val & (1 << 29)) {
+ s->perf_monitor &= 0x0000ffff;
+ }
+ s->perf_control = val & 0xd007d007;
+ break;
+
+ /* Error Registers. */
+ case 0x8200:
+ /* pyxis_err */
+ /* Zap the RW1C fields; the rest are RO. */
+ s->pyxis_err &= ~(val & 0xbff);
+ break;
+
+ case 0x8240:
+ /* pyxis_stat: RO */
+ break;
+ case 0x8280:
+ s->err_mask = val & 0x5ff;
+ break;
+ case 0x8300:
+ /* pyxis_syn: RO */
+ break;
+ case 0x8308:
+ /* pyxis_err_data: RO */
+ break;
+ case 0x8400:
+ /* mear: RO */
+ break;
+ case 0x8440:
+ /* mesr: */
+ /* There are a bunch of RO fields in here; preserve them. */
+ s->mesr = (s->mesr & ~0xfe000000) | (val & 0xfe000000);
+ break;
+ case 0x8800:
+ /* pci_err0: RO */
+ break;
+ case 0x8840:
+ /* pci_err1: RO */
+ break;
+ case 0x8880:
+ /* pci_err2: RO */
+ break;
+
+ default:
+ do_unassigned_access(addr + 0x8740000000ull, 1, 0, 0, 4);
+ return;
+ }
+}
+
+static void csr_875_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+
+ switch (addr) {
+ /* Memory Controller Registers. */
+ case 0x0000: /* mcr: */
+ /* The SERVER_MODE and BCACHE_TYPE fields are RO. */
+ s->mcr = (s->mcr & 0x300) | (val & 0x3ffffc01);
+ break;
+ case 0x0040:
+ s->mcmr = val & 0xffff;
+ break;
+ case 0x0200:
+ s->gtr = val & 0x0737;
+ break;
+ case 0x0300:
+ s->rtr = val & 0x9ff0;
+ break;
+ case 0x0400:
+ s->rhpr = val & 0xffff;
+ break;
+ case 0x0500:
+ s->mdr[0] = val & 0xbf3f3f3f;
+ break;
+ case 0x0540:
+ s->mdr[1] = val & 0xbf3f3f3f;
+ break;
+
+ case 0x0600: case 0x0640: case 0x0680: case 0x06c0:
+ case 0x0700: case 0x0740: case 0x0780: case 0x07c0:
+ s->bbar[(addr - 0x0600) / 0x40] = val & 0xffc0;
+ break;
+
+ case 0x0800: case 0x0840: case 0x0880: case 0x08c0:
+ case 0x0900: case 0x0940: case 0x0980: case 0x09c0:
+ s->bcr[(addr - 0x0800) / 0x40] = val & 0xff;
+ break;
+
+ case 0x0a00: case 0x0a40: case 0x0a80: case 0x0ac0:
+ case 0x0b00: case 0x0b40: case 0x0b80: case 0x0bc0:
+ s->btr[(addr - 0x0a00) / 0x40] = val & 0x23;
+ break;
+
+ case 0x0c00: /* cvm: */
+ /* All bits are RW1C. */
+ s->cvm &= ~val;
+ break;
+
+ default:
+ do_unassigned_access(addr + 0x8750000000ull, 1, 0, 0, 4);
+ return;
+ }
+}
+
+static void csr_876_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+ int i;
+
+ switch (addr) {
+ /* PCI Window Control Registers. */
+ case 0x0100:
+ switch (val & 3) {
+ case 0: /* No operation. */
+ break;
+ case 1: /* Invalidate and unlock TLB tags that are locked. */
+ for (i = 0; i < 4; ++i) {
+ if (s->tb_tag[i] & 2) {
+ invalidate_tag(s, i);
+ }
+ }
+ break;
+ case 2: /* Invalidate and unlock TLB tags that are unlocked. */
+ for (i = 0; i < 4; ++i) {
+ if ((s->tb_tag[i] & 2) == 0) {
+ invalidate_tag(s, i);
+ }
+ }
+ break;
+ case 3: /* Invalidate and unlock all TLB tag entries. */
+ memset(s->tb_tag, 0, sizeof(s->tb_tag));
+ memset(s->tb_page, 0, sizeof(s->tb_page));
+ break;
+ }
+ break;
+
+ case 0x0400: case 0x0500: case 0x0600: case 0x0700:
+ s->wbase[(addr - 0x0400) / 0x0100] = val & 0xfff0000f;
+ break;
+
+ case 0x0440: case 0x0540: case 0x0640: case 0x0740:
+ s->wmask[(addr - 0x0440) / 0x0100] = val & 0xfff00000;
+ break;
+
+ case 0x0480: case 0x0580: case 0x0680: case 0x0780:
+ s->tbase[(addr - 0x0480) / 0x0100] = val & 0xffffff00;
+ break;
+
+ case 0x07c0:
+ s->w_dac = val & 0xffffff00;
+ break;
+
+ /* Scatter-gather Address Translation Registers. */
+ case 0x0800: case 0x0840: case 0x0880: case 0x08c0: /* lockable */
+ s->tb_tag[(addr - 0x0800) / 0x40] = val & 0xffff8007;
+ break;
+ case 0x0900: case 0x0940: case 0x0980: case 0x09c0: /* not lockable */
+ s->tb_tag[(addr - 0x0800) / 0x40] = val & 0xffff8005;
+ break;
+
+ case 0x1000: case 0x1040: case 0x1080: case 0x10c0:
+ case 0x1100: case 0x1140: case 0x1180: case 0x11c0:
+ case 0x1200: case 0x1240: case 0x1280: case 0x12c0:
+ case 0x1300: case 0x1340: case 0x1380: case 0x13c0:
+ case 0x1400: case 0x1440: case 0x1480: case 0x14c0:
+ case 0x1500: case 0x1540: case 0x1580: case 0x15c0:
+ case 0x1600: case 0x1640: case 0x1680: case 0x16c0:
+ case 0x1700: case 0x1740: case 0x1780: case 0x17c0:
+ *(&s->tb_page[0][0] + ((addr - 0x1000) / 0x40)) = val & 0x003fffff;
+ break;
+
+ default:
+ do_unassigned_access(addr + 0x8760000000ull, 1, 0, 0, 4);
+ return;
+ }
+}
+
+static void csr_878_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+
+ switch (addr) {
+ /* Miscellaneous Registers. */
+ case 0x0000:
+ s->ccr = val & 0xff071773;
+ break;
+ case 0x0100:
+ /* clk_stat: RO */
+ break;
+ case 0x0900:
+ /* reset: */
+ /* Yes, the value is architected. Jokers... */
+ if (val == 0x0000dead) {
+ /* ??? This should be reset, but shutdown makes for easier
+ debugging for the moment. */
+ qemu_system_shutdown_request();
+ }
+ break;
+
+ default:
+ do_unassigned_access(addr + 0x8780000000ull, 1, 0, 0, 4);
+ return;
+ }
+}
+
+/* ??? We should probably not accept partial writes to the 64-bit registers.
+ In particular, INT_MASK, RT_COUNT and INT_TIME are likely to do the wrong
+ thing with partial writes. */
+
+static void csr_87a_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PyxisState *s = opaque;
+ uint64_t val64 = ((uint64_t)val << 32) | s->latch_tmp;
+
+ switch (addr) {
+ /* Interrupt Control Registers. */
+ case 0x0000:
+ s->latch_tmp = val;
+ break;
+ case 0x0004:
+ s->int_req &= ~(val64 & 0x7ffffffffffffffful);
+ pyxis_irq_change(s);
+ break;
+ case 0x0040:
+ s->latch_tmp = val;
+ break;
+ case 0x0044:
+ s->int_mask = val64;
+ pyxis_irq_change(s);
+ break;
+ case 0x00c0:
+ s->int_hilo = val & 0x7f;
+ break;
+ case 0x00c4:
+ /* int_hilo highpart all 0 */
+ break;
+ case 0x0140:
+ s->int_route = val & 0x7f;
+ break;
+ case 0x0144:
+ /* int_route highpart all 0 */
+ break;
+ case 0x0180:
+ s->latch_tmp = val;
+ break;
+ case 0x0184:
+ s->gpo = val64;
+ break;
+ case 0x01c0:
+ s->int_cnfg = val;
+ break;
+ case 0x0200:
+ /* rt_count low */
+ break;
+ case 0x0204:
+ /* rt_count high */
+ break;
+ case 0x0240:
+ s->latch_tmp = val;
+ break;
+ case 0x0244:
+ s->int_time = val64;
+ break;
+ case 0x02c0:
+ s->iic_ctrl = val;
+ break;
+
+ default:
+ do_unassigned_access(addr + 0x87a0000000ull, 1, 0, 0, 4);
+ return;
+ }
+}
+
+static CPUReadMemoryFunc * const sparse0_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ sparse0_readl
+};
+
+static CPUWriteMemoryFunc * const sparse0_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ sparse0_writel
+};
+
+static CPUReadMemoryFunc * const sparse1_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ sparse1_readl
+};
+
+static CPUWriteMemoryFunc * const sparse1_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ sparse1_writel
+};
+
+static CPUReadMemoryFunc * const sparse2_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ sparse2_readl
+};
+
+static CPUWriteMemoryFunc * const sparse2_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ sparse2_writel
+};
+
+static CPUReadMemoryFunc * const sparseA_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ sparseA_inl
+};
+
+static CPUWriteMemoryFunc * const sparseA_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ sparseA_outl
+};
+
+static CPUReadMemoryFunc * const sparseB_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ sparseB_inl
+};
+
+static CPUWriteMemoryFunc * const sparseB_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ sparseB_outl
+};
+
+static CPUReadMemoryFunc * const csr_874_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ csr_874_readl
+};
+
+static CPUWriteMemoryFunc * const csr_874_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ csr_874_writel
+};
+
+static CPUReadMemoryFunc * const csr_875_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ csr_875_readl
+};
+
+static CPUWriteMemoryFunc * const csr_875_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ csr_875_writel
+};
+
+static CPUReadMemoryFunc * const csr_876_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ csr_876_readl
+};
+
+static CPUWriteMemoryFunc * const csr_876_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ csr_876_writel
+};
+
+static CPUReadMemoryFunc * const csr_878_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ csr_878_readl
+};
+
+static CPUWriteMemoryFunc * const csr_878_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ csr_878_writel
+};
+
+static CPUReadMemoryFunc * const csr_87a_reads[] = {
+ unassigned_mem_readb,
+ unassigned_mem_readw,
+ csr_87a_readl
+};
+
+static CPUWriteMemoryFunc * const csr_87a_writes[] = {
+ unassigned_mem_writeb,
+ unassigned_mem_writew,
+ csr_87a_writel
+};
+
+
+static void pyxis_line_change(void *opaque, int irq, int level)
+{
+ PyxisState *s = opaque;
+ uint64_t req;
+
+ /* Set/Reset the bit in INT_REQ based on IRQ+LEVEL. */
+ req = s->int_req;
+ if (level) {
+ req |= 1ull << irq;
+ } else {
+ req &= ~(1ull << irq);
+ }
+ s->int_req = req;
+
+ pyxis_irq_change(s);
+}
+
+static void pyxis_pci_set_irq(void *opaque, int irq_num, int level)
+{
+ qemu_irq *irqs = opaque;
+ qemu_set_irq(irqs[irq_num], level);
+}
+
+static int pyxis_pci_map_irq(PCIDevice *d, int irq_num)
+{
+ int slot = (d->devfn >> 3) & 3;
+
+ assert(irq_num >= 0 && irq_num <= 3);
+
+ return irq_num * 4 + (11 - slot);
+}
+
+PCIBus *pyxis_init(uint64_t ram_size, qemu_irq *p_isa_irq)
+{
+ const uint64_t GB = 1024 * 1024 * 1024;
+ DeviceState *dev;
+ PCIHostState *p;
+ PyxisState *s;
+ PCIBus *b;
+ int region;
+
+ dev = qdev_create(NULL, "pyxis-pcihost");
+ p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+ s = container_of(p, PyxisState, host);
+
+ s->irqs = qemu_allocate_irqs(pyxis_line_change, s, 64);
+ *p_isa_irq = s->irqs[7];
+
+ b = pci_register_bus(&s->host.busdev.qdev, "pci", pyxis_pci_set_irq,
+ pyxis_pci_map_irq, s->irqs, 0, 32);
+ s->host.bus = b;
+
+ qdev_init_nofail(dev);
+
+ /* Main memory region, 0x00.0000.0000, 8GB. */
+
+ /* Dummy memory region, 0x0e.0000.0000, 4GB. */
+ region = cpu_register_io_memory(dummy_reads, dummy_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0xe00000000ull, 4*GB, region);
+
+ /* PCI Sparse memory region 0, 0x80.0000.0000, 16GB (covers 512MB). */
+ region = cpu_register_io_memory(sparse0_reads, sparse0_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8000000000ull, 16*GB, region);
+
+ /* PCI Sparse memory region 1, 0x84.0000.0000, 4GB (covers 128MB). */
+ region = cpu_register_io_memory(sparse1_reads, sparse1_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8400000000ull, 4*GB, region);
+
+ /* PCI Sparse memory region 2, 0x85.0000.0000, 2GB (covers 64MB). */
+ region = cpu_register_io_memory(sparse2_reads, sparse2_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8500000000ull, 2*GB, region);
+
+ /* PCI Sparse I/O region A, 0x85.8000.0000, 1GB (covers 32MB). */
+ region = cpu_register_io_memory(sparseA_reads, sparseA_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8580000000ull, 1*GB, region);
+
+ /* PCI Sparse I/O region B, 0x85.C000.0000, 1GB (covers 32MB). */
+ region = cpu_register_io_memory(sparseB_reads, sparseB_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x85c0000000ull, 1*GB, region);
+
+ /* PCI Dense memory, 0x86.0000.0000, 4GB. */
+ region = cpu_register_io_memory(alpha_pci_dense_mem_reads,
+ alpha_pci_dense_mem_writes, b,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8600000000ull, 4*GB, region);
+
+ /* Sparse configuration space, 0x87.0000.0000, 512MB. */
+ /* ??? Best I can tell, type 0 and type 1 accesses really only differ
+ when it comes to the actual bits placed on the PCI bus lines.
+ Which does not matter inside QEMU. Which means that the contents
+ of the CFG register doesn't really matter. */
+ region = cpu_register_io_memory(alpha_pci_sparse_conf1_reads,
+ alpha_pci_sparse_conf1_writes, b,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8700000000ull, GB/2, region);
+
+ /* PCI special/interrupt acknowledge 0x87.2000.0000, 512MB. */
+ region = cpu_register_io_memory(alpha_pci_iack_reads,
+ alpha_pci_special_writes, b,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8720000000ull, GB/2, region);
+
+ /* PYXIS Main CSRs, 0x87.4000.0000, 128MB. */
+ region = cpu_register_io_memory(csr_874_reads, csr_874_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8740000000ull, GB/4, region);
+
+ /* PYXIS Memory Control CSRs, 0x87.5000.0000, 128MB. */
+ region = cpu_register_io_memory(csr_875_reads, csr_875_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8750000000ull, GB/4, region);
+
+ /* PYXIS Address Translation CSRs, 0x87.6000.0000, 128MB. */
+ region = cpu_register_io_memory(csr_876_reads, csr_876_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8760000000ull, GB/4, region);
+
+ /* PYXIS Miscellaneous CSRs, 0x87.8000.0000, 128MB. */
+ region = cpu_register_io_memory(csr_878_reads, csr_878_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8780000000ull, GB/4, region);
+
+ /* ??? PYXIS Power Management CSRs, 0x87.9000.0000, 128MB. */
+
+ /* PYXIS Interrupt Control CSRs, 0x87.a000.0000, 128MB. */
+ region = cpu_register_io_memory(csr_87a_reads, csr_87a_writes, s,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x87a0000000ull, GB/4, region);
+
+ /* ??? Flash ROM read/write space, 0x87.c000.0000, 1GB. */
+
+ /* PCI BW memory, 0x88.0000.0000, 4GB. */
+ pci_bus_set_mem_base(b, 0x8800000000ull);
+
+ /* PCI BW I/O, 0x89.0000.0000, 4GB. */
+ region = cpu_register_io_memory(alpha_pci_bw_io_reads,
+ alpha_pci_bw_io_writes, b,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8900000000ull, 4*GB, region);
+
+ /* PCI configuration space type 0, 0x8a.0000.0000, 4GB. */
+ /* ??? Best I can tell, type 0 and type 1 accesses really only differ
+ when it comes to the actual bits placed on the PCI bus lines.
+ Which does not matter inside QEMU. */
+ region = cpu_register_io_memory(alpha_pci_bw_conf1_reads,
+ alpha_pci_bw_conf1_writes, b,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8a00000000ull, 4*GB, region);
+
+ /* PCI configuration space type 1, 0x8b.0000.0000, 4GB. */
+ region = cpu_register_io_memory(alpha_pci_bw_conf1_reads,
+ alpha_pci_bw_conf1_writes, b,
+ DEVICE_LITTLE_ENDIAN);
+ cpu_register_physical_memory(0x8b00000000ull, 4*GB, region);
+
+ s->ram_size = ram_size;
+ /* Call reset function. */
+
+ return b;
+}
+
+static int pyxis_pcihost_init(SysBusDevice *dev)
+{
+ return 0;
+}
+
+static SysBusDeviceInfo pyxis_pcihost_info = {
+ .init = pyxis_pcihost_init,
+ .qdev.name = "pyxis-pcihost",
+ .qdev.size = sizeof(PyxisState),
+ .qdev.no_user = 1
+};
+
+static void pyxis_register(void)
+{
+ sysbus_register_withprop(&pyxis_pcihost_info);
+}
+device_init(pyxis_register);
new file mode 100644
@@ -0,0 +1,195 @@
+/*
+ * QEMU Alpha SX164 hardware system emulator.
+ */
+
+#include "hw.h"
+#include "elf.h"
+#include "loader.h"
+#include "boards.h"
+#include "alpha_sys.h"
+#include "sysemu.h"
+#include "mc146818rtc.h"
+
+
+#define MAX_IDE_BUS 2
+
+
+static uint64_t cpu_alpha_superpage_to_phys(void *opaque, uint64_t addr)
+{
+ if (((addr >> 41) & 3) == 2) {
+ addr &= 0xffffffffffull;
+ }
+ return addr;
+}
+
+static void rtc_set_irq(void *opaque, int irq_num, int level)
+{
+ CPUState *env = first_cpu;
+ if (level) {
+ cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ } else {
+ cpu_reset_interrupt(env, CPU_INTERRUPT_TIMER);
+ }
+}
+
+static void sx164_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ CPUState *env = NULL;
+ ram_addr_t ram_offset;
+ PCIBus *pci_bus;
+ ISABus *isa_bus;
+ qemu_irq isa_pci_irq, *rtc_irqs, *isa_irqs;
+ long size, i;
+ const char *palcode_filename;
+ uint64_t palcode_entry, palcode_low, palcode_high;
+ uint64_t kernel_entry, kernel_low, kernel_high;
+
+ env = cpu_init(cpu_model ? cpu_model : "pca56");
+
+ env->trap_arg0 = ram_size;
+ env->trap_arg1 = 0;
+ env->trap_arg2 = 0;
+
+ ram_offset = qemu_ram_alloc(NULL, "ram", ram_size);
+ cpu_register_physical_memory(0, ram_size, ram_offset);
+
+ /* Init pyxis. */
+ pci_bus = pyxis_init(ram_size, &isa_pci_irq);
+
+ /* ??? There should be a Cypress CY82C693U SuperIO chip here
+ providing the PCI-to-ISA bridge. But the generic ISA support
+ doesn't expect a bridge, so we sort-of hard-code things in.
+ Ideally, the SuperIO device would capture all unhandled accesses
+ within the PCI space and then forward to the ISA bus. If the
+ access is unhandled within the ISA bus only then report to the
+ CPU via machine check. */
+ isa_bus = isa_bus_new(NULL);
+ isa_mem_base = 0x8800000000ull;
+
+ isa_irqs = i8259_init(isa_pci_irq);
+ isa_bus_irqs(isa_irqs);
+
+ /* ??? This isn't 100% correct, but should be Good Enough given that
+ we hide most of the actual details inside our custom PALcode.
+ The real HW somehow routes the TOY clock to cpu_int<2> (Int22).
+ How this relates to either the i8259 or the 21174 interrupt masks
+ is not documented. */
+ rtc_irqs = qemu_allocate_irqs(rtc_set_irq, NULL, 1);
+ rtc_init(1980, rtc_irqs[0]);
+
+ pit_init(0x40, 0);
+
+ /* VGA setup. Don't bother loading the bios. */
+ pci_vga_init(pci_bus);
+
+ for (i = 0; i < MAX_SERIAL_PORTS; ++i) {
+ if (serial_hds[i]) {
+ serial_isa_init(i, serial_hds[i]);
+ }
+ }
+
+#if 0
+ /* IDE setup. */
+ /* ??? Real SX164 actually has a Cypress CY82C693U. */
+ {
+ DriveInfo * hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+
+ if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+ hw_error("qemu: too many IDE buses\n");
+ exit(1);
+ }
+
+ for (i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+ hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+ }
+ pci_cmd646_ide_init(pci_bus, hd, 0);
+ }
+#endif
+
+#if 0
+ /* USB setup. The Cypress chip is OHCI compliant; this ought not
+ be too far off Really Correct. */
+ usb_ohci_init_pci(pci_bus, -1);
+#endif
+
+ /* Network setup. NE2K is good enough, failing Tulip support. */
+ for (i = 0; i < nb_nics; i++) {
+ pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
+ }
+
+ /* Load PALcode. Given that this is not "real" cpu palcode,
+ but one explicitly written for the emulation, we might as
+ well load it directly from and ELF image. */
+ palcode_filename = (bios_name ? bios_name : "palcode-sx164");
+ palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
+ if (palcode_filename == NULL) {
+ hw_error("qemu: no palcode provided\n");
+ exit(1);
+ }
+ size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
+ NULL, &palcode_entry, &palcode_low, &palcode_high,
+ 0, EM_ALPHA, 0);
+ if (size < 0) {
+ hw_error("qemu: could not load palcode '%s'\n", palcode_filename);
+ exit(1);
+ }
+ env->pc = palcode_entry;
+ env->pal_unix.palbr = palcode_entry;
+
+ /* Load a kernel. */
+ if (kernel_filename) {
+ uint64_t param_offset;
+
+ size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
+ NULL, &kernel_entry, &kernel_low, &kernel_high,
+ 0, EM_ALPHA, 0);
+ if (size < 0) {
+ hw_error("qemu: could not load kernel '%s'\n", kernel_filename);
+ exit(1);
+ }
+
+ env->trap_arg1 = kernel_entry;
+
+ param_offset = kernel_low - 0x6000;
+
+ if (kernel_cmdline) {
+ pstrcpy_targphys("cmdline", param_offset, 0x100, kernel_cmdline);
+ }
+
+ if (initrd_filename) {
+ long initrd_base, initrd_size;
+
+ initrd_base = (kernel_high | TARGET_PAGE_SIZE) + 1;
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
+ if (initrd_size < 0) {
+ hw_error("qemu: could not load initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+
+ stq_phys(param_offset + 0x100, initrd_base);
+ stq_phys(param_offset + 0x108, initrd_size);
+ }
+ }
+}
+
+static QEMUMachine sx164_machine = {
+ .name = "sx164",
+ .desc = "Alpha SX164",
+ .init = sx164_init,
+ .max_cpus = 1,
+ .is_default = 1,
+};
+
+static void sx164_machine_init(void)
+{
+ qemu_register_machine(&sx164_machine);
+}
+
+machine_init(sx164_machine_init);
new file mode 100644
@@ -0,0 +1,41 @@
+/* Alpha cores and system support chips. */
+
+#ifndef HW_ALPHA_H
+#define HW_ALPHA_H 1
+
+#include "pci.h"
+#include "pci_host.h"
+#include "ide.h"
+#include "net.h"
+#include "pc.h"
+#include "usb-ohci.h"
+#include "irq.h"
+
+
+extern PCIBus *pyxis_init(uint64_t, qemu_irq *);
+
+/* alpha_pci.c. */
+extern CPUReadMemoryFunc * const alpha_pci_bw_io_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_bw_io_writes[];
+extern CPUReadMemoryFunc * const alpha_pci_bw_conf1_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_bw_conf1_writes[];
+
+extern CPUReadMemoryFunc * const alpha_pci_dense_mem_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_dense_mem_writes[];
+
+extern CPUReadMemoryFunc * const alpha_pci_sparse_conf1_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_sparse_conf1_writes[];
+
+extern CPUReadMemoryFunc * const alpha_pci_iack_reads[];
+extern CPUWriteMemoryFunc * const alpha_pci_special_writes[];
+
+extern uint32_t alpha_sparse_io_read(target_phys_addr_t);
+extern void alpha_sparse_io_write(target_phys_addr_t, uint32_t);
+
+extern uint32_t alpha_sparse_mem_read(PCIBus *, target_phys_addr_t);
+extern void alpha_sparse_mem_write(PCIBus *, target_phys_addr_t, uint32_t);
+
+extern uint32_t alpha_sparse_conf1_read(PCIBus *, target_phys_addr_t);
+extern void alpha_sparse_conf1_write(PCIBus *, target_phys_addr_t, uint32_t);
+
+#endif
@@ -2526,6 +2526,11 @@ void cpu_loop (CPUState *env)
fprintf(stderr, "Machine check exception. Exit\n");
exit(1);
break;
+ case EXCP_CLK_INTERRUPT:
+ case EXCP_DEV_INTERRUPT:
+ fprintf(stderr, "External interrupt. Exit\n");
+ exit(1);
+ break;
case EXCP_ARITH:
env->lock_addr = -1;
info.si_signo = TARGET_SIGFPE;
@@ -2534,41 +2539,21 @@ void cpu_loop (CPUState *env)
info._sifields._sigfault._addr = env->pc;
queue_signal(env, info.si_signo, &info);
break;
- case EXCP_HW_INTERRUPT:
- fprintf(stderr, "External interrupt. Exit\n");
- exit(1);
- break;
- case EXCP_DFAULT:
+ case EXCP_MMFAULT:
env->lock_addr = -1;
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
- info.si_code = (page_get_flags(env->ipr[IPR_EXC_ADDR]) & PAGE_VALID
+ info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
- info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR];
+ info._sifields._sigfault._addr = env->trap_arg0;
queue_signal(env, info.si_signo, &info);
break;
- case EXCP_DTB_MISS_PAL:
- fprintf(stderr, "MMU data TLB miss in PALcode\n");
- exit(1);
- break;
- case EXCP_ITB_MISS:
- fprintf(stderr, "MMU instruction TLB miss\n");
- exit(1);
- break;
- case EXCP_ITB_ACV:
- fprintf(stderr, "MMU instruction access violation\n");
- exit(1);
- break;
- case EXCP_DTB_MISS_NATIVE:
- fprintf(stderr, "MMU data TLB miss\n");
- exit(1);
- break;
case EXCP_UNALIGN:
env->lock_addr = -1;
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR];
+ info._sifields._sigfault._addr = env->trap_arg0;
queue_signal(env, info.si_signo, &info);
break;
case EXCP_OPCDEC:
@@ -2583,9 +2568,9 @@ void cpu_loop (CPUState *env)
case EXCP_FEN:
/* No-op. Linux simply re-enables the FPU. */
break;
- case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
+ case EXCP_CALL_PAL:
env->lock_addr = -1;
- switch ((trapnr >> 6) | 0x80) {
+ switch (env->error_code) {
case 0x80:
/* BPT */
info.si_signo = TARGET_SIGTRAP;
@@ -2676,8 +2661,6 @@ void cpu_loop (CPUState *env)
goto do_sigill;
}
break;
- case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1):
- goto do_sigill;
case EXCP_DEBUG:
info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
if (info.si_signo) {
new file mode 100644
GIT binary patch
literal 107781
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
We`Y%IX8`CgF4)hCOK<j{9QZ%WjL0+q
literal 0
HcmV?d00001
@@ -192,171 +192,107 @@ enum {
#define SWCR_MASK (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)
-/* Internal processor registers */
-/* XXX: TOFIX: most of those registers are implementation dependant */
-enum {
-#if defined(CONFIG_USER_ONLY)
- IPR_EXC_ADDR,
- IPR_EXC_SUM,
- IPR_EXC_MASK,
-#else
- /* Ebox IPRs */
- IPR_CC = 0xC0, /* 21264 */
- IPR_CC_CTL = 0xC1, /* 21264 */
-#define IPR_CC_CTL_ENA_SHIFT 32
-#define IPR_CC_CTL_COUNTER_MASK 0xfffffff0UL
- IPR_VA = 0xC2, /* 21264 */
- IPR_VA_CTL = 0xC4, /* 21264 */
-#define IPR_VA_CTL_VA_48_SHIFT 1
-#define IPR_VA_CTL_VPTB_SHIFT 30
- IPR_VA_FORM = 0xC3, /* 21264 */
- /* Ibox IPRs */
- IPR_ITB_TAG = 0x00, /* 21264 */
- IPR_ITB_PTE = 0x01, /* 21264 */
- IPR_ITB_IAP = 0x02,
- IPR_ITB_IA = 0x03, /* 21264 */
- IPR_ITB_IS = 0x04, /* 21264 */
- IPR_PMPC = 0x05,
- IPR_EXC_ADDR = 0x06, /* 21264 */
- IPR_IVA_FORM = 0x07, /* 21264 */
- IPR_CM = 0x09, /* 21264 */
-#define IPR_CM_SHIFT 3
-#define IPR_CM_MASK (3ULL << IPR_CM_SHIFT) /* 21264 */
- IPR_IER = 0x0A, /* 21264 */
-#define IPR_IER_MASK 0x0000007fffffe000ULL
- IPR_IER_CM = 0x0B, /* 21264: = CM | IER */
- IPR_SIRR = 0x0C, /* 21264 */
-#define IPR_SIRR_SHIFT 14
-#define IPR_SIRR_MASK 0x7fff
- IPR_ISUM = 0x0D, /* 21264 */
- IPR_HW_INT_CLR = 0x0E, /* 21264 */
- IPR_EXC_SUM = 0x0F,
- IPR_PAL_BASE = 0x10,
- IPR_I_CTL = 0x11,
-#define IPR_I_CTL_CHIP_ID_SHIFT 24 /* 21264 */
-#define IPR_I_CTL_BIST_FAIL (1 << 23) /* 21264 */
-#define IPR_I_CTL_IC_EN_SHIFT 2 /* 21264 */
-#define IPR_I_CTL_SDE1_SHIFT 7 /* 21264 */
-#define IPR_I_CTL_HWE_SHIFT 12 /* 21264 */
-#define IPR_I_CTL_VA_48_SHIFT 15 /* 21264 */
-#define IPR_I_CTL_SPE_SHIFT 3 /* 21264 */
-#define IPR_I_CTL_CALL_PAL_R23_SHIFT 20 /* 21264 */
- IPR_I_STAT = 0x16, /* 21264 */
- IPR_IC_FLUSH = 0x13, /* 21264 */
- IPR_IC_FLUSH_ASM = 0x12, /* 21264 */
- IPR_CLR_MAP = 0x15,
- IPR_SLEEP = 0x17,
- IPR_PCTX = 0x40,
- IPR_PCTX_ASN = 0x01, /* field */
-#define IPR_PCTX_ASN_SHIFT 39
- IPR_PCTX_ASTER = 0x02, /* field */
-#define IPR_PCTX_ASTER_SHIFT 5
- IPR_PCTX_ASTRR = 0x04, /* field */
-#define IPR_PCTX_ASTRR_SHIFT 9
- IPR_PCTX_PPCE = 0x08, /* field */
-#define IPR_PCTX_PPCE_SHIFT 1
- IPR_PCTX_FPE = 0x10, /* field */
-#define IPR_PCTX_FPE_SHIFT 2
- IPR_PCTX_ALL = 0x5f, /* all fields */
- IPR_PCTR_CTL = 0x14, /* 21264 */
- /* Mbox IPRs */
- IPR_DTB_TAG0 = 0x20, /* 21264 */
- IPR_DTB_TAG1 = 0xA0, /* 21264 */
- IPR_DTB_PTE0 = 0x21, /* 21264 */
- IPR_DTB_PTE1 = 0xA1, /* 21264 */
- IPR_DTB_ALTMODE = 0xA6,
- IPR_DTB_ALTMODE0 = 0x26, /* 21264 */
-#define IPR_DTB_ALTMODE_MASK 3
- IPR_DTB_IAP = 0xA2,
- IPR_DTB_IA = 0xA3, /* 21264 */
- IPR_DTB_IS0 = 0x24,
- IPR_DTB_IS1 = 0xA4,
- IPR_DTB_ASN0 = 0x25, /* 21264 */
- IPR_DTB_ASN1 = 0xA5, /* 21264 */
-#define IPR_DTB_ASN_SHIFT 56
- IPR_MM_STAT = 0x27, /* 21264 */
- IPR_M_CTL = 0x28, /* 21264 */
-#define IPR_M_CTL_SPE_SHIFT 1
-#define IPR_M_CTL_SPE_MASK 7
- IPR_DC_CTL = 0x29, /* 21264 */
- IPR_DC_STAT = 0x2A, /* 21264 */
- /* Cbox IPRs */
- IPR_C_DATA = 0x2B,
- IPR_C_SHIFT = 0x2C,
-
- IPR_ASN,
- IPR_ASTEN,
- IPR_ASTSR,
- IPR_DATFX,
- IPR_ESP,
- IPR_FEN,
- IPR_IPIR,
- IPR_IPL,
- IPR_KSP,
- IPR_MCES,
- IPR_PERFMON,
- IPR_PCBB,
- IPR_PRBR,
- IPR_PTBR,
- IPR_SCBB,
- IPR_SISR,
- IPR_SSP,
- IPR_SYSPTBR,
- IPR_TBCHK,
- IPR_TBIA,
- IPR_TBIAP,
- IPR_TBIS,
- IPR_TBISD,
- IPR_TBISI,
- IPR_USP,
- IPR_VIRBND,
- IPR_VPTB,
- IPR_WHAMI,
- IPR_ALT_MODE,
+#ifndef CONFIG_USER_ONLY
+#define CONFIG_PALMODE 1
#endif
- IPR_LAST,
+
+/* What kind of PALmode handling is active. */
+enum {
+ PAL_UNIX,
+ PAL_OPENVMS,
+ PAL_WINNT,
+ PAL_NATIVE_21064,
+ PAL_NATIVE_21164,
+ PAL_NATIVE_21264,
};
-typedef struct CPUAlphaState CPUAlphaState;
+enum {
+ PTE_VALID = 0x0001,
+ PTE_FOR = 0x0002, /* used for page protection (fault on read) */
+ PTE_FOW = 0x0004, /* used for page protection (fault on write) */
+ PTE_FOE = 0x0008, /* used for page protection (fault on exec) */
+ PTE_ASM = 0x0010,
+ PTE_KRE = 0x0100,
+ PTE_URE = 0x0200,
+ PTE_KWE = 0x1000,
+ PTE_UWE = 0x2000
+};
+
+/* Instruction fault (entIF) constants. */
+enum {
+ IF_K_BPT,
+ IF_K_BUGCHK,
+ IF_K_GENTRAP,
+ IF_K_FEN,
+ IF_K_OPCDEC,
+};
-typedef struct pal_handler_t pal_handler_t;
-struct pal_handler_t {
- /* Reset */
- void (*reset)(CPUAlphaState *env);
- /* Uncorrectable hardware error */
- void (*machine_check)(CPUAlphaState *env);
- /* Arithmetic exception */
- void (*arithmetic)(CPUAlphaState *env);
- /* Interrupt / correctable hardware error */
- void (*interrupt)(CPUAlphaState *env);
- /* Data fault */
- void (*dfault)(CPUAlphaState *env);
- /* DTB miss pal */
- void (*dtb_miss_pal)(CPUAlphaState *env);
- /* DTB miss native */
- void (*dtb_miss_native)(CPUAlphaState *env);
- /* Unaligned access */
- void (*unalign)(CPUAlphaState *env);
- /* ITB miss */
- void (*itb_miss)(CPUAlphaState *env);
- /* Instruction stream access violation */
- void (*itb_acv)(CPUAlphaState *env);
- /* Reserved or privileged opcode */
- void (*opcdec)(CPUAlphaState *env);
- /* Floating point exception */
- void (*fen)(CPUAlphaState *env);
- /* Call pal instruction */
- void (*call_pal)(CPUAlphaState *env, uint32_t palcode);
+/* Hardware interrupt (entInt) constants. */
+enum {
+ INT_K_IP,
+ INT_K_CLK,
+ INT_K_MCHK,
+ INT_K_DEV,
+ INT_K_PERF,
+};
+
+/* Memory management (entMM) constants. */
+enum {
+ MM_K_TNV,
+ MM_K_ACV,
+ MM_K_FOR,
+ MM_K_FOE,
+ MM_K_FOW
+};
+
+/* Arithmetic exception (entArith) constants. */
+enum {
+ EXC_M_SWC = 1, /* Software completion */
+ EXC_M_INV = 2, /* Invalid operation */
+ EXC_M_DZE = 4, /* Division by zero */
+ EXC_M_FOV = 8, /* Overflow */
+ EXC_M_UNF = 16, /* Underflow */
+ EXC_M_INE = 32, /* Inexact result */
+ EXC_M_IOV = 64 /* Integer Overflow */
};
-#define NB_MMU_MODES 4
+/* Processor status constants. */
+enum {
+ /* Low 3 bits are interrupt mask level. */
+ PS_INT_MASK = 7,
+
+ /* Bits 4 and 5 are the mmu mode. The VMS PALcode uses all 4 modes;
+ The Unix PALcode only uses bit 4. */
+ PS_USER_MODE = 8
+};
+
+/* MMU modes definitions */
+
+/* ??? Alpha has 4 MMU modes: PALcode, kernel, executive, supervisor,
+ and user. The Unix PALcode only exposes the kernel and user modes;
+ presumably executive and supervisor are used by VMS.
+
+ PALcode itself uses physical mode for code and kernel mode for data;
+ there are PALmode instructions that can access data via physical mode
+ or via an os-installed "alternate mode", which is one of the 4 above.
+
+ Since we're emulating Unix PALcode, and not the full cpu, elide the
+ unused MMU modes to save space. */
+
+
+#define NB_MMU_MODES 2
+
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_KERNEL_IDX 0
+#define MMU_USER_IDX 1
+
+typedef struct CPUAlphaState CPUAlphaState;
struct CPUAlphaState {
uint64_t ir[31];
float64 fir[31];
uint64_t pc;
- uint64_t ipr[IPR_LAST];
- uint64_t ps;
uint64_t unique;
uint64_t lock_addr;
uint64_t lock_st_addr;
@@ -371,10 +307,27 @@ struct CPUAlphaState {
uint8_t fpcr_dnod;
uint8_t fpcr_undz;
- /* Used for HW_LD / HW_ST */
- uint8_t saved_mode;
- /* For RC and RS */
+ uint8_t ps;
uint8_t intr_flag;
+ uint8_t fen;
+ uint8_t pal_mode;
+ uint32_t pcc_ofs;
+
+ /* The Internal Processor Registers. Some of these we assume always
+ exist for use in user-mode. */
+ uint64_t trap_arg0;
+ uint64_t trap_arg1;
+ uint64_t trap_arg2;
+
+ /* The internal data required by our emulation of the Unix PALcode. */
+ struct {
+ uint64_t exc_addr;
+ uint64_t palbr;
+ uint64_t ptbr;
+ uint64_t vptptr;
+ uint64_t shadow[8];
+ uint64_t scratch[24];
+ } pal_unix;
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* temporary fixed-point registers
@@ -386,14 +339,11 @@ struct CPUAlphaState {
/* Those resources are used only in Qemu core */
CPU_COMMON
- uint32_t hflags;
-
int error_code;
uint32_t features;
uint32_t amask;
int implver;
- pal_handler_t *pal_handler;
};
#define cpu_init cpu_alpha_init
@@ -401,15 +351,11 @@ struct CPUAlphaState {
#define cpu_gen_code cpu_alpha_gen_code
#define cpu_signal_handler cpu_alpha_signal_handler
-/* MMU modes definitions */
-#define MMU_MODE0_SUFFIX _kernel
-#define MMU_MODE1_SUFFIX _executive
-#define MMU_MODE2_SUFFIX _supervisor
-#define MMU_MODE3_SUFFIX _user
-#define MMU_USER_IDX 3
+#define CPU_SAVE_VERSION 1
+
static inline int cpu_mmu_index (CPUState *env)
{
- return (env->ps >> 3) & 3;
+ return (env->ps & PS_USER_MODE) != 0;
}
#include "cpu-all.h"
@@ -422,37 +368,21 @@ enum {
};
enum {
- EXCP_RESET = 0x0000,
- EXCP_MCHK = 0x0020,
- EXCP_ARITH = 0x0060,
- EXCP_HW_INTERRUPT = 0x00E0,
- EXCP_DFAULT = 0x01E0,
- EXCP_DTB_MISS_PAL = 0x09E0,
- EXCP_ITB_MISS = 0x03E0,
- EXCP_ITB_ACV = 0x07E0,
- EXCP_DTB_MISS_NATIVE = 0x08E0,
- EXCP_UNALIGN = 0x11E0,
- EXCP_OPCDEC = 0x13E0,
- EXCP_FEN = 0x17E0,
- EXCP_CALL_PAL = 0x2000,
- EXCP_CALL_PALP = 0x3000,
- EXCP_CALL_PALE = 0x4000,
- /* Pseudo exception for console */
- EXCP_CONSOLE_DISPATCH = 0x4001,
- EXCP_CONSOLE_FIXUP = 0x4002,
- EXCP_STL_C = 0x4003,
- EXCP_STQ_C = 0x4004,
+ EXCP_RESET,
+ EXCP_MCHK,
+ EXCP_CLK_INTERRUPT,
+ EXCP_DEV_INTERRUPT,
+ EXCP_MMFAULT,
+ EXCP_UNALIGN,
+ EXCP_OPCDEC,
+ EXCP_ARITH,
+ EXCP_FEN,
+ EXCP_CALL_PAL,
+ /* For Usermode emulation. */
+ EXCP_STL_C,
+ EXCP_STQ_C,
};
-/* Arithmetic exception */
-#define EXC_M_IOV (1<<16) /* Integer Overflow */
-#define EXC_M_INE (1<<15) /* Inexact result */
-#define EXC_M_UNF (1<<14) /* Underflow */
-#define EXC_M_FOV (1<<13) /* Overflow */
-#define EXC_M_DZE (1<<12) /* Division by zero */
-#define EXC_M_INV (1<<11) /* Invalid operation */
-#define EXC_M_SWC (1<<10) /* Software completion */
-
enum {
IR_V0 = 0,
IR_T0 = 1,
@@ -502,21 +432,26 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw,
#define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
void do_interrupt (CPUState *env);
+uint64_t cpu_load_pcc(CPUState *env);
uint64_t cpu_alpha_load_fpcr (CPUState *env);
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
#if !defined (CONFIG_USER_ONLY)
-void pal_init (CPUState *env);
-void call_pal (CPUState *env);
+void swap_shadow_regs(CPUState *);
+void do_unassigned_access(target_phys_addr_t addr, int, int, int, int);
#endif
+enum {
+ TB_FLAGS_PAL_MODE = 1,
+ TB_FLAGS_FEN = 2
+};
+
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
*pc = env->pc;
*cs_base = 0;
- *flags = env->ps;
+ *flags = ( (env->pal_mode ? TB_FLAGS_PAL_MODE : 0)
+ | (env->fen ? TB_FLAGS_FEN : 0));
}
#if defined(CONFIG_USER_ONLY)
@@ -39,7 +39,12 @@ register struct CPUAlphaState *env asm(AREG0);
static inline int cpu_has_work(CPUState *env)
{
- return (env->interrupt_request & CPU_INTERRUPT_HARD);
+ /* ??? There's a model-specific mapping between external hardware
+ interrupt numbers and the Unix PALcode interrupt levels. */
+ int req = CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER;
+ return ((env->interrupt_request & req)
+ && env->pal_mode == 0
+ && (env->ps & 7) == 0);
}
static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
@@ -24,6 +24,14 @@
#include "cpu.h"
#include "exec-all.h"
#include "softfloat.h"
+#include "qemu-timer.h"
+
+
+uint64_t cpu_load_pcc(CPUState *env)
+{
+ /* ??? This isn't a timer for which we have any rate info. */
+ return (uint32_t)cpu_get_real_ticks() - env->pcc_ofs;
+}
uint64_t cpu_alpha_load_fpcr (CPUState *env)
{
@@ -160,382 +168,304 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
}
#if defined(CONFIG_USER_ONLY)
-
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
- if (rw == 2)
- env->exception_index = EXCP_ITB_MISS;
- else
- env->exception_index = EXCP_DFAULT;
- env->ipr[IPR_EXC_ADDR] = address;
-
+ env->exception_index = EXCP_MMFAULT;
+ env->trap_arg0 = address;
return 1;
}
-
-void do_interrupt (CPUState *env)
+#else
+/* Returns the OSF/1 entMM failure indication, or -1 on success. */
+static int get_physical_address(CPUState *env, target_ulong addr,
+ int prot_need, int mmu_idx,
+ target_ulong *pphys, int *pprot)
{
- env->exception_index = -1;
-}
+ target_long saddr = addr;
+ target_ulong phys = 0;
+ target_ulong L1pte, L2pte, L3pte;
+ target_ulong pt, index;
+ int prot = 0;
+ int ret = MM_K_ACV;
+
+ /* Ensure that the virtual address is properly sign-extended from
+ the last implemented virtual address bit. */
+ if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
+ goto exit;
+ }
-#else
+ /* Translate the superpage. */
+ /* ??? When we do more than emulate Unix PALcode, we'll need to
+ determine which superpage is actually active. */
+ if (saddr < 0 && (saddr >> (TARGET_VIRT_ADDR_SPACE_BITS - 2) & 3) == 2) {
+ /* User-space cannot access kseg addresses. */
+ if (mmu_idx != MMU_KERNEL_IDX) {
+ goto exit;
+ }
+
+ phys = saddr & ((1ull << 40) - 1);
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ ret = -1;
+ goto exit;
+ }
+
+ /* Interpret the page table exactly like PALcode does. */
+
+ pt = env->pal_unix.ptbr;
+
+ /* L1 page table read. */
+ index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
+ L1pte = ldq_phys(pt + index*8);
+
+ if (unlikely((L1pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+ if (unlikely((L1pte & PTE_KRE) == 0)) {
+ goto exit;
+ }
+ pt = L1pte >> 32 << TARGET_PAGE_BITS;
+
+ /* L2 page table read. */
+ index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
+ L2pte = ldq_phys(pt + index*8);
+
+ if (unlikely((L2pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+ if (unlikely((L2pte & PTE_KRE) == 0)) {
+ goto exit;
+ }
+ pt = L2pte >> 32 << TARGET_PAGE_BITS;
+
+ /* L3 page table read. */
+ index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
+ L3pte = ldq_phys(pt + index*8);
+
+ phys = L3pte >> 32 << TARGET_PAGE_BITS;
+ if (unlikely((L3pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+
+#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
+# error page bits out of date
+#endif
+
+ /* Check access violations. */
+ if (L3pte & (PTE_KRE << mmu_idx)) {
+ prot |= PAGE_READ | PAGE_EXEC;
+ }
+ if (L3pte & (PTE_KWE << mmu_idx)) {
+ prot |= PAGE_WRITE;
+ }
+ if (unlikely((prot & prot_need) == 0 && prot_need)) {
+ goto exit;
+ }
+
+ /* Check fault-on-operation violations. */
+ prot &= ~(L3pte >> 1);
+ ret = -1;
+ if (unlikely((prot & prot_need) == 0)) {
+ ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
+ prot_need & PAGE_WRITE ? MM_K_FOW :
+ prot_need & PAGE_READ ? MM_K_FOR : -1);
+ }
+
+ exit:
+ *pphys = phys;
+ *pprot = prot;
+ return ret;
+}
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
{
- return -1;
+ target_ulong phys;
+ int prot, fail;
+
+ fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
+ return (fail >= 0 ? -1 : phys);
}
-int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmmu)
+int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
+ int mmu_idx, int is_softmmu)
{
- uint32_t opc;
-
- if (rw == 2) {
- /* Instruction translation buffer miss */
- env->exception_index = EXCP_ITB_MISS;
- } else {
- if (env->ipr[IPR_EXC_ADDR] & 1)
- env->exception_index = EXCP_DTB_MISS_PAL;
- else
- env->exception_index = EXCP_DTB_MISS_NATIVE;
- opc = (ldl_code(env->pc) >> 21) << 4;
- if (rw) {
- opc |= 0x9;
- } else {
- opc |= 0x4;
- }
- env->ipr[IPR_MM_STAT] = opc;
+ target_ulong phys;
+ int prot, fail;
+
+ fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
+ if (unlikely(fail >= 0)) {
+ env->exception_index = EXCP_MMFAULT;
+ env->trap_arg0 = addr;
+ env->trap_arg1 = fail;
+ env->trap_arg2 = (rw == 2 ? -1 : rw);
+ return 1;
}
- return 1;
+ tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
+ prot, mmu_idx, TARGET_PAGE_SIZE);
+ return 0;
}
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
+void swap_shadow_regs(CPUState *env)
{
- uint64_t hwpcb;
- int ret = 0;
-
- hwpcb = env->ipr[IPR_PCBB];
- switch (iprn) {
- case IPR_ASN:
- if (env->features & FEATURE_ASN)
- *valp = env->ipr[IPR_ASN];
- else
- *valp = 0;
- break;
- case IPR_ASTEN:
- *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
- break;
- case IPR_ASTSR:
- *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
- break;
- case IPR_DATFX:
- /* Write only */
- ret = -1;
- break;
- case IPR_ESP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_ESP];
- else
- *valp = ldq_raw(hwpcb + 8);
- break;
- case IPR_FEN:
- *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
- break;
- case IPR_IPIR:
- /* Write-only */
- ret = -1;
- break;
- case IPR_IPL:
- *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
- break;
- case IPR_KSP:
- if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
- ret = -1;
- } else {
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_KSP];
- else
- *valp = ldq_raw(hwpcb + 0);
- }
- break;
- case IPR_MCES:
- *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
- break;
- case IPR_PERFMON:
- /* Implementation specific */
- *valp = 0;
- break;
- case IPR_PCBB:
- *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
- break;
- case IPR_PRBR:
- *valp = env->ipr[IPR_PRBR];
- break;
- case IPR_PTBR:
- *valp = env->ipr[IPR_PTBR];
- break;
- case IPR_SCBB:
- *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
- break;
- case IPR_SIRR:
- /* Write-only */
- ret = -1;
- break;
- case IPR_SISR:
- *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
- case IPR_SSP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_SSP];
- else
- *valp = ldq_raw(hwpcb + 16);
- break;
- case IPR_SYSPTBR:
- if (env->features & FEATURE_VIRBND)
- *valp = env->ipr[IPR_SYSPTBR];
- else
- ret = -1;
- break;
- case IPR_TBCHK:
- if ((env->features & FEATURE_TBCHK)) {
- /* XXX: TODO */
- *valp = 0;
- ret = -1;
- } else {
- ret = -1;
- }
- break;
- case IPR_TBIA:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBIAP:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBIS:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBISD:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBISI:
- /* Write-only */
- ret = -1;
- break;
- case IPR_USP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_USP];
- else
- *valp = ldq_raw(hwpcb + 24);
- break;
- case IPR_VIRBND:
- if (env->features & FEATURE_VIRBND)
- *valp = env->ipr[IPR_VIRBND];
- else
- ret = -1;
- break;
- case IPR_VPTB:
- *valp = env->ipr[IPR_VPTB];
- break;
- case IPR_WHAMI:
- *valp = env->ipr[IPR_WHAMI];
- break;
- default:
- /* Invalid */
- ret = -1;
- break;
- }
-
- return ret;
+ uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
+
+ i0 = env->ir[8];
+ i1 = env->ir[9];
+ i2 = env->ir[10];
+ i3 = env->ir[11];
+ i4 = env->ir[12];
+ i5 = env->ir[13];
+ i6 = env->ir[14];
+ i7 = env->ir[25];
+
+ env->ir[8] = env->pal_unix.shadow[0];
+ env->ir[9] = env->pal_unix.shadow[1];
+ env->ir[10] = env->pal_unix.shadow[2];
+ env->ir[11] = env->pal_unix.shadow[3];
+ env->ir[12] = env->pal_unix.shadow[4];
+ env->ir[13] = env->pal_unix.shadow[5];
+ env->ir[14] = env->pal_unix.shadow[6];
+ env->ir[25] = env->pal_unix.shadow[7];
+
+ env->pal_unix.shadow[0] = i0;
+ env->pal_unix.shadow[1] = i1;
+ env->pal_unix.shadow[2] = i2;
+ env->pal_unix.shadow[3] = i3;
+ env->pal_unix.shadow[4] = i4;
+ env->pal_unix.shadow[5] = i5;
+ env->pal_unix.shadow[6] = i6;
+ env->pal_unix.shadow[7] = i7;
}
+#endif /* USER_ONLY */
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
+void do_interrupt(CPUState *env)
{
- uint64_t hwpcb, tmp64;
- uint8_t tmp8;
- int ret = 0;
-
- hwpcb = env->ipr[IPR_PCBB];
- switch (iprn) {
- case IPR_ASN:
- /* Read-only */
- ret = -1;
- break;
- case IPR_ASTEN:
- tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
- *oldvalp = tmp8;
- tmp8 &= val & 0xF;
- tmp8 |= (val >> 4) & 0xF;
- env->ipr[IPR_ASTEN] &= ~0xF;
- env->ipr[IPR_ASTEN] |= tmp8;
- ret = 1;
- break;
- case IPR_ASTSR:
- tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
- *oldvalp = tmp8;
- tmp8 &= val & 0xF;
- tmp8 |= (val >> 4) & 0xF;
- env->ipr[IPR_ASTSR] &= ~0xF;
- env->ipr[IPR_ASTSR] |= tmp8;
- ret = 1;
- case IPR_DATFX:
- env->ipr[IPR_DATFX] &= ~0x1;
- env->ipr[IPR_DATFX] |= val & 1;
- tmp64 = ldq_raw(hwpcb + 56);
- tmp64 &= ~0x8000000000000000ULL;
- tmp64 |= (val & 1) << 63;
- stq_raw(hwpcb + 56, tmp64);
- break;
- case IPR_ESP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_ESP] = val;
- else
- stq_raw(hwpcb + 8, val);
- break;
- case IPR_FEN:
- env->ipr[IPR_FEN] = val & 1;
- tmp64 = ldq_raw(hwpcb + 56);
- tmp64 &= ~1;
- tmp64 |= val & 1;
- stq_raw(hwpcb + 56, tmp64);
- break;
- case IPR_IPIR:
- /* XXX: TODO: Send IRQ to CPU #ir[16] */
- break;
- case IPR_IPL:
- *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
- env->ipr[IPR_IPL] &= ~0x1F;
- env->ipr[IPR_IPL] |= val & 0x1F;
- /* XXX: may issue an interrupt or ASR _now_ */
- ret = 1;
- break;
- case IPR_KSP:
- if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
- ret = -1;
- } else {
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_KSP] = val;
- else
- stq_raw(hwpcb + 0, val);
+ int intno = env->exception_index;
+
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
+ static int count;
+ const char *name = "<unknown>";
+ int i, args = 0;
+
+ switch (intno) {
+ case EXCP_RESET:
+ name = "reset";
+ args = 2;
+ break;
+ case EXCP_MCHK:
+ name = "mchk";
+ break;
+ case EXCP_CLK_INTERRUPT:
+ name = "clk_interrupt";
+ break;
+ case EXCP_DEV_INTERRUPT:
+ name = "dev_interrupt";
+ break;
+ case EXCP_MMFAULT:
+ name = "mmfault";
+ args = 2;
+ break;
+ case EXCP_UNALIGN:
+ name = "unalign";
+ args = 2;
+ break;
+ case EXCP_OPCDEC:
+ name = "opcdec";
+ args = 1;
+ break;
+ case EXCP_ARITH:
+ name = "arith";
+ args = 2;
+ break;
+ case EXCP_FEN:
+ name = "fen";
+ args = 1;
+ break;
+ case EXCP_CALL_PAL:
+ qemu_log("INT %6d: call_pal %x pc=%016" PRIx64
+ " sp=%016" PRIx64 "\n"
+ " arg0=%016" PRIx64
+ " arg1=%016" PRIx64
+ " arg2=%016" PRIx64 "\n",
+ ++count, env->error_code, env->pc, env->ir[IR_SP],
+ env->ir[16], env->ir[17], env->ir[18]);
+ goto print_done;
+ case EXCP_STL_C:
+ name = "stl_c";
+ break;
+ case EXCP_STQ_C:
+ name = "stq_c";
+ break;
}
- break;
- case IPR_MCES:
- env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
- env->ipr[IPR_MCES] |= val & 0x18;
- break;
- case IPR_PERFMON:
- /* Implementation specific */
- *oldvalp = 0;
- ret = 1;
- break;
- case IPR_PCBB:
- /* Read-only */
- ret = -1;
- break;
- case IPR_PRBR:
- env->ipr[IPR_PRBR] = val;
- break;
- case IPR_PTBR:
- /* Read-only */
- ret = -1;
- break;
- case IPR_SCBB:
- env->ipr[IPR_SCBB] = (uint32_t)val;
- break;
- case IPR_SIRR:
- if (val & 0xF) {
- env->ipr[IPR_SISR] |= 1 << (val & 0xF);
- /* XXX: request a software interrupt _now_ */
+ qemu_log("INT %6d: %s pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
+ ++count, name, env->pc, env->ir[IR_SP]);
+ for (i = 0; i < args; ++i) {
+ qemu_log(" arg%d=%016" PRIx64, i, (&env->trap_arg0)[i]);
}
- break;
- case IPR_SISR:
- /* Read-only */
- ret = -1;
- break;
- case IPR_SSP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_SSP] = val;
- else
- stq_raw(hwpcb + 16, val);
- break;
- case IPR_SYSPTBR:
- if (env->features & FEATURE_VIRBND)
- env->ipr[IPR_SYSPTBR] = val;
- else
- ret = -1;
- break;
- case IPR_TBCHK:
- /* Read-only */
- ret = -1;
- break;
- case IPR_TBIA:
- tlb_flush(env, 1);
- break;
- case IPR_TBIAP:
- tlb_flush(env, 1);
- break;
- case IPR_TBIS:
- tlb_flush_page(env, val);
- break;
- case IPR_TBISD:
- tlb_flush_page(env, val);
- break;
- case IPR_TBISI:
- tlb_flush_page(env, val);
- break;
- case IPR_USP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_USP] = val;
- else
- stq_raw(hwpcb + 24, val);
- break;
- case IPR_VIRBND:
- if (env->features & FEATURE_VIRBND)
- env->ipr[IPR_VIRBND] = val;
- else
- ret = -1;
- break;
- case IPR_VPTB:
- env->ipr[IPR_VPTB] = val;
- break;
- case IPR_WHAMI:
- /* Read-only */
- ret = -1;
- break;
- default:
- /* Invalid */
- ret = -1;
- break;
+ print_done:;
}
- return ret;
-}
-
-void do_interrupt (CPUState *env)
-{
- int excp;
- env->ipr[IPR_EXC_ADDR] = env->pc | 1;
- excp = env->exception_index;
env->exception_index = -1;
- env->error_code = 0;
- /* XXX: disable interrupts and memory mapping */
- if (env->ipr[IPR_PAL_BASE] != -1ULL) {
- /* We use native PALcode */
- env->pc = env->ipr[IPR_PAL_BASE] + excp;
- } else {
- /* We use emulated PALcode */
- call_pal(env);
- /* Emulate REI */
- env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
- env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
- /* XXX: re-enable interrupts and memory mapping */
+
+#if !defined(CONFIG_USER_ONLY)
+ {
+ int offset = -1;
+ switch (intno) {
+ case EXCP_RESET:
+ offset = 0x0000;
+ break;
+ case EXCP_MCHK:
+ offset = 0x0080;
+ break;
+ case EXCP_CLK_INTERRUPT:
+ offset = 0x0100;
+ break;
+ case EXCP_DEV_INTERRUPT:
+ offset = 0x0180;
+ break;
+ case EXCP_MMFAULT:
+ offset = 0x0200;
+ break;
+ case EXCP_UNALIGN:
+ offset = 0x0280;
+ break;
+ case EXCP_OPCDEC:
+ offset = 0x0300;
+ break;
+ case EXCP_ARITH:
+ offset = 0x0380;
+ break;
+ case EXCP_FEN:
+ offset = 0x0400;
+ break;
+ case EXCP_CALL_PAL:
+ offset = env->error_code;
+ /* There are 64 entry points for both privilaged and unprivlaged,
+ with bit 0x80 indicating unprivlaged. Each entry point gets
+ 64 bytes to do its job. */
+ if (offset & 0x80) {
+ offset = 0x2000 + (offset - 0x80) * 64;
+ } else {
+ offset = 0x1000 + offset * 64;
+ }
+ break;
+ }
+ if (offset < 0) {
+ abort();
+ }
+ env->pal_unix.exc_addr = env->pc | env->pal_mode;
+ env->pc = env->pal_unix.palbr + offset;
+ if (!env->pal_mode) {
+ env->pal_mode = 1;
+ swap_shadow_regs(env);
+ }
}
-}
#endif
+}
void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
int flags)
@@ -548,8 +478,10 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
};
int i;
- cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
- env->pc, env->ps);
+ cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x%s%s\n",
+ env->pc, env->ps,
+ env->pal_mode ? " PAL" : "",
+ env->fen ? " FEN" : "");
for (i = 0; i < 31; i++) {
cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
linux_reg_names[i], env->ir[i]);
@@ -99,28 +99,20 @@ DEF_HELPER_1(ieee_input, i64, i64)
DEF_HELPER_1(ieee_input_cmp, i64, i64)
DEF_HELPER_1(ieee_input_s, i64, i64)
-#if !defined (CONFIG_USER_ONLY)
-DEF_HELPER_0(hw_rei, void)
+#ifdef CONFIG_PALMODE
DEF_HELPER_1(hw_ret, void, i64)
-DEF_HELPER_2(mfpr, i64, int, i64)
-DEF_HELPER_2(mtpr, void, int, i64)
-DEF_HELPER_0(set_alt_mode, void)
-DEF_HELPER_0(restore_mode, void)
-
-DEF_HELPER_1(ld_virt_to_phys, i64, i64)
-DEF_HELPER_1(st_virt_to_phys, i64, i64)
-DEF_HELPER_2(ldl_raw, void, i64, i64)
-DEF_HELPER_2(ldq_raw, void, i64, i64)
-DEF_HELPER_2(ldl_l_raw, void, i64, i64)
-DEF_HELPER_2(ldq_l_raw, void, i64, i64)
-DEF_HELPER_2(ldl_kernel, void, i64, i64)
-DEF_HELPER_2(ldq_kernel, void, i64, i64)
-DEF_HELPER_2(ldl_data, void, i64, i64)
-DEF_HELPER_2(ldq_data, void, i64, i64)
-DEF_HELPER_2(stl_raw, void, i64, i64)
-DEF_HELPER_2(stq_raw, void, i64, i64)
-DEF_HELPER_2(stl_c_raw, i64, i64, i64)
-DEF_HELPER_2(stq_c_raw, i64, i64, i64)
+
+DEF_HELPER_1(ldl_phys, i64, i64)
+DEF_HELPER_1(ldq_phys, i64, i64)
+DEF_HELPER_1(ldl_l_phys, i64, i64)
+DEF_HELPER_1(ldq_l_phys, i64, i64)
+DEF_HELPER_2(stl_phys, void, i64, i64)
+DEF_HELPER_2(stq_phys, void, i64, i64)
+DEF_HELPER_2(stl_c_phys, i64, i64, i64)
+DEF_HELPER_2(stq_c_phys, i64, i64, i64)
+
+DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
+DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
#endif
#include "def-helper.h"
new file mode 100644
@@ -0,0 +1,84 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static int get_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+ CPUAlphaState *env = opaque;
+ cpu_alpha_store_fpcr(env, qemu_get_be64(f));
+ return 0;
+}
+
+static void put_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+ CPUAlphaState *env = opaque;
+ qemu_put_be64(f, cpu_alpha_load_fpcr(env));
+}
+
+static const VMStateInfo vmstate_fpcr = {
+ .name = "fpcr",
+ .get = get_fpcr,
+ .put = put_fpcr,
+};
+
+static VMStateField vmstate_cpu_fields[] = {
+ VMSTATE_UINTTL_ARRAY(ir, CPUState, 31),
+ VMSTATE_UINTTL_ARRAY(fir, CPUState, 31),
+ /* Save the architecture value of the fpcr, not the internally
+ expanded version. Since this architecture value does not
+ exist in memory to be stored, this requires a but of hoop
+ jumping. We want OFFSET=0 so that we effectively pass ENV
+ to the helper functions, and we need to fill in the name by
+ hand since there's no field of that name. */
+ {
+ .name = "fpcr",
+ .version_id = 0,
+ .size = sizeof(uint64_t),
+ .info = &vmstate_fpcr,
+ .flags = VMS_SINGLE,
+ .offset = 0
+ },
+ VMSTATE_UINTTL(pc, CPUState),
+ VMSTATE_UINTTL(unique, CPUState),
+ VMSTATE_UINTTL(lock_addr, CPUState),
+ VMSTATE_UINTTL(lock_value, CPUState),
+ /* Note that lock_st_addr is not saved; it is a temporary
+ used during the execution of the st[lq]_c insns. */
+
+ VMSTATE_UINT8(ps, CPUState),
+ VMSTATE_UINT8(intr_flag, CPUState),
+ VMSTATE_UINT8(fen, CPUState),
+ VMSTATE_UINT8(pal_mode, CPUState),
+
+ VMSTATE_UINT32(pcc_ofs, CPUState),
+ VMSTATE_UINTTL(trap_arg0, CPUState),
+ VMSTATE_UINTTL(trap_arg1, CPUState),
+ VMSTATE_UINTTL(trap_arg2, CPUState),
+
+ VMSTATE_UINTTL(pal_unix.exc_addr, CPUState),
+ VMSTATE_UINTTL(pal_unix.palbr, CPUState),
+ VMSTATE_UINTTL(pal_unix.ptbr, CPUState),
+ VMSTATE_UINTTL(pal_unix.vptptr, CPUState),
+
+ VMSTATE_UINTTL_ARRAY(pal_unix.shadow, CPUState, 8),
+ VMSTATE_UINTTL_ARRAY(pal_unix.scratch, CPUState, 24),
+
+ VMSTATE_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_cpu = {
+ .name = "cpu",
+ .version_id = CPU_SAVE_VERSION,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = vmstate_cpu_fields,
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+ vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
@@ -21,31 +21,38 @@
#include "host-utils.h"
#include "softfloat.h"
#include "helper.h"
-#include "qemu-timer.h"
/*****************************************************************************/
/* Exceptions processing helpers */
-void QEMU_NORETURN helper_excp (int excp, int error)
+void QEMU_NORETURN helper_excp(int excp, int error)
{
env->exception_index = excp;
env->error_code = error;
cpu_loop_exit();
}
+static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
+{
+ env->exception_index = EXCP_ARITH;
+ env->error_code = 0;
+ env->trap_arg0 = exc;
+ env->trap_arg1 = mask;
+ cpu_loop_exit();
+}
+
uint64_t helper_load_pcc (void)
{
- /* ??? This isn't a timer for which we have any rate info. */
- return (uint32_t)cpu_get_real_ticks();
+ return cpu_load_pcc(env);
}
uint64_t helper_load_fpcr (void)
{
- return cpu_alpha_load_fpcr (env);
+ return cpu_alpha_load_fpcr(env);
}
void helper_store_fpcr (uint64_t val)
{
- cpu_alpha_store_fpcr (env, val);
+ cpu_alpha_store_fpcr(env, val);
}
uint64_t helper_addqv (uint64_t op1, uint64_t op2)
@@ -53,7 +60,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 += op2;
if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return op1;
}
@@ -63,7 +70,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 = (uint32_t)(op1 + op2);
if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return op1;
}
@@ -73,7 +80,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2)
uint64_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return res;
}
@@ -83,7 +90,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2)
uint32_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return res;
}
@@ -93,7 +100,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2)
int64_t res = (int64_t)op1 * (int64_t)op2;
if (unlikely((int32_t)res != res)) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return (int64_t)((int32_t)res);
}
@@ -105,7 +112,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
muls64(&tl, &th, op1, op2);
/* If th != 0 && th != -1, then we had an overflow */
if (unlikely((th + 1) > 1)) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return tl;
}
@@ -373,8 +380,6 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
if (exc) {
uint32_t hw_exc = 0;
- env->ipr[IPR_EXC_MASK] |= 1ull << regno;
-
if (exc & float_flag_invalid) {
hw_exc |= EXC_M_INV;
}
@@ -390,7 +395,8 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
if (exc & float_flag_inexact) {
hw_exc |= EXC_M_INE;
}
- helper_excp(EXCP_ARITH, hw_exc);
+
+ arith_excp(hw_exc, 1ull << regno);
}
}
@@ -420,7 +426,7 @@ uint64_t helper_ieee_input(uint64_t val)
if (env->fpcr_dnz) {
val &= 1ull << 63;
} else {
- helper_excp(EXCP_ARITH, EXC_M_UNF);
+ arith_excp(EXC_M_UNF, 0);
}
}
} else if (exp == 0x7ff) {
@@ -428,7 +434,7 @@ uint64_t helper_ieee_input(uint64_t val)
/* ??? I'm not sure these exception bit flags are correct. I do
know that the Linux kernel, at least, doesn't rely on them and
just emulates the insn to figure out what exception to use. */
- helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV);
+ arith_excp(frac ? EXC_M_INV : EXC_M_FOV, 0);
}
return val;
}
@@ -445,12 +451,12 @@ uint64_t helper_ieee_input_cmp(uint64_t val)
if (env->fpcr_dnz) {
val &= 1ull << 63;
} else {
- helper_excp(EXCP_ARITH, EXC_M_UNF);
+ arith_excp(EXC_M_UNF, 0);
}
}
} else if (exp == 0x7ff && frac) {
/* NaN. */
- helper_excp(EXCP_ARITH, EXC_M_INV);
+ arith_excp(EXC_M_INV, 0);
}
return val;
}
@@ -1154,188 +1160,136 @@ uint64_t helper_cvtqg (uint64_t a)
}
/* PALcode support special instructions */
-#if !defined (CONFIG_USER_ONLY)
-void helper_hw_rei (void)
-{
- env->pc = env->ipr[IPR_EXC_ADDR] & ~3;
- env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
- env->intr_flag = 0;
- env->lock_addr = -1;
- /* XXX: re-enable interrupts and memory mapping */
-}
-
+#if defined(CONFIG_PALMODE)
void helper_hw_ret (uint64_t a)
{
env->pc = a & ~3;
- env->ipr[IPR_EXC_ADDR] = a & 1;
env->intr_flag = 0;
env->lock_addr = -1;
+ if ((a & 1) == 0) {
+ env->pal_mode = 0;
+ swap_shadow_regs(env);
+ }
/* XXX: re-enable interrupts and memory mapping */
}
-uint64_t helper_mfpr (int iprn, uint64_t val)
+uint64_t helper_ldl_phys(uint64_t p)
{
- uint64_t tmp;
-
- if (cpu_alpha_mfpr(env, iprn, &tmp) == 0)
- val = tmp;
-
- return val;
+ return (int32_t)ldl_phys(p);
}
-void helper_mtpr (int iprn, uint64_t val)
+uint64_t helper_ldq_phys(uint64_t p)
{
- cpu_alpha_mtpr(env, iprn, val, NULL);
+ return ldq_phys(p);
}
-void helper_set_alt_mode (void)
+uint64_t helper_ldl_l_phys(uint64_t p)
{
- env->saved_mode = env->ps & 0xC;
- env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC);
+ env->lock_addr = p;
+ return env->lock_value = (int32_t)ldl_phys(p);
}
-void helper_restore_mode (void)
+uint64_t helper_ldq_l_phys(uint64_t p)
{
- env->ps = (env->ps & ~0xC) | env->saved_mode;
-}
-
-#endif
-
-/*****************************************************************************/
-/* Softmmu support */
-#if !defined (CONFIG_USER_ONLY)
-
-/* XXX: the two following helpers are pure hacks.
- * Hopefully, we emulate the PALcode, then we should never see
- * HW_LD / HW_ST instructions.
- */
-uint64_t helper_ld_virt_to_phys (uint64_t virtaddr)
-{
- uint64_t tlb_addr, physaddr;
- int index, mmu_idx;
- void *retaddr;
-
- mmu_idx = cpu_mmu_index(env);
- index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
- tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
- if ((virtaddr & TARGET_PAGE_MASK) ==
- (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
- physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
- } else {
- /* the page is not in the TLB : fill it */
- retaddr = GETPC();
- tlb_fill(virtaddr, 0, mmu_idx, retaddr);
- goto redo;
- }
- return physaddr;
+ env->lock_addr = p;
+ return env->lock_value = ldq_phys(p);
}
-uint64_t helper_st_virt_to_phys (uint64_t virtaddr)
+void helper_stl_phys(uint64_t p, uint64_t v)
{
- uint64_t tlb_addr, physaddr;
- int index, mmu_idx;
- void *retaddr;
-
- mmu_idx = cpu_mmu_index(env);
- index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
- tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
- if ((virtaddr & TARGET_PAGE_MASK) ==
- (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
- physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
- } else {
- /* the page is not in the TLB : fill it */
- retaddr = GETPC();
- tlb_fill(virtaddr, 1, mmu_idx, retaddr);
- goto redo;
- }
- return physaddr;
+ stl_phys(p, v);
}
-void helper_ldl_raw(uint64_t t0, uint64_t t1)
+void helper_stq_phys(uint64_t p, uint64_t v)
{
- ldl_raw(t1, t0);
+ stq_phys(p, v);
}
-void helper_ldq_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
{
- ldq_raw(t1, t0);
-}
+ uint64_t ret = 0;
-void helper_ldl_l_raw(uint64_t t0, uint64_t t1)
-{
- env->lock = t1;
- ldl_raw(t1, t0);
-}
+ if (p == env->lock_addr) {
+ int32_t old = ldl_phys(p);
+ if (old == (int32_t)env->lock_value) {
+ stl_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
-void helper_ldq_l_raw(uint64_t t0, uint64_t t1)
-{
- env->lock = t1;
- ldl_raw(t1, t0);
+ return ret;
}
-void helper_ldl_kernel(uint64_t t0, uint64_t t1)
+uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
{
- ldl_kernel(t1, t0);
-}
+ uint64_t ret = 0;
-void helper_ldq_kernel(uint64_t t0, uint64_t t1)
-{
- ldq_kernel(t1, t0);
-}
+ if (p == env->lock_addr) {
+ uint64_t old = ldq_phys(p);
+ if (old == env->lock_value) {
+ stq_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
-void helper_ldl_data(uint64_t t0, uint64_t t1)
-{
- ldl_data(t1, t0);
+ return ret;
}
-void helper_ldq_data(uint64_t t0, uint64_t t1)
+void helper_tbia(void)
{
- ldq_data(t1, t0);
+ tlb_flush(env, 1);
}
-void helper_stl_raw(uint64_t t0, uint64_t t1)
+void helper_tbis(uint64_t p)
{
- stl_raw(t1, t0);
+ tlb_flush_page(env, p);
}
+#endif /* PALMODE */
-void helper_stq_raw(uint64_t t0, uint64_t t1)
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined(CONFIG_USER_ONLY)
+
+static void do_restore_state(void *pc_ptr)
{
- stq_raw(t1, t0);
+ TranslationBlock *tb;
+ unsigned long pc = (unsigned long) pc_ptr;
+
+ tb = tb_find_pc(pc);
+ if (tb) {
+ cpu_restore_state(tb, env, pc, NULL);
+ }
}
-uint64_t helper_stl_c_raw(uint64_t t0, uint64_t t1)
+static void do_unaligned_access(target_ulong addr, int is_write,
+ int is_user, void *retaddr)
{
- uint64_t ret;
+ uint64_t pc;
+ uint32_t insn;
- if (t1 == env->lock) {
- stl_raw(t1, t0);
- ret = 0;
- } else
- ret = 1;
+ do_restore_state(retaddr);
- env->lock = 1;
+ pc = env->pc;
+ insn = ldl_code(pc);
- return ret;
+ env->trap_arg0 = addr;
+ env->trap_arg1 = insn >> 26; /* opcode */
+ env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
+ helper_excp(EXCP_UNALIGN, 0);
}
-uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1)
+void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
+ int unused, int size)
{
- uint64_t ret;
-
- if (t1 == env->lock) {
- stq_raw(t1, t0);
- ret = 0;
- } else
- ret = 1;
-
- env->lock = 1;
-
- return ret;
+ env->trap_arg0 = addr;
+ env->trap_arg1 = is_write;
+ helper_excp(EXCP_MCHK, 0);
}
#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
#define SHIFT 0
#include "softmmu_template.h"
@@ -1365,7 +1319,7 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
saved_env = env;
env = cpu_single_env;
ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
- if (!likely(ret == 0)) {
+ if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
pc = (unsigned long)retaddr;
@@ -1381,5 +1335,4 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
}
env = saved_env;
}
-
#endif
@@ -47,9 +47,6 @@ struct DisasContext {
CPUAlphaState *env;
uint64_t pc;
int mem_idx;
-#if !defined (CONFIG_USER_ONLY)
- int pal_mode;
-#endif
uint32_t amask;
/* Current rounding mode for this TB. */
@@ -89,9 +86,7 @@ static TCGv cpu_pc;
static TCGv cpu_lock_addr;
static TCGv cpu_lock_st_addr;
static TCGv cpu_lock_value;
-#ifdef CONFIG_USER_ONLY
static TCGv cpu_uniq;
-#endif
/* register names */
static char cpu_reg_names[10*4+21*5 + 10*5+21*6];
@@ -134,11 +129,8 @@ static void alpha_translate_init(void)
cpu_lock_value = tcg_global_mem_new_i64(TCG_AREG0,
offsetof(CPUState, lock_value),
"lock_value");
-
-#ifdef CONFIG_USER_ONLY
cpu_uniq = tcg_global_mem_new_i64(TCG_AREG0,
offsetof(CPUState, unique), "uniq");
-#endif
/* register helpers */
#define GEN_HELPER 2
@@ -322,7 +314,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
#if defined(CONFIG_USER_ONLY)
addr = cpu_lock_st_addr;
#else
- addr = tcg_local_new();
+ addr = tcg_temp_local_new();
#endif
if (rb != 31) {
@@ -345,7 +337,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
lab_fail = gen_new_label();
lab_done = gen_new_label();
- tcg_gen_brcond(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
+ tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
val = tcg_temp_new();
if (quad) {
@@ -353,7 +345,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
} else {
tcg_gen_qemu_ld32s(val, addr, ctx->mem_idx);
}
- tcg_gen_brcond(TCG_COND_NE, val, cpu_lock_value, lab_fail);
+ tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail);
if (quad) {
tcg_gen_qemu_st64(cpu_ir[ra], addr, ctx->mem_idx);
@@ -1464,6 +1456,183 @@ static void gen_rx(int ra, int set)
tcg_temp_free_i32(tmp);
}
+static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
+{
+ /* We're emulating OSF/1 PALcode. Many of these are trivial access
+ to internal cpu registers. */
+
+ /* Unprivileged PAL call */
+ if (palcode >= 0x80 && palcode < 0xC0) {
+ switch (palcode) {
+ case 0x86:
+ /* IMB */
+ /* No-op inside QEMU. */
+ break;
+ case 0x9E:
+ /* RDUNIQUE */
+ tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_uniq);
+ break;
+ case 0x9F:
+ /* WRUNIQUE */
+ tcg_gen_mov_i64(cpu_uniq, cpu_ir[IR_A0]);
+ break;
+ default:
+ return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf);
+ }
+ return NO_EXIT;
+ }
+
+#ifndef CONFIG_USER_ONLY
+ /* Privileged PAL code */
+ if (palcode < 0x40 && ctx->mem_idx == 0) {
+ switch (palcode) {
+ case 0x01:
+ /* CFLUSH */
+ /* No-op inside QEMU. */
+ break;
+ case 0x02:
+ /* DRAINA */
+ /* No-op inside QEMU. */
+ break;
+ case 0x2D:
+ /* WRVPTPTR */
+ tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env,
+ offsetof(CPUAlphaState, pal_unix.vptptr));
+ break;
+ case 0x35: {
+ /* SWPIPL */
+ TCGv tmp;
+
+ /* Note that we already know we're in kernel mode, so we know
+ that PS only contains the 3 IPL bits. */
+ tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env,
+ offsetof(CPUAlphaState, ps));
+
+ /* But make sure and store only the 3 IPL bits from the user. */
+ tmp = tcg_temp_new();
+ tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], 7);
+ tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, ps));
+ tcg_temp_free(tmp);
+ break;
+ }
+
+ case 0x36:
+ /* RDPS */
+ tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env,
+ offsetof(CPUAlphaState, ps));
+ break;
+
+ /* TODO:
+ 0x31 WrVal
+ 0x32 RdVal
+ 0x38 WrUsp
+ 0x3A RdUsp
+ 0x3C Whami
+ These merely need more cooperation in designation of
+ internal processor registers w/ palcode. These are
+ currently stored in palcode scratch registers and
+ should be treated like UNIQUE. */
+
+ default:
+ return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f);
+ }
+ return NO_EXIT;
+ }
+#endif
+
+ return gen_invalid(ctx);
+}
+
+#if defined(CONFIG_PALMODE)
+
+#define PR_BYTE 0x100000
+#define PR_LONG 0x200000
+
+static int cpu_pr_data(int pr)
+{
+ switch (pr) {
+ case 0: return offsetof(CPUAlphaState, ps) | PR_BYTE;
+ case 1: return offsetof(CPUAlphaState, fen) | PR_BYTE;
+ case 2: return offsetof(CPUAlphaState, pcc_ofs) | PR_LONG;
+ case 3: return offsetof(CPUAlphaState, trap_arg0);
+ case 4: return offsetof(CPUAlphaState, trap_arg1);
+ case 5: return offsetof(CPUAlphaState, trap_arg2);
+ case 6: return offsetof(CPUAlphaState, pal_unix.exc_addr);
+ case 7: return offsetof(CPUAlphaState, pal_unix.palbr);
+ case 8: return offsetof(CPUAlphaState, pal_unix.ptbr);
+ case 9: return offsetof(CPUAlphaState, pal_unix.vptptr);
+ case 10: return offsetof(CPUAlphaState, unique);
+ case 11: return offsetof(CPUAlphaState, lock_addr);
+
+ case 32 ... 39:
+ return offsetof(CPUAlphaState, pal_unix.shadow[pr - 32]);
+ case 40 ... 63:
+ return offsetof(CPUAlphaState, pal_unix.scratch[pr - 40]);
+ }
+ return 0;
+}
+
+static void gen_mfpr(int ra, int regno)
+{
+ int data = cpu_pr_data(regno);
+
+ /* In our emulated PALcode, these processor registers have no
+ side effects from reading. */
+ if (ra == 31) {
+ return;
+ }
+
+ if (data == 0) {
+ tcg_gen_movi_i64(cpu_ir[ra], 0);
+ } else if (data & PR_BYTE) {
+ tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, data & ~PR_BYTE);
+ } else if (data & PR_LONG) {
+ tcg_gen_ld32s_i64(cpu_ir[ra], cpu_env, data & ~PR_LONG);
+ } else {
+ tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data);
+ }
+}
+
+static void gen_mtpr(int rb, int regno)
+{
+ TCGv tmp;
+
+ if (rb == 31) {
+ tmp = tcg_const_i64(0);
+ } else {
+ tmp = cpu_ir[rb];
+ }
+
+ /* These two register numbers perform a TLB cache flush. Thankfully we
+ can only do this inside PALmode, which means that the current basic
+ block cannot be affected by the change in mappings. */
+ if (regno == 255) {
+ /* TBIA */
+ gen_helper_tbia();
+ } else if (regno == 254) {
+ /* TBIS */
+ gen_helper_tbis(tmp);
+ } else {
+ /* Otherwise the registers are data only, and unknown registers
+ are read-zero, write-ignore. */
+ int data = cpu_pr_data(regno);
+ if (data != 0) {
+ if (data & PR_BYTE) {
+ tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
+ } else if (data & PR_LONG) {
+ tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG);
+ } else {
+ tcg_gen_st_i64(tmp, cpu_env, data);
+ }
+ }
+ }
+
+ if (rb == 31) {
+ tcg_temp_free(tmp);
+ }
+}
+#endif /* PALMODE */
+
static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
{
uint32_t palcode;
@@ -1499,32 +1668,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch (opc) {
case 0x00:
/* CALL_PAL */
-#ifdef CONFIG_USER_ONLY
- if (palcode == 0x9E) {
- /* RDUNIQUE */
- tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_uniq);
- break;
- } else if (palcode == 0x9F) {
- /* WRUNIQUE */
- tcg_gen_mov_i64(cpu_uniq, cpu_ir[IR_A0]);
- break;
- }
-#endif
- if (palcode >= 0x80 && palcode < 0xC0) {
- /* Unprivileged PAL call */
- ret = gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x3F) << 6), 0);
- break;
- }
-#ifndef CONFIG_USER_ONLY
- if (palcode < 0x40) {
- /* Privileged PAL code */
- if (ctx->mem_idx & 1)
- goto invalid_opc;
- ret = gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x3F) << 6), 0);
- }
-#endif
- /* Invalid PAL call */
- goto invalid_opc;
+ ret = gen_call_pal(ctx, palcode);
+ break;
case 0x01:
/* OPC01 */
goto invalid_opc;
@@ -2571,18 +2716,13 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x19:
/* HW_MFPR (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- if (ra != 31) {
- TCGv tmp = tcg_const_i32(insn & 0xFF);
- gen_helper_mfpr(cpu_ir[ra], tmp, cpu_ir[ra]);
- tcg_temp_free(tmp);
+#if defined(CONFIG_PALMODE)
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ gen_mfpr(ra, insn & 0xffff);
+ break;
}
- break;
#endif
+ goto invalid_opc;
case 0x1A:
/* JMP, JSR, RET, JSR_COROUTINE. These only differ by the branch
prediction stack action, which of course we don't implement. */
@@ -2598,41 +2738,43 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x1B:
/* HW_LD (PALcode) */
-#if defined (CONFIG_USER_ONLY)
+#if !defined(CONFIG_PALMODE)
goto invalid_opc;
#else
- if (!ctx->pal_mode)
+ if ((ctx->tb->flags & TB_FLAGS_PAL_MODE) == 0) {
goto invalid_opc;
+ }
if (ra != 31) {
TCGv addr = tcg_temp_new();
+
if (rb != 31)
tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
else
tcg_gen_movi_i64(addr, disp12);
+
switch ((insn >> 12) & 0xF) {
case 0x0:
/* Longword physical access (hw_ldl/p) */
- gen_helper_ldl_raw(cpu_ir[ra], addr);
+ gen_helper_ldl_phys(cpu_ir[ra], addr);
break;
case 0x1:
/* Quadword physical access (hw_ldq/p) */
- gen_helper_ldq_raw(cpu_ir[ra], addr);
+ gen_helper_ldq_phys(cpu_ir[ra], addr);
break;
case 0x2:
/* Longword physical access with lock (hw_ldl_l/p) */
- gen_helper_ldl_l_raw(cpu_ir[ra], addr);
+ gen_helper_ldl_l_phys(cpu_ir[ra], addr);
break;
case 0x3:
/* Quadword physical access with lock (hw_ldq_l/p) */
- gen_helper_ldq_l_raw(cpu_ir[ra], addr);
+ gen_helper_ldq_l_phys(cpu_ir[ra], addr);
break;
case 0x4:
/* Longword virtual PTE fetch (hw_ldl/v) */
- tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
- break;
+ goto invalid_opc;
case 0x5:
/* Quadword virtual PTE fetch (hw_ldq/v) */
- tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+ goto invalid_opc;
break;
case 0x6:
/* Incpu_ir[ra]id */
@@ -2641,54 +2783,33 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
/* Incpu_ir[ra]id */
goto invalid_opc;
case 0x8:
- /* Longword virtual access (hw_ldl) */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldl_raw(cpu_ir[ra], addr);
- break;
+ /* Longword virtual access (hw_ldl) (no access check) */
+ goto invalid_opc;
case 0x9:
- /* Quadword virtual access (hw_ldq) */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldq_raw(cpu_ir[ra], addr);
- break;
+ /* Quadword virtual access (hw_ldq) (no access check) */
+ goto invalid_opc;
case 0xA:
/* Longword virtual access with protection check (hw_ldl/w) */
- tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
- break;
+ goto invalid_opc;
case 0xB:
/* Quadword virtual access with protection check (hw_ldq/w) */
- tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
- break;
+ goto invalid_opc;
case 0xC:
/* Longword virtual access with alt access mode (hw_ldl/a)*/
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldl_raw(cpu_ir[ra], addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xD:
/* Quadword virtual access with alt access mode (hw_ldq/a) */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldq_raw(cpu_ir[ra], addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xE:
/* Longword virtual access with alternate access mode and
- * protection checks (hw_ldl/wa)
- */
- gen_helper_set_alt_mode();
- gen_helper_ldl_data(cpu_ir[ra], addr);
- gen_helper_restore_mode();
- break;
+ protection checks (hw_ldl/wa) */
+ goto invalid_opc;
case 0xF:
/* Quadword virtual access with alternate access mode and
- * protection checks (hw_ldq/wa)
- */
- gen_helper_set_alt_mode();
- gen_helper_ldq_data(cpu_ir[ra], addr);
- gen_helper_restore_mode();
- break;
+ protection checks (hw_ldq/wa) */
+ goto invalid_opc;
}
+
tcg_temp_free(addr);
}
break;
@@ -2870,57 +2991,41 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x1D:
/* HW_MTPR (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- else {
- TCGv tmp1 = tcg_const_i32(insn & 0xFF);
- if (ra != 31)
- gen_helper_mtpr(tmp1, cpu_ir[ra]);
- else {
- TCGv tmp2 = tcg_const_i64(0);
- gen_helper_mtpr(tmp1, tmp2);
- tcg_temp_free(tmp2);
- }
- tcg_temp_free(tmp1);
- ret = EXIT_PC_STALE;
+#if defined(CONFIG_PALMODE)
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ gen_mtpr(rb, insn & 0xffff);
+ break;
}
- break;
#endif
+ goto invalid_opc;
case 0x1E:
/* HW_REI (PALcode) */
-#if defined (CONFIG_USER_ONLY)
+#if !defined(CONFIG_PALMODE)
goto invalid_opc;
#else
- if (!ctx->pal_mode)
+ if ((ctx->tb->flags & TB_FLAGS_PAL_MODE) == 0) {
goto invalid_opc;
+ }
if (rb == 31) {
/* "Old" alpha */
- gen_helper_hw_rei();
- } else {
- TCGv tmp;
-
- if (ra != 31) {
- tmp = tcg_temp_new();
- tcg_gen_addi_i64(tmp, cpu_ir[rb], (((int64_t)insn << 51) >> 51));
- } else
- tmp = tcg_const_i64(((int64_t)insn << 51) >> 51);
+ TCGv tmp = tcg_temp_new();
+ tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUState, pal_unix.exc_addr));
gen_helper_hw_ret(tmp);
tcg_temp_free(tmp);
+ } else {
+ gen_helper_hw_ret(cpu_ir[rb]);
}
ret = EXIT_PC_UPDATED;
break;
#endif
case 0x1F:
/* HW_ST (PALcode) */
-#if defined (CONFIG_USER_ONLY)
+#if !defined(CONFIG_PALMODE)
goto invalid_opc;
#else
- if (!ctx->pal_mode)
+ if ((ctx->tb->flags & TB_FLAGS_PAL_MODE) == 0) {
goto invalid_opc;
- else {
+ } else {
TCGv addr, val;
addr = tcg_temp_new();
if (rb != 31)
@@ -2936,29 +3041,27 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch ((insn >> 12) & 0xF) {
case 0x0:
/* Longword physical access */
- gen_helper_stl_raw(val, addr);
+ gen_helper_stl_phys(addr, val);
break;
case 0x1:
/* Quadword physical access */
- gen_helper_stq_raw(val, addr);
+ gen_helper_stq_phys(addr, val);
break;
case 0x2:
/* Longword physical access with lock */
- gen_helper_stl_c_raw(val, val, addr);
+ gen_helper_stl_c_phys(val, addr, val);
break;
case 0x3:
/* Quadword physical access with lock */
- gen_helper_stq_c_raw(val, val, addr);
+ gen_helper_stq_c_phys(val, addr, val);
break;
case 0x4:
- /* Longword virtual access */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
+ /* Longword virtual access (no access check) */
+ tcg_gen_qemu_st32(val, addr, 0);
break;
case 0x5:
- /* Quadword virtual access */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stq_raw(val, addr);
+ /* Quadword virtual access (no access check) */
+ tcg_gen_qemu_st64(val, addr, 0);
break;
case 0x6:
/* Invalid */
@@ -2980,18 +3083,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
goto invalid_opc;
case 0xC:
/* Longword virtual access with alternate access mode */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xD:
/* Quadword virtual access with alternate access mode */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xE:
/* Invalid */
goto invalid_opc;
@@ -3156,12 +3251,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
ctx.env = env;
ctx.pc = pc_start;
ctx.amask = env->amask;
-#if defined (CONFIG_USER_ONLY)
- ctx.mem_idx = 0;
-#else
- ctx.mem_idx = ((env->ps >> 3) & 3);
- ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
-#endif
+ ctx.mem_idx = cpu_mmu_index(env);
/* ??? Every TB begins with unset rounding mode, to be initialized on
the first fp insn of the TB. Alternately we could define a proper
@@ -3325,43 +3415,17 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
env->implver = implver;
env->amask = amask;
- env->ps = 0x1F00;
-#if defined (CONFIG_USER_ONLY)
- env->ps |= 1 << 3;
+#if defined(CONFIG_USER_ONLY)
cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
| FPCR_UNFD | FPCR_INED | FPCR_DNOD));
+ env->ps = PS_USER_MODE;
+ env->pal_mode = 0;
#else
- pal_init(env);
+ env->ps = 7;
+ env->pal_mode = 1;
#endif
env->lock_addr = -1;
-
- /* Initialize IPR */
-#if defined (CONFIG_USER_ONLY)
- env->ipr[IPR_EXC_ADDR] = 0;
- env->ipr[IPR_EXC_SUM] = 0;
- env->ipr[IPR_EXC_MASK] = 0;
-#else
- {
- // uint64_t hwpcb;
- // hwpcb = env->ipr[IPR_PCBB];
- env->ipr[IPR_ASN] = 0;
- env->ipr[IPR_ASTEN] = 0;
- env->ipr[IPR_ASTSR] = 0;
- env->ipr[IPR_DATFX] = 0;
- /* XXX: fix this */
- // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8);
- // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0);
- // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16);
- // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24);
- env->ipr[IPR_FEN] = 0;
- env->ipr[IPR_IPL] = 31;
- env->ipr[IPR_MCES] = 0;
- env->ipr[IPR_PERFMON] = 0; /* Implementation specific */
- // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32);
- env->ipr[IPR_SISR] = 0;
- env->ipr[IPR_VIRBND] = -1ULL;
- }
-#endif
+ env->fen = 1;
qemu_init_vcpu(env);
return env;
Delete the old partial support for alpha-softmmu, which kind-of tried to emulate real HW and its PALcode. Instead, use a custom HW interface for a custom PALcode. Wire up as much of the device emulation as is available. This is enough to boot the Linux kernel until it starts scheduling. Signed-off-by: Richard Henderson <rth@twiddle.net> --- Makefile.target | 4 +- configure | 1 + cpu-exec.c | 16 +- default-configs/alpha-softmmu.mak | 9 + hw/alpha_palcode.c | 1048 ------------------------------------ hw/alpha_pci.c | 327 ++++++++++++ hw/alpha_pyxis.c | 1057 +++++++++++++++++++++++++++++++++++++ hw/alpha_sx164.c | 195 +++++++ hw/alpha_sys.h | 41 ++ linux-user/main.c | 39 +- pc-bios/palcode-sx164 | Bin 0 -> 107781 bytes target-alpha/cpu.h | 337 +++++------- target-alpha/exec.h | 7 +- target-alpha/helper.c | 630 ++++++++++------------ target-alpha/helper.h | 34 +- target-alpha/machine.c | 84 +++ target-alpha/op_helper.c | 249 ++++------ target-alpha/translate.c | 422 +++++++++------- 18 files changed, 2521 insertions(+), 1979 deletions(-) create mode 100644 default-configs/alpha-softmmu.mak delete mode 100644 hw/alpha_palcode.c create mode 100644 hw/alpha_pci.c create mode 100644 hw/alpha_pyxis.c create mode 100644 hw/alpha_sx164.c create mode 100644 hw/alpha_sys.h create mode 100644 pc-bios/palcode-sx164 create mode 100644 target-alpha/machine.c