diff --git a/Makefile.target b/Makefile.target
index d5761b7..f702780 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -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)
 
diff --git a/configure b/configure
index 4a93972..872747f 100755
--- a/configure
+++ b/configure
@@ -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 \
diff --git a/cpu-exec.c b/cpu-exec.c
index 5d6c9a8..854cfe5 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -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
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
new file mode 100644
index 0000000..abadcff
--- /dev/null
+++ b/default-configs/alpha-softmmu.mak
@@ -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
diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c
deleted file mode 100644
index 033b542..0000000
--- a/hw/alpha_palcode.c
+++ /dev/null
@@ -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
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
new file mode 100644
index 0000000..744b68b
--- /dev/null
+++ b/hw/alpha_pci.c
@@ -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,
+};
diff --git a/hw/alpha_pyxis.c b/hw/alpha_pyxis.c
new file mode 100644
index 0000000..0f4c038
--- /dev/null
+++ b/hw/alpha_pyxis.c
@@ -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);
diff --git a/hw/alpha_sx164.c b/hw/alpha_sx164.c
new file mode 100644
index 0000000..c2adc90
--- /dev/null
+++ b/hw/alpha_sx164.c
@@ -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);
diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h
new file mode 100644
index 0000000..43e9892
--- /dev/null
+++ b/hw/alpha_sys.h
@@ -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
diff --git a/linux-user/main.c b/linux-user/main.c
index a1e37e4..4c0a55a 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -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) {
diff --git a/pc-bios/palcode-sx164 b/pc-bios/palcode-sx164
new file mode 100644
index 0000000000000000000000000000000000000000..986fea9a5d6440269c1ec2297ed0e7d892319867
GIT binary patch
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 686fb4a..c40cf33 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -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)
diff --git a/target-alpha/exec.h b/target-alpha/exec.h
index 6ae96d1..345b017 100644
--- a/target-alpha/exec.h
+++ b/target-alpha/exec.h
@@ -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)
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 3ba4478..944676e 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -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]);
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index ccf6a2a..ae48d7f 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -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"
diff --git a/target-alpha/machine.c b/target-alpha/machine.c
new file mode 100644
index 0000000..94a695f
--- /dev/null
+++ b/target-alpha/machine.c
@@ -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);
+}
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 6c2ae20..5c3571f 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -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
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 96e922b..ac0217f 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -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;
