diff mbox

[5/5] target-alpha: Emulate Alpha SX164.

Message ID 1303056876-14320-6-git-send-email-rth@twiddle.net
State New
Headers show

Commit Message

Richard Henderson April 17, 2011, 4:14 p.m. UTC
Delete the old partial support for alpha-softmmu, which kind-of tried
to emulate real HW and its PALcode.  Instead, use a custom HW interface
for a custom PALcode.  Wire up as much of the device emulation as is
available.

This is enough to boot the Linux kernel until it starts scheduling.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 Makefile.target                   |    4 +-
 configure                         |    1 +
 cpu-exec.c                        |   16 +-
 default-configs/alpha-softmmu.mak |    9 +
 hw/alpha_palcode.c                | 1048 ------------------------------------
 hw/alpha_pci.c                    |  327 ++++++++++++
 hw/alpha_pyxis.c                  | 1057 +++++++++++++++++++++++++++++++++++++
 hw/alpha_sx164.c                  |  195 +++++++
 hw/alpha_sys.h                    |   41 ++
 linux-user/main.c                 |   39 +-
 pc-bios/palcode-sx164             |  Bin 0 -> 107781 bytes
 target-alpha/cpu.h                |  337 +++++-------
 target-alpha/exec.h               |    7 +-
 target-alpha/helper.c             |  630 ++++++++++------------
 target-alpha/helper.h             |   34 +-
 target-alpha/machine.c            |   84 +++
 target-alpha/op_helper.c          |  249 ++++------
 target-alpha/translate.c          |  422 +++++++++-------
 18 files changed, 2521 insertions(+), 1979 deletions(-)
 create mode 100644 default-configs/alpha-softmmu.mak
 delete mode 100644 hw/alpha_palcode.c
 create mode 100644 hw/alpha_pci.c
 create mode 100644 hw/alpha_pyxis.c
 create mode 100644 hw/alpha_sx164.c
 create mode 100644 hw/alpha_sys.h
 create mode 100644 pc-bios/palcode-sx164
 create mode 100644 target-alpha/machine.c

Comments

Alexander Graf April 17, 2011, 4:42 p.m. UTC | #1
On 17.04.2011, at 18:14, Richard Henderson wrote:

> Delete the old partial support for alpha-softmmu, which kind-of tried
> to emulate real HW and its PALcode.  Instead, use a custom HW interface
> for a custom PALcode.  Wire up as much of the device emulation as is
> available.

Mind to split it up? I'm having a hard time reading such huge patches O_o. Awesome work, btw :).


Alex
Peter Maydell April 17, 2011, 5:03 p.m. UTC | #2
On 17 April 2011 17:14, Richard Henderson <rth@twiddle.net> wrote:
> Delete the old partial support for alpha-softmmu, which kind-of tried
> to emulate real HW and its PALcode.  Instead, use a custom HW interface
> for a custom PALcode.  Wire up as much of the device emulation as is
> available.

>  pc-bios/palcode-sx164             |  Bin 0 -> 107781 bytes

My personal opinion is that if we have the binary blob in qemu git
we should also have its corresponding source code.

(plus it should be in the same commit that adds it to configure's
list of files, because configure doesn't do the right thing for
missing binary blobs)

-- PMM
Richard Henderson April 17, 2011, 5:11 p.m. UTC | #3
On 04/17/2011 10:03 AM, Peter Maydell wrote:
> On 17 April 2011 17:14, Richard Henderson <rth@twiddle.net> wrote:
>> Delete the old partial support for alpha-softmmu, which kind-of tried
>> to emulate real HW and its PALcode.  Instead, use a custom HW interface
>> for a custom PALcode.  Wire up as much of the device emulation as is
>> available.
> 
>>  pc-bios/palcode-sx164             |  Bin 0 -> 107781 bytes
> 
> My personal opinion is that if we have the binary blob in qemu git
> we should also have its corresponding source code.
> 

How does this differ from e.g. SeaBios?

And while I might agree that this ought to be in-tree, this isn't
true for any of the other blobs we currently have in-tree.  We 
don't really have any configury for cross-compilation of the bios bits.


r~
Richard Henderson April 17, 2011, 5:12 p.m. UTC | #4
On 04/17/2011 09:42 AM, Alexander Graf wrote:
> Mind to split it up? I'm having a hard time reading such huge patches O_o. Awesome work, btw :).

What sort of split would you like to see?

I thought about it, but there's not too many splits that actually
compile individually.


r~
Alexander Graf April 17, 2011, 6:22 p.m. UTC | #5
On 17.04.2011, at 19:12, Richard Henderson wrote:

> On 04/17/2011 09:42 AM, Alexander Graf wrote:
>> Mind to split it up? I'm having a hard time reading such huge patches O_o. Awesome work, btw :).
> 
> What sort of split would you like to see?
> 
> I thought about it, but there's not too many splits that actually
> compile individually.

Yeah, I was in a similar dilemma. I'm pretty sure you can at least split linux-user, device emulation and cpu emulation patches :). Usually, I just try to split things by file and see if it's easy enough to get back to bisectability using a script I got from Avi a while back:

#!/bin/bash -e
for commit in $(git rev-list --reverse "$@"); do
    echo "Commit $commit"
    git checkout "$commit"
    make -j
done


Alex
Alexander Graf April 17, 2011, 6:23 p.m. UTC | #6
On 17.04.2011, at 19:11, Richard Henderson wrote:

> On 04/17/2011 10:03 AM, Peter Maydell wrote:
>> On 17 April 2011 17:14, Richard Henderson <rth@twiddle.net> wrote:
>>> Delete the old partial support for alpha-softmmu, which kind-of tried
>>> to emulate real HW and its PALcode.  Instead, use a custom HW interface
>>> for a custom PALcode.  Wire up as much of the device emulation as is
>>> available.
>> 
>>> pc-bios/palcode-sx164             |  Bin 0 -> 107781 bytes
>> 
>> My personal opinion is that if we have the binary blob in qemu git
>> we should also have its corresponding source code.
>> 
> 
> How does this differ from e.g. SeaBios?
> 
> And while I might agree that this ought to be in-tree, this isn't
> true for any of the other blobs we currently have in-tree.  We 
> don't really have any configury for cross-compilation of the bios bits.

We try to keep a reference in pc-bios/README on where it comes from and Anthony usually wants you to also add git submodule magic for easy cloning :).


Alex
Richard Henderson April 17, 2011, 6:26 p.m. UTC | #7
On 04/17/2011 11:23 AM, Alexander Graf wrote:
> We try to keep a reference in pc-bios/README on where it comes from
> and Anthony usually wants you to also add git submodule magic for
> easy cloning :).

The README is easy.  I don't know what a git submodule is.
Pointers are very welcome...


r~
Alexander Graf April 17, 2011, 6:31 p.m. UTC | #8
On 17.04.2011, at 20:26, Richard Henderson wrote:

> On 04/17/2011 11:23 AM, Alexander Graf wrote:
>> We try to keep a reference in pc-bios/README on where it comes from
>> and Anthony usually wants you to also add git submodule magic for
>> easy cloning :).
> 
> The README is easy.  I don't know what a git submodule is.
> Pointers are very welcome...

Pointers are easy: http://patchwork.ozlabs.org/patch/90696/
I personally have no clue about them though - better to pester Anthony for details :).


Alex
Paolo Bonzini April 18, 2011, 6:58 a.m. UTC | #9
On 04/17/2011 08:31 PM, Alexander Graf wrote:
>
> On 17.04.2011, at 20:26, Richard Henderson wrote:
>
>> On 04/17/2011 11:23 AM, Alexander Graf wrote:
>>> We try to keep a reference in pc-bios/README on where it comes from
>>> and Anthony usually wants you to also add git submodule magic for
>>> easy cloning :).
>>
>> The README is easy. I don't know what a git submodule is.
>> Pointers are very welcome...
>
> Pointers are easy: http://patchwork.ozlabs.org/patch/90696/
> I personally have no clue about them though - better to pester Anthony
> for details :).

All that is done just with

git submodule add git://repo.or.cz/qemu-palcode.git roms/qemu-palcode

Paolo
Peter Maydell April 18, 2011, 9:22 a.m. UTC | #10
On 17 April 2011 18:11, Richard Henderson <rth@twiddle.net> wrote:
> On 04/17/2011 10:03 AM, Peter Maydell wrote:
>> On 17 April 2011 17:14, Richard Henderson <rth@twiddle.net> wrote:
>>>  pc-bios/palcode-sx164             |  Bin 0 -> 107781 bytes
>>
>> My personal opinion is that if we have the binary blob in qemu git
>> we should also have its corresponding source code.

> How does this differ from e.g. SeaBios?

I think that ought to follow the same rule: 'git clone' and
making a release tarball from a git repo should both either
(a) not ship a binary blob
or (b) include the sources which made up that binary blob

I know this isn't exactly where we are today; to some extent
I'm trying to see if anybody else agrees with this position...

> We don't really have any configury for cross-compilation of the
> bios bits.

Yes, this is a difficult problem (which also holds for test cases);
I'm not objecting to having the blobs in git and in tarballs, I
just want the sources too.

-- PMM
diff mbox

Patch

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
literal 107781
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
We`Y%IX8`CgF4)hCOK<j{9QZ%WjL0+q

literal 0
HcmV?d00001

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;