qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] new knoppix SegFault
@ 2003-11-17  9:51 Jens Arm
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
                   ` (3 more replies)
  0 siblings, 4 replies; 65+ messages in thread
From: Jens Arm @ 2003-11-17  9:51 UTC (permalink / raw)
  To: qemu-devel

Hi

If I boot knoppix 3.3 (newest cd-image (3.11.03))
I get a SegFault if knoppix try to autoconfig the devices :(

Jens

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [Qemu-devel] [PATCH] Fixes for qemu
  2003-11-17  9:51 [Qemu-devel] new knoppix SegFault Jens Arm
@ 2003-11-18  7:15 ` J. Mayer
  2003-11-18  7:30   ` J. Mayer
                     ` (5 more replies)
  2003-11-18  7:22 ` [Qemu-devel] [ADD] floppy disk emulation J. Mayer
                   ` (2 subsequent siblings)
  3 siblings, 6 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:15 UTC (permalink / raw)
  To: qemu-devel

Hi,

some patches for qemu will follow.
Some are reposts.
Please apply them.
Here's the file list:
dma.c.diff
fixes.patches
sb16.c.diff
signal.c.diff
translate.c.diff

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [Qemu-devel] [ADD] floppy disk emulation
  2003-11-17  9:51 [Qemu-devel] new knoppix SegFault Jens Arm
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
@ 2003-11-18  7:22 ` J. Mayer
  2003-11-18  7:37   ` J. Mayer
                     ` (4 more replies)
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
  2003-11-18  7:29 ` [Qemu-devel] [PATCH] Term prompt for qemu J. Mayer
  3 siblings, 5 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:22 UTC (permalink / raw)
  To: qemu-devel

This is a rework of the previous set of patches I sent for floppy disk
emulation. The emulation is now more complete. Floppies are seen well
under Linux. Format is not implemented yet, and write commands seem to
be buggy, but it allows to boot with a lot of bootloaders and to be
usable as read-only devices. Grub doesn't boot but doesn't from CDROM
either...
Here's the file list:
Makefile.target.diff
fdc.c.diff
fdc.patches
vl.c.diff
vl.h.diff

Please note that fdc.c.diff is bigger than 40 kbytes, so the post will
need approbation.

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [Qemu-devel] [ADD] PPC processor emulation
  2003-11-17  9:51 [Qemu-devel] new knoppix SegFault Jens Arm
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
  2003-11-18  7:22 ` [Qemu-devel] [ADD] floppy disk emulation J. Mayer
@ 2003-11-18  7:28 ` J. Mayer
  2003-11-18  7:43   ` J. Mayer
                     ` (25 more replies)
  2003-11-18  7:29 ` [Qemu-devel] [PATCH] Term prompt for qemu J. Mayer
  3 siblings, 26 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:28 UTC (permalink / raw)
  To: qemu-devel

Here's a set of patches which adds PPC processor as a new target.
The emulation is not complete:
there is no floating point instructions, only quick hacks for
instructions used by the glibc when starting programs.
there is no supervisor mode support for now
the qemu elf loader is buggy and I didn't find the right patch to fix it
by now, so a lot of dynamic programs won't load. I did test a dynamic
bash successfully.
Please note that there are fixes to do in syscalls: terminal control
seems not to work,  so I don't get any prompt with bash.

The good point is that the test programs I did, which checks almost all
emulated instructions, says that all that is implemented works quite
well, for the core CPU emulation.

Here's the file list:
Makefile.diff
Makefile.target.diff
configure.diff
cpu-all.h.diff
cpu-exec.c.diff
disas.c.diff
dyngen-exec.h.diff
elfload.c.diff
gen_multi.c.diff
main.c.diff
ppc.patches
syscall.c.diff
syscall_defs.h.diff
target-ppc__cpu.h.diff
target-ppc__exec.h.diff
target-ppc__helper.c.diff
target-ppc__op.c.diff
target-ppc__op.tpl.diff
target-ppc__ppc_ops.h.diff
target-ppc__syscall.h.diff
target-ppc__syscall_nr.h.diff
target-ppc__translate.c.diff
translate-all.c.diff

Please note that target-ppc__translate.c.diff is bigger than 40 kb so
the mail will need approbation.

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [Qemu-devel] [PATCH] Term prompt for qemu
  2003-11-17  9:51 [Qemu-devel] new knoppix SegFault Jens Arm
                   ` (2 preceding siblings ...)
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
@ 2003-11-18  7:29 ` J. Mayer
  2003-11-18  8:11   ` J. Mayer
                     ` (3 more replies)
  3 siblings, 4 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:29 UTC (permalink / raw)
  To: qemu-devel

Here's a patch to give a prompt to the user through the qemu serial line
with <CTRL><a>+<c> command. This allows, for example, the user to change
a flopppy disk,
and boot from a set of floppies.

Here's the file list:
cpu-all.h.diff
exec.c.diff
misc.patches
translate.c.diff
vl.c.diff

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Fixes for qemu
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
@ 2003-11-18  7:30   ` J. Mayer
  2003-11-18  7:31   ` Chad Page
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:30 UTC (permalink / raw)
  To: qemu-devel

dma.c.diff

diff -urNbB -x CVS qemu-current/dma.c qemu/dma.c
--- qemu-current/dma.c	Tue Nov 18 06:51:07 2003
+++ qemu/dma.c	Thu Nov 13 19:53:00 2003
@@ -28,6 +28,7 @@
 #include "vl.h"
 #include "cpu.h"
 
+//#define DEBUG_DMA
 #define log(...) fprintf (stderr, "dma: " __VA_ARGS__)
 #ifdef DEBUG_DMA
 #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
@@ -215,17 +216,17 @@
 
     case 0xb:                   /* mode */
         {
-#ifdef DMA_DEBUG
+            ichan = data & 3;
+#ifdef DEBUG_DMA
             int op;
             int ai;
             int dir;
             int opmode;
 
-            ichan = val & 3;
-            op = (val >> 2) & 3;
-            ai = (val >> 4) & 1;
-            dir = (val >> 5) & 1;
-            opmode = (val >> 6) & 3;
+            op = (data >> 2) & 3;
+            ai = (data >> 4) & 1;
+            dir = (data >> 5) & 1;
+            opmode = (data >> 6) & 3;
 
             linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
                    ichan, op, ai, dir, opmode);
@@ -259,7 +259,7 @@
         goto error;
     }
 
-#ifdef DMA_DEBUG
+#ifdef DEBUG_DMA
     if (0xc != iport) {
         linfo ("nport %#06x, ncont %d, ichan % 2d, val %#06x\n",
                nport, d != dma_controllers, ichan, data);

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Fixes for qemu
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
  2003-11-18  7:30   ` J. Mayer
@ 2003-11-18  7:31   ` Chad Page
  2003-11-18  7:32   ` J. Mayer
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 65+ messages in thread
From: Chad Page @ 2003-11-18  7:31 UTC (permalink / raw)
  To: qemu-devel


	Got a tarball with all these patches that you can post somewhere?
I'm particularly interested in the ppc stuff... thanks!

	- Chad


On 18 Nov 2003, J. Mayer wrote:

> Hi,
> 
> some patches for qemu will follow.
> Some are reposts.
> Please apply them.
> Here's the file list:
> dma.c.diff
> fixes.patches
> sb16.c.diff
> signal.c.diff
> translate.c.diff
> 
> -- 
> J. Mayer <l_indien@magic.fr>
> Never organized
> 
> 
> 
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://mail.nongnu.org/mailman/listinfo/qemu-devel
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Fixes for qemu
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
  2003-11-18  7:30   ` J. Mayer
  2003-11-18  7:31   ` Chad Page
@ 2003-11-18  7:32   ` J. Mayer
  2003-11-18  7:33   ` J. Mayer
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:32 UTC (permalink / raw)
  To: qemu-devel

sb16.c.diff
Avoid crashes:
printf("%s", -1); isn't so good...

diff -urNbB -x CVS qemu-current/sb16.c qemu/sb16.c
--- qemu-current/sb16.c	Tue Nov 18 06:51:09 2003
+++ qemu/sb16.c	Sun Nov 16 07:37:30 2003
@@ -205,7 +205,7 @@
 {
     char *msg;
 
-    msg = (char *)-1;
+    msg = "\n";
 
     linfo ("%#x\n", cmd);
 
@@ -469,7 +469,7 @@
     char *msg;
     int iport, retval;
 
-    msg = (char *) -1;
+    msg = "\n";
     iport = nport - sb.port;
 
     switch (iport) {

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Fixes for qemu
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
                     ` (2 preceding siblings ...)
  2003-11-18  7:32   ` J. Mayer
@ 2003-11-18  7:33   ` J. Mayer
  2003-11-18  7:34   ` J. Mayer
  2003-11-18  8:24   ` J. Mayer
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:33 UTC (permalink / raw)
  To: qemu-devel

signal.c.diff

Seems that registers definition, for debugging i386 target, isn't all right.

diff -urNbB -x CVS qemu-current/signal.c qemu/signal.c
--- qemu-current/signal.c	Tue Nov 18 06:51:09 2003
+++ qemu/signal.c	Tue Nov 11 00:22:54 2003
@@ -371,23 +371,23 @@
 }
 
 #if defined(DEBUG_SIGNAL)
-#ifdef __i386__
+#if defined(TARGET_I386)
 static void dump_regs(struct ucontext *uc)
 {
     fprintf(stderr, 
             "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
             "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
             "EFL=%08x EIP=%08x\n",
-            uc->uc_mcontext.gregs[EAX],
-            uc->uc_mcontext.gregs[EBX],
-            uc->uc_mcontext.gregs[ECX],
-            uc->uc_mcontext.gregs[EDX],
-            uc->uc_mcontext.gregs[ESI],
-            uc->uc_mcontext.gregs[EDI],
-            uc->uc_mcontext.gregs[EBP],
-            uc->uc_mcontext.gregs[ESP],
-            uc->uc_mcontext.gregs[EFL],
-            uc->uc_mcontext.gregs[EIP]);
+            uc->uc_mcontext.gregs[REG_EAX],
+            uc->uc_mcontext.gregs[REG_EBX],
+            uc->uc_mcontext.gregs[REG_ECX],
+            uc->uc_mcontext.gregs[REG_EDX],
+            uc->uc_mcontext.gregs[REG_ESI],
+            uc->uc_mcontext.gregs[REG_EDI],
+            uc->uc_mcontext.gregs[REG_EBP],
+            uc->uc_mcontext.gregs[REG_ESP],
+            uc->uc_mcontext.gregs[REG_EFL],
+            uc->uc_mcontext.gregs[REG_EIP]);
 }
 #else
 static void dump_regs(struct ucontext *uc)

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Fixes for qemu
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
                     ` (3 preceding siblings ...)
  2003-11-18  7:33   ` J. Mayer
@ 2003-11-18  7:34   ` J. Mayer
  2003-11-18  8:24   ` J. Mayer
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:34 UTC (permalink / raw)
  To: qemu-devel

translate.c.diff

Added two fake instructions to make QNX CDROM start booting.
Infortunately, it still doesn't boot completely.

diff -urNbB -x CVS qemu-current/target-i386/translate.c qemu/target-i386/translate.c
--- qemu-current/target-i386/translate.c	Fri Nov 14 00:09:07 2003
+++ qemu/target-i386/translate.c	Fri Nov 14 19:09:46 2003
@@ -4071,6 +4071,10 @@
             gen_op_clts();
         }
         break;
+    case 0x108: /* invd */
+    case 0x109: /* wbinvd */
+        /* Do nothing */
+        break;
     default:
         goto illegal_op;
     }

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] floppy disk emulation
  2003-11-18  7:22 ` [Qemu-devel] [ADD] floppy disk emulation J. Mayer
@ 2003-11-18  7:37   ` J. Mayer
  2003-11-18  7:38   ` J. Mayer
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:37 UTC (permalink / raw)
  To: qemu-devel

fdc.c.diff

Here's the core of the floppy disk emulation.

diff -urNbB -x CVS qemu-current/fdc.c qemu/fdc.c
--- qemu-current/fdc.c	Thu Jan  1 01:00:00 1970
+++ qemu/fdc.c	Tue Nov 18 03:36:48 2003
@@ -0,0 +1,1410 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "vl.h"
+
+uint32_t __attribute((regparm(1))) __ldl_cmmu(unsigned long addr,
+                                              int is_user);
+void __attribute((regparm(2))) __stl_cmmu(unsigned long addr, uint32_t v,
+                                          int is_user);
+uint8_t __attribute((regparm(1))) __ldb_cmmu(unsigned long addr,
+                                             int is_user);
+void __attribute((regparm(2))) __stb_cmmu(unsigned long addr, uint8_t v,
+                                          int is_user);
+/********************************************************/
+/* debug Floppy devices */
+//#define DEBUG_FLOPPY
+
+#ifdef DEBUG_FLOPPY
+#define FLOPPY_DPRINTF(fmt, args...) \
+do { printf("FLOPPY: " fmt , ##args); } while (0)
+#else
+#define FLOPPY_DPRINTF(fmt, args...)
+#endif
+
+#define FLOPPY_ERROR(fmt, args...) \
+do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
+
+/********************************************************/
+/* Floppy drive emulation                               */
+
+/* Will always be a fixed parameter for us */
+#define FD_SECTOR_LEN 512
+#define FD_SECTOR_SC  2   /* Sector size code */
+
+/* Floppy disk drive emulation */
+typedef enum fdisk_type_t {
+    FDRIVE_DISK_288   = 0x01, /* 2.88 MB disk           */
+    FDRIVE_DISK_144   = 0x02, /* 1.44 MB disk           */
+    FDRIVE_DISK_720   = 0x03, /* 720 kB disk            */
+    FDRIVE_DISK_NONE  = 0x04, /* No disk                */
+} fdisk_type_t;
+
+typedef enum fdrive_type_t {
+    FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
+    FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
+    FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
+    FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
+} fdrive_type_t;
+
+typedef struct fdrive_t {
+    BlockDriverState *bs;
+    /* Drive status */
+    fdrive_type_t drive;
+    uint8_t motor;            /* on/off                 */
+    uint8_t perpendicular;    /* 2.88 MB access mode    */
+    uint8_t rv;               /* Revalidated            */
+    /* Position */
+    uint8_t head;
+    uint8_t track;
+    uint8_t sect;
+    /* Last operation status */
+    uint8_t dir;              /* Direction              */
+    uint8_t rw;               /* Read/write             */
+    /* Media */
+    fdisk_type_t disk;        /* Disk type              */
+    uint8_t last_sect;        /* Nb sector per track    */
+    uint8_t max_track;        /* Nb of tracks           */
+    uint8_t ro;               /* Is read-only           */
+} fdrive_t;
+
+static void fd_init (fdrive_t *drv)
+{
+    /* Drive */
+    drv->bs = NULL;
+//    drv->drive = FDRIVE_DRV_288;
+    drv->drive = FDRIVE_DRV_144;
+    drv->motor = 0;
+    drv->perpendicular = 0;
+    drv->rv = 0;
+    /* Disk */
+    drv->disk = FDRIVE_DISK_NONE;
+    drv->last_sect = 1;
+    drv->max_track = 0;
+}
+
+static int _fd_sector (uint8_t head, uint8_t track,
+                        uint8_t sect, uint8_t last_sect)
+{
+    return (((track * 2) + head) * last_sect) + sect - 1;
+}
+
+/* Returns current position, in sectors, for given drive */
+static int fd_sector (fdrive_t *drv)
+{
+    return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
+}
+
+static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
+                    int enable_seek)
+{
+    uint32_t sector;
+
+    if (track > drv->max_track) {
+        FLOPPY_ERROR("try to read %d %02x %02x (max=%d %02x %02x)\n",
+                     head, track, sect, 1, drv->max_track, drv->last_sect);
+        return 2;
+    }
+    if (sect > drv->last_sect) {
+        FLOPPY_ERROR("try to read %d %02x %02x (max=%d %02x %02x)\n",
+                     head, track, sect, 1, drv->max_track, drv->last_sect);
+        return 3;
+    }
+    sector = _fd_sector(head, track, sect, drv->last_sect);
+    if (sector != fd_sector(drv)) {
+#if 0
+        if (!enable_seek) {
+            FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
+                         head, track, sect, 1, drv->max_track, drv->last_sect);
+            return 4;
+        }
+#endif
+        drv->head = head;
+        drv->track = track;
+        drv->sect = sect;
+        return 1;
+    }
+
+    return 0;
+}
+
+/* Set drive back to track 0 */
+static void fd_recalibrate (fdrive_t *drv)
+{
+    FLOPPY_DPRINTF("recalibrate\n");
+    drv->head = 0;
+    drv->track = 0;
+    drv->sect = 1;
+    drv->dir = 1;
+    drv->rw = 0;
+}
+
+/* Revalidate a disk drive after a disk change */
+static void fd_revalidate (fdrive_t *drv, int ro)
+{
+    int64_t nb_sectors;
+
+    FLOPPY_DPRINTF("revalidate\n");
+    drv->rv = 0;
+    if (drv->bs != NULL) {
+        bdrv_get_geometry(drv->bs, &nb_sectors);
+#if 1
+        if (nb_sectors > 2880) 
+#endif
+        {
+            /* Pretend we have a 2.88 MB disk */
+            drv->disk = FDRIVE_DISK_288;
+            drv->last_sect = 36;
+            drv->max_track = 80;
+#if 1
+        } else if (nb_sectors > 1440) {
+            /* Pretend we have a 1.44 MB disk */
+            drv->disk = FDRIVE_DISK_144;
+            drv->last_sect = 18;
+            drv->max_track = 80;
+        } else {
+            /* Pretend we have a 720 kB disk */
+            drv->disk = FDRIVE_DISK_720;
+            drv->last_sect = 9;
+            drv->max_track = 80;
+#endif
+        }
+    } else {
+        drv->disk = FDRIVE_DISK_NONE;
+        drv->last_sect = 1; /* Avoid eventual divide by 0 bugs */
+    }
+    drv->ro = ro;
+    drv->rv = 1;
+}
+
+/* Motor control */
+static void fd_start (fdrive_t *drv)
+{
+    drv->motor = 1;
+}
+
+static void fd_stop (fdrive_t *drv)
+{
+    drv->motor = 0;
+}
+
+/* Re-initialise a drives (motor off, repositioned) */
+static void fd_reset (fdrive_t *drv)
+{
+    fd_stop(drv);
+    fd_recalibrate(drv);
+}
+
+/********************************************************/
+/* Intel 82078 floppy disk controler emulation          */
+
+static void fdctrl_reset (void);
+static void fdctrl_reset_fifo (void);
+static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq);
+static int fdctrl_misc_handler (int duknwo);
+
+static uint32_t fdctrl_read_statusB (CPUState *env, uint32_t reg);
+static uint32_t fdctrl_read_dor (CPUState *env, uint32_t reg);
+static void fdctrl_write_dor (CPUState *env, uint32_t reg, uint32_t value);
+static uint32_t fdctrl_read_tape (CPUState *env, uint32_t reg);
+static void fdctrl_write_tape (CPUState *env, uint32_t reg, uint32_t value);
+static uint32_t fdctrl_read_main_status (CPUState *env, uint32_t reg);
+static void fdctrl_write_rate (CPUState *env, uint32_t reg, uint32_t value);
+static uint32_t fdctrl_read_data (CPUState *env, uint32_t reg);
+static void fdctrl_write_data (CPUState *env, uint32_t reg, uint32_t value);
+static uint32_t fdctrl_read_dir (CPUState *env, uint32_t reg);
+
+enum {
+    FD_CTRL_ACTIVE = 0x01,
+    FD_CTRL_RESET  = 0x02,
+    FD_CTRL_SLEEP  = 0x04,
+    FD_CTRL_BUSY   = 0x08,
+    FD_CTRL_INTR   = 0x10,
+};
+
+enum {
+    FD_DIR_WRITE   = 0,
+    FD_DIR_READ    = 1,
+    FD_DIR_SCANE   = 2,
+    FD_DIR_SCANL   = 3,
+    FD_DIR_SCANH   = 4,
+};
+
+enum {
+    FD_STATE_CMD    = 0x00,
+    FD_STATE_STATUS = 0x01,
+    FD_STATE_DATA   = 0x02,
+    FD_STATE_STATE  = 0x03,
+    FD_STATE_MULTI  = 0x10,
+    FD_STATE_SEEK   = 0x20,
+};
+
+#define FD_STATE(state) ((state) & FD_STATE_STATE)
+#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
+#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
+
+typedef struct fdctrl_t {
+    /* Controler's identification */
+    uint8_t version;
+    /* HW */
+    int irq_lvl;
+    int dma_chann;
+    /* Controler state */
+    uint8_t state;
+    uint8_t dma_en;
+    uint8_t cur_drv;
+    uint8_t bootsel;
+    /* Command FIFO */
+    uint8_t fifo[FD_SECTOR_LEN];
+    uint32_t data_pos;
+    uint32_t data_len;
+    uint8_t data_state;
+    uint8_t data_dir;
+    uint8_t int_status;
+    /* States kept only to be returned back */
+    /* Timers state */
+    uint8_t timer0;
+    uint8_t timer1;
+    /* precompensation */
+    uint8_t precomp_trk;
+    uint8_t config;
+    uint8_t lock;
+    /* Power down config (also with status regB access mode */
+    uint8_t pwrd;
+    /* Floppy drives */
+    fdrive_t drives[2];
+} fdctrl_t;
+
+static fdctrl_t fdctrl;
+
+void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base,
+                  char boot_device)
+{
+//    int io_mem;
+    int i;
+
+    FLOPPY_DPRINTF("init controler\n");
+    memset(&fdctrl, 0, sizeof(fdctrl));
+    fdctrl.version = 0x90; /* Intel 82078 controler */
+    fdctrl.irq_lvl = irq_lvl;
+    fdctrl.dma_chann = dma_chann;
+    fdctrl.config = 0x40; /* Implicit seek, polling & FIFO enabled */
+    if (fdctrl.dma_chann != -1) {
+        fdctrl.dma_en = 1;
+        DMA_register_channel(dma_chann, &fdctrl_transfer_handler,
+                             &fdctrl_misc_handler);
+    } else {
+        fdctrl.dma_en = 0;
+    }
+    for (i = 0; i < MAX_FD; i++)
+        fd_init(&fdctrl.drives[i]);
+    fdctrl_reset();
+    fdctrl.state = FD_CTRL_ACTIVE;
+    if (mem_mapped) {
+        FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
+#if 0
+        io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
+        cpu_register_physical_memory(base, 0x08, io_mem);
+#endif
+    } else {
+        register_ioport_read(base + 0x01, 1, fdctrl_read_statusB, 1);
+        register_ioport_read(base + 0x02, 1, fdctrl_read_dor, 1);
+        register_ioport_write(base + 0x02, 1, fdctrl_write_dor, 1);
+        register_ioport_read(base + 0x03, 1, fdctrl_read_tape, 1);
+        register_ioport_write(base + 0x03, 1, fdctrl_write_tape, 1);
+        register_ioport_read(base + 0x04, 1, fdctrl_read_main_status, 1);
+        register_ioport_write(base + 0x04, 1, fdctrl_write_rate, 1);
+        register_ioport_read(base + 0x05, 1, fdctrl_read_data, 1);
+        register_ioport_write(base + 0x05, 1, fdctrl_write_data, 1);
+        register_ioport_read(base + 0x07, 1, fdctrl_read_dir, 1);
+    }
+    if (boot_device == 'b')
+        fdctrl.bootsel = 1;
+    else
+        fdctrl.bootsel = 0;
+    cmos_register_fd(fdctrl.drives[0].drive, fdctrl.drives[1].drive);
+}
+
+int fdctrl_disk_change (int idx, const unsigned char *filename, int ro)
+{
+    fdrive_t *drv;
+    
+    if (idx < 0 || idx > 1)
+        return -1;
+    FLOPPY_DPRINTF("disk %d change: %s (%s)\n", idx, filename,
+                   ro == 0 ? "rw" : "ro");
+    drv = &fdctrl.drives[idx];
+    if (fd_table[idx] != NULL) {
+        bdrv_close(fd_table[idx]);
+        fd_table[idx] = NULL;
+    }
+    fd_table[idx] = bdrv_open(filename, ro);
+    drv->bs = fd_table[idx];
+    if (fd_table[idx] == NULL)
+        return -1;
+    fd_revalidate(drv, ro);
+    fd_recalibrate(drv);
+
+    return 0;
+}
+
+/* Change IRQ state */
+static void fdctrl_reset_irq (void)
+{
+    if (fdctrl.state & FD_CTRL_INTR) {
+        pic_set_irq(fdctrl.irq_lvl, 0);
+        fdctrl.state &= ~(FD_CTRL_INTR | FD_CTRL_SLEEP | FD_CTRL_BUSY);
+    }
+}
+
+static void fdctrl_raise_irq (uint8_t status)
+{
+    if (~(fdctrl.state & FD_CTRL_INTR)) {
+        pic_set_irq(fdctrl.irq_lvl, 1);
+        fdctrl.state |= FD_CTRL_INTR;
+    }
+    fdctrl.int_status = status;
+}
+
+/* Reset controler */
+static void fdctrl_reset (void)
+{
+    int i;
+
+    FLOPPY_DPRINTF("reset controler\n");
+    fdctrl_reset_irq();
+    /* Initialise controler */
+    fdctrl.cur_drv = 0;
+    /* FIFO state */
+    fdctrl.data_pos = 0;
+    fdctrl.data_len = 0;
+    fdctrl.data_state = FD_STATE_CMD;
+    fdctrl.data_dir = FD_DIR_WRITE;
+    for (i = 0; i < MAX_FD; i++)
+        fd_reset(&fdctrl.drives[i]);
+    fdctrl_reset_fifo();
+    fdctrl_raise_irq(0x00);
+}
+
+/* Status B register : 0x01 (read-only) */
+static uint32_t fdctrl_read_statusB (CPUState *env, uint32_t reg)
+{
+    fdctrl_reset_irq();
+    FLOPPY_DPRINTF("status register: 0x00\n");
+
+    return 0;
+}
+
+/* Digital output register : 0x02 */
+static uint32_t fdctrl_read_dor (CPUState *env, uint32_t reg)
+{
+    fdrive_t *cur_drv, *drv0, *drv1;
+    uint32_t retval = 0;
+
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+    /* Drive motors state indicators */
+    retval |= drv1->motor << 5;
+    retval |= drv0->motor << 4;
+    /* DMA enable */
+    retval |= fdctrl.dma_en << 3;
+    /* Reset indicator */
+    retval |= (fdctrl.state & FD_CTRL_RESET) == 0 ? 0x04 : 0;
+    /* Selected drive */
+    retval |= fdctrl.cur_drv;
+    FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_write_dor (CPUState *env, uint32_t reg, uint32_t value)
+{
+    fdrive_t *drv0, *drv1;
+    
+    fdctrl_reset_irq();
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    /* Reset mode */
+    if (fdctrl.state & FD_CTRL_RESET) {
+        if (!(value & 0x04)) {
+            FLOPPY_DPRINTF("Floppy controler in RESET state !\n");
+            return;
+        }
+    }
+    FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
+    /* Drive motors state indicators */
+    if (value & 0x20)
+        fd_start(drv1);
+    else
+        fd_stop(drv1);
+    if (value & 0x10)
+        fd_start(drv0);
+    else
+        fd_stop(drv0);
+    /* DMA enable */
+#if 0
+    if (fdctrl.dma_chann != -1)
+        fdctrl.dma_en = 1 - ((value >> 3) & 1);
+#endif
+    /* Reset */
+    if (!(value & 0x04)) {
+        if (!(fdctrl.state & FD_CTRL_RESET)) {
+            FLOPPY_DPRINTF("controler enter RESET state\n");
+            fdctrl.state |= FD_CTRL_RESET;
+            fdctrl_reset();
+        }
+    } else {
+        if (fdctrl.state & FD_CTRL_RESET) {
+            FLOPPY_DPRINTF("controler out of RESET state\n");
+            fdctrl.state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
+        }
+    }
+    /* Selected drive */
+    fdctrl.cur_drv = value & 1;
+}
+
+/* Tape drive register : 0x03 */
+static uint32_t fdctrl_read_tape (CPUState *env, uint32_t reg)
+{
+    uint32_t retval = 0;
+
+    fdctrl_reset_irq();
+    /* Disk boot selection indicator */
+    retval |= fdctrl.bootsel << 2;
+    /* Tape indicators: never allowed */
+    FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_write_tape (CPUState *env, uint32_t reg, uint32_t value)
+{
+    fdctrl_reset_irq();
+    /* Reset mode */
+    if (fdctrl.state & FD_CTRL_RESET) {
+        FLOPPY_DPRINTF("Floppy controler in RESET state !\n");
+        return;
+    }
+    FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
+    /* Disk boot selection indicator */
+    fdctrl.bootsel = (value >> 2) & 1;
+    /* Tape indicators: never allow */
+}
+
+/* Main status register : 0x04 (read) */
+static uint32_t fdctrl_read_main_status (CPUState *env, uint32_t reg)
+{
+    uint32_t retval = 0;
+
+    fdctrl_reset_irq();
+    fdctrl.state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET);
+    if (!(fdctrl.state & FD_CTRL_BUSY)) {
+        /* Data transfer allowed */
+        retval |= 0x80;
+        /* Data transfer direction indicator */
+        if (fdctrl.data_dir == FD_DIR_READ)
+            retval |= 0x40;
+    }
+    /* Should handle 0x20 for SPECIFY command */
+    /* Command busy indicator */
+    if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA ||
+        FD_STATE(fdctrl.data_state) == FD_STATE_STATUS)
+        retval |= 0x10;
+    FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+/* Data select rate register : 0x04 (write) */
+static void fdctrl_write_rate (CPUState *env, uint32_t reg, uint32_t value)
+{
+    fdctrl_reset_irq();
+    /* Reset mode */
+    if (fdctrl.state & FD_CTRL_RESET) {
+        if (reg != 0x2 || !(value & 0x04)) {
+            FLOPPY_DPRINTF("Floppy controler in RESET state !\n");
+            return;
+        }
+    }
+    FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
+    /* Reset: autoclear */
+    if (value & 0x80) {
+        fdctrl.state |= FD_CTRL_RESET;
+        fdctrl_reset();
+        fdctrl.state &= ~FD_CTRL_RESET;
+    }
+    if (value & 0x40) {
+        fdctrl.state |= FD_CTRL_SLEEP;
+        fdctrl_reset();
+    }
+//        fdctrl.precomp = (value >> 2) & 0x07;
+}
+
+/* Digital input register : 0x07 (read-only) */
+static uint32_t fdctrl_read_dir (CPUState *env, uint32_t reg)
+{
+    fdrive_t *drv0, *drv1;
+    uint32_t retval = 0;
+
+    fdctrl_reset_irq();
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    if (drv0->rv || drv1->rv)
+        retval |= 0x80;
+    if (retval != 0)
+        FLOPPY_ERROR("Floppy digital input register: 0x%02x\n", retval);
+    drv0->rv = 0;
+    drv1->rv = 0;
+
+    return retval;
+}
+
+/* FIFO state control */
+static void fdctrl_reset_fifo (void)
+{
+    fdctrl.data_dir = FD_DIR_WRITE;
+    fdctrl.data_pos = 0;
+    fdctrl.data_state = FD_STATE_CMD;
+}
+
+/* Set FIFO status for the host to read */
+static void fdctrl_set_fifo (int fifo_len, int do_irq)
+{
+    fdctrl.data_dir = FD_DIR_READ;
+    fdctrl.data_len = fifo_len;
+    fdctrl.data_pos = 0;
+    fdctrl.data_state = FD_STATE_STATUS;
+    if (do_irq)
+        fdctrl_raise_irq(0x00);
+}
+
+/* Set an error: unimplemented/unknown command */
+static void fdctrl_unimplemented (void)
+{
+#if 0
+    fdrive_t *cur_drv, *drv0, *drv1;
+
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+    fdctrl.fifo[0] = 0x60 | (cur_drv->head << 1) | fdctrl.cur_drv;
+    fdctrl.fifo[1] = 0x00;
+    fdctrl.fifo[2] = 0x00;
+    fdctrl_set_fifo(3, 1);
+#else
+    fdctrl_reset_fifo();
+#endif
+}
+
+/* Callback for transfer end (stop or abort) */
+static void fdctrl_stop_transfer (uint8_t status0, uint8_t status1,
+                                  uint8_t status2)
+{
+    fdrive_t *cur_drv, *drv0, *drv1;
+
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+    FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
+                   status0, status1, status2,
+                   status0 | (cur_drv->head << 1) | fdctrl.cur_drv);
+    fdctrl.fifo[0] = status0 | (cur_drv->head << 1) | fdctrl.cur_drv;
+    fdctrl.fifo[1] = status1;
+    fdctrl.fifo[2] = status2;
+    fdctrl.fifo[3] = cur_drv->track;
+    fdctrl.fifo[4] = cur_drv->head;
+    fdctrl.fifo[5] = cur_drv->sect;
+    fdctrl.fifo[6] = FD_SECTOR_SC;
+    fdctrl.data_dir = FD_DIR_READ;
+    if (fdctrl.state & FD_CTRL_BUSY)
+        DMA_release_DREQ(fdctrl.dma_chann);
+    fdctrl_set_fifo(7, 1);
+}
+
+/* Prepare a data transfer (either DMA or FIFO) */
+static void fdctrl_start_transfer (int direction)
+{
+    fdrive_t *cur_drv, *drv0, *drv1;
+    uint8_t kh, kt, ks;
+    int did_seek;
+
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    fdctrl.cur_drv = fdctrl.fifo[1] & 1;
+    cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+    kt = fdctrl.fifo[2];
+    kh = fdctrl.fifo[3];
+    ks = fdctrl.fifo[4];
+    FLOPPY_DPRINTF("Start tranfert at %d %d %02x %02x (%d)\n",
+                   fdctrl.cur_drv, kh, kt, ks,
+                   _fd_sector(kh, kt, ks, cur_drv->last_sect));
+    did_seek = 0;
+    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl.config & 0x40)) {
+    case 2:
+        /* sect too big */
+        fdctrl_stop_transfer(0x40, 0x00, 0x00);
+        fdctrl.fifo[3] = kt;
+        fdctrl.fifo[4] = kh;
+        fdctrl.fifo[5] = ks;
+        return;
+    case 3:
+        /* track too big */
+        fdctrl_stop_transfer(0x40, 0x80, 0x00);
+        fdctrl.fifo[3] = kt;
+        fdctrl.fifo[4] = kh;
+        fdctrl.fifo[5] = ks;
+        return;
+    case 4:
+        /* No seek enabled */
+        fdctrl_stop_transfer(0x40, 0x00, 0x00);
+        fdctrl.fifo[3] = kt;
+        fdctrl.fifo[4] = kh;
+        fdctrl.fifo[5] = ks;
+        return;
+    case 1:
+        did_seek = 1;
+        break;
+    default:
+        break;
+    }
+    /* Set the FIFO state */
+    fdctrl.data_dir = direction;
+    fdctrl.data_pos = 0;
+    fdctrl.data_state = FD_STATE_DATA; /* FIFO ready for data */
+    if (fdctrl.fifo[0] & 0x80)
+        fdctrl.data_state |= FD_STATE_MULTI;
+    if (did_seek)
+        fdctrl.data_state |= FD_STATE_SEEK;
+    if (fdctrl.dma_en) {
+        int dma_mode;
+        /* DMA transfer are enabled. Check if DMA channel is well programmed */
+        dma_mode = DMA_get_channel_mode(fdctrl.dma_chann);
+        dma_mode = (dma_mode >> 2) & 3;
+        FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d)\n", dma_mode, direction,
+                       (128 << fdctrl.fifo[5]) *
+                       (cur_drv->last_sect - ks + 1));
+        if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
+              direction == FD_DIR_SCANH) && dma_mode == 0) ||
+            (direction == FD_DIR_WRITE && dma_mode == 2) ||
+            (direction == FD_DIR_READ && dma_mode == 1)) {
+            /* No access is allowed until DMA transfer has completed */
+            fdctrl.state |= FD_CTRL_BUSY;
+            /* Now, we just have to wait for the DMA controler to
+             * recall us...
+             */
+            DMA_hold_DREQ(fdctrl.dma_chann);
+            return;
+        }
+    }
+    FLOPPY_DPRINTF("start non-DMA transfer\n");
+    /* IO based transfer: calculate len */
+    if (fdctrl.fifo[5] == 00) {
+        fdctrl.data_len = fdctrl.fifo[8];
+    } else {
+        fdctrl.data_len = 128 << fdctrl.fifo[5];
+        fdctrl.data_len *= (cur_drv->last_sect - ks + 1);
+        if (fdctrl.fifo[0] & 0x80)
+            fdctrl.data_len *= 2;
+    }
+    fdctrl_raise_irq(0x00);
+
+    return;
+}
+
+/* Prepare a transfer of deleted data */
+static void fdctrl_start_transfer_del (int direction)
+{
+    /* We don't handle deleted data,
+     * so we don't return *ANYTHING*
+     */
+    fdctrl_stop_transfer(0x60, 0x00, 0x00);
+}
+
+/* handlers for DMA transfers */
+static int fdctrl_transfer_handler (uint32_t addr, int size, int *irq)
+{
+    fdrive_t *cur_drv, *drv0, *drv1;
+    void *orig;
+    int len;
+    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
+
+    fdctrl_reset_irq();
+    if (!(fdctrl.state & FD_CTRL_BUSY)) {
+        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
+        return 0;
+    }
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+//    *irq = fdctrl.irq_lvl;
+    *irq = -1;
+    if (fdctrl.data_dir == FD_DIR_SCANE || fdctrl.data_dir == FD_DIR_SCANL ||
+        fdctrl.data_dir == FD_DIR_SCANH)
+        status2 = 0x04;
+    for (fdctrl.data_len = size; fdctrl.data_pos < fdctrl.data_len;
+         fdctrl.data_pos += len) {
+        len = size - fdctrl.data_pos;
+        if (len > FD_SECTOR_LEN)
+            len = FD_SECTOR_LEN;
+        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x "
+                       "(%d-0x%08x)\n", len, size, fdctrl.data_pos,
+                       fdctrl.data_len, fdctrl.cur_drv, cur_drv->head,
+                       cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
+                       fd_sector(cur_drv) * 512);
+        if (len < FD_SECTOR_LEN) {
+            memset(&fdctrl.fifo[FD_SECTOR_LEN - len], 0,
+                   FD_SECTOR_LEN - len - 1);
+            orig = fdctrl.fifo;
+        } else {
+            orig = (void *)(addr + fdctrl.data_pos);
+        }
+        if (fdctrl.data_dir != FD_DIR_WRITE) {
+            /* READ & SCAN commands */
+            if (cur_drv->bs == NULL ||
+                bdrv_read(cur_drv->bs, fd_sector(cur_drv), orig, 1) < 0) {
+                FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
+                               fd_sector(cur_drv));
+                /* Sure, image size is too small... */
+                memset((void *)(addr + fdctrl.data_pos), 0, FD_SECTOR_LEN);
+            }
+            if (fdctrl.data_dir == FD_DIR_READ) {
+                if (len < FD_SECTOR_LEN) {
+                    memcpy((void *)(addr + fdctrl.data_pos),
+                           fdctrl.fifo, FD_SECTOR_LEN);
+                }
+            } else {
+                int ret;
+                ret = memcmp((void *)(addr + fdctrl.data_pos),
+                             fdctrl.fifo, FD_SECTOR_LEN);
+                if (ret == 0) {
+                    status2 = 0x08;
+                    goto end_transfer;
+                }
+                if ((ret < 0 && fdctrl.data_dir == FD_DIR_SCANL) ||
+                    (ret > 0 && fdctrl.data_dir == FD_DIR_SCANH)) {
+                    status2 = 0x00;
+                    goto end_transfer;
+                }
+            }
+        } else {
+            /* WRITE commands */
+            if (cur_drv->bs == NULL ||
+                bdrv_write(cur_drv->bs, fd_sector(cur_drv), orig, 1) < 0) {
+                FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
+                fdctrl_stop_transfer(0x60, 0x00, 0x00);
+                goto transfer_error;
+            }
+        }
+        if (len == FD_SECTOR_LEN) {
+            /* Seek to next sector */
+            if (cur_drv->sect == cur_drv->last_sect) {
+                if (cur_drv->head == 0) {
+                    cur_drv->head = 1;
+                } else {
+                    cur_drv->track++;
+                    cur_drv->head = 0;
+                }
+                cur_drv->sect = 1;
+                FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
+                               cur_drv->head, cur_drv->track, cur_drv->sect,
+                               fd_sector(cur_drv));
+                if (cur_drv->head == 0) {
+                    FLOPPY_DPRINTF("end transfer\n");
+                    goto end_transfer;
+                }
+                if (!FD_MULTI_TRACK(fdctrl.data_state)) {
+                    /* Single track read */
+                    FLOPPY_DPRINTF("single track transfert: end transfer\n");
+//                    status1 |= 0x80;
+                    goto end_transfer;
+                }
+            } else {
+                cur_drv->sect++;
+                FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
+                               cur_drv->head, cur_drv->track, cur_drv->sect,
+                               fd_sector(cur_drv));
+            }
+        }
+    }
+end_transfer:
+    if (fdctrl.data_dir == FD_DIR_SCANE ||
+        fdctrl.data_dir == FD_DIR_SCANL ||
+        fdctrl.data_dir == FD_DIR_SCANH)
+        status2 = 0x08;
+    if (FD_DID_SEEK(fdctrl.data_state))
+        status0 |= 0x20;
+    fdctrl_stop_transfer(status0, status1, status2);
+transfer_error:
+
+    return fdctrl.data_pos;
+}
+
+/* Unused... */
+static int fdctrl_misc_handler (int duknwo)
+{
+    return -1;
+}
+
+/* Data register : 0x05 */
+static uint32_t fdctrl_read_data (CPUState *env, uint32_t reg)
+{
+    fdrive_t *cur_drv, *drv0, *drv1;
+    uint32_t retval = 0;
+    int pos, len;
+
+    fdctrl_reset_irq();
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+    fdctrl.state &= ~FD_CTRL_SLEEP;
+    if (FD_STATE(fdctrl.data_state) == FD_STATE_CMD) {
+        FLOPPY_ERROR("can't read data in CMD state\n");
+        return 0;
+    }
+    pos = fdctrl.data_pos;
+    if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) {
+        pos %= FD_SECTOR_LEN;
+        if (pos == 0) {
+            len = fdctrl.data_len - fdctrl.data_pos;
+            if (len > FD_SECTOR_LEN)
+                len = FD_SECTOR_LEN;
+            bdrv_read(cur_drv->bs, fd_sector(cur_drv),
+                      fdctrl.fifo, len);
+        }
+    }
+    retval = fdctrl.fifo[pos];
+    if (++fdctrl.data_pos == fdctrl.data_len) {
+        fdctrl.data_pos = 0;
+        /* Switch from transfert mode to status mode
+         * then from status mode to command mode
+         */
+        if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA)
+            fdctrl_stop_transfer(0x20, 0x00, 0x00);
+        else
+            fdctrl_reset_fifo();
+    }
+    FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_write_data (CPUState *env, uint32_t reg, uint32_t value)
+{
+    fdrive_t *cur_drv, *drv0, *drv1;
+
+    fdctrl_reset_irq();
+    drv0 = &fdctrl.drives[fdctrl.bootsel];
+    drv1 = &fdctrl.drives[1 - fdctrl.bootsel];
+    cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+    /* Reset mode */
+    if (fdctrl.state & FD_CTRL_RESET) {
+        FLOPPY_DPRINTF("Floppy controler in RESET state !\n");
+        return;
+    }
+    fdctrl.state &= ~FD_CTRL_SLEEP;
+    if ((fdctrl.data_state & FD_STATE_STATE) == FD_STATE_STATUS) {
+        FLOPPY_ERROR("can't write data in status mode\n");
+        return;
+    }
+    /* Is it write command time ? */
+    if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA) {
+        /* FIFO data write */
+        fdctrl.fifo[fdctrl.data_pos++] = value;
+        if (fdctrl.data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||
+            fdctrl.data_pos == fdctrl.data_len) {
+            bdrv_write(cur_drv->bs, fd_sector(cur_drv),
+                       fdctrl.fifo, FD_SECTOR_LEN);
+        }
+        /* Switch from transfert mode to status mode
+         * then from status mode to command mode
+         */
+        if (FD_STATE(fdctrl.data_state) == FD_STATE_DATA)
+            fdctrl_stop_transfer(0x20, 0x00, 0x00);
+        return;
+    }
+    if (fdctrl.data_pos == 0) {
+        /* Command */
+        switch (value & 0x5F) {
+        case 0x46:
+            /* READ variants */
+            FLOPPY_DPRINTF("READ command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        case 0x4C:
+            /* READ_DELETED variants */
+            FLOPPY_DPRINTF("READ_DELETED command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        case 0x50:
+            /* SCAN_EQUAL variants */
+            FLOPPY_DPRINTF("SCAN_EQUAL command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        case 0x56:
+            /* VERIFY variants */
+            FLOPPY_DPRINTF("VERIFY command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        case 0x59:
+            /* SCAN_LOW_OR_EQUAL variants */
+            FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        case 0x5D:
+            /* SCAN_HIGH_OR_EQUAL variants */
+            FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        default:
+            break;
+        }
+        switch (value & 0x7F) {
+        case 0x45:
+            /* WRITE variants */
+            FLOPPY_DPRINTF("WRITE command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        case 0x49:
+            /* WRITE_DELETED variants */
+            FLOPPY_DPRINTF("WRITE_DELETED command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        default:
+            break;
+        }
+        switch (value) {
+        case 0x03:
+            /* SPECIFY */
+            FLOPPY_DPRINTF("SPECIFY command\n");
+            /* 1 parameter cmd */
+            fdctrl.data_len = 3;
+            goto enqueue;
+        case 0x04:
+            /* SENSE_DRIVE_STATUS */
+            FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
+            /* 1 parameter cmd */
+            fdctrl.data_len = 2;
+            goto enqueue;
+        case 0x07:
+            /* RECALIBRATE */
+            FLOPPY_DPRINTF("RECALIBRATE command\n");
+            /* 1 parameter cmd */
+            fdctrl.data_len = 2;
+            goto enqueue;
+        case 0x08:
+            /* SENSE_INTERRUPT_STATUS */
+            FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command\n");
+            /* No parameters cmd: returns status if no interrupt */
+            fdctrl.fifo[0] =
+                fdctrl.int_status | (cur_drv->head << 2) | fdctrl.cur_drv;
+            fdctrl.fifo[1] = cur_drv->track;
+            fdctrl_set_fifo(2, 0);
+            return;
+        case 0x0E:
+            /* DUMPREG */
+            FLOPPY_DPRINTF("DUMPREG command\n");
+            /* Drives position */
+            fdctrl.fifo[0] = drv0->track;
+            fdctrl.fifo[1] = drv1->track;
+            fdctrl.fifo[2] = 0;
+            fdctrl.fifo[3] = 0;
+            /* timers */
+            fdctrl.fifo[4] = fdctrl.timer0;
+            fdctrl.fifo[5] = (fdctrl.timer1 << 1) | fdctrl.dma_en;
+            fdctrl.fifo[6] = cur_drv->last_sect;
+            fdctrl.fifo[7] = (fdctrl.lock << 7) |
+                    (cur_drv->perpendicular << 2);
+            fdctrl.fifo[8] = fdctrl.config;
+            fdctrl.fifo[9] = fdctrl.precomp_trk;
+            fdctrl_set_fifo(10, 0);
+            return;
+        case 0x0F:
+            /* SEEK */
+            FLOPPY_DPRINTF("SEEK command\n");
+            /* 2 parameters cmd */
+            fdctrl.data_len = 3;
+            goto enqueue;
+        case 0x10:
+            /* VERSION */
+            FLOPPY_DPRINTF("VERSION command\n");
+            /* No parameters cmd */
+            /* Controler's version */
+            fdctrl.fifo[0] = fdctrl.version;
+            fdctrl_set_fifo(1, 1);
+            return;
+        case 0x12:
+            /* PERPENDICULAR_MODE */
+            FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
+            /* 1 parameter cmd */
+            fdctrl.data_len = 2;
+            goto enqueue;
+        case 0x13:
+            /* CONFIGURE */
+            FLOPPY_DPRINTF("CONFIGURE command\n");
+            /* 3 parameters cmd */
+            fdctrl.data_len = 4;
+            goto enqueue;
+        case 0x14:
+            /* UNLOCK */
+            FLOPPY_DPRINTF("UNLOCK command\n");
+            /* No parameters cmd */
+            fdctrl.lock = 0;
+            fdctrl.fifo[0] = 0;
+            fdctrl_set_fifo(1, 0);
+            return;
+        case 0x17:
+            /* POWERDOWN_MODE */
+            FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
+            /* 2 parameters cmd */
+            fdctrl.data_len = 3;
+            goto enqueue;
+        case 0x18:
+            /* PART_ID */
+            FLOPPY_DPRINTF("PART_ID command\n");
+            /* No parameters cmd */
+            fdctrl.fifo[0] = 0x41; /* Stepping 1 */
+            fdctrl_set_fifo(1, 0);
+            return;
+        case 0x2C:
+            /* SAVE */
+            FLOPPY_DPRINTF("SAVE command\n");
+            /* No parameters cmd */
+            fdctrl.fifo[0] = 0;
+            fdctrl.fifo[1] = 0;
+            /* Drives position */
+            fdctrl.fifo[2] = drv0->track;
+            fdctrl.fifo[3] = drv1->track;
+            fdctrl.fifo[4] = 0;
+            fdctrl.fifo[5] = 0;
+            /* timers */
+            fdctrl.fifo[6] = fdctrl.timer0;
+            fdctrl.fifo[7] = fdctrl.timer1;
+            fdctrl.fifo[8] = cur_drv->last_sect;
+            fdctrl.fifo[9] = (fdctrl.lock << 7) |
+                    (cur_drv->perpendicular << 2);
+            fdctrl.fifo[10] = fdctrl.config;
+            fdctrl.fifo[11] = fdctrl.precomp_trk;
+            fdctrl.fifo[12] = fdctrl.pwrd;
+            fdctrl.fifo[13] = 0;
+            fdctrl.fifo[14] = 0;
+            fdctrl_set_fifo(15, 1);
+            return;
+        case 0x33:
+            /* OPTION */
+            FLOPPY_DPRINTF("OPTION command\n");
+            /* 1 parameter cmd */
+            fdctrl.data_len = 2;
+            goto enqueue;
+        case 0x42:
+            /* READ_TRACK */
+            FLOPPY_DPRINTF("READ_TRACK command\n");
+            /* 8 parameters cmd */
+            fdctrl.data_len = 9;
+            goto enqueue;
+        case 0x4A:
+            /* READ_ID */
+            FLOPPY_DPRINTF("READ_ID command\n");
+            /* 1 parameter cmd */
+            fdctrl.data_len = 2;
+            goto enqueue;
+        case 0x4C:
+            /* RESTORE */
+            FLOPPY_DPRINTF("RESTORE command\n");
+            /* 17 parameters cmd */
+            fdctrl.data_len = 18;
+            goto enqueue;
+        case 0x4D:
+            /* FORMAT_TRACK */
+            FLOPPY_DPRINTF("FORMAT_TRACK command\n");
+            /* 5 parameters cmd */
+            fdctrl.data_len = 6;
+            goto enqueue;
+        case 0x8E:
+            /* DRIVE_SPECIFICATION_COMMAND */
+            FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
+            /* 5 parameters cmd */
+            fdctrl.data_len = 6;
+            goto enqueue;
+        case 0x8F:
+            /* RELATIVE_SEEK_OUT */
+            FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
+            /* 2 parameters cmd */
+            fdctrl.data_len = 3;
+            goto enqueue;
+        case 0x94:
+            /* LOCK */
+            FLOPPY_DPRINTF("LOCK command\n");
+            /* No parameters cmd */
+            fdctrl.lock = 1;
+            fdctrl.fifo[0] = 0x10;
+            fdctrl_set_fifo(1, 1);
+            return;
+        case 0xCD:
+            /* FORMAT_AND_WRITE */
+            FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
+            /* 10 parameters cmd */
+            fdctrl.data_len = 11;
+            goto enqueue;
+        case 0xCF:
+            /* RELATIVE_SEEK_IN */
+            FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
+            /* 2 parameters cmd */
+            fdctrl.data_len = 3;
+            goto enqueue;
+        default:
+            /* Unknown command */
+            FLOPPY_ERROR("unknown command: 0x%02x\n", value);
+            fdctrl_unimplemented();
+            return;
+        }
+    }
+enqueue:
+    fdctrl.fifo[fdctrl.data_pos] = value;
+    if (++fdctrl.data_pos == fdctrl.data_len) {
+        /* We now have all parameters
+         * and will be able to treat the command
+         */
+        switch (fdctrl.fifo[0] & 0x1F) {
+        case 0x06:
+        {
+            /* READ variants */
+            FLOPPY_DPRINTF("treat READ command\n");
+            fdctrl_start_transfer(FD_DIR_READ);
+            return;
+        }
+        case 0x0C:
+            /* READ_DELETED variants */
+//            FLOPPY_DPRINTF("treat READ_DELETED command\n");
+            FLOPPY_ERROR("treat READ_DELETED command\n");
+            fdctrl_start_transfer_del(1);
+            return;
+        case 0x16:
+            /* VERIFY variants */
+//            FLOPPY_DPRINTF("treat VERIFY command\n");
+            FLOPPY_ERROR("treat VERIFY command\n");
+            fdctrl_stop_transfer(0x20, 0x00, 0x00);
+            return;
+        case 0x10:
+            /* SCAN_EQUAL variants */
+//            FLOPPY_DPRINTF("treat SCAN_EQUAL command\n");
+            FLOPPY_ERROR("treat SCAN_EQUAL command\n");
+            fdctrl_start_transfer(FD_DIR_SCANE);
+            return;
+        case 0x19:
+            /* SCAN_LOW_OR_EQUAL variants */
+//            FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n");
+            FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
+            fdctrl_start_transfer(FD_DIR_SCANL);
+            return;
+        case 0x1D:
+            /* SCAN_HIGH_OR_EQUAL variants */
+//            FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n");
+            FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
+            fdctrl_start_transfer(FD_DIR_SCANH);
+            return;
+        default:
+            break;
+        }
+        switch (fdctrl.fifo[0] & 0x3F) {
+        case 0x05:
+            /* WRITE variants */
+            FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl.fifo[0]);
+            fdctrl_start_transfer(FD_DIR_WRITE);
+            return;
+        case 0x09:
+            /* WRITE_DELETED variants */
+//            FLOPPY_DPRINTF("treat WRITE_DELETED command\n");
+            FLOPPY_ERROR("treat WRITE_DELETED command\n");
+            fdctrl_start_transfer_del(FD_DIR_WRITE);
+            return;
+        default:
+            break;
+        }
+        switch (fdctrl.fifo[0]) {
+        case 0x03:
+            /* SPECIFY */
+            FLOPPY_DPRINTF("treat SPECIFY command\n");
+            fdctrl.timer0 = (fdctrl.fifo[1] >> 4) & 0xF;
+            fdctrl.timer1 = fdctrl.fifo[1] >> 1;
+            /* No result back */
+            fdctrl_reset_fifo();
+            break;
+        case 0x04:
+            /* SENSE_DRIVE_STATUS */
+            FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
+            fdctrl.cur_drv = fdctrl.fifo[1] & 1;
+            cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+            cur_drv->head = (fdctrl.fifo[1] >> 2) & 1;
+            /* 1 Byte status back */
+            fdctrl.fifo[0] = (cur_drv->ro << 6) |
+                (cur_drv->track == 0 ? 0x10 : 0x00) |
+                fdctrl.cur_drv;
+            fdctrl_set_fifo(1, 0);
+            break;
+        case 0x07:
+            /* RECALIBRATE */
+            FLOPPY_DPRINTF("treat RECALIBRATE command\n");
+            fdctrl.cur_drv = fdctrl.fifo[1] & 1;
+            cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+            cur_drv->track = 0;
+            fdctrl_reset_fifo();
+            /* Raise Interrupt */
+            fdctrl_raise_irq(0x20);
+            break;
+        case 0x0F:
+            /* SEEK */
+            FLOPPY_DPRINTF("treat SEEK command\n");
+            fdctrl.cur_drv = fdctrl.fifo[1] & 1;
+            cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+            if (fdctrl.fifo[2] <= cur_drv->track)
+                cur_drv->dir = 1;
+            else
+                cur_drv->dir = 0;
+            cur_drv->head = (fdctrl.fifo[1] >> 2) & 1;
+            if (fdctrl.fifo[2] > cur_drv->max_track) {
+                fdctrl_raise_irq(0x60);
+            } else {
+                cur_drv->track = fdctrl.fifo[2];
+                fdctrl_reset_fifo();
+                /* Raise Interrupt */
+                fdctrl_raise_irq(0x20);
+            }
+            break;
+        case 0x12:
+            /* PERPENDICULAR_MODE */
+            FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
+            if (fdctrl.fifo[1] & 0x80)
+                cur_drv->perpendicular = fdctrl.fifo[1] & 0x7;
+            /* No result back */
+            fdctrl_reset_fifo();
+            break;
+        case 0x13:
+            /* CONFIGURE */
+            FLOPPY_DPRINTF("treat CONFIGURE command\n");
+            fdctrl.config = fdctrl.fifo[2];
+            fdctrl.precomp_trk =  fdctrl.fifo[3];
+            /* No result back */
+            fdctrl_reset_fifo();
+            break;
+        case 0x17:
+            /* POWERDOWN_MODE */
+            FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
+            fdctrl.pwrd = fdctrl.fifo[1];
+            fdctrl.fifo[0] = fdctrl.fifo[1];
+            fdctrl_set_fifo(1, 1);
+            break;
+        case 0x33:
+            /* OPTION */
+            FLOPPY_DPRINTF("treat OPTION command\n");
+            /* No result back */
+            fdctrl_reset_fifo();
+            break;
+        case 0x42:
+            /* READ_TRACK */
+//            FLOPPY_DPRINTF("treat READ_TRACK command\n");
+            FLOPPY_ERROR("treat READ_TRACK command\n");
+            fdctrl_unimplemented();
+            break;
+        case 0x4A:
+                /* READ_ID */
+//            FLOPPY_DPRINTF("treat READ_ID command\n");
+            FLOPPY_ERROR("treat READ_ID command\n");
+            fdctrl_unimplemented();
+            break;
+        case 0x4C:
+            /* RESTORE */
+            FLOPPY_DPRINTF("treat RESTORE command\n");
+            /* Drives position */
+            drv0->track = fdctrl.fifo[3];
+            drv1->track = fdctrl.fifo[4];
+            /* timers */
+            fdctrl.timer0 = fdctrl.fifo[7];
+            fdctrl.timer1 = fdctrl.fifo[8];
+            cur_drv->last_sect = fdctrl.fifo[9];
+            fdctrl.lock = fdctrl.fifo[10] >> 7;
+            cur_drv->perpendicular = (fdctrl.fifo[10] >> 2) & 0xF;
+            fdctrl.config = fdctrl.fifo[11];
+            fdctrl.precomp_trk = fdctrl.fifo[12];
+            fdctrl.pwrd = fdctrl.fifo[13];
+            fdctrl_reset_fifo();
+            break;
+        case 0x4D:
+            /* FORMAT_TRACK */
+//                FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
+            FLOPPY_ERROR("treat FORMAT_TRACK command\n");
+            fdctrl_unimplemented();
+            break;
+        case 0x8E:
+            /* DRIVE_SPECIFICATION_COMMAND */
+            FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
+            if (fdctrl.fifo[fdctrl.data_pos - 1] & 0x80) {
+                /* Command parameters done */
+                if (fdctrl.fifo[fdctrl.data_pos - 1] & 0x40) {
+                    fdctrl.fifo[0] = fdctrl.fifo[1];
+                    fdctrl.fifo[2] = 0;
+                    fdctrl.fifo[3] = 0;
+                    fdctrl_set_fifo(4, 1);
+                } else {
+                    fdctrl_reset_fifo();
+                }
+            } else if (fdctrl.data_len > 7) {
+                /* ERROR */
+                fdctrl.fifo[0] = 0x80 |
+                    (cur_drv->head << 2) | fdctrl.cur_drv;
+                fdctrl_set_fifo(1, 1);
+            }
+            break;
+        case 0x8F:
+            /* RELATIVE_SEEK_OUT */
+            FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
+            fdctrl.cur_drv = fdctrl.fifo[1] & 1;
+            cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+            cur_drv->head = (fdctrl.fifo[1] >> 2) & 1;
+            if (fdctrl.fifo[2] + cur_drv->track > cur_drv->max_track) {
+                /* ERROR */
+                fdctrl_raise_irq(0x70);
+            } else {
+                cur_drv->track += fdctrl.fifo[2];
+                cur_drv->dir = 0;
+                fdctrl_reset_fifo();
+                fdctrl_raise_irq(0x20);
+            }
+            break;
+        case 0xCD:
+            /* FORMAT_AND_WRITE */
+//                FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n");
+            FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
+            fdctrl_unimplemented();
+            break;
+        case 0xCF:
+                /* RELATIVE_SEEK_IN */
+            FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
+            fdctrl.cur_drv = fdctrl.fifo[1] & 1;
+            cur_drv = fdctrl.cur_drv == 0 ? drv0 : drv1;
+            cur_drv->head = (fdctrl.fifo[1] >> 2) & 1;
+            if (fdctrl.fifo[2] > cur_drv->track) {
+                /* ERROR */
+                fdctrl_raise_irq(0x60);
+            } else {
+                fdctrl_reset_fifo();
+                cur_drv->track -= fdctrl.fifo[2];
+                cur_drv->dir = 1;
+                /* Raise Interrupt */
+                fdctrl_raise_irq(0x20);
+            }
+            break;
+        }
+    }
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] floppy disk emulation
  2003-11-18  7:22 ` [Qemu-devel] [ADD] floppy disk emulation J. Mayer
  2003-11-18  7:37   ` J. Mayer
@ 2003-11-18  7:38   ` J. Mayer
  2003-11-18  7:39   ` J. Mayer
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:38 UTC (permalink / raw)
  To: qemu-devel

vl.c.diff

Add helper to register floppy drives in CMOS memory.
Make qemu able to boot from floppy
Add floppy init.

diff -urNbB -x CVS qemu-current/vl.c qemu/vl.c
--- qemu-current/vl.c	Tue Nov 18 06:51:10 2003
+++ qemu/vl.c	Tue Nov 18 02:19:33 2003
@@ -49,6 +50,8 @@
 #include "thunk.h"
 
 #include "vl.h"
+
+#define USE_FLOPPY
 
 #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
 #define BIOS_FILENAME "bios.bin"
@@ -210,7 +217,7 @@
 CPUX86State *cpu_single_env;
 IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
 IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
-BlockDriverState *bs_table[MAX_DISKS];
+BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD];
 int vga_ram_size;
 static DisplayState display_state;
 int nographic;
@@ -577,9 +584,12 @@
     cmos_data[0x35] = val >> 8;
     
     switch(boot_device) {
+#ifdef USE_FLOPPY
     case 'a':
+    case 'b':
         cmos_data[0x3d] = 0x01; /* floppy boot */
         break;
+#endif
     default:
     case 'c':
         cmos_data[0x3d] = 0x02; /* hard drive boot */
@@ -593,6 +603,57 @@
     register_ioport_read(0x70, 2, cmos_ioport_read, 1);
 }
 
+#ifdef USE_FLOPPY
+void cmos_register_fd (uint8_t fd0, uint8_t fd1)
+{
+    int nb = 0;
+
+    cmos_data[0x10] = 0;
+    switch (fd0) {
+    case 0:
+        /* 1.44 Mb 3"5 drive */
+        cmos_data[0x10] |= 0x40;
+        break;
+    case 1:
+        /* 2.88 Mb 3"5 drive */
+        cmos_data[0x10] |= 0x60;
+        break;
+    case 2:
+        /* 1.2 Mb 5"5 drive */
+        cmos_data[0x10] |= 0x20;
+        break;
+    }
+    switch (fd1) {
+    case 0:
+        /* 1.44 Mb 3"5 drive */
+        cmos_data[0x10] |= 0x04;
+        break;
+    case 1:
+        /* 2.88 Mb 3"5 drive */
+        cmos_data[0x10] |= 0x06;
+        break;
+    case 2:
+        /* 1.2 Mb 5"5 drive */
+        cmos_data[0x10] |= 0x02;
+        break;
+    }
+    if (fd0 < 3)
+        nb++;
+    if (fd1 < 3)
+        nb++;
+    switch (nb) {
+    case 0:
+        break;
+    case 1:
+        cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */
+        break;
+    case 2:
+        cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */
+        break;
+    }
+}
+#endif
+
 /***********************************************************/
 /* 8259 pic emulation */
 
@@ -1952,6 +2127,26 @@
 }
 
 /***********************************************************/
+/* PC floppy disk controler emulation glue */
+#define PC_FDC_DMA  0x2
+#define PC_FDC_IRQ  0x6
+#define PC_FDC_BASE 0x3F0
+
+static void fdctrl_register (unsigned char **disknames, int ro,
+                             char boot_device)
+{
+#ifdef USE_FLOPPY
+    int i;
+
+    fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device);
+    for (i = 0; i < MAX_FD; i++) {
+        if (disknames[i] != NULL)
+            fdctrl_disk_change(i, disknames[i], ro);
+    }
+#endif
+}
+
+/***********************************************************/
 /* keyboard emulation */
 
 /*	Keyboard Controller Commands */
@@ -2853,6 +3053,8 @@
            "'disk_image' is a raw hard image image for IDE hard disk 0\n"
            "\n"
            "Standard options:\n"
+           "-fda file       use 'file' as floppy disk 0 image\n"
+           "-fdb file       use 'file' as floppy disk 1 image\n"
            "-hda/-hdb file  use 'file' as IDE hard disk 0/1 image\n"
            "-hdc/-hdd file  use 'file' as IDE hard disk 2/3 image\n"
            "-cdrom file     use 'file' as IDE cdrom 2 image\n"
@@ -2907,6 +3109,8 @@
     { "hdd", 1, NULL, 0, },
     { "cdrom", 1, NULL, 0, },
     { "boot", 1, NULL, 0, },
+    { "fda", 1, NULL, 0, },
+    { "fdb", 1, NULL, 0, },
     { NULL, 0, NULL, 0 },
 };
 
@@ -2931,13 +3135,15 @@
     struct itimerval itv;
     CPUX86State *env;
     const char *initrd_filename;
-    const char *hd_filename[MAX_DISKS];
+    const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
     const char *kernel_filename, *kernel_cmdline;
     DisplayState *ds = &display_state;
 
     /* we never want that malloc() uses mmap() */
     mallopt(M_MMAP_THRESHOLD, 4096 * 1024);
     initrd_filename = NULL;
+    for(i = 0; i < MAX_FD; i++)
+        fd_filename[i] = NULL;
     for(i = 0; i < MAX_DISKS; i++)
         hd_filename[i] = NULL;
     phys_ram_size = 32 * 1024 * 1024;
@@ -3012,11 +3218,18 @@
                 break;
             case 12:
                 boot_device = optarg[0];
-                if (boot_device != 'c' && boot_device != 'd') {
+                if (boot_device != 'a' && boot_device != 'b' &&
+                    boot_device != 'c' && boot_device != 'd') {
                     fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device);
                     exit(1);
                 }
                 break;
+            case 13:
+                fd_filename[0] = optarg;
+                break;
+            case 14:
+                fd_filename[1] = optarg;
+                break;
             }
             break;
         case 'h':
@@ -3056,7 +3269,8 @@
 
     linux_boot = (kernel_filename != NULL);
         
-    if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0')
+    if (!linux_boot && hd_filename[0] == '\0' && hd_filename[2] == '\0' &&
+        fd_filename[0] == '\0')
         help();
     
     /* boot to cd by default if no hard disk */
@@ -3268,7 +3482,8 @@
     AUD_init();
     DMA_init();
     SB16_init();
    
+    fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device);
     /* setup cpu signal handlers for MMU / self modifying code handling */
     sigfillset(&act.sa_mask);
     act.sa_flags = SA_SIGINFO;

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] floppy disk emulation
  2003-11-18  7:22 ` [Qemu-devel] [ADD] floppy disk emulation J. Mayer
  2003-11-18  7:37   ` J. Mayer
  2003-11-18  7:38   ` J. Mayer
@ 2003-11-18  7:39   ` J. Mayer
  2003-11-18  7:39   ` J. Mayer
  2003-11-18  8:24   ` J. Mayer
  4 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:39 UTC (permalink / raw)
  To: qemu-devel

vl.h.diff

Add definitions for floppy disk emulation.

diff -urNbB -x CVS qemu-current/vl.h qemu/vl.h
--- qemu-current/vl.h	Tue Nov 18 06:51:10 2003
+++ qemu/vl.h	Mon Nov 17 21:58:39 2003
@@ -143,5 +143,13 @@
 /* sb16.c */
 void SB16_run (void);
 void SB16_init (void);
+
+/* fdc.c */
+#define MAX_FD 2
+void cmos_register_fd (uint8_t fd0, uint8_t fd1);
+extern BlockDriverState *fd_table[MAX_FD];
+void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base,
+                  char boot_device);
+int fdctrl_disk_change (int idx, const unsigned char *filename, int ro);
  
 #endif /* VL_H */

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] floppy disk emulation
  2003-11-18  7:22 ` [Qemu-devel] [ADD] floppy disk emulation J. Mayer
                     ` (2 preceding siblings ...)
  2003-11-18  7:39   ` J. Mayer
@ 2003-11-18  7:39   ` J. Mayer
  2003-11-18  8:24   ` J. Mayer
  4 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:39 UTC (permalink / raw)
  To: qemu-devel

Makefile.target.diff

Compile floppy disk emulation.

diff -urNbB -x CVS qemu-current/Makefile.target qemu/Makefile.target
--- qemu-current/Makefile.target	Tue Nov 18 06:51:06 2003
+++ qemu/Makefile.target	Tue Nov 18 06:03:59 2003
@@ -179,7 +198,7 @@
 endif
 
 # must use static linking to avoid leaving stuff in virtual address space
-VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o
+VL_OBJS=vl.o block.o ide.o vga.o sb16.o fdc.o dma.o oss.o
 ifdef CONFIG_SDL
 VL_OBJS+=sdl.o
 ifdef CONFIG_STATIC

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
@ 2003-11-18  7:43   ` J. Mayer
  2003-11-18  7:43   ` J. Mayer
                     ` (24 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:43 UTC (permalink / raw)
  To: qemu-devel

Makefile.diff

Add new utility to generate repetitive micro-operations for PPC emulation.

diff -urNbB -x CVS qemu-current/Makefile qemu/Makefile
--- qemu-current/Makefile	Tue Nov 18 06:51:06 2003
+++ qemu/Makefile	Tue Nov 11 00:42:03 2003
@@ -4,7 +4,7 @@
 LDFLAGS=-g
 LIBS=
 DEFINES+=-D_GNU_SOURCE
-TOOLS=qemu-mkcow
+TOOLS=qemu-mkcow gen_multi
 
 all: dyngen $(TOOLS) qemu-doc.html qemu.1
 	for d in $(TARGET_DIRS); do \
@@ -23,7 +23,7 @@
 clean:
 # avoid old build problems by removing potentially incorrect old files
 	rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h 
-	rm -f *.o *.a $(TOOLS) dyngen TAGS qemu.pod
+	rm -f *.o *.a $(TOOLS) dyngen gen_multi TAGS qemu.pod
 	for d in $(TARGET_DIRS); do \
 	make -C $$d $@ || exit 1 ; \
         done

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
  2003-11-18  7:43   ` J. Mayer
@ 2003-11-18  7:43   ` J. Mayer
  2003-11-18  7:44   ` J. Mayer
                     ` (23 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:43 UTC (permalink / raw)
  To: qemu-devel

Makefile.target.diff

Add PPC target.

diff -urNbB -x CVS qemu-current/Makefile.target qemu/Makefile.target
--- qemu-current/Makefile.target	Tue Nov 18 06:51:06 2003
+++ qemu/Makefile.target	Tue Nov 18 06:03:59 2003
@@ -146,6 +161,10 @@
 LIBOBJS+=helper.o helper2.o
 endif
 
+ifeq ($(TARGET_ARCH), ppc)
+LIBOBJS+=helper.o
+endif
+
 # NOTE: the disassembler code is only needed for debugging
 LIBOBJS+=disas.o 
 ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -242,11 +261,18 @@
 op.o: op.c op_template.h
 endif
 
+ifeq ($(TARGET_ARCH), ppc)
+op.o: op.c op-multi.c
+endif
+
+select.h op-multi.c: op.tpl ../gen_multi
+	../gen_multi -o op-multi.c -s select.h $<
+
 %.o: %.c
 	$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
 
 clean:
-	rm -f *.o  *.a *~ $(PROGS) gen-op.h opc.h op.h
+	rm -f *.o  *.a *~ $(PROGS) gen-op.h opc.h op.h select.h op-multi.c
 
 install: all 
 	install -m 755 -s $(PROGS) $(prefix)/bin

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
  2003-11-18  7:43   ` J. Mayer
  2003-11-18  7:43   ` J. Mayer
@ 2003-11-18  7:44   ` J. Mayer
  2003-11-18  7:45   ` J. Mayer
                     ` (22 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:44 UTC (permalink / raw)
  To: qemu-devel

configure.diff

Add ppc-user target.

diff -urNbB -x CVS qemu-current/configure qemu/configure
--- qemu-current/configure	Tue Nov 18 06:51:06 2003
+++ qemu/configure	Tue Nov 18 06:03:20 2003
@@ -27,7 +27,7 @@
 make="make"
 strip="strip"
 cpu=`uname -m`
-target_list="i386-user i386 i386-softmmu arm-user sparc-user"
+target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user"
 case "$cpu" in
   i386|i486|i586|i686|i86pc|BePC)
     cpu="i386"
@@ -358,6 +358,11 @@
   echo "TARGET_ARCH=sparc" >> $config_mak
   echo "#define TARGET_ARCH \"sparc\"" >> $config_h
   echo "#define TARGET_SPARC 1" >> $config_h
+elif test "$target_cpu" = "ppc" ; then
+  echo "TARGET_ARCH=ppc" >> $config_mak
+  echo "#define TARGET_ARCH \"ppc\"" >> $config_h
+  echo "#define TARGET_PPC 1" >> $config_h
+  target_bigendian="yes"
 else
   echo "Unsupported target CPU"
   exit 1

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (2 preceding siblings ...)
  2003-11-18  7:44   ` J. Mayer
@ 2003-11-18  7:45   ` J. Mayer
  2003-11-18  7:45   ` J. Mayer
                     ` (21 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:45 UTC (permalink / raw)
  To: qemu-devel

cpu-all.h.diff

Defines for PPC target.

diff -urNbB -x CVS qemu-current/cpu-all.h qemu/cpu-all.h
--- qemu-current/cpu-all.h	Tue Nov 18 06:51:06 2003
+++ qemu/cpu-all.h	Sun Nov 16 04:08:35 2003
@@ -395,6 +395,15 @@
 #define cpu_interrupt cpu_sparc_interrupt
 #define cpu_signal_handler cpu_sparc_signal_handler
 
+#elif defined(TARGET_PPC)
+
+#define CPUState CPUPPCState
+#define cpu_init cpu_ppc_init
+#define cpu_exec cpu_ppc_exec
+#define cpu_gen_code cpu_ppc_gen_code
+#define cpu_interrupt cpu_ppc_interrupt
+#define cpu_signal_handler cpu_ppc_signal_handler
+
 #else
 
 #error unsupported target CPU

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (3 preceding siblings ...)
  2003-11-18  7:45   ` J. Mayer
@ 2003-11-18  7:45   ` J. Mayer
  2003-11-18  7:46   ` J. Mayer
                     ` (20 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:45 UTC (permalink / raw)
  To: qemu-devel

cpu-exec.c.diff

Add PPC target

diff -urNbB -x CVS qemu-current/cpu-exec.c qemu/cpu-exec.c
--- qemu-current/cpu-exec.c	Tue Nov 18 06:51:06 2003
+++ qemu/cpu-exec.c	Sun Nov 16 04:09:07 2003
@@ -131,6 +131,7 @@
         env->cpsr = psr & ~0xf0000000;
     }
 #elif defined(TARGET_SPARC)
+#elif defined(TARGET_PPC)
 #else
 #error unsupported target CPU
 #endif
@@ -226,6 +227,8 @@
                     env->cpsr &= ~0xf0000000;
 #elif defined(TARGET_SPARC)
                     cpu_sparc_dump_state (env, logfile, 0);
+#elif defined(TARGET_PPC)
+                    cpu_ppc_dump_state(env, logfile, 0);
 #else
 #error unsupported target CPU 
 #endif
@@ -251,6 +254,10 @@
 					env->npc = 0;
 				}
 				pc = (uint8_t *) env->pc;
+#elif defined(TARGET_PPC)
+                flags = 0;
+                cs_base = 0;
+                pc = (uint8_t *)env->nip;
 #else
 #error unsupported CPU
 #endif
@@ -365,6 +372,7 @@
 #elif defined(TARGET_ARM)
     env->cpsr = compute_cpsr();
 #elif defined(TARGET_SPARC)
+#elif defined(TARGET_PPC)
 #else
 #error unsupported target CPU
 #endif
@@ -501,6 +509,43 @@
                                     int is_write, sigset_t *old_set)
 {
 	return 0;
+}
+#elif defined (TARGET_PPC)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+                                    int is_write, sigset_t *old_set)
+{
+    TranslationBlock *tb;
+    
+#if 0
+    if (cpu_single_env)
+        env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#endif
+#if defined(DEBUG_SIGNAL)
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+           pc, address, is_write, *(unsigned long *)old_set);
+#endif
+    /* XXX: locking issue */
+    if (is_write && page_unprotect(address)) {
+        return 1;
+    }
+
+    /* now we have a real cpu fault */
+    tb = tb_find_pc(pc);
+    if (tb) {
+        /* the PC is inside the translated code. It means that we have
+           a virtual CPU fault */
+        cpu_restore_state(tb, env, pc);
+    }
+#if 0
+    printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
+           env->eip, env->cr[2], env->error_code);
+#endif
+    /* we restore the process signal mask as the sigreturn should
+       do it (XXX: use sigsetjmp) */
+    sigprocmask(SIG_SETMASK, old_set, NULL);
+    raise_exception_err(EXCP_PROGRAM, env->error_code);
+    /* never comes here */
+    return 1;
 }
 #else
 #error unsupported target CPU

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (4 preceding siblings ...)
  2003-11-18  7:45   ` J. Mayer
@ 2003-11-18  7:46   ` J. Mayer
  2003-11-18  7:46   ` J. Mayer
                     ` (19 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:46 UTC (permalink / raw)
  To: qemu-devel

disas.c.diff

Add PPC target

diff -urNbB -x CVS qemu-current/disas.c qemu/disas.c
--- qemu-current/disas.c	Tue Nov 18 06:51:07 2003
+++ qemu/disas.c	Tue Nov 11 00:32:21 2003
@@ -171,6 +171,8 @@
 	print_insn = print_insn_arm;
 #elif defined(TARGET_SPARC)
 	print_insn = print_insn_sparc;
+#elif defined(TARGET_PPC)
+	print_insn = print_insn_ppc;
 #else
 	fprintf(out, "Asm output not supported on this arch\n");
 	return;

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (5 preceding siblings ...)
  2003-11-18  7:46   ` J. Mayer
@ 2003-11-18  7:46   ` J. Mayer
  2003-11-18  7:48   ` J. Mayer
                     ` (18 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:46 UTC (permalink / raw)
  To: qemu-devel

dyngen-exec.h.diff

Add definitions used by PPC target

diff -urNbB -x CVS qemu-current/dyngen-exec.h qemu/dyngen-exec.h
--- qemu-current/dyngen-exec.h	Tue Nov 18 06:51:07 2003
+++ qemu/dyngen-exec.h	Tue Nov 11 01:16:05 2003
@@ -17,6 +17,9 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#if !defined(__DYNGEN_EXEC_H__)
+#define __DYNGEN_EXEC_H__
+
 typedef unsigned char uint8_t;
 typedef unsigned short uint16_t;
 typedef unsigned int uint32_t;
@@ -27,6 +30,19 @@
 typedef signed int int32_t;
 typedef signed long long int64_t;
 
+# define INT8_MIN		(-128)
+# define INT16_MIN		(-32767-1)
+# define INT32_MIN		(-2147483647-1)
+# define INT64_MIN		(-(int64_t)(9223372036854775807)-1)
+# define INT8_MAX		(127)
+# define INT16_MAX		(32767)
+# define INT32_MAX		(2147483647)
+# define INT64_MAX		((int64_t)(9223372036854775807))
+# define UINT8_MAX		(255)
+# define UINT16_MAX		(65535)
+# define UINT32_MAX		(4294967295U)
+# define UINT64_MAX		((uint64_t)(18446744073709551615))
+
 #define bswap32(x) \
 ({ \
 	uint32_t __x = (x); \
@@ -191,3 +207,5 @@
 #ifdef __mc68000
 #define EXIT_TB() asm volatile ("rts")
 #endif
+
+#endif /* !defined(__DYNGEN_EXEC_H__) */

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (6 preceding siblings ...)
  2003-11-18  7:46   ` J. Mayer
@ 2003-11-18  7:48   ` J. Mayer
  2003-11-18  7:48   ` J. Mayer
                     ` (17 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:48 UTC (permalink / raw)
  To: qemu-devel

elfload.c.diff

Make it able to load PPC ELF executables.
At least for static ones and a few dynamic ones.

diff -urNbB -x CVS qemu-current/elfload.c qemu/elfload.c
--- qemu-current/elfload.c	Tue Nov 18 06:51:07 2003
+++ qemu/elfload.c	Tue Nov 11 00:30:10 2003
@@ -104,6 +104,46 @@
 
 #endif
 
+#ifdef TARGET_PPC
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_PPC )
+
+#define ELF_CLASS	ELFCLASS32
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA	ELFDATA2MSB
+#else
+#define ELF_DATA	ELFDATA2LSB
+#endif
+#define ELF_ARCH	EM_PPC
+
+/* Note that isn't exactly what regular kernel does
+ * but this is what the ABI wants and is needed to allow
+ * execution of PPC BSD programs.
+ */
+#define ELF_PLAT_INIT(_r)                                  \
+do {                                                       \
+   unsigned long *pos = (unsigned long *)bprm->p, tmp = 1; \
+    _r->gpr[3] = bprm->argc;                               \
+    _r->gpr[4] = (unsigned long)++pos;                     \
+    for (; tmp != 0; pos++)                                \
+        tmp = *pos;                                        \
+     _r->gpr[5] = (unsigned long)pos;                      \
+} while (0)
+
+static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
+{
+    _regs->msr = 1 << MSR_PR; /* Set user mode */
+    _regs->gpr[1] = infop->start_stack;
+    _regs->nip = infop->entry;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
+#endif
+
 #include "elf.h"
 
 /*

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (7 preceding siblings ...)
  2003-11-18  7:48   ` J. Mayer
@ 2003-11-18  7:48   ` J. Mayer
  2003-11-18  7:49   ` J. Mayer
                     ` (16 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:48 UTC (permalink / raw)
  To: qemu-devel

gen_multi.c.diff

New utility to generate repetitive micro-ops

diff -urNbB -x CVS qemu-current/gen_multi.c qemu/gen_multi.c
--- qemu-current/gen_multi.c	Thu Jan  1 01:00:00 1970
+++ qemu/gen_multi.c	Sun Aug 17 13:36:23 2003
@@ -0,0 +1,519 @@
+/*
+ * Minimalist preprocessor.
+ * Recognized token:
+ * $DEF regname number
+ * $OP name rega0 rega1 regb0
+ * ...
+ * $ENDOP
+ *
+ * example:
+ * $DEF gpr 32
+ * $DEF T   3
+ * $OP load_gpr gpr0 T0
+ * {
+ *     ....
+ * }
+ * $ENDOP
+ * $OP add T0 T1
+ * {
+ *     ....
+ * }
+ * $ENDOP
+ * $OP op3 T0 T1 T2
+ * {
+ *     ....
+ * }
+ * $ENDOP
+ *
+ * The '$' MUST be at start of the line.
+ *
+ * The preprocessor will generate:
+ * - n micro-routines
+ * - 1 routine to select the right micro helper at run-time.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+const unsigned char *prologue_str =
+"/* This file has been auto-generated - PLEASE DON'T EDIT BY HAND */\n\n";
+
+typedef struct reg_t {
+    char *name;
+    int nr;
+} reg_t;
+
+static int regtypes_nr;
+static reg_t regtypes[16], *host_reg; /* Should be sufficient... */
+static FILE *fuops = NULL, *fc = NULL;
+static int verbose, limit, host_max;
+
+static int outbuf (FILE *file,
+                   const unsigned char *start,
+                   const unsigned char *end)
+{
+    int out;
+
+    for (out = 0; out == 0;) {
+        out = fwrite(start, end - start, 1, file);
+        if (out == 0) {
+            if (errno != EINTR && errno != ERESTART) {
+                fprintf(stderr, "Unable to copy function out\n");
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int recurs_out_uop (const unsigned char *name,
+                           const unsigned char *start,
+                           const unsigned char *end,
+                           int nr, int *regnums, const int *regmax,
+                           unsigned char *const *regs)
+{
+    int hostregs[16] = { 0, };
+    int i, j, tmphost = 0, tmpemu = 0, tmpparm = 0;
+    
+    /* Generate function prototype */
+    if (fuops != NULL) {
+        /* Define registers */
+        for (i = 0; i < nr; i++) {
+            if (strcmp(regs[i], host_reg->name) == 0) {
+                fprintf(fuops, "#define %s%c %s%d\n",
+                        regs[i], 'a' + tmphost, regs[i], regnums[i]);
+                hostregs[regnums[i]] = 1;
+                tmphost++;
+            } else if (strcmp(regs[i], "PARAM") == 0) {
+                tmpparm++;
+            } else {
+                fprintf(fuops, "#define %s%c %s[%d]\n",
+                        regs[i], 'a' + tmpemu, regs[i], regnums[i]);
+                tmpemu++;
+            }
+        }
+        j = 0;
+        fprintf(fuops, "volatile void op_%s", name);
+    }
+    if (fc != NULL && nr > tmpparm)
+        fprintf(fc, "    &gen_op_%s", name);
+    for (i = 0; i < nr; i++) {
+        if (strcmp(regs[i], "PARAM") == 0)
+            continue;
+        if (fuops != NULL)
+            fprintf(fuops, "_%s%d", regs[i], regnums[i]);
+        if (fc != NULL)
+            fprintf(fc, "_%s%d", regs[i], regnums[i]);
+    }
+    if (fuops != NULL)
+        fprintf(fuops, " (void)\n");
+    if (fc != NULL && nr > tmpparm)
+        fprintf(fc, ",\n");
+    if (fuops != NULL) {
+        /* Copy function core */
+        if (outbuf(fuops, start, end) < 0)
+            return -1;
+        /* Undef registers */
+        tmphost = tmpemu = 0;
+        for (i = 0; i < nr; i++) {
+            if (strcmp(regs[i], host_reg->name) == 0) {
+                fprintf(fuops, "#undef %s%c\n", regs[i], 'a' + tmphost++);
+            } else if (strcmp(regs[i], "PARAM") == 0) {
+                continue;
+            } else {
+                fprintf(fuops, "#undef %s%c\n", regs[i], 'a' + tmpemu++);
+            }
+        }
+        /* Separate functions */
+        fprintf(fuops, "\n");
+    }
+
+    return 0;
+}
+
+static int _recurs_out_uop (const unsigned char *name,
+                            const unsigned char *start,
+                            const unsigned char *end,
+                            int nr, int *regnums, const int *regmax,
+                            unsigned char *const *regs, int level)
+{
+    int i;
+
+    if (level >= 0) {
+        if (strcmp(regs[level], "PARAM") == 0) {
+            if (_recurs_out_uop(name, start, end, nr, regnums, regmax,
+                                regs, level - 1) < 0)
+                return -1;
+        } else if (strcmp(regs[level], host_reg->name) == 0) {
+            for (i = 0; i < regmax[level]; i++) {
+                regnums[level] = i;
+                if (_recurs_out_uop(name, start, end, nr, regnums, regmax,
+                                    regs, level - 1) < 0)
+                    return -1;
+            }
+#if 0
+            for (; i < regmax[level]; i++) {
+                if (fc != NULL && nr > 0)
+                    fprintf(fc, "    NULL,\n");
+            }
+#endif
+        } else {
+            for (i = 0; i < regmax[level]; i++) {
+                regnums[level] = i;
+                if (_recurs_out_uop(name, start, end, nr, regnums, regmax,
+                                    regs, level - 1) < 0)
+                    return -1;
+            }
+        }
+    } else {
+        if (recurs_out_uop(name, start, end, nr,
+                           regnums, regmax, regs) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+static void usage (const unsigned char *progname,
+                   const unsigned char *message)
+{
+    fprintf(stderr, "Usage: %s -o uops_file -s -h h_file in_file\n",
+            progname);
+    fprintf(stderr, "Generate C-code...\n");
+    fprintf(stderr, "\tuops_file: C-code: micro-operations routines\n");
+    fprintf(stderr, "\th_file   : C-code; run-time selector for uops\n");
+    if (message != NULL)
+        fprintf(stderr, message);
+}
+
+int main (int argc, char **argv)
+{
+    unsigned char *function, *regs[32];
+    int regnums[16], regmax[16];
+    struct stat st;
+    const unsigned char *message;
+    unsigned char *map, *start, *end;
+    unsigned char *name_start, *name_end, *tmp_end;
+    int fd_in = -1;
+    int nr_regs, nr_tmp;
+    int tmp, mul;
+    int i, j;
+    int c;
+
+    while ((c = getopt(argc, argv, "o:s:lvh?")) != -1) {
+        switch (c) {
+        case 'o':
+            if (fuops != NULL) {
+                message = "Can output only one uops file at once\n";
+                goto out_error;
+            }
+            fuops = fopen(argv[optind - 1], "w");
+            if (fuops == NULL) {
+                message = "Can't open fuops file\n";
+                goto out_error;
+            }
+            break;
+        case 's':
+            if (fc != NULL) {
+                message = "Can output only one C file at once\n";
+                goto out_error;
+            }
+            fc = fopen(argv[optind - 1], "w");
+            if (fc == NULL) {
+                message = "Can't open C file\n";
+                goto out_error;
+            }
+            break;
+        case 'v':
+            verbose++;
+            break;
+        case 'l':
+            limit++;
+            break;
+        case 'h':
+        case '?':
+            usage(argv[0], NULL);
+            exit(0);
+            break;
+        default:
+            message = "Unknown option\n";
+            goto out_error;
+        }
+    }
+    if (fuops == NULL && fc == NULL) {
+        message = "Must have at least one output file\n";
+        goto out_error;
+    }
+    if (optind != (argc - 1)) {
+        message = "Bad number of arguments\n";
+        goto out_error;
+    }
+    fd_in = open(argv[optind], O_RDONLY);
+    if (fd_in < 0) {
+        message = "Error oppening in file\n";
+        goto out_error;
+    }
+    if (fstat(fd_in, &st) < 0) {
+        message = "Error getting in file infos\n";
+        goto out_error;
+    }
+    map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
+               fd_in, 0);
+    if (map == NULL) {
+        message = "Can't map in_file\n";
+        goto out_error;
+    }
+
+    /* Get variables definitions */
+    end = map;
+    for (regtypes_nr = 0; regtypes_nr < 16;) {
+        start = strstr(end, "$DEF");
+        if (start == NULL)
+            break;
+        if (start == map || *(start - 1) == '\n') {
+            end = strchr(start, '\n');
+            if (end == NULL)
+                end = start + st.st_size;
+            start += 4;
+            if (*start == 'H') {
+                if (host_reg != NULL) {
+                    message = "host regs cannot be defined more than once";
+                    goto out_error;
+                }
+                host_reg = &regtypes[regtypes_nr];
+                start++;
+            }
+            if (!isspace(*start++)) {
+                message = "invalid $DEF token\n";
+                goto out_error;
+            }
+            for (name_start = start; isspace(*name_start); name_start++)
+                continue;
+            if (name_start == end) {
+                message = "no $DEF name\n";
+                goto out_error;
+            }
+            for (name_end = name_start;
+                 !isspace(*name_end) && name_end < end; name_end++)
+                continue;
+            tmp = strtol(name_end + 1, NULL, 0);
+            if (tmp == 0) {
+                message = "invalid number of registers\n";
+                goto out_error;
+            }
+            regtypes[regtypes_nr].nr = tmp;
+            tmp = name_end - name_start;
+            regtypes[regtypes_nr].name = malloc(tmp + 1);
+            if (regtypes[regtypes_nr].name == NULL) {
+                message = "memory error\n";
+                goto out_error;
+            }
+            memcpy(regtypes[regtypes_nr].name, name_start, tmp);
+            regtypes[regtypes_nr].name[tmp] = '\0';
+            if (verbose > 0) {
+                printf("Registered %d vars of type: %s\n",
+                       regtypes[regtypes_nr].nr, regtypes[regtypes_nr].name);
+            }
+            regtypes_nr++;
+        } else {
+            end = start + 4;
+        }
+    }
+
+    if (host_reg == NULL) {
+        message = "No host registers defined !\n";
+        goto out_error;
+    }
+
+    tmp = strlen(prologue_str);
+    if (fuops != NULL) {
+        fwrite(prologue_str, tmp, 1, fuops);
+    }
+
+    if (fc != NULL)
+        fwrite(prologue_str, tmp, 1, fc);
+    /* Proceed micro-operations */
+    while (1) {
+        host_max = 0;
+        start = strstr(end, "$OP");
+        if (start == NULL)
+            break;
+        if (outbuf(fuops, end, start) < 0)
+            return -1;
+        if (start == map || *(start - 1) == '\n') {
+            tmp_end = strchr(start, '\n');
+            if (tmp_end == NULL)
+                tmp_end = start + st.st_size;
+            start += 3;
+            if (!isspace(*start++)) {
+                message = "invalid $OP token\n";
+                goto out_error;
+            }
+            for (name_start = start; isspace(*name_start); name_start++)
+                continue;
+            if (name_start == tmp_end) {
+                message = "no $OP name\n";
+                goto out_error;
+            }
+            for (name_end = name_start;
+                 !isspace(*name_end) && name_end < tmp_end; name_end++)
+                continue;
+            tmp = name_end - name_start;
+            function = malloc(tmp + 1);
+            if (function == NULL) {
+                message = "memory error\n";
+                goto out_error;
+            }
+            memcpy(function, name_start, tmp);
+            function[tmp] = '\0';
+            for (nr_regs = 0;
+                 name_end != tmp_end && nr_regs < 32;) {
+                for (name_start = name_end + 1;
+                     isspace(*name_start); name_start++)
+                    continue;
+                if (name_start == tmp_end)
+                    break;
+                for (name_end = name_start;
+                     !isspace(*name_end) && name_end < tmp_end; name_end++)
+                    continue;
+                tmp = name_end - name_start;
+                regs[nr_regs] = malloc(tmp + 1);
+                if (regs[nr_regs] == NULL) {
+                    message = "memory error\n";
+                    goto out_error;
+                }
+                memcpy(regs[nr_regs], name_start, tmp);
+                (regs[nr_regs++])[tmp] = '\0';
+            }
+            end = strstr(tmp_end, "$ENDOP");
+            if (end == NULL) {
+                message = "operation with no end\n";
+                goto out_error;
+            }
+            if (verbose > 0)
+                printf("Generate function: %s\n", function);
+
+            nr_tmp = 0;
+            for (i = 0; i < nr_regs; i++) {
+                for (j = 0; j < regtypes_nr; j++) {
+                    if (strcmp(regs[i], regtypes[j].name) == 0) {
+                        if (verbose > 0) {
+                            printf("\tregister of type: %s (%s - %d)\n",
+                                   regs[i], regtypes[j].name, regtypes[j].nr);
+                        }
+                        regmax[i] = regtypes[j].nr;
+                        goto got_it;
+                    }
+                    if (strcmp(regs[i], "PARAM") == 0) {
+                        nr_tmp++;
+                        goto got_it;
+                    }
+                }
+                printf("register %s not found\n", regs[i]);
+                message = "register not found\n";
+                goto out_error;
+            got_it:
+                continue;
+            }
+            
+            if (nr_regs > nr_tmp) {
+                if (fc != NULL)
+                    fprintf(fc, "static void *table_%s[] = {\n", function);
+                memset(regnums, 0, sizeof(regnums));
+            }
+            if (_recurs_out_uop(function, tmp_end + 1, end, nr_regs,
+                                regnums, regmax, regs, nr_regs - 1) < 0) {
+                message = "code generation error\n";
+                goto out_error;
+            }
+            if (nr_regs > nr_tmp) {
+                if (fc != NULL) {
+                    fprintf(fc, "};\n\n");
+                    fprintf(fc, "static inline void gen_op_%s (", function);
+                }
+            }
+            if (nr_regs == nr_tmp)
+                goto do_free;
+
+            if (fc != NULL) {
+                int tmp = 0;
+                for (i = 0; i < nr_tmp; i++) {
+                    if (i > 0)
+                        fprintf(fc, ", ");
+                    fprintf(fc, "unsigned long parm%d", i);
+                }
+                for (i = 0; i < nr_regs; i++) {
+                    if (strcmp(regs[i], "PARAM") == 0)
+                        continue;
+                    if (tmp++ > 0 || nr_tmp > 0)
+                        fprintf(fc, ", ");
+                    if (fc != NULL)
+                        fprintf(fc, "int regn%d", i);
+                }
+                fprintf(fc, ")\n");
+                fprintf(fc, "{\n");
+                fprintf(fc, "    void (*gen_op)(");
+                for (i = 0; i < nr_tmp; i++) {
+                    if (i > 0)
+                        fprintf(fc, ", ");
+                    fprintf(fc, "unsigned long p%d", i);
+                }
+                fprintf(fc, ");\n\n");
+                fprintf(fc, "    gen_op = table_%s[", function);
+                fprintf(fc, "regn0");
+                mul = 1;
+                for (i = 1; i < nr_regs; i++) {
+                    if (strcmp(regs[i], "PARAM") == 0)
+                        continue;
+                    mul *= regmax[i - 1];
+                    fprintf(fc, " + (regn%d * %d)", i, mul);
+                }
+                fprintf(fc, "];\n");
+                fprintf(fc, "    (*gen_op)(");
+                for (i = 0; i < nr_tmp; i++) {
+                    if (i > 0)
+                        fprintf(fc, ", ");
+                    fprintf(fc, "parm%d", i);
+                }
+                fprintf(fc, ");\n");
+                fprintf(fc, "}\n\n");
+            }
+        do_free:
+            free(function);
+            for (; nr_regs > 0; nr_regs--)
+                free(regs[nr_regs - 1]);
+            end = strchr(end, '\n');
+            if (end == NULL)
+                break;
+        } else {
+            end = start + 3;
+        }
+    }
+
+    if (fuops != NULL)
+        fclose(fuops);
+    if (fc != NULL)
+        fclose(fc);
+    close(fd_in);
+
+    exit(0);
+
+out_error:
+    if (fuops != NULL)
+        fclose(fuops);
+    if (fc != NULL)
+        fclose(fc);
+    if (fd_in >= 0)
+        close(fd_in);
+    usage(argv[0], message);
+
+    exit(1);
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (8 preceding siblings ...)
  2003-11-18  7:48   ` J. Mayer
@ 2003-11-18  7:49   ` J. Mayer
  2003-11-18  7:50   ` J. Mayer
                     ` (15 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:49 UTC (permalink / raw)
  To: qemu-devel

main.c.diff

Add PPC target main loop

diff -urNbB -x CVS qemu-current/main.c qemu/main.c
--- qemu-current/main.c	Tue Nov 18 06:51:08 2003
+++ qemu/main.c	Tue Nov 11 00:58:06 2003
@@ -324,6 +324,128 @@
 
 #endif
 
+#ifdef TARGET_PPC
+#include "cpu.h"
+
+void cpu_loop(CPUPPCState *env)
+{
+    int trapnr;
+    target_siginfo_t info;
+    
+    for(;;) {
+        trapnr = cpu_ppc_exec(env);
+       switch(trapnr) {
+        case EXCP_NONE:
+        case EXCP_INTERRUPT:
+        case EXCP_MTMSR: /* mtmsr instruction:               */
+        case EXCP_BRANCH: /* branch instruction               */
+            /* Single step mode */
+            break;
+#if 0
+        case EXCP_RESET: /* System reset                     */
+            fprintf(stderr, "RESET asked... Stop emulation\n");
+            cpu_ppc_dump_state(env, stderr, 0);
+            abort();
+#endif
+        case EXCP_MACHINE_CHECK: /* Machine check exception          */
+            fprintf(stderr, "Machine check exeption... "
+                    "See you in kernel code !\n");
+            cpu_ppc_dump_state(env, stderr, 0);
+            abort();
+        case EXCP_DSI:  /* Impossible memory access         */
+            fprintf(stderr, "Invalid memory access\n");
+            info.si_signo = SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->nip;
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP_ISI: /* Impossible instruction fetch     */
+            fprintf(stderr, "Invalid instruction fetch\n");
+            info.si_signo = SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->nip;
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP_EXTERNAL: /* External interruption            */
+            fprintf(stderr, "External access exeption\n");
+            cpu_ppc_dump_state(env, stderr, 0);
+            abort();
+        case EXCP_ALIGN: /* Alignment exception              */
+            fprintf(stderr, "Alignment exception\n");
+            cpu_ppc_dump_state(env, stderr, 0);
+            abort();
+        case EXCP_PROGRAM: /* Program exception                */
+            fprintf(stderr, "Program exception\n");
+            cpu_ppc_dump_state(env, stderr, 0);
+            abort();
+            break;
+        /* Trap */
+        case EXCP_TRAP: /* Trap                             */
+        case EXCP_TRACE: /* Trace exception (optional)       */
+            info.si_signo = SIGTRAP;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->nip;
+            queue_signal(info.si_signo, &info);
+            break;
+        /* Invalid instruction */
+        case EXCP_INVAL:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->nip;
+            queue_signal(info.si_signo, &info);
+            break;
+        /* Privileged instruction */
+        case EXCP_PRIV: /* Privileged instruction           */
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->nip;
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP_NO_FP: /* No floating point                */
+        case EXCP_DECR: /* Decrementer exception            */
+        case EXCP_RESA: /* Implementation specific          */
+        case EXCP_RESB: /* Implementation specific          */
+        case EXCP_FP_ASSIST: /* Floating-point assist (optional) */
+            fprintf(stderr, "Misc expt...\n");
+            cpu_ppc_dump_state(env, stderr, 0);
+            abort();
+
+        case EXCP_SYSCALL:
+        {
+            uint32_t ret;
+            /* system call */
+            /* WARNING:
+             * PPC ABI uses overflow flag in cr0 to signal an error
+             * in syscalls.
+             */
+            env->crf[0] &= ~0x1;
+            ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+                             env->gpr[5], env->gpr[6], env->gpr[7],
+                             env->gpr[8]);
+            if (ret > (uint32_t)(-515)) {
+                env->crf[0] |= 0x1;
+                ret = -ret;
+            }
+            env->gpr[3] = ret;
+            break;
+        }
+        default:
+//        error:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 
+                    trapnr);
+            cpu_ppc_dump_state(env, stderr, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+#endif
+
 void usage(void)
 {
     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
@@ -517,6 +639,16 @@
 #elif defined(TARGET_SPARC)
 	env->pc = regs->u_regs[0];
 	env->regwptr[6] = regs->u_regs[1]-0x40;
+#elif defined(TARGET_PPC)
+    {
+        int i;
+        for (i = 0; i < 32; i++)
+            env->msr[i] = (regs->msr >> i) & 1;
+        env->nip = regs->nip;
+        for(i = 0; i < 32; i++) {
+            env->gpr[i] = regs->gpr[i];
+        }
+    }
 #else
 #error unsupported target CPU
 #endif

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (9 preceding siblings ...)
  2003-11-18  7:49   ` J. Mayer
@ 2003-11-18  7:50   ` J. Mayer
  2003-11-18  7:50   ` J. Mayer
                     ` (14 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:50 UTC (permalink / raw)
  To: qemu-devel

syscall.c.diff

First set of fixes to handle syscalls for PPC target.
Still need work.

diff -urNbB -x CVS qemu-current/syscall.c qemu/syscall.c
--- qemu-current/syscall.c	Tue Nov 18 06:51:10 2003
+++ qemu/syscall.c	Tue Nov 11 01:06:31 2003
@@ -1265,6 +1265,15 @@
         new_env->regs[0] = 0;
 #elif defined(TARGET_SPARC)
 		printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+#elif defined(TARGET_PPC)
+        if (!newsp)
+            newsp = env->gpr[1];
+        new_env->gpr[1] = newsp;
+        { 
+            int i;
+            for (i = 7; i < 32; i++)
+                new_env->gpr[i] = 0;
+        }
 #else
 #error unsupported target CPU
 #endif
@@ -1472,9 +1481,11 @@
     case TARGET_NR_chmod:
         ret = get_errno(chmod((const char *)arg1, arg2));
         break;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_lchown:
         ret = get_errno(chown((const char *)arg1, arg2, arg3));
         break;
+#endif
 #ifdef TARGET_NR_break
     case TARGET_NR_break:
         goto unimplemented;
@@ -1495,12 +1506,14 @@
     case TARGET_NR_umount:
         ret = get_errno(umount((const char *)arg1));
         break;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_setuid:
         ret = get_errno(setuid(low2highuid(arg1)));
         break;
     case TARGET_NR_getuid:
         ret = get_errno(getuid());
         break;
+#endif
     case TARGET_NR_stime:
         {
             int *time_ptr = (int *)arg1;
@@ -1596,20 +1609,24 @@
     case TARGET_NR_prof:
         goto unimplemented;
 #endif
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_setgid:
         ret = get_errno(setgid(low2highgid(arg1)));
         break;
     case TARGET_NR_getgid:
         ret = get_errno(getgid());
         break;
+#endif
     case TARGET_NR_signal:
         goto unimplemented;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_geteuid:
         ret = get_errno(geteuid());
         break;
     case TARGET_NR_getegid:
         ret = get_errno(getegid());
         break;
+#endif
     case TARGET_NR_acct:
         goto unimplemented;
     case TARGET_NR_umount2:
@@ -1844,12 +1861,14 @@
         /* NOTE: ret is eax, so not transcoding must be done */
         ret = do_rt_sigreturn(cpu_env);
         break;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_setreuid:
         ret = get_errno(setreuid(arg1, arg2));
         break;
     case TARGET_NR_setregid:
         ret = get_errno(setregid(arg1, arg2));
         break;
+#endif
     case TARGET_NR_sethostname:
         ret = get_errno(sethostname((const char *)arg1, arg2));
         break;
@@ -1906,6 +1925,7 @@
             ret = get_errno(settimeofday(&tv, NULL));
         }
         break;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_getgroups:
         {
             int gidsetsize = arg1;
@@ -1934,6 +1954,7 @@
             ret = get_errno(setgroups(gidsetsize, grouplist));
         }
         break;
+#endif
     case TARGET_NR_select:
         {
             struct target_sel_arg_struct *sel = (void *)arg1;
@@ -2026,9 +2047,11 @@
     case TARGET_NR_fchmod:
         ret = get_errno(fchmod(arg1, arg2));
         break;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_fchown:
         ret = get_errno(fchown(arg1, arg2, arg3));
         break;
+#endif
     case TARGET_NR_getpriority:
         ret = get_errno(getpriority(arg1, arg2));
         break;
@@ -2119,12 +2142,18 @@
         do_stat:
             if (!is_error(ret)) {
                 struct target_stat *target_st = (void *)arg2;
-                target_st->st_dev = tswap16(st.st_dev);
-                target_st->st_ino = tswapl(st.st_ino);
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
                 target_st->st_mode = tswap16(st.st_mode);
-                target_st->st_nlink = tswap16(st.st_nlink);
                 target_st->st_uid = tswap16(st.st_uid);
                 target_st->st_gid = tswap16(st.st_gid);
+#elif defined(TARGET_PPC)
+                target_st->st_mode = tswapl(st.st_mode);
+                target_st->st_uid = tswap32(st.st_uid);
+                target_st->st_gid = tswap32(st.st_gid);
+#endif
+                target_st->st_dev = tswap16(st.st_dev);
+                target_st->st_ino = tswapl(st.st_ino);
+                target_st->st_nlink = tswap16(st.st_nlink);
                 target_st->st_rdev = tswap16(st.st_rdev);
                 target_st->st_size = tswapl(st.st_size);
                 target_st->st_blksize = tswapl(st.st_blksize);
@@ -2230,12 +2259,14 @@
         break;
     case TARGET_NR_afs_syscall:
         goto unimplemented;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_setfsuid:
         ret = get_errno(setfsuid(arg1));
         break;
     case TARGET_NR_setfsgid:
         ret = get_errno(setfsgid(arg1));
         break;
+#endif
     case TARGET_NR__llseek:
         {
             int64_t res;
@@ -2311,6 +2342,7 @@
         }
 #endif
         break;
+#ifdef TARGET_NR_getdents64
     case TARGET_NR_getdents64:
         {
             struct dirent64 *dirp = (void *)arg2;
@@ -2334,6 +2366,7 @@
             }
         }
         break;
+#endif /* TARGET_NR_getdents64 */
     case TARGET_NR__newselect:
         ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4, 
                         (void *)arg5);
@@ -2465,6 +2498,7 @@
             }
         }
         break;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
 #ifdef TARGET_NR_setresuid
     case TARGET_NR_setresuid:
         ret = get_errno(setresuid(low2highuid(arg1), 
@@ -2505,12 +2539,14 @@
         }
         break;
 #endif
+#endif
     case TARGET_NR_query_module:
         goto unimplemented;
     case TARGET_NR_nfsservctl:
         goto unimplemented;
     case TARGET_NR_prctl:
         goto unimplemented;
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_pread:
         page_unprotect_range((void *)arg2, arg3);
         ret = get_errno(pread(arg1, (void *)arg2, arg3, arg4));
@@ -2518,9 +2554,17 @@
     case TARGET_NR_pwrite:
         ret = get_errno(pwrite(arg1, (void *)arg2, arg3, arg4));
         break;
+#elif defined(TARGET_PPC)
+    case TARGET_NR_pread64:
+        goto unimplemented;
+    case TARGET_NR_pwrite64:
+        goto unimplemented;
+#endif
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_chown:
         ret = get_errno(chown((const char *)arg1, arg2, arg3));
         break;
+#endif
     case TARGET_NR_getcwd:
         ret = get_errno(sys_getcwd1((char *)arg1, arg2));
         break;
@@ -2573,6 +2617,7 @@
             if (!is_error(ret)) {
                 struct target_stat64 *target_st = (void *)arg2;
                 memset(target_st, 0, sizeof(struct target_stat64));
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
                 target_st->st_dev = tswap16(st.st_dev);
                 target_st->st_ino = tswap64(st.st_ino);
 #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
@@ -2590,10 +2635,26 @@
                 target_st->target_st_atime = tswapl(st.st_atime);
                 target_st->target_st_mtime = tswapl(st.st_mtime);
                 target_st->target_st_ctime = tswapl(st.st_ctime);
+#elif defined(TARGET_PPC)
+                target_st->st_dev = tswap64(st.st_dev);
+                target_st->st_ino = tswap64(st.st_ino);
+                target_st->st_mode = tswap32(st.st_mode);
+                target_st->st_nlink = tswap32(st.st_nlink);
+                target_st->st_uid = tswap32(st.st_uid);
+                target_st->st_gid = tswap32(st.st_gid);
+                target_st->st_rdev = tswap64(st.st_rdev);
+                target_st->st_size = tswap64(st.st_size);
+                target_st->st_blksize = tswapl(st.st_blksize);
+                target_st->st_blocks = tswap64(st.st_blocks);
+                target_st->target_st_atime = tswapl(st.st_atime);
+                target_st->target_st_mtime = tswapl(st.st_mtime);
+                target_st->target_st_ctime = tswapl(st.st_ctime);
+#endif
             }
         }
         break;
 
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
     case TARGET_NR_lchown32:
         ret = get_errno(lchown((const char *)arg1, arg2, arg3));
         break;
@@ -2665,12 +2726,91 @@
     case TARGET_NR_setfsgid32:
         ret = get_errno(setfsgid(arg1));
         break;
+#elif defined (TARGET_PPC)
+    case TARGET_NR_lchown:
+        ret = get_errno(lchown((const char *)arg1, arg2, arg3));
+        break;
+    case TARGET_NR_getuid:
+        ret = get_errno(getuid());
+        break;
+    case TARGET_NR_getgid:
+        ret = get_errno(getgid());
+        break;
+    case TARGET_NR_geteuid:
+        ret = get_errno(geteuid());
+        break;
+    case TARGET_NR_getegid:
+        ret = get_errno(getegid());
+        break;
+    case TARGET_NR_setreuid:
+        ret = get_errno(setreuid(arg1, arg2));
+        break;
+    case TARGET_NR_setregid:
+        ret = get_errno(setregid(arg1, arg2));
+        break;
+    case TARGET_NR_getgroups:
+        goto unimplemented;
+    case TARGET_NR_setgroups:
+        goto unimplemented;
+    case TARGET_NR_fchown:
+        ret = get_errno(fchown(arg1, arg2, arg3));
+        break;
+    case TARGET_NR_setresuid:
+        ret = get_errno(setresuid(arg1, arg2, arg3));
+        break;
+    case TARGET_NR_getresuid:
+        {
+            int ruid, euid, suid;
+            ret = get_errno(getresuid(&ruid, &euid, &suid));
+            if (!is_error(ret)) {
+                *(uint32_t *)arg1 = tswap32(ruid);
+                *(uint32_t *)arg2 = tswap32(euid);
+                *(uint32_t *)arg3 = tswap32(suid);
+            }
+        }
+        break;
+    case TARGET_NR_setresgid:
+        ret = get_errno(setresgid(arg1, arg2, arg3));
+        break;
+    case TARGET_NR_getresgid:
+        {
+            int rgid, egid, sgid;
+            ret = get_errno(getresgid(&rgid, &egid, &sgid));
+            if (!is_error(ret)) {
+                *(uint32_t *)arg1 = tswap32(rgid);
+                *(uint32_t *)arg2 = tswap32(egid);
+                *(uint32_t *)arg3 = tswap32(sgid);
+            }
+        }
+        break;
+    case TARGET_NR_chown:
+        ret = get_errno(chown((const char *)arg1, arg2, arg3));
+        break;
+    case TARGET_NR_setuid:
+        ret = get_errno(setuid(arg1));
+        break;
+    case TARGET_NR_setgid:
+        ret = get_errno(setgid(arg1));
+        break;
+    case TARGET_NR_setfsuid:
+        ret = get_errno(setfsuid(arg1));
+        break;
+    case TARGET_NR_setfsgid:
+        ret = get_errno(setfsgid(arg1));
+        break;
+#endif
+#ifdef TARGET_NR_pivot_root
     case TARGET_NR_pivot_root:
         goto unimplemented;
+#endif
+#ifdef TARGET_NR_mincore
     case TARGET_NR_mincore:
         goto unimplemented;
+#endif
+#ifdef TARGET_NR_madvise
     case TARGET_NR_madvise:
         goto unimplemented;
+#endif
 #if TARGET_LONG_BITS == 32
     case TARGET_NR_fcntl64:
     {

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (10 preceding siblings ...)
  2003-11-18  7:50   ` J. Mayer
@ 2003-11-18  7:50   ` J. Mayer
  2003-11-18  7:51   ` J. Mayer
                     ` (13 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:50 UTC (permalink / raw)
  To: qemu-devel

syscall_defs.h.diff

Changes for some syscalls for PPC target.

diff -urNbB -x CVS qemu-current/syscall_defs.h qemu/syscall_defs.h
--- qemu-current/syscall_defs.h	Tue Nov 18 06:51:10 2003
+++ qemu/syscall_defs.h	Tue Nov 11 00:17:08 2003
@@ -279,7 +279,7 @@
 int do_sigaction(int sig, const struct target_sigaction *act,
                  struct target_sigaction *oact);
 
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC)
 
 #define TARGET_SA_NOCLDSTOP	0x00000001
 #define TARGET_SA_NOCLDWAIT	0x00000002 /* not supported yet */
@@ -664,7 +664,7 @@
 #define TARGET_HDIO_SET_PIO_MODE      0x0327  /* reconfig interface to new speed */
 
 
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC)
 
 /* 0x54 is just a magic number to make these relatively unique ('T') */
 
@@ -891,6 +891,9 @@
 #define TARGET_MAP_LOCKED	0x2000		/* pages are locked */
 #define TARGET_MAP_NORESERVE	0x4000		/* don't check for reservations */
 
+#endif /* defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) */
+
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
 struct target_stat {
 	unsigned short st_dev;
 	unsigned short __pad1;
@@ -949,6 +952,61 @@
 	target_ulong	__pad7;		/* will be high 32 bits of ctime someday */
 
 	unsigned long long	st_ino;
+} __attribute__((packed));
+
+#elif defined(TARGET_PPC)
+
+struct target_stat {
+	unsigned short st_dev;
+	target_ulong st_ino;
+	unsigned int st_mode;
+	unsigned short st_nlink;
+	unsigned int st_uid;
+	unsigned int st_gid;
+	unsigned short st_rdev;
+	target_ulong  st_size;
+	target_ulong  st_blksize;
+	target_ulong  st_blocks;
+	target_ulong  target_st_atime;
+	target_ulong  __unused1;
+	target_ulong  target_st_mtime;
+	target_ulong  __unused2;
+	target_ulong  target_st_ctime;
+	target_ulong  __unused3;
+	target_ulong  __unused4;
+	target_ulong  __unused5;
+};
+
+struct target_stat64 {
+	unsigned long long st_dev;
+
+        unsigned long long st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	unsigned int st_uid;
+	unsigned int st_gid;
+
+	unsigned long long	st_rdev;
+	unsigned short int __pad2;
+
+	long long	st_size;
+	target_ulong	st_blksize;
+
+	long long	st_blocks;	/* Number 512-byte blocks allocated. */
+
+	target_ulong	target_st_atime;
+        target_ulong    target_st_atime_nsec;
+
+	target_ulong	target_st_mtime;
+        target_ulong    target_st_mtime_nsec;
+
+	target_ulong	target_st_ctime;
+        target_ulong    target_st_ctime_nsec;
+
+        target_ulong    __unused4;
+        target_ulong    __unused5;
 } __attribute__((packed));
 
 #endif /* defined(TARGET_I386) || defined(TARGET_ARM) */

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (11 preceding siblings ...)
  2003-11-18  7:50   ` J. Mayer
@ 2003-11-18  7:51   ` J. Mayer
  2003-11-18  7:53   ` J. Mayer
                     ` (12 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:51 UTC (permalink / raw)
  To: qemu-devel

target-ppc__cpu.h.diff

CPU definitions for PPC target.

diff -urNbB -x CVS qemu-current/target-ppc/cpu.h qemu/target-ppc/cpu.h
--- qemu-current/target-ppc/cpu.h	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/cpu.h	Tue Nov 18 06:40:52 2003
@@ -0,0 +1,407 @@
+/*
+ *  PPC emulation cpu definitions for qemu.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#if !defined (__CPU_PPC_H__)
+#define __CPU_PPC_H__
+
+#include <endian.h>
+#include <asm/byteorder.h>
+
+#include "cpu-defs.h"
+
+/***                          Sign extend constants                        ***/
+/* 8 to 32 bits */
+static inline int32_t s_ext8 (uint8_t value)
+{
+    int8_t *tmp = &value;
+
+    return *tmp;
+}
+
+/* 16 to 32 bits */
+static inline int32_t s_ext16 (uint16_t value)
+{
+    int16_t *tmp = &value;
+
+    return *tmp;
+}
+
+/* 24 to 32 bits */
+static inline int32_t s_ext24 (uint32_t value)
+{
+    uint16_t utmp = (value >> 8) & 0xFFFF;
+    int16_t *tmp = &utmp;
+
+    return (*tmp << 8) | (value & 0xFF);
+}
+
+#include "config.h"
+#include <setjmp.h>
+
+/* Floting point status and control register */
+#define FPSCR_FX     31
+#define FPSCR_FEX    30
+#define FPSCR_VX     29
+#define FPSCR_OX     28
+#define FPSCR_UX     27
+#define FPSCR_ZX     26
+#define FPSCR_XX     25
+#define FPSCR_VXSNAN 24
+#define FPSCR_VXISI  26
+#define FPSCR_VXIDI  25
+#define FPSCR_VXZDZ  21
+#define FPSCR_VXIMZ  20
+
+#define FPSCR_VXVC   18
+#define FPSCR_FR     17
+#define FPSCR_FI     16
+#define FPSCR_FPRF   11
+#define FPSCR_VXSOFT 9
+#define FPSCR_VXSQRT 8
+#define FPSCR_VXCVI  7
+#define FPSCR_OE     6
+#define FPSCR_UE     5
+#define FPSCR_ZE     4
+#define FPSCR_XE     3
+#define FPSCR_NI     2
+#define FPSCR_RN     0
+#define fpscr_fx     env->fpscr[FPSCR_FX]
+#define fpscr_fex    env->fpscr[FPSCR_FEX]
+#define fpscr_vx     env->fpscr[FPSCR_VX]
+#define fpscr_ox     env->fpscr[FPSCR_OX]
+#define fpscr_ux     env->fpscr[FPSCR_UX]
+#define fpscr_zx     env->fpscr[FPSCR_ZX]
+#define fpscr_xx     env->fpscr[FPSCR_XX]
+#define fpscr_vsxnan env->fpscr[FPSCR_VXSNAN]
+#define fpscr_vxisi  env->fpscr[FPSCR_VXISI]
+#define fpscr_vxidi  env->fpscr[FPSCR_VXIDI]
+#define fpscr_vxzdz  env->fpscr[FPSCR_VXZDZ]
+#define fpscr_vximz  env->fpscr[FPSCR_VXIMZ]
+#define fpscr_fr     env->fpscr[FPSCR_FR]
+#define fpscr_fi     env->fpscr[FPSCR_FI]
+#define fpscr_fprf   env->fpscr[FPSCR_FPRF]
+#define fpscr_vxsoft env->fpscr[FPSCR_VXSOFT]
+#define fpscr_vxsqrt env->fpscr[FPSCR_VXSQRT]
+#define fpscr_oe     env->fpscr[FPSCR_OE]
+#define fpscr_ue     env->fpscr[FPSCR_UE]
+#define fpscr_ze     env->fpscr[FPSCR_ZE]
+#define fpscr_xe     env->fpscr[FPSCR_XE]
+#define fpscr_ni     env->fpscr[FPSCR_NI]
+#define fpscr_rn     env->fpscr[FPSCR_RN]
+
+/* Supervisor mode registers */
+/* Machine state register */
+#define MSR_POW 18
+#define MSR_ILE 16
+#define MSR_EE  15
+#define MSR_PR  14
+#define MSR_FP  13
+#define MSR_ME  12
+#define MSR_FE0 11
+#define MSR_SE  10
+#define MSR_BE  9
+#define MSR_FE1 8
+#define MSR_IP 6
+#define MSR_IR 5
+#define MSR_DR 4
+#define MSR_RI 1
+#define MSR_LE 0
+#define msr_pow env->msr[MSR_POW]
+#define msr_ile env->msr[MSR_ILE]
+#define msr_ee  env->msr[MSR_EE]
+#define msr_pr  env->msr[MSR_PR]
+#define msr_fp  env->msr[MSR_FP]
+#define msr_me  env->msr[MSR_ME]
+#define msr_fe0 env->msr[MSR_FE0]
+#define msr_se  env->msr[MSR_SE]
+#define msr_be  env->msr[MSR_BE]
+#define msr_fe1 env->msr[MSR_FE1]
+#define msr_ip  env->msr[MSR_IP]
+#define msr_ir  env->msr[MSR_IR]
+#define msr_dr  env->msr[MSR_DR]
+#define msr_ri  env->msr[MSR_RI]
+#define msr_le  env->msr[MSR_LE]
+
+/* Segment registers */
+typedef struct ppc_sr_t {
+    uint32_t t:1;
+    uint32_t ks:1;
+    uint32_t kp:1;
+    uint32_t n:1;
+    uint32_t res:4;
+    uint32_t vsid:24;
+} ppc_sr_t;
+
+typedef struct CPUPPCState {
+    /* general purpose registers */
+    uint32_t gpr[32];
+    /* floating point registers */
+    uint64_t fpr[32];
+    /* segment registers */
+    ppc_sr_t sr[16];
+    /* special purpose registers */
+    uint32_t spr[1024];
+    /* XER */
+    uint8_t xer[32];
+    /* Reservation address */
+    uint32_t reserve;
+    /* machine state register */
+    uint8_t msr[32];
+    /* condition register */
+    uint8_t crf[8];
+    /* floating point status and control register */
+    uint8_t fpscr[32];
+    uint32_t nip;
+    /* CPU exception code */
+    uint32_t exception;
+
+    /* qemu dedicated */
+    int interrupt_request;
+    jmp_buf jmp_env;
+    int exception_index;
+    int error_code;
+    int user_mode_only; /* user mode only simulation */
+    struct TranslationBlock *current_tb; /* currently executing TB */
+
+    /* user data */
+    void *opaque;
+} CPUPPCState;
+
+CPUPPCState *cpu_ppc_init(void);
+int cpu_ppc_exec(CPUPPCState *s);
+void cpu_ppc_close(CPUPPCState *s);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+   signal handlers to inform the virtual CPU of exceptions. non zero
+   is returned if the signal was handled by the virtual CPU.  */
+struct siginfo;
+int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, 
+                           void *puc);
+
+void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags);
+
+#define TARGET_PAGE_BITS 12
+#include "cpu-all.h"
+
+#define ugpr(n) (env->gpr[n])
+#define fpr(n) (env->fpr[n])
+
+#define SPR_ENCODE(sprn)                               \
+(((sprn) >> 5) | (((sprn) & 0x1F) << 5))
+
+/* User mode SPR */
+#define spr(n) env->spr[n]
+//#define XER    spr[1]
+#define XER env->xer
+#define XER_SO 31
+#define XER_OV 30
+#define XER_CA 29
+#define XER_BC 0
+#define xer_so env->xer[XER_SO]
+#define xer_ov env->xer[XER_OV]
+#define xer_ca env->xer[XER_CA]
+#define xer_bc env->xer[XER_BC]
+
+#define LR     spr[SPR_ENCODE(8)]
+#define CTR    spr[SPR_ENCODE(9)]
+/* VEA mode SPR */
+#define V_TBL  spr[SPR_ENCODE(268)]
+#define V_TBU  spr[SPR_ENCODE(269)]
+/* supervisor mode SPR */
+#define DSISR  spr[SPR_ENCODE(18)]
+#define DAR    spr[SPR_ENCODE(19)]
+#define DEC    spr[SPR_ENCODE(22)]
+#define SDR1   spr[SPR_ENCODE(25)]
+typedef struct ppc_sdr1_t {
+    uint32_t htaborg:16;
+    uint32_t res:7;
+    uint32_t htabmask:9;
+} ppc_sdr1_t;
+#define SRR0   spr[SPR_ENCODE(26)]
+#define SRR0_MASK 0xFFFFFFFC
+#define SRR1   spr[SPR_ENCODE(27)]
+#define SPRG0  spr[SPR_ENCODE(272)]
+#define SPRG1  spr[SPR_ENCODE(273)]
+#define SPRG2  spr[SPR_ENCODE(274)]
+#define SPRG3  spr[SPR_ENCODE(275)]
+#define EAR    spr[SPR_ENCODE(282)]
+typedef struct ppc_ear_t {
+    uint32_t e:1;
+    uint32_t res:25;
+    uint32_t rid:6;
+} ppc_ear_t;
+#define TBL    spr[SPR_ENCODE(284)]
+#define TBU    spr[SPR_ENCODE(285)]
+#define PVR    spr[SPR_ENCODE(287)]
+typedef struct ppc_pvr_t {
+    uint32_t version:16;
+    uint32_t revision:16;
+} ppc_pvr_t;
+#define IBAT0U spr[SPR_ENCODE(528)]
+#define IBAT0L spr[SPR_ENCODE(529)]
+#define IBAT1U spr[SPR_ENCODE(530)]
+#define IBAT1L spr[SPR_ENCODE(531)]
+#define IBAT2U spr[SPR_ENCODE(532)]
+#define IBAT2L spr[SPR_ENCODE(533)]
+#define IBAT3U spr[SPR_ENCODE(534)]
+#define IBAT3L spr[SPR_ENCODE(535)]
+#define DBAT0U spr[SPR_ENCODE(536)]
+#define DBAT0L spr[SPR_ENCODE(537)]
+#define DBAT1U spr[SPR_ENCODE(538)]
+#define DBAT1L spr[SPR_ENCODE(539)]
+#define DBAT2U spr[SPR_ENCODE(540)]
+#define DBAT2L spr[SPR_ENCODE(541)]
+#define DBAT3U spr[SPR_ENCODE(542)]
+#define DBAT3L spr[SPR_ENCODE(543)]
+typedef struct ppc_ubat_t {
+    uint32_t bepi:15;
+    uint32_t res:4;
+    uint32_t bl:11;
+    uint32_t vs:1;
+    uint32_t vp:1;
+} ppc_ubat_t;
+typedef struct ppc_lbat_t {
+    uint32_t brpn:15;
+    uint32_t res0:10;
+    uint32_t w:1;
+    uint32_t i:1;
+    uint32_t m:1;
+    uint32_t g:1;
+    uint32_t res1:1;
+    uint32_t pp:2;
+} ppc_lbat_t;
+#define DABR   spr[SPR_ENCODE(1013)]
+#define DABR_MASK 0xFFFFFFF8
+typedef struct ppc_dabr_t {
+    uint32_t dab:29;
+    uint32_t bt:1;
+    uint32_t dw:1;
+    uint32_t dr:1;
+} ppc_dabr_t;
+#define FPECR  spr[SPR_ENCODE(1022)]
+#define PIR    spr[SPR_ENCODE(1023)]
+
+#define TARGET_PAGE_BITS 12
+#include "cpu-all.h"
+
+CPUPPCState *cpu_ppc_init(void);
+int cpu_ppc_exec(CPUPPCState *s);
+void cpu_ppc_close(CPUPPCState *s);
+void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags);
+
+/* Exeptions */
+enum {
+    EXCP_NONE          = 0x00,
+    /* PPC hardware exceptions : exception vector / 0x100 */
+    EXCP_RESET         = 0x01, /* System reset                     */
+    EXCP_MACHINE_CHECK = 0x02, /* Machine check exception          */
+    EXCP_DSI           = 0x03, /* Impossible memory access         */
+    EXCP_ISI           = 0x04, /* Impossible instruction fetch     */
+    EXCP_EXTERNAL      = 0x05, /* External interruption            */
+    EXCP_ALIGN         = 0x06, /* Alignment exception              */
+    EXCP_PROGRAM       = 0x07, /* Program exception                */
+    EXCP_NO_FP         = 0x08, /* No floating point                */
+    EXCP_DECR          = 0x09, /* Decrementer exception            */
+    EXCP_RESA          = 0x0A, /* Implementation specific          */
+    EXCP_RESB          = 0x0B, /* Implementation specific          */
+    EXCP_SYSCALL       = 0x0C, /* System call                      */
+    EXCP_TRACE         = 0x0D, /* Trace exception (optional)       */
+    EXCP_FP_ASSIST     = 0x0E, /* Floating-point assist (optional) */
+#if 0
+    /* Exeption subtypes for EXCP_DSI */
+    EXCP_DSI_TRANSLATE = 0x10301, /* Data address can't be translated */
+    EXCP_DSI_NOTSUP    = 0x10302, /* Access type not supported        */
+    EXCP_DSI_PROT      = 0x10303, /* Memory protection violation      */
+    EXCP_DSI_EXTERNAL  = 0x10304, /* External access disabled         */
+    EXCP_DSI_DABR      = 0x10305, /* Data address breakpoint          */
+    /* Exeption subtypes for EXCP_ISI */
+    EXCP_ISI_TRANSLATE = 0x10401, /* Code address can't be translated */
+    EXCP_ISI_NOTSUP    = 0x10402, /* Access type not supported        */
+    EXCP_ISI_PROT      = 0x10403, /* Memory protection violation      */
+    EXCP_ISI_GUARD     = 0x10404, /* Fetch into guarded memory        */
+    /* Exeption subtypes for EXCP_ALIGN */
+    EXCP_ALIGN_FP      = 0x10601, /* FP alignment exception           */
+    EXCP_ALIGN_LST     = 0x10602, /* Unaligned memory load/store      */
+    EXCP_ALIGN_LE      = 0x10603, /* Unaligned little-endian access   */
+    EXCP_ALIGN_PROT    = 0x10604, /* Access cross protection boundary */
+    EXCP_ALIGN_BAT     = 0x10605, /* Access cross a BAT/seg boundary  */
+    EXCP_ALIGN_CACHE   = 0x10606, /* Impossible dcbz access           */
+    /* Exeption subtypes for EXCP_PROGRAM */
+    /* FP exceptions */
+    EXCP_FP_OX         = 0x10701, /* FP overflow                      */
+    EXCP_FP_UX         = 0x10702, /* FP underflow                     */
+    EXCP_FP_ZX         = 0x10703, /* FP divide by zero                */
+    EXCP_FP_XX         = 0x10704, /* FP inexact                       */
+    EXCP_FP_VXNAN      = 0x10705, /* FP invalid SNaN op               */
+    EXCP_FP_VXISI      = 0x10706, /* FP invalid infinite substraction */
+    EXCP_FP_VXIDI      = 0x10707, /* FP invalid infinite divide       */
+    EXCP_FP_VXZDZ      = 0x10708, /* FP invalid zero divide           */
+    EXCP_FP_VXIMZ      = 0x10709, /* FP invalid infinite * zero       */
+    EXCP_FP_VXVC       = 0x1070A, /* FP invalid compare               */
+    EXCP_FP_VXSOFT     = 0x1070B, /* FP invalid operation             */
+    EXCP_FP_VXSQRT     = 0x1070C, /* FP invalid square root           */
+    EXCP_FP_VXCVI      = 0x1070D, /* FP invalid integer conversion    */
+    /* Invalid instruction */
+    EXCP_INVAL_INVAL   = 0x10711, /* Invalid instruction              */
+    EXCP_INVAL_LSWX    = 0x10712, /* Invalid lswx instruction         */
+    EXCP_INVAL_SPR     = 0x10713, /* Invalid SPR access               */
+    EXCP_INVAL_FP      = 0x10714, /* Unimplemented mandatory fp instr */
+#endif
+    EXCP_INVAL         = 0x70,    /* Invalid instruction              */
+    /* Privileged instruction */
+    EXCP_PRIV          = 0x71,    /* Privileged instruction           */
+    /* Trap */
+    EXCP_TRAP          = 0x72,    /* Trap                             */
+    /* Special cases where we want to stop translation */
+    EXCP_MTMSR         = 0x103,   /* mtmsr instruction:               */
+                                  /* may change privilege level       */
+    EXCP_BRANCH        = 0x104,   /* branch instruction               */
+};
+
+/*
+ * We need to put in some extra aux table entries to tell glibc what
+ * the cache block size is, so it can use the dcbz instruction safely.
+ */
+#define AT_DCACHEBSIZE          19
+#define AT_ICACHEBSIZE          20
+#define AT_UCACHEBSIZE          21
+/* A special ignored type value for PPC, for glibc compatibility.  */
+#define AT_IGNOREPPC            22
+/*
+ * The requirements here are:
+ * - keep the final alignment of sp (sp & 0xf)
+ * - make sure the 32-bit value at the first 16 byte aligned position of
+ *   AUXV is greater than 16 for glibc compatibility.
+ *   AT_IGNOREPPC is used for that.
+ * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
+ *   even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
+ */
+#define DLINFO_ARCH_ITEMS       3
+#define ARCH_DLINFO                                                     \
+do {                                                                    \
+        /*                                                              \
+         * Now handle glibc compatibility.                              \
+         */                                                             \
+        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
+        NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);                        \
+                                                                        \
+        NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20);                              \
+        NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20);                              \
+        NEW_AUX_ENT(AT_UCACHEBSIZE, 0);                                 \
+ } while (0)
+#endif /* !defined (__CPU_PPC_H__) */

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (12 preceding siblings ...)
  2003-11-18  7:51   ` J. Mayer
@ 2003-11-18  7:53   ` J. Mayer
  2003-11-18  7:54   ` J. Mayer
                     ` (11 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:53 UTC (permalink / raw)
  To: qemu-devel

target-ppc__exec.h.diff

inline helpers and definitions for PPC emulation.
Some of those helpers are redundant with qemu ones
and need to be replaced (ldxx & stxx)...

diff -urNbB -x CVS qemu-current/target-ppc/exec.h qemu/target-ppc/exec.h
--- qemu-current/target-ppc/exec.h	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/exec.h	Tue Nov 11 01:15:08 2003
@@ -0,0 +1,157 @@
+/*
+ *  PPC emulation definitions for qemu.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#if !defined (__PPC_H__)
+#define __PPC_H__
+
+#include "dyngen-exec.h"
+
+register struct CPUPPCState *env asm(AREG0);
+register uint32_t T0 asm(AREG1);
+register uint32_t T1 asm(AREG2);
+register uint32_t T2 asm(AREG3);
+
+#define PARAM(n) ((uint32_t)PARAM##n)
+#define SPARAM(n) ((int32_t)PARAM##n)
+
+#define RETURN() __asm__ __volatile__("");
+
+#include "cpu.h"
+#include "exec-all.h"
+
+static inline uint8_t ld8 (uint32_t EA)
+{
+    return *((uint8_t *)EA);
+}
+
+static inline uint16_t ld16 (uint32_t EA)
+{
+    return __be16_to_cpu(*((uint16_t *)EA));
+}
+
+static inline uint16_t ld16r (uint32_t EA)
+{
+    return __le16_to_cpu(*((uint16_t *)EA));
+}
+
+static inline uint32_t ld32 (uint32_t EA)
+{
+    return __be32_to_cpu(*((uint32_t *)EA));
+}
+
+static inline uint32_t ld32r (uint32_t EA)
+{
+    return __le32_to_cpu(*((uint32_t *)EA));
+}
+
+static inline uint64_t ld64 (uint32_t EA)
+{
+    return __be64_to_cpu(*((uint64_t *)EA));
+}
+
+static inline uint64_t ld64r (uint32_t EA)
+{
+    return __le64_to_cpu(*((uint64_t *)EA));
+}
+
+static inline void st8 (uint32_t EA, uint8_t data)
+{
+    *((uint8_t *)EA) = data;
+}
+
+static inline void st16 (uint32_t EA, uint16_t data)
+{
+    *((uint16_t *)EA) = __cpu_to_be16(data);
+}
+
+static inline void st16r (uint32_t EA, uint16_t data)
+{
+    *((uint16_t *)EA) = __cpu_to_le16(data);
+}
+
+static inline void st32 (uint32_t EA, uint32_t data)
+{
+    *((uint32_t *)EA) = __cpu_to_be32(data);
+}
+
+static inline void st32r (uint32_t EA, uint32_t data)
+{
+    *((uint32_t *)EA) = __cpu_to_le32(data);
+}
+
+static inline void st64 (uint32_t EA, uint64_t data)
+{
+    *((uint64_t *)EA) = __cpu_to_be64(data);
+}
+
+static inline void st64r (uint32_t EA, uint64_t data)
+{
+    *((uint64_t *)EA) = __cpu_to_le64(data);
+}
+
+static inline void set_CRn(int n, uint8_t value)
+{
+    env->crf[n] = value;
+}
+
+static inline void set_carry (void)
+{
+    xer_ca = 1;
+}
+
+static inline void reset_carry (void)
+{
+    xer_ca = 0;
+}
+
+static inline void set_overflow (void)
+{
+    xer_so = 1;
+    xer_ov = 1;
+}
+
+static inline void reset_overflow (void)
+{
+    xer_ov = 0;
+}
+
+static inline uint32_t rotl (uint32_t i, int n)
+{
+    return ((i << n) | (i >> (32 - n)));
+}
+
+void raise_exception (int exception_index);
+void raise_exception_err (int exception_index, int error_code);
+
+uint32_t do_load_cr (void);
+void do_store_cr (uint32_t crn, uint32_t value);
+uint32_t do_load_xer (void);
+void do_store_xer (uint32_t value);
+uint32_t do_load_msr (void);
+void do_store_msr (uint32_t msr_value);
+uint32_t do_load_fpscr (void);
+void do_store_fpscr (uint8_t mask, uint32_t fp);
+
+int32_t do_sraw(int32_t Ta, uint32_t Tb);
+void do_lmw (int reg, uint32_t src);
+void do_stmw (int reg, uint32_t dest);
+void do_lsw (uint32_t reg, int count, uint32_t src);
+void do_stsw (uint32_t reg, int count, uint32_t dest);
+
+#endif /* !defined (__PPC_H__) */

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (13 preceding siblings ...)
  2003-11-18  7:53   ` J. Mayer
@ 2003-11-18  7:54   ` J. Mayer
  2003-11-18  7:55   ` J. Mayer
                     ` (10 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:54 UTC (permalink / raw)
  To: qemu-devel

target-ppc__helper.c.diff

helpers for PPC target: operations that are too complex to be
implemented as micro-ops.

diff -urNbB -x CVS qemu-current/target-ppc/helper.c qemu/target-ppc/helper.c
--- qemu-current/target-ppc/helper.c	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/helper.c	Wed Nov 12 10:29:37 2003
@@ -0,0 +1,262 @@
+/*
+ *  PPC emulation helpers for qemu.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "exec.h"
+
+extern FILE *logfile;
+
+void cpu_loop_exit(void)
+{
+    longjmp(env->jmp_env, 1);
+}
+
+/* shortcuts to generate exceptions */
+void raise_exception_err (int exception_index, int error_code)
+{
+    env->exception_index = exception_index;
+    env->error_code = error_code;
+
+    cpu_loop_exit();
+}
+
+void raise_exception (int exception_index)
+{
+    env->exception_index = exception_index;
+    env->error_code = 0;
+
+    cpu_loop_exit();
+}
+
+/* Helpers for "fat" micro operations */
+uint32_t do_load_cr (void)
+{
+    return (env->crf[0] << 28) |
+        (env->crf[1] << 24) |
+        (env->crf[2] << 20) |
+        (env->crf[3] << 16) |
+        (env->crf[4] << 12) |
+        (env->crf[5] << 8) |
+        (env->crf[6] << 4) |
+        (env->crf[7] << 0);
+}
+
+void do_store_cr (uint32_t crn, uint32_t value)
+{
+    int i, sh;
+
+    for (i = 0, sh = 7; i < 8; i++, sh --) {
+        if (crn & (1 << sh))
+            env->crf[i] = (value >> (sh * 4)) & 0xF;
+    }
+}
+
+uint32_t do_load_xer (void)
+{
+    return (xer_so << XER_SO) |
+        (xer_ov << XER_OV) |
+        (xer_ca << XER_CA) |
+        (xer_bc << XER_BC);
+}
+
+void do_store_xer (uint32_t value)
+{
+    xer_so = (value >> XER_SO) & 0x01;
+    xer_ov = (value >> XER_OV) & 0x01;
+    xer_ca = (value >> XER_CA) & 0x01;
+    xer_bc = (value >> XER_BC) & 0x1f;
+}
+
+uint32_t do_load_msr (void)
+{
+    return (msr_pow << MSR_POW) |
+        (msr_ile << MSR_ILE) |
+        (msr_ee << MSR_EE) |
+        (msr_pr << MSR_PR) |
+        (msr_fp << MSR_FP) |
+        (msr_me << MSR_ME) |
+        (msr_fe0 << MSR_FE0) |
+        (msr_se << MSR_SE) |
+        (msr_be << MSR_BE) |
+        (msr_fe1 << MSR_FE1) |
+        (msr_ip << MSR_IP) |
+        (msr_ir << MSR_IR) |
+        (msr_dr << MSR_DR) |
+        (msr_ri << MSR_RI) |
+        (msr_le << MSR_LE);
+}
+
+void do_store_msr (uint32_t msr_value)
+{
+    msr_pow = (msr_value >> MSR_POW) & 0x03;
+    msr_ile = (msr_value >> MSR_ILE) & 0x01;
+    msr_ee = (msr_value >> MSR_EE) & 0x01;
+    msr_pr = (msr_value >> MSR_PR) & 0x01;
+    msr_fp = (msr_value >> MSR_FP) & 0x01;
+    msr_me = (msr_value >> MSR_ME) & 0x01;
+    msr_fe0 = (msr_value >> MSR_FE0) & 0x01;
+    msr_se = (msr_value >> MSR_SE) & 0x01;
+    msr_be = (msr_value >> MSR_BE) & 0x01;
+    msr_fe1 = (msr_value >> MSR_FE1) & 0x01;
+    msr_ip = (msr_value >> MSR_IP) & 0x01;
+    msr_ir = (msr_value >> MSR_IR) & 0x01;
+    msr_dr = (msr_value >> MSR_DR) & 0x01;
+    msr_ri = (msr_value >> MSR_RI) & 0x01;
+    msr_le = (msr_value >> MSR_LE) & 0x01;
+}
+
+/* The 32 MSB of the target fpr are undefined. They'll be zero... */
+uint32_t do_load_fpscr (void)
+{
+    return (fpscr_fx  << FPSCR_FX) |
+        (fpscr_fex    << FPSCR_FEX) |
+        (fpscr_vx     << FPSCR_VX) |
+        (fpscr_ox     << FPSCR_OX) |
+        (fpscr_ux     << FPSCR_UX) |
+        (fpscr_zx     << FPSCR_ZX) |
+        (fpscr_xx     << FPSCR_XX) |
+        (fpscr_vsxnan << FPSCR_VXSNAN) |
+        (fpscr_vxisi  << FPSCR_VXISI) |
+        (fpscr_vxidi  << FPSCR_VXIDI) |
+        (fpscr_vxzdz  << FPSCR_VXZDZ) |
+        (fpscr_vximz  << FPSCR_VXIMZ) |
+        (fpscr_fr     << FPSCR_FR) |
+        (fpscr_fi     << FPSCR_FI) |
+        (fpscr_fprf   << FPSCR_FPRF) |
+        (fpscr_vxsoft << FPSCR_VXSOFT) |
+        (fpscr_vxsqrt << FPSCR_VXSQRT) |
+        (fpscr_oe     << FPSCR_OE) |
+        (fpscr_ue     << FPSCR_UE) |
+        (fpscr_ze     << FPSCR_ZE) |
+        (fpscr_xe     << FPSCR_XE) |
+        (fpscr_ni     << FPSCR_NI) |
+        (fpscr_rn     << FPSCR_RN);
+}
+
+/* We keep only 32 bits of input... */
+/* For now, this is COMPLETELY BUGGY ! */
+void do_store_fpscr (uint8_t mask, uint32_t fp)
+{
+    int i;
+
+    for (i = 0; i < 7; i++) {
+        if ((mask & (1 << i)) == 0)
+            fp &= ~(0xf << (4 * i));
+    }
+    if ((mask & 80) != 0)
+        fpscr_fx = (fp >> FPSCR_FX) & 0x01;
+    fpscr_fex = (fp >> FPSCR_FEX) & 0x01;
+    fpscr_vx = (fp >> FPSCR_VX) & 0x01;
+    fpscr_ox = (fp >> FPSCR_OX) & 0x01;
+    fpscr_ux = (fp >> FPSCR_UX) & 0x01;
+    fpscr_zx = (fp >> FPSCR_ZX) & 0x01;
+    fpscr_xx = (fp >> FPSCR_XX) & 0x01;
+    fpscr_vsxnan = (fp >> FPSCR_VXSNAN) & 0x01;
+    fpscr_vxisi = (fp >> FPSCR_VXISI) & 0x01;
+    fpscr_vxidi = (fp >> FPSCR_VXIDI) & 0x01;
+    fpscr_vxzdz = (fp >> FPSCR_VXZDZ) & 0x01;
+    fpscr_vximz = (fp >> FPSCR_VXIMZ) & 0x01;
+    fpscr_fr = (fp >> FPSCR_FR) & 0x01;
+    fpscr_fi = (fp >> FPSCR_FI) & 0x01;
+    fpscr_fprf = (fp >> FPSCR_FPRF) & 0x1F;
+    fpscr_vxsoft = (fp >> FPSCR_VXSOFT) & 0x01;
+    fpscr_vxsqrt = (fp >> FPSCR_VXSQRT) & 0x01;
+    fpscr_oe = (fp >> FPSCR_OE) & 0x01;
+    fpscr_ue = (fp >> FPSCR_UE) & 0x01;
+    fpscr_ze = (fp >> FPSCR_ZE) & 0x01;
+    fpscr_xe = (fp >> FPSCR_XE) & 0x01;
+    fpscr_ni = (fp >> FPSCR_NI) & 0x01;
+    fpscr_rn = (fp >> FPSCR_RN) & 0x03;
+}
+
+int32_t do_sraw(int32_t value, uint32_t shift)
+{
+    int32_t ret;
+
+    xer_ca = 0;
+    if (shift & 0x20) {
+        ret = (-1) * ((uint32_t)value >> 31);
+        if (ret < 0)
+            xer_ca = 1;
+    } else {
+        ret = value >> (shift & 0x1f);
+        if (ret < 0 && (value & ((1 << shift) - 1)) != 0)
+            xer_ca = 1;
+    }
+
+    return ret;
+}
+
+void do_lmw (int reg, uint32_t src)
+{
+    for (; reg <= 31; reg++, src += 4)
+        ugpr(reg) = ld32(src);
+}
+
+void do_stmw (int reg, uint32_t dest)
+{
+    for (; reg <= 31; reg++, dest += 4)
+        st32(dest, ugpr(reg));
+}
+
+void do_lsw (uint32_t reg, int count, uint32_t src)
+{
+    uint32_t tmp;
+    int sh;
+    
+    for (; count > 3; count -= 4, src += 4) {
+        if (reg == 32)
+            reg = 0;
+        ugpr(reg++) = ld32(src);
+    }
+    if (count > 0) {
+        for (sh = 24, tmp = 0; count > 0; count--, src++, sh -= 8) {
+            if (reg == 32)
+                reg = 0;
+            tmp |= ld8(src) << sh;
+            if (sh == 0) {
+                sh = 32;
+                ugpr(reg++) = tmp;
+                tmp = 0;
+            }
+        }
+        ugpr(reg) = tmp;
+    }
+}
+
+void do_stsw (uint32_t reg, int count, uint32_t dest)
+{
+    int sh;
+
+    for (; count > 3; count -= 4, dest += 4) {
+        if (reg == 32)
+            reg = 0;
+        st32(dest, ugpr(reg++));
+    }
+    if (count > 0) {
+        for (sh = 24; count > 0; count--, dest++, sh -= 8) {
+            if (reg == 32)
+                reg = 0;
+            st8(dest, (ugpr(reg) >> sh) & 0xFF);
+            if (sh == 0) {
+                sh = 32;
+                reg++;
+            }
+        }
+    }
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (14 preceding siblings ...)
  2003-11-18  7:54   ` J. Mayer
@ 2003-11-18  7:55   ` J. Mayer
  2003-11-18  7:56   ` J. Mayer
                     ` (9 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:55 UTC (permalink / raw)
  To: qemu-devel

target-ppc__op.c.diff

Micro-operations for PPC emulation.

diff -urNbB -x CVS qemu-current/target-ppc/op.c qemu/target-ppc/op.c
--- qemu-current/target-ppc/op.c	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/op.c	Tue Nov 11 01:11:33 2003
@@ -0,0 +1,1116 @@
+/*
+ *  PPC emulation micro-operations for qemu.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include "exec.h"
+
+#define regs (env)
+extern uint32_t __a;
+extern uint32_t __b;
+extern uint32_t __c;
+extern uint32_t __d;
+extern uint32_t __e;
+extern uint32_t __f;
+#define Ts0 (int32_t)T0
+#define Ts1 (int32_t)T1
+#define Ts2 (int32_t)T2
+
+#include "op-multi.c"
+
+#define PPC_OP(name) void op_##name(void)
+
+/* PPC state maintenance operations */
+/* set_Rc0 */
+PPC_OP(set_Rc0)
+{
+    uint32_t tmp;
+
+    if (Ts0 < 0) {
+        tmp = 0x08;
+    } else if (Ts0 > 0) {
+        tmp = 0x04;
+    } else {
+        tmp = 0x02;
+    }
+    set_CRn(0, tmp);
+    RETURN();
+}
+
+PPC_OP(set_Rc0_ov)
+{
+    uint32_t tmp;
+
+    if (Ts0 < 0) {
+        tmp = 0x08;
+    } else if (Ts0 > 0) {
+        tmp = 0x04;
+    } else {
+        tmp = 0x02;
+    }
+    tmp |= xer_ov;
+    set_CRn(0, tmp);
+    RETURN();
+}
+
+/* reset_Rc0 */
+PPC_OP(reset_Rc0)
+{
+    set_CRn(0, 0x02 | xer_ov);
+    RETURN();
+}
+
+/* set_Rc0_1 */
+PPC_OP(set_Rc0_1)
+{
+    set_CRn(0, 0x04 | xer_ov);
+    RETURN();
+}
+
+PPC_OP(set_T0)
+{
+    T0 = PARAM(1);
+    RETURN();
+}
+
+PPC_OP(set_T1)
+{
+    T1 = PARAM(1);
+    RETURN();
+}
+
+PPC_OP(set_T2)
+{
+    T2 = PARAM(1);
+    RETURN();
+}
+
+/* Update time base */
+PPC_OP(update_tb)
+{
+    T0 = regs->spr[SPR_ENCODE(268)];
+    T1 = T0;
+    T0 += PARAM(1);
+    if (T0 < T1) {
+        T1 = regs->spr[SPR_ENCODE(269)] + 1;
+        regs->spr[SPR_ENCODE(269)] = T1;
+    }
+    regs->spr[SPR_ENCODE(268)] = T0;
+    RETURN();
+}
+
+PPC_OP(raise_exception)
+{
+    raise_exception(PARAM(1));
+    RETURN();
+}
+
+PPC_OP(exit_tb)
+{
+    EXIT_TB();
+}
+
+PPC_OP(load_cr)
+{
+    T0 = do_load_cr();
+    RETURN();
+}
+
+PPC_OP(store_cr)
+{
+    do_store_cr(PARAM(1), T0);
+    RETURN();
+}
+
+PPC_OP(load_xer_cr)
+{
+    T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1);
+    RETURN();
+}
+
+PPC_OP(clear_xer_cr)
+{
+    xer_so = 0;
+    xer_ov = 0;
+    xer_ca = 0;
+    RETURN();
+}
+
+PPC_OP(load_xer_bc)
+{
+    T0 = xer_bc;
+    RETURN();
+}
+
+PPC_OP(load_xer)
+{
+    T0 = do_load_xer();
+    RETURN();
+}
+
+PPC_OP(store_xer)
+{
+    do_store_xer(T0);
+    RETURN();
+}
+
+PPC_OP(load_msr)
+{
+    T0 = do_load_msr();
+    RETURN();
+}
+
+PPC_OP(store_msr)
+{
+    do_store_msr(T0);
+    RETURN();
+}
+
+PPC_OP(load_lr)
+{
+    regs->LR = PARAM(1);
+    RETURN();
+}
+
+/* Set reservation */
+PPC_OP(set_reservation)
+{
+    regs->reserve = T1 & ~0x03;
+    RETURN();
+}
+
+/* Reset reservation */
+PPC_OP(reset_reservation)
+{
+    regs->reserve = 0;
+    RETURN();
+}
+
+/* crf operations */
+PPC_OP(getbit_T0)
+{
+    T0 = (T0 >> PARAM(1)) & 1;
+    RETURN();
+}
+
+PPC_OP(getbit_T1)
+{
+    T1 = (T1 >> PARAM(1)) & 1;
+    RETURN();
+}
+
+PPC_OP(setcrfbit)
+{
+    T1 = (T1 & PARAM(1)) | (T0 << PARAM(2)); 
+    RETURN();
+}
+
+/* Branch */
+#define __PPC_OP_B(name, target)                                              \
+PPC_OP(name)                                                                  \
+{                                                                             \
+    regs->nip = (target);                                                     \
+    RETURN();                                                                 \
+}
+
+#define __PPC_OP_BL(name, target)                                             \
+PPC_OP(name)                                                                  \
+{                                                                             \
+    regs->LR = PARAM(1);                                                      \
+    regs->nip = (target);                                                     \
+    RETURN();                                                                 \
+}
+
+#define PPC_OP_B(name, target)                                                \
+__PPC_OP_B(name, target);                                                     \
+__PPC_OP_BL(name##l, target)
+
+#define __PPC_OP_BC(name, cond, target)                                       \
+PPC_OP(name)                                                                  \
+{                                                                             \
+    if (cond) {                                                               \
+        T0 = (target);                                                        \
+    } else {                                                                  \
+        T0 = PARAM(1);                                                        \
+    }                                                                         \
+    regs->nip = T0;                                                           \
+    RETURN();                                                                 \
+}
+
+#define __PPC_OP_BCL(name, cond, target)                                      \
+PPC_OP(name)                                                                  \
+{                                                                             \
+    if (cond) {                                                               \
+        T0 = (target);                                                        \
+        regs->LR = PARAM(1);                                                  \
+    } else {                                                                  \
+        T0 = PARAM(1);                                                        \
+    }                                                                         \
+    regs->nip = T0;                                                           \
+    RETURN();                                                                 \
+}
+
+#define _PPC_OP_BC(name, namel, cond, target)                                 \
+__PPC_OP_BC(name, cond, target);                                              \
+__PPC_OP_BCL(namel, cond, target)
+
+/* Branch to target */
+#define PPC_OP_BC(name, cond)                                                 \
+_PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2))
+
+PPC_OP_B(b, PARAM(1));
+PPC_OP_BC(ctr,        (regs->CTR != 0));
+PPC_OP_BC(ctr_true,   (regs->CTR != 0 && (T0 & PARAM(3)) != 0));
+PPC_OP_BC(ctr_false,  (regs->CTR != 0 && (T0 & PARAM(3)) == 0));
+PPC_OP_BC(ctrz,       (regs->CTR == 0));
+PPC_OP_BC(ctrz_true,  (regs->CTR == 0 && (T0 & PARAM(3)) != 0));
+PPC_OP_BC(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(3)) == 0));
+PPC_OP_BC(true,       ((T0 & PARAM(3)) != 0));
+PPC_OP_BC(false,      ((T0 & PARAM(3)) == 0));
+
+/* Branch to CTR */
+#define PPC_OP_BCCTR(name, cond)                                              \
+_PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->CTR & ~0x03)
+
+PPC_OP_B(bctr, regs->CTR & ~0x03);
+PPC_OP_BCCTR(ctr,        (regs->CTR != 0));
+PPC_OP_BCCTR(ctr_true,   (regs->CTR != 0 && (T0 & PARAM(2)) != 0));
+PPC_OP_BCCTR(ctr_false,  (regs->CTR != 0 && (T0 & PARAM(2)) == 0));
+PPC_OP_BCCTR(ctrz,       (regs->CTR == 0));
+PPC_OP_BCCTR(ctrz_true,  (regs->CTR == 0 && (T0 & PARAM(2)) != 0));
+PPC_OP_BCCTR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0));
+PPC_OP_BCCTR(true,       ((T0 & PARAM(2)) != 0));
+PPC_OP_BCCTR(false,      ((T0 & PARAM(2)) == 0));
+
+/* Branch to LR */
+#define PPC_OP_BCLR(name, cond)                                               \
+_PPC_OP_BC(blr_##name, blrl_##name, cond, regs->LR & ~0x03)
+
+PPC_OP_B(blr, regs->LR & ~0x03);
+PPC_OP_BCLR(ctr,        (regs->CTR != 0));
+PPC_OP_BCLR(ctr_true,   (regs->CTR != 0 && (T0 & PARAM(2)) != 0));
+PPC_OP_BCLR(ctr_false,  (regs->CTR != 0 && (T0 & PARAM(2)) == 0));
+PPC_OP_BCLR(ctrz,       (regs->CTR == 0));
+PPC_OP_BCLR(ctrz_true,  (regs->CTR == 0 && (T0 & PARAM(2)) != 0));
+PPC_OP_BCLR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0));
+PPC_OP_BCLR(true,       ((T0 & PARAM(2)) != 0));
+PPC_OP_BCLR(false,      ((T0 & PARAM(2)) == 0));
+
+/* CTR maintenance */
+PPC_OP(dec_ctr)
+{
+    regs->CTR--;
+    RETURN();
+}
+
+/***                           Integer arithmetic                          ***/
+/* add */
+PPC_OP(add)
+{
+    T0 += T1;
+    RETURN();
+}
+
+PPC_OP(addo)
+{
+    T2 = T0;
+    T0 += T1;
+    if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    RETURN();
+}
+
+/* add carrying */
+PPC_OP(addc)
+{
+    T2 = T0;
+    T0 += T1;
+    if (T0 < T2) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+PPC_OP(addco)
+{
+    T2 = T0;
+    T0 += T1;
+    if (T0 < T2) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    RETURN();
+}
+
+/* add extended */
+/* candidate for helper (too long) */
+PPC_OP(adde)
+{
+    T2 = T0;
+    T0 += T1 + xer_ca;
+    if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+PPC_OP(addeo)
+{
+    T2 = T0;
+    T0 += T1 + xer_ca;
+    if (T0 < T2 || (xer_ca == 1 && T0 == T2)) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    if ((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    RETURN();
+}
+
+/* add immediate */
+PPC_OP(addi)
+{
+    T0 += PARAM(1);
+    RETURN();
+}
+
+/* add immediate carrying */
+PPC_OP(addic)
+{
+    T1 = T0;
+    T0 += PARAM(1);
+    if (T0 < T1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+/* add to minus one extended */
+PPC_OP(addme)
+{
+    T1 = T0;
+    T0 += xer_ca + (-1);
+    if (T1 != 0)
+        xer_ca = 1;
+    RETURN();
+}
+
+PPC_OP(addmeo)
+{
+    T1 = T0;
+    T0 += xer_ca + (-1);
+    if (T1 & (T1 ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    if (T1 != 0)
+        xer_ca = 1;
+    RETURN();
+}
+
+/* add to zero extended */
+PPC_OP(addze)
+{
+    T1 = T0;
+    T0 += xer_ca;
+    if (T0 < T1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+PPC_OP(addzeo)
+{
+    T1 = T0;
+    T0 += xer_ca;
+    if ((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    if (T0 < T1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+/* divide word */
+/* candidate for helper (too long) */
+PPC_OP(divw)
+{
+    if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+        Ts0 = (-1) * (T0 >> 31);
+    } else {
+        Ts0 /= Ts1;
+    }
+    RETURN();
+}
+
+PPC_OP(divwo)
+{
+    if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+        xer_so = 1;
+        xer_ov = 1;
+        T0 = (-1) * (T0 >> 31);
+    } else {
+        xer_ov = 0;
+        Ts0 /= Ts1;
+    }
+    RETURN();
+}
+
+/* divide word unsigned */
+PPC_OP(divwu)
+{
+    if (T1 == 0) {
+        T0 = 0;
+    } else {
+        T0 /= T1;
+    }
+    RETURN();
+}
+
+PPC_OP(divwuo)
+{
+    if (T1 == 0) {
+        xer_so = 1;
+        xer_ov = 1;
+        T0 = 0;
+    } else {
+        xer_ov = 0;
+        T0 /= T1;
+    }
+    RETURN();
+}
+
+/* multiply high word */
+PPC_OP(mulhw)
+{
+    Ts0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32;
+    RETURN();
+}
+
+/* multiply high word unsigned */
+PPC_OP(mulhwu)
+{
+    T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32;
+    RETURN();
+}
+
+/* multiply low immediate */
+PPC_OP(mulli)
+{
+    Ts0 *= SPARAM(1);
+    RETURN();
+}
+
+/* multiply low word */
+PPC_OP(mullw)
+{
+    T0 *= T1;
+    RETURN();
+}
+
+PPC_OP(mullwo)
+{
+    int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
+
+    if ((int32_t)res != res) {
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        xer_ov = 0;
+    }
+    Ts0 = res;
+    RETURN();
+}
+
+/* negate */
+PPC_OP(neg)
+{
+    if (T0 != 0x80000000) {
+        Ts0 = -Ts0;
+    }
+    RETURN();
+}
+
+PPC_OP(nego)
+{
+    if (T0 == 0x80000000) {
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        xer_ov = 0;
+        Ts0 = -Ts0;
+    }
+    RETURN();
+}
+
+/* substract from */
+PPC_OP(subf)
+{
+    T0 = T1 - T0;
+    RETURN();
+}
+
+PPC_OP(subfo)
+{
+    T2 = T0;
+    T0 = T1 - T0;
+    if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    RETURN();
+}
+
+/* substract from carrying */
+PPC_OP(subfc)
+{
+    T0 = T1 - T0;
+    if (T0 <= T1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+PPC_OP(subfco)
+{
+    T2 = T0;
+    T0 = T1 - T0;
+    if (T0 <= T1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    RETURN();
+}
+
+/* substract from extended */
+/* candidate for helper (too long) */
+PPC_OP(subfe)
+{
+    T0 = T1 + ~T0 + xer_ca;
+    if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+PPC_OP(subfeo)
+{
+    T2 = T0;
+    T0 = T1 + ~T0 + xer_ca;
+    if ((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    if (T0 < T1 || (xer_ca == 1 && T0 == T1)) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+/* substract from immediate carrying */
+PPC_OP(subfic)
+{
+    T0 = PARAM(1) + ~T0 + 1;
+    if (T0 <= PARAM(1)) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+/* substract from minus one extended */
+PPC_OP(subfme)
+{
+    T0 = ~T0 + xer_ca - 1;
+
+    if (T0 != -1)
+        xer_ca = 1;
+    RETURN();
+}
+
+PPC_OP(subfmeo)
+{
+    T1 = T0;
+    T0 = ~T0 + xer_ca - 1;
+    if (~T1 & (~T1 ^ T0) & (1 << 31)) {
+        xer_so = 1;
+        xer_ov = 1;
+    } else {
+        xer_ov = 0;
+    }
+    if (T1 != -1)
+        xer_ca = 1;
+    RETURN();
+}
+
+/* substract from zero extended */
+PPC_OP(subfze)
+{
+    T1 = ~T0;
+    T0 = T1 + xer_ca;
+    if (T0 < T1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+PPC_OP(subfzeo)
+{
+    T1 = T0;
+    T0 = ~T0 + xer_ca;
+    if ((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)) {
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        xer_ov = 0;
+    }
+    if (T0 < ~T1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+/***                           Integer comparison                          ***/
+/* compare */
+PPC_OP(cmp)
+{
+    if (Ts0 < Ts1) {
+        T0 = 0x08;
+    } else if (Ts0 > Ts1) {
+        T0 = 0x04;
+    } else {
+        T0 = 0x02;
+    }
+    RETURN();
+}
+
+/* compare immediate */
+PPC_OP(cmpi)
+{
+    if (Ts0 < SPARAM(1)) {
+        T0 = 0x08;
+    } else if (Ts0 > SPARAM(1)) {
+        T0 = 0x04;
+    } else {
+        T0 = 0x02;
+    }
+    RETURN();
+}
+
+/* compare logical */
+PPC_OP(cmpl)
+{
+    if (T0 < T1) {
+        T0 = 0x08;
+    } else if (T0 > T1) {
+        T0 = 0x04;
+    } else {
+        T0 = 0x02;
+    }
+    RETURN();
+}
+
+/* compare logical immediate */
+PPC_OP(cmpli)
+{
+    if (T0 < PARAM(1)) {
+        T0 = 0x08;
+    } else if (T0 > PARAM(1)) {
+        T0 = 0x04;
+    } else {
+        T0 = 0x02;
+    }
+    RETURN();
+}
+
+/***                            Integer logical                            ***/
+/* and */
+PPC_OP(and)
+{
+    T0 &= T1;
+    RETURN();
+}
+
+/* andc */
+PPC_OP(andc)
+{
+    T0 &= ~T1;
+    RETURN();
+}
+
+/* andi. */
+PPC_OP(andi_)
+{
+    T0 &= PARAM(1);
+    RETURN();
+}
+
+/* count leading zero */
+PPC_OP(cntlzw)
+{
+    T1 = T0;
+    for (T0 = 32; T1 > 0; T0--)
+        T1 = T1 >> 1;
+    RETURN();
+}
+
+/* eqv */
+PPC_OP(eqv)
+{
+    T0 = ~(T0 ^ T1);
+    RETURN();
+}
+
+/* extend sign byte */
+PPC_OP(extsb)
+{
+    Ts0 = s_ext8(Ts0);
+    RETURN();
+}
+
+/* extend sign half word */
+PPC_OP(extsh)
+{
+    Ts0 = s_ext16(Ts0);
+    RETURN();
+}
+
+/* nand */
+PPC_OP(nand)
+{
+    T0 = ~(T0 & T1);
+    RETURN();
+}
+
+/* nor */
+PPC_OP(nor)
+{
+    T0 = ~(T0 | T1);
+    RETURN();
+}
+
+/* or */
+PPC_OP(or)
+{
+    T0 |= T1;
+    RETURN();
+}
+
+/* orc */
+PPC_OP(orc)
+{
+    T0 |= ~T1;
+    RETURN();
+}
+
+/* ori */
+PPC_OP(ori)
+{
+    T0 |= PARAM(1);
+    RETURN();
+}
+
+/* xor */
+PPC_OP(xor)
+{
+    T0 ^= T1;
+    RETURN();
+}
+
+/* xori */
+PPC_OP(xori)
+{
+    T0 ^= PARAM(1);
+    RETURN();
+}
+
+/***                             Integer rotate                            ***/
+/* rotate left word immediate then mask insert */
+PPC_OP(rlwimi)
+{
+    T0 = rotl(T0, PARAM(1) & PARAM(2)) | (T0 & PARAM(3));
+    RETURN();
+}
+
+/* rotate left immediate then and with mask insert */
+PPC_OP(rotlwi)
+{
+    T0 = rotl(T0, PARAM(1));
+    RETURN();
+}
+
+PPC_OP(slwi)
+{
+    T0 = T0 << PARAM(1);
+    RETURN();
+}
+
+PPC_OP(srwi)
+{
+    T0 = T0 >> PARAM(1);
+    RETURN();
+}
+
+/* rotate left word then and with mask insert */
+PPC_OP(rlwinm)
+{
+    T0 = rotl(T0, PARAM(1)) & PARAM(2);
+    RETURN();
+}
+
+PPC_OP(rotl)
+{
+    T0 = rotl(T0, T1);
+    RETURN();
+}
+
+PPC_OP(rlwnm)
+{
+    T0 = rotl(T0, T1) & PARAM(1);
+    RETURN();
+}
+
+/***                             Integer shift                             ***/
+/* shift left word */
+PPC_OP(slw)
+{
+    if (T1 & 0x20) {
+        T0 = 0;
+    } else {
+        T0 = T0 << T1;
+    }
+    RETURN();
+}
+
+/* shift right algebraic word */
+PPC_OP(sraw)
+{
+    Ts0 = do_sraw(Ts0, T1);
+    RETURN();
+}
+
+/* shift right algebraic word immediate */
+PPC_OP(srawi)
+{
+    Ts1 = Ts0;
+    Ts0 = Ts0 >> PARAM(1);
+    if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+
+/* shift right word */
+PPC_OP(srw)
+{
+    if (T1 & 0x20) {
+        T0 = 0;
+    } else {
+        T0 = T0 >> T1;
+    }
+    RETURN();
+}
+
+/***                       Floating-Point arithmetic                       ***/
+
+/***                     Floating-Point multiply-and-add                   ***/
+
+/***                     Floating-Point round & convert                    ***/
+
+/***                         Floating-Point compare                        ***/
+
+/***                  Floating-Point status & ctrl register                ***/
+
+/***                             Integer load                              ***/
+#define ld16x(x) s_ext16(ld16(x))
+#define PPC_ILD_OPX(name, op)                                                 \
+PPC_OP(l##name##x_z)                                                          \
+{                                                                             \
+    T1 = op(T0);                                                              \
+    RETURN();                                                                 \
+}                                                                             \
+PPC_OP(l##name##x)                                                            \
+{                                                                             \
+    T0 += T1;                                                                 \
+    T1 = op(T0);                                                              \
+    RETURN();                                                                 \
+}
+
+#define PPC_ILD_OP(name, op)                                                  \
+PPC_OP(l##name##_z)                                                           \
+{                                                                             \
+    T1 = op(SPARAM(1));                                                       \
+    RETURN();                                                                 \
+}                                                                             \
+PPC_OP(l##name)                                                               \
+{                                                                             \
+    T0 += SPARAM(1);                                                          \
+    T1 = op(T0);                                                              \
+    RETURN();                                                                 \
+}                                                                             \
+PPC_ILD_OPX(name, op)
+
+PPC_ILD_OP(bz, ld8);
+PPC_ILD_OP(ha, ld16x);
+PPC_ILD_OP(hz, ld16);
+PPC_ILD_OP(wz, ld32);
+
+/***                              Integer store                            ***/
+#define PPC_IST_OPX(name, op)                                                 \
+PPC_OP(st##name##x_z)                                                         \
+{                                                                             \
+    op(T0, T1);                                                               \
+    RETURN();                                                                 \
+}                                                                             \
+PPC_OP(st##name##x)                                                           \
+{                                                                             \
+    T0 += T1;                                                                 \
+    op(T0, T2);                                                               \
+    RETURN();                                                                 \
+}
+
+#define PPC_IST_OP(name, op)                                                  \
+PPC_OP(st##name##_z)                                                          \
+{                                                                             \
+    op(SPARAM(1), T0);                                                        \
+    RETURN();                                                                 \
+}                                                                             \
+PPC_OP(st##name)                                                              \
+{                                                                             \
+    T0 += SPARAM(1);                                                          \
+    op(T0, T1);                                                               \
+    RETURN();                                                                 \
+}                                                                             \
+PPC_IST_OPX(name, op);
+
+PPC_IST_OP(b, st8);
+PPC_IST_OP(h, st16);
+PPC_IST_OP(w, st32);
+
+/***                Integer load and store with byte reverse               ***/
+PPC_ILD_OPX(hbr, ld16r);
+PPC_ILD_OPX(wbr, ld32r);
+PPC_IST_OPX(hbr, st16r);
+PPC_IST_OPX(wbr, st32r);
+
+/***                    Integer load and store multiple                    ***/
+PPC_OP(lmw)
+{
+    do_lmw(PARAM(1), SPARAM(2) + T0);
+    RETURN();
+}
+
+PPC_OP(stmw)
+{
+    do_stmw(PARAM(1), SPARAM(2) + T0);
+    RETURN();
+}
+
+/***                    Integer load and store strings                     ***/
+PPC_OP(lswi)
+{
+    do_lsw(PARAM(1), PARAM(2), T0);
+    RETURN();
+}
+
+PPC_OP(lswx)
+{
+    do_lsw(PARAM(1), T0, T1 + T2);
+    RETURN();
+}
+
+PPC_OP(stswi_z)
+{
+    do_stsw(PARAM(1), PARAM(2), 0);
+    RETURN();
+}
+
+PPC_OP(stswi)
+{
+    do_stsw(PARAM(1), PARAM(2), T0);
+    RETURN();
+}
+
+PPC_OP(stswx_z)
+{
+    do_stsw(PARAM(1), T0, T1);
+    RETURN();
+}
+
+PPC_OP(stswx)
+{
+    do_stsw(PARAM(1), T0, T1 + T2);
+    RETURN();
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (15 preceding siblings ...)
  2003-11-18  7:55   ` J. Mayer
@ 2003-11-18  7:56   ` J. Mayer
  2003-11-18  7:56   ` J. Mayer
                     ` (8 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:56 UTC (permalink / raw)
  To: qemu-devel

target-ppc__op.tpl.diff

Repetitive micro-ops for PPC target. C code will be generated from
this file by gen_multi program.

diff -urNbB -x CVS qemu-current/target-ppc/op.tpl qemu/target-ppc/op.tpl
--- qemu-current/target-ppc/op.tpl	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/op.tpl	Thu Aug  7 09:26:59 2003
@@ -0,0 +1,197 @@
+/*
+ *  PPC emulation micro-operations for qemu.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Host registers definitions */
+$DEFH T 3
+/* PPC registers definitions */
+$DEF gpr 32
+$DEF fpr 32
+$DEF crf 8
+$DEF spr 1024
+
+/* PPC registers <-> host registers move */
+/* GPR */
+$OP load_gpr_T0 gpr
+{
+    T0 = regs->gpra;
+    RETURN();
+}
+$ENDOP
+
+$OP load_gpr_T1 gpr
+{
+    T1 = regs->gpra;
+    RETURN();
+}
+$ENDOP
+
+$OP load_gpr_T2 gpr
+{
+    T2 = regs->gpra;
+    RETURN();
+}
+$ENDOP
+
+$OP store_T0_gpr gpr
+{
+    regs->gpra = T0;
+    RETURN();
+}
+$ENDOP
+
+$OP store_T1_gpr gpr
+{
+    regs->gpra = T1;
+    RETURN();
+}
+$ENDOP
+
+$OP store_gpr_P gpr PARAM
+{
+    regs->gpra = PARAM(1);
+    RETURN();
+}
+$ENDOP
+
+/* crf */
+$OP load_crf_T0 crf
+{
+    T0 = regs->crfa;
+    RETURN();
+}
+$ENDOP
+
+$OP load_crf_T1 crf
+{
+    T1 = regs->crfa;
+    RETURN();
+}
+$ENDOP
+
+$OP store_T0_crf crf
+{
+    regs->crfa = T0;
+    RETURN();
+}
+$ENDOP
+
+$OP store_T1_crf crf
+{
+    regs->crfa = T1;
+    RETURN();
+}
+$ENDOP
+
+/* SPR */
+$OP load_spr spr
+{
+    T0 = regs->spra;
+    RETURN();
+}
+$ENDOP
+
+$OP store_spr spr
+{
+    regs->spra = T0;
+    RETURN();
+}
+$ENDOP
+
+/* FPSCR */
+$OP load_fpscr fpr
+{
+    regs->fpra = do_load_fpscr();
+    RETURN();
+}
+$ENDOP
+
+$OP store_fpscr fpr PARAM
+{
+    do_store_fpscr(PARAM(1), regs->fpra);
+    RETURN();
+}
+$ENDOP
+
+/***                         Floating-point store                          ***/
+/* candidate for helper (too long on x86 host) */
+$OP stfd_z fpr PARAM
+{
+    st64(SPARAM(1), regs->fpra);
+    RETURN();
+}
+$ENDOP
+
+/* candidate for helper (too long on x86 host) */
+$OP stfd fpr PARAM
+{
+    T0 += SPARAM(1);
+    st64(T0, regs->fpra);
+    RETURN();
+}
+$ENDOP
+
+/* candidate for helper (too long on x86 host) */
+$OP stfdx_z fpr
+{
+    st64(T0, regs->fpra);
+    RETURN();
+}
+$ENDOP
+/* candidate for helper (too long on x86 host) */
+$OP stfdx fpr
+{
+    T0 += T1;
+    st64(T0, regs->fpra);
+    RETURN();
+}
+$ENDOP
+
+/* candidate for helper (too long on x86 host) */
+$OP lfd_z fpr PARAM
+{
+    regs->fpra = ld64(SPARAM(1));
+    RETURN();
+}
+$ENDOP
+
+/* candidate for helper (too long) */
+$OP lfd fpr PARAM
+{
+    T0 += SPARAM(1);
+    regs->fpra = ld64(T0);
+    RETURN();
+}
+$ENDOP
+
+$OP lfdx_z fpr
+{
+    regs->fpra = ld64(T0);
+    RETURN();
+}
+$ENDOP
+
+$OP lfdx fpr
+{
+    T0 += T1;
+    regs->fpra = ld64(T0);
+    RETURN();
+}
+$ENDOP
+/*****************************************************************************/

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (16 preceding siblings ...)
  2003-11-18  7:56   ` J. Mayer
@ 2003-11-18  7:56   ` J. Mayer
  2003-11-18  7:57   ` J. Mayer
                     ` (7 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:56 UTC (permalink / raw)
  To: qemu-devel

target-ppc__ppc_ops.h.diff

Micro-ops header for PPC target.

diff -urNbB -x CVS qemu-current/target-ppc/ppc_ops.h qemu/target-ppc/ppc_ops.h
--- qemu-current/target-ppc/ppc_ops.h	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/ppc_ops.h	Tue Nov 11 01:12:08 2003
@@ -0,0 +1,32 @@
+/*
+ *  PPC emulation for qemu.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "dyngen-exec.h"
+#include "exec.h"
+#include "cpu.h"
+#include "ppc_decode.h"
+
+enum {
+#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#include "opc-ppc.h"
+#undef DEF
+    NB_OPS,
+};
+
+#include "gen-op-ppc.h"

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (17 preceding siblings ...)
  2003-11-18  7:56   ` J. Mayer
@ 2003-11-18  7:57   ` J. Mayer
  2003-11-18  7:58   ` J. Mayer
                     ` (6 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:57 UTC (permalink / raw)
  To: qemu-devel

target-ppc__syscall.h.diff

Kernel structures definitions for PPC target.
May have to be fixed...

diff -urNbB -x CVS qemu-current/target-ppc/syscall.h qemu/target-ppc/syscall.h
--- qemu-current/target-ppc/syscall.h	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/syscall.h	Sun Jun 29 19:59:03 2003
@@ -0,0 +1,129 @@
+/*
+ *  PPC emulation for qemu: syscall definitions.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* XXX: ABSOLUTELY BUGGY:
+ * for now, this is quite just a cut-and-paste from i386 target...
+ */
+
+/* default linux values for the selectors */
+#define __USER_DS	(1)
+
+struct target_pt_regs {
+	unsigned long gpr[32];
+	unsigned long nip;
+	unsigned long msr;
+	unsigned long orig_gpr3;	/* Used for restarting system calls */
+	unsigned long ctr;
+	unsigned long link;
+	unsigned long xer;
+	unsigned long ccr;
+	unsigned long mq;		/* 601 only (not used at present) */
+					/* Used on APUS to hold IPL value. */
+	unsigned long trap;		/* Reason for being here */
+	unsigned long dar;		/* Fault registers */
+	unsigned long dsisr;
+	unsigned long result; 		/* Result of a system call */
+};
+
+/* ioctls */
+struct target_revectored_struct {
+	target_ulong __map[8];			/* 256 bits */
+};
+
+/*
+ * flags masks
+ */
+
+/* ipcs */
+
+#define TARGET_SEMOP           1
+#define TARGET_SEMGET          2
+#define TARGET_SEMCTL          3 
+#define TARGET_MSGSND          11 
+#define TARGET_MSGRCV          12
+#define TARGET_MSGGET          13
+#define TARGET_MSGCTL          14
+#define TARGET_SHMAT           21
+#define TARGET_SHMDT           22
+#define TARGET_SHMGET          23
+#define TARGET_SHMCTL          24
+
+struct target_msgbuf {
+	int mtype;
+	char mtext[1];
+};
+
+struct target_ipc_kludge {
+	unsigned int	msgp;	/* Really (struct msgbuf *) */
+	int msgtyp;
+};	
+
+struct target_ipc_perm {
+	int	key;
+	unsigned short	uid;
+	unsigned short	gid;
+	unsigned short	cuid;
+	unsigned short	cgid;
+	unsigned short	mode;
+	unsigned short	seq;
+};
+
+struct target_msqid_ds {
+	struct target_ipc_perm	msg_perm;
+	unsigned int		msg_first;	/* really struct target_msg* */
+	unsigned int		msg_last;	/* really struct target_msg* */
+	unsigned int		msg_stime;	/* really target_time_t */
+	unsigned int		msg_rtime;	/* really target_time_t */
+	unsigned int		msg_ctime;	/* really target_time_t */
+	unsigned int		wwait;		/* really struct wait_queue* */
+	unsigned int		rwait;		/* really struct wait_queue* */
+	unsigned short		msg_cbytes;
+	unsigned short		msg_qnum;
+	unsigned short		msg_qbytes;
+	unsigned short		msg_lspid;
+	unsigned short		msg_lrpid;
+};
+
+struct target_shmid_ds {
+	struct target_ipc_perm	shm_perm;
+	int			shm_segsz;
+	unsigned int		shm_atime;	/* really target_time_t */
+	unsigned int		shm_dtime;	/* really target_time_t */
+	unsigned int		shm_ctime;	/* really target_time_t */
+	unsigned short		shm_cpid;
+	unsigned short		shm_lpid;
+	short			shm_nattch;
+	unsigned short		shm_npages;
+	unsigned long		*shm_pages;
+	void 			*attaches;	/* really struct shm_desc * */
+};
+
+#define TARGET_IPC_RMID	0
+#define TARGET_IPC_SET	1
+#define TARGET_IPC_STAT	2
+
+union target_semun {
+    int val;
+    unsigned int buf;	/* really struct semid_ds * */
+    unsigned int array; /* really unsigned short * */
+    unsigned int __buf;	/* really struct seminfo * */
+    unsigned int __pad;	/* really void* */
+};
+

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (18 preceding siblings ...)
  2003-11-18  7:57   ` J. Mayer
@ 2003-11-18  7:58   ` J. Mayer
  2003-11-18  7:59   ` J. Mayer
                     ` (5 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:58 UTC (permalink / raw)
  To: qemu-devel

target-ppc__syscall_nr.h.diff

Syscall numbers definition for PPC target.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (19 preceding siblings ...)
  2003-11-18  7:58   ` J. Mayer
@ 2003-11-18  7:59   ` J. Mayer
  2003-11-18  7:59   ` J. Mayer
                     ` (4 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:59 UTC (permalink / raw)
  To: qemu-devel

target-ppc__syscall_nr.h.diff

Let's retry :=)
Syscall numbers definition for PPC target.

diff -urNbB -x CVS qemu-current/target-ppc/syscall_nr.h qemu/target-ppc/syscall_nr.h
--- qemu-current/target-ppc/syscall_nr.h	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/syscall_nr.h	Tue Nov 11 00:55:05 2003
@@ -0,0 +1,258 @@
+/*
+ * This file contains the system call numbers.
+ */
+#define TARGET_NR_restart_syscall          0
+#define TARGET_NR_exit                     1
+#define TARGET_NR_fork                     2
+#define TARGET_NR_read                     3
+#define TARGET_NR_write                    4
+#define TARGET_NR_open                     5
+#define TARGET_NR_close                    6
+#define TARGET_NR_waitpid                  7
+#define TARGET_NR_creat                    8
+#define TARGET_NR_link                     9
+#define TARGET_NR_unlink                  10
+#define TARGET_NR_execve                  11
+#define TARGET_NR_chdir                   12
+#define TARGET_NR_time                    13
+#define TARGET_NR_mknod                   14
+#define TARGET_NR_chmod                   15
+#define TARGET_NR_lchown                  16
+#define TARGET_NR_break                   17
+#define TARGET_NR_oldstat                 18
+#define TARGET_NR_lseek                   19
+#define TARGET_NR_getpid                  20
+#define TARGET_NR_mount                   21
+#define TARGET_NR_umount                  22
+#define TARGET_NR_setuid                  23
+#define TARGET_NR_getuid                  24
+#define TARGET_NR_stime                   25
+#define TARGET_NR_ptrace                  26
+#define TARGET_NR_alarm                   27
+#define TARGET_NR_oldfstat                28
+#define TARGET_NR_pause                   29
+#define TARGET_NR_utime                   30
+#define TARGET_NR_stty                    31
+#define TARGET_NR_gtty                    32
+#define TARGET_NR_access                  33
+#define TARGET_NR_nice                    34
+#define TARGET_NR_ftime                   35
+#define TARGET_NR_sync                    36
+#define TARGET_NR_kill                    37
+#define TARGET_NR_rename                  38
+#define TARGET_NR_mkdir                   39
+#define TARGET_NR_rmdir                   40
+#define TARGET_NR_dup                     41
+#define TARGET_NR_pipe                    42
+#define TARGET_NR_times                   43
+#define TARGET_NR_prof                    44
+#define TARGET_NR_brk                     45
+#define TARGET_NR_setgid                  46
+#define TARGET_NR_getgid                  47
+#define TARGET_NR_signal                  48
+#define TARGET_NR_geteuid                 49
+#define TARGET_NR_getegid                 50
+#define TARGET_NR_acct                    51
+#define TARGET_NR_umount2                 52
+#define TARGET_NR_lock                    53
+#define TARGET_NR_ioctl                   54
+#define TARGET_NR_fcntl                   55
+#define TARGET_NR_mpx                     56
+#define TARGET_NR_setpgid                 57
+#define TARGET_NR_ulimit                  58
+#define TARGET_NR_oldolduname             59
+#define TARGET_NR_umask                   60
+#define TARGET_NR_chroot                  61
+#define TARGET_NR_ustat                   62
+#define TARGET_NR_dup2                    63
+#define TARGET_NR_getppid                 64
+#define TARGET_NR_getpgrp                 65
+#define TARGET_NR_setsid                  66
+#define TARGET_NR_sigaction               67
+#define TARGET_NR_sgetmask                68
+#define TARGET_NR_ssetmask                69
+#define TARGET_NR_setreuid                70
+#define TARGET_NR_setregid                71
+#define TARGET_NR_sigsuspend              72
+#define TARGET_NR_sigpending              73
+#define TARGET_NR_sethostname             74
+#define TARGET_NR_setrlimit               75
+#define TARGET_NR_getrlimit               76
+#define TARGET_NR_getrusage               77
+#define TARGET_NR_gettimeofday            78
+#define TARGET_NR_settimeofday            79
+#define TARGET_NR_getgroups               80
+#define TARGET_NR_setgroups               81
+#define TARGET_NR_select                  82
+#define TARGET_NR_symlink                 83
+#define TARGET_NR_oldlstat                84
+#define TARGET_NR_readlink                85
+#define TARGET_NR_uselib                  86
+#define TARGET_NR_swapon                  87
+#define TARGET_NR_reboot                  88
+#define TARGET_NR_readdir                 89
+#define TARGET_NR_mmap                    90
+#define TARGET_NR_munmap                  91
+#define TARGET_NR_truncate                92
+#define TARGET_NR_ftruncate               93
+#define TARGET_NR_fchmod                  94
+#define TARGET_NR_fchown                  95
+#define TARGET_NR_getpriority             96
+#define TARGET_NR_setpriority             97
+#define TARGET_NR_profil                  98
+#define TARGET_NR_statfs                  99
+#define TARGET_NR_fstatfs                100
+#define TARGET_NR_ioperm                 101
+#define TARGET_NR_socketcall             102
+#define TARGET_NR_syslog                 103
+#define TARGET_NR_setitimer              104
+#define TARGET_NR_getitimer              105
+#define TARGET_NR_stat                   106
+#define TARGET_NR_lstat                  107
+#define TARGET_NR_fstat                  108
+#define TARGET_NR_olduname               109
+#define TARGET_NR_iopl                   110
+#define TARGET_NR_vhangup                111
+#define TARGET_NR_idle                   112
+#define TARGET_NR_vm86                   113
+#define TARGET_NR_wait4                  114
+#define TARGET_NR_swapoff                115
+#define TARGET_NR_sysinfo                116
+#define TARGET_NR_ipc                    117
+#define TARGET_NR_fsync                  118
+#define TARGET_NR_sigreturn              119
+#define TARGET_NR_clone                  120
+#define TARGET_NR_setdomainname          121
+#define TARGET_NR_uname                  122
+#define TARGET_NR_modify_ldt             123
+#define TARGET_NR_adjtimex               124
+#define TARGET_NR_mprotect               125
+#define TARGET_NR_sigprocmask            126
+#define TARGET_NR_create_module          127
+#define TARGET_NR_init_module            128
+#define TARGET_NR_delete_module          129
+#define TARGET_NR_get_kernel_syms        130
+#define TARGET_NR_quotactl               131
+#define TARGET_NR_getpgid                132
+#define TARGET_NR_fchdir                 133
+#define TARGET_NR_bdflush                134
+#define TARGET_NR_sysfs                  135
+#define TARGET_NR_personality            136
+#define TARGET_NR_afs_syscall            137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid               138
+#define TARGET_NR_setfsgid               139
+#define TARGET_NR__llseek                140
+#define TARGET_NR_getdents               141
+#define TARGET_NR__newselect             142
+#define TARGET_NR_flock                  143
+#define TARGET_NR_msync                  144
+#define TARGET_NR_readv                  145
+#define TARGET_NR_writev                 146
+#define TARGET_NR_getsid                 147
+#define TARGET_NR_fdatasync              148
+#define TARGET_NR__sysctl                149
+#define TARGET_NR_mlock                  150
+#define TARGET_NR_munlock                151
+#define TARGET_NR_mlockall               152
+#define TARGET_NR_munlockall             153
+#define TARGET_NR_sched_setparam         154
+#define TARGET_NR_sched_getparam         155
+#define TARGET_NR_sched_setscheduler     156
+#define TARGET_NR_sched_getscheduler     157
+#define TARGET_NR_sched_yield            158
+#define TARGET_NR_sched_get_priority_max 159
+#define TARGET_NR_sched_get_priority_min 160
+#define TARGET_NR_sched_rr_get_interval  161
+#define TARGET_NR_nanosleep              162
+#define TARGET_NR_mremap                 163
+#define TARGET_NR_setresuid              164
+#define TARGET_NR_getresuid              165
+#define TARGET_NR_query_module           166
+#define TARGET_NR_poll                   167
+#define TARGET_NR_nfsservctl             168
+#define TARGET_NR_setresgid              169
+#define TARGET_NR_getresgid              170
+#define TARGET_NR_prctl                  171
+#define TARGET_NR_rt_sigreturn           172
+#define TARGET_NR_rt_sigaction           173
+#define TARGET_NR_rt_sigprocmask         174
+#define TARGET_NR_rt_sigpending          175
+#define TARGET_NR_rt_sigtimedwait        176
+#define TARGET_NR_rt_sigqueueinfo        177
+#define TARGET_NR_rt_sigsuspend          178
+#define TARGET_NR_pread64                179
+#define TARGET_NR_pwrite64               180
+#define TARGET_NR_chown                  181
+#define TARGET_NR_getcwd                 182
+#define TARGET_NR_capget                 183
+#define TARGET_NR_capset                 184
+#define TARGET_NR_sigaltstack            185
+#define TARGET_NR_sendfile               186
+#define TARGET_NR_getpmsg                187     /* some people actually want streams */
+#define TARGET_NR_putpmsg                188     /* some people actually want streams */
+#define TARGET_NR_vfork                  189
+#define TARGET_NR_ugetrlimit             190     /* SuS compliant getrlimit */
+#define TARGET_NR_readahead              191
+#define TARGET_NR_mmap2                  192
+#define TARGET_NR_truncate64             193
+#define TARGET_NR_ftruncate64            194
+#define TARGET_NR_stat64                 195
+#define TARGET_NR_lstat64                196
+#define TARGET_NR_fstat64                197
+#define TARGET_NR_pciconfig_read         198
+#define TARGET_NR_pciconfig_write        199
+#define TARGET_NR_pciconfig_iobase       200
+#define TARGET_NR_multiplexer            201
+#define TARGET_NR_getdents64             202
+#define TARGET_NR_pivot_root             203
+#define TARGET_NR_fcntl64                204
+#define TARGET_NR_madvise                205
+#define TARGET_NR_mincore                206
+#define TARGET_NR_gettid                 207
+#define TARGET_NR_tkill                  208
+#define TARGET_NR_setxattr               209
+#define TARGET_NR_lsetxattr              210
+#define TARGET_NR_fsetxattr              211
+#define TARGET_NR_getxattr               212
+#define TARGET_NR_lgetxattr              213
+#define TARGET_NR_fgetxattr              214
+#define TARGET_NR_listxattr              215
+#define TARGET_NR_llistxattr             216
+#define TARGET_NR_flistxattr             217
+#define TARGET_NR_removexattr            218
+#define TARGET_NR_lremovexattr           219
+#define TARGET_NR_fremovexattr           220
+#define TARGET_NR_futex                  221
+#define TARGET_NR_sched_setaffinity      222
+#define TARGET_NR_sched_getaffinity      223
+/* 224 currently unused */
+#define TARGET_NR_tuxcall                225
+#define TARGET_NR_sendfile64             226
+#define TARGET_NR_io_setup               227
+#define TARGET_NR_io_destroy             228
+#define TARGET_NR_io_getevents           229
+#define TARGET_NR_io_submit              230
+#define TARGET_NR_io_cancel              231
+#define TARGET_NR_set_tid_address        232
+#define TARGET_NR_fadvise64              233
+#define TARGET_NR_exit_group             234
+#define TARGET_NR_lookup_dcookie         235
+#define TARGET_NR_epoll_create           236
+#define TARGET_NR_epoll_ctl              237
+#define TARGET_NR_epoll_wait             238
+#define TARGET_NR_remap_file_pages       239
+#define TARGET_NR_timer_create           240
+#define TARGET_NR_timer_settime          241
+#define TARGET_NR_timer_gettime          242
+#define TARGET_NR_timer_getoverrun       243
+#define TARGET_NR_timer_delete           244
+#define TARGET_NR_clock_settime          245
+#define TARGET_NR_clock_gettime          246
+#define TARGET_NR_clock_getres           247
+#define TARGET_NR_clock_nanosleep        248
+#define TARGET_NR_swapcontext            249
+#define TARGET_NR_tgkill                 250
+#define TARGET_NR_utimes                 251
+#define TARGET_NR_statfs64               252
+#define TARGET_NR_fstatfs64              253
+#define TARGET_NR_fadvise64_64           254

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (20 preceding siblings ...)
  2003-11-18  7:59   ` J. Mayer
@ 2003-11-18  7:59   ` J. Mayer
  2003-11-18  8:00   ` J. Mayer
                     ` (3 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  7:59 UTC (permalink / raw)
  To: qemu-devel

target-ppc__translate.c.diff

Micro ops generator for PPC target.

diff -urNbB -x CVS qemu-current/target-ppc/translate.c qemu/target-ppc/translate.c
--- qemu-current/target-ppc/translate.c	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/translate.c	Tue Nov 11 02:52:04 2003
@@ -0,0 +1,2376 @@
+/*
+ *  PPC emulation for qemu: main translation routines.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "dyngen-exec.h"
+#include "cpu.h"
+#include "exec.h"
+#include "disas.h"
+
+//#define DO_SINGLE_STEP
+//#define DO_STEP_FLUSH
+
+enum {
+#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#include "opc.h"
+#undef DEF
+    NB_OPS,
+};
+
+static uint16_t *gen_opc_ptr;
+static uint32_t *gen_opparam_ptr;
+
+#include "gen-op.h"
+#include "select.h"
+
+static uint8_t  spr_access[1024 / 2];
+
+/* internal defines */
+typedef struct DisasContext {
+    struct TranslationBlock *tb;
+    uint32_t *nip;
+    uint32_t opcode;
+    int exception;
+    int retcode;
+    /* Time base */
+    uint32_t tb_offset;
+    int supervisor;
+} DisasContext;
+
+typedef struct opc_handler_t {
+    /* invalid bits */
+    uint32_t inval;
+    /* handler */
+    void (*handler)(DisasContext *ctx);
+} opc_handler_t;
+
+#define SET_RETVAL(n)                                                         \
+do {                                                                          \
+    if ((n) != 0) {                                                           \
+        ctx->exception = (n);                                                 \
+    }                                                                         \
+    return;                                                                   \
+} while (0)
+
+#define GET_RETVAL(func, __opcode)                                            \
+({                                                                            \
+    (func)(&ctx);                                                             \
+    ctx.exception;                                                            \
+})
+
+#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
+static void gen_##name (DisasContext *ctx);                                   \
+GEN_OPCODE(name, opc1, opc2, opc3, inval, type);                              \
+static void gen_##name (DisasContext *ctx)
+
+/* Instruction types */
+enum {
+    PPC_INTEGER  = 0x0001, /* CPU has integer operations instructions        */
+    PPC_FLOAT    = 0x0002, /* CPU has floating point operations instructions */
+    PPC_FLOW     = 0x0004, /* CPU has flow control instructions              */
+    PPC_MEM      = 0x0008, /* CPU has virtual memory instructions            */
+    PPC_MISC     = 0x0010, /* CPU has spr/msr access instructions            */
+    PPC_EXTERN   = 0x0020, /* CPU has external control instructions          */
+    PPC_SEGMENT  = 0x0040, /* CPU has memory segment instructions            */
+};
+
+typedef struct opcode_t {
+    unsigned char opc1, opc2, opc3;
+    uint32_t type;
+    opc_handler_t handler;
+} opcode_t;
+
+/* XXX: move that elsewhere */
+extern FILE *logfile;
+extern int loglevel;
+
+/* XXX: shouldn't stay all alone here ! */
+static int reserve = 0;
+
+/***                           Instruction decoding                        ***/
+#define EXTRACT_HELPER(name, shift, nb)                                       \
+static inline uint32_t name (uint32_t opcode)                                 \
+{                                                                             \
+    return (opcode >> (shift)) & ((1 << (nb)) - 1);                           \
+}
+
+#define EXTRACT_SHELPER(name, shift, nb)                                      \
+static inline int32_t name (uint32_t opcode)                                  \
+{                                                                             \
+    return s_ext16((opcode >> (shift)) & ((1 << (nb)) - 1));                  \
+}
+
+/* Opcode part 1 */
+EXTRACT_HELPER(opc1, 26, 6);
+/* Opcode part 2 */
+EXTRACT_HELPER(opc2, 1, 5);
+/* Opcode part 3 */
+EXTRACT_HELPER(opc3, 6, 5);
+/* Update Cr0 flags */
+EXTRACT_HELPER(Rc, 0, 1);
+/* Destination */
+EXTRACT_HELPER(rD, 21, 5);
+/* Source */
+EXTRACT_HELPER(rS, 21, 5);
+/* First operand */
+EXTRACT_HELPER(rA, 16, 5);
+/* Second operand */
+EXTRACT_HELPER(rB, 11, 5);
+/* Third operand */
+EXTRACT_HELPER(rC, 6, 5);
+/***                               Get CRn                                 ***/
+EXTRACT_HELPER(crfD, 23, 3);
+EXTRACT_HELPER(crfS, 18, 3);
+EXTRACT_HELPER(crbD, 21, 5);
+EXTRACT_HELPER(crbA, 16, 5);
+EXTRACT_HELPER(crbB, 11, 5);
+/* SPR / TBL */
+EXTRACT_HELPER(SPR, 11, 10);
+/***                              Get constants                            ***/
+EXTRACT_HELPER(IMM, 12, 8);
+/* 16 bits signed immediate value */
+EXTRACT_SHELPER(SIMM, 0, 16);
+/* 16 bits unsigned immediate value */
+EXTRACT_HELPER(UIMM, 0, 16);
+/* Bit count */
+EXTRACT_HELPER(NB, 11, 5);
+/* Shift count */
+EXTRACT_HELPER(SH, 11, 5);
+/* Mask start */
+EXTRACT_HELPER(MB, 6, 5);
+/* Mask end */
+EXTRACT_HELPER(ME, 1, 5);
+
+EXTRACT_HELPER(CRM, 12, 8);
+EXTRACT_HELPER(FM, 17, 8);
+EXTRACT_HELPER(SR, 16, 4);
+/***                            Jump target decoding                       ***/
+/* Displacement */
+EXTRACT_SHELPER(d, 0, 16);
+/* Immediate address */
+static inline uint32_t LI (uint32_t opcode)
+{
+    return (opcode >> 0) & 0x03FFFFFC;
+}
+
+static inline uint32_t BD (uint32_t opcode)
+{
+    return (opcode >> 0) & 0xFFFC;
+}
+
+EXTRACT_HELPER(BO, 21, 5);
+EXTRACT_HELPER(BI, 16, 5);
+/* Absolute/relative address */
+EXTRACT_HELPER(AA, 1, 1);
+/* Link */
+EXTRACT_HELPER(LK, 0, 1);
+
+/* Create a mask between <start> and <end> bits */
+static inline uint32_t MASK (uint32_t start, uint32_t end)
+{
+    uint32_t ret;
+
+    ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
+    if (start > end)
+        return ~ret;
+
+    return ret;
+}
+
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
+__attribute__ ((section(".opcodes"), unused))                                 \
+static opcode_t opc_##name = {                                                \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .type = _typ,                                                             \
+    .handler = {                                                              \
+        .inval   = invl,                                                      \
+        .handler = &gen_##name,                                               \
+    },                                                                        \
+}
+
+#define GEN_OPCODE_MARK(name)                                                 \
+__attribute__ ((section(".opcodes"), unused))                                 \
+static opcode_t opc_##name = {                                                \
+    .opc1 = 0xFF,                                                             \
+    .opc2 = 0xFF,                                                             \
+    .opc3 = 0xFF,                                                             \
+    .type = 0x00,                                                             \
+    .handler = {                                                              \
+        .inval   = 0x00000000,                                                \
+        .handler = NULL,                                                      \
+    },                                                                        \
+}
+
+/* Start opcode list */
+GEN_OPCODE_MARK(start);
+
+/* Invalid instruction */
+GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, 0)
+{
+    /* Branch to next instruction to force nip update */
+    gen_op_b((uint32_t)ctx->nip);
+    SET_RETVAL(EXCP_INVAL);
+}
+
+static opc_handler_t invalid_handler = {
+    .inval   = 0xFFFFFFFF,
+    .handler = gen_invalid,
+};
+
+/***                           Integer arithmetic                          ***/
+#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval)                       \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    gen_op_##name();                                                          \
+    if (Rc(ctx->opcode) != 0)                                                 \
+        gen_op_set_Rc0();                                                     \
+    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval)                     \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    gen_op_##name();                                                          \
+    if (Rc(ctx->opcode) != 0)                                                 \
+        gen_op_set_Rc0_ov();                                                  \
+    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define __GEN_INT_ARITH1(name, opc1, opc2, opc3)                              \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER)                  \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_##name();                                                          \
+    if (Rc(ctx->opcode) != 0)                                                 \
+        gen_op_set_Rc0();                                                     \
+    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3)                            \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER)                  \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_##name();                                                          \
+    if (Rc(ctx->opcode) != 0)                                                 \
+        gen_op_set_Rc0_ov();                                                  \
+    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+/* Two operands arithmetic functions */
+#define GEN_INT_ARITH2(name, opc1, opc2, opc3)                                \
+__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000)                          \
+__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)
+
+/* Two operands arithmetic functions with no overflow allowed */
+#define GEN_INT_ARITHN(name, opc1, opc2, opc3)                                \
+__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)
+
+/* One operand arithmetic functions */
+#define GEN_INT_ARITH1(name, opc1, opc2, opc3)                                \
+__GEN_INT_ARITH1(name, opc1, opc2, opc3)                                      \
+__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)
+
+/* add    add.    addo    addo.    */
+GEN_INT_ARITH2 (add,    0x1F, 0x0A, 0x08);
+/* addc   addc.   addco   addco.   */
+GEN_INT_ARITH2 (addc,   0x1F, 0x0A, 0x00);
+/* adde   adde.   addeo   addeo.   */
+GEN_INT_ARITH2 (adde,   0x1F, 0x0A, 0x04);
+/* addme  addme.  addmeo  addmeo.  */
+GEN_INT_ARITH1 (addme,  0x1F, 0x0A, 0x07);
+/* addze  addze.  addzeo  addzeo.  */
+GEN_INT_ARITH1 (addze,  0x1F, 0x0A, 0x06);
+/* divw   divw.   divwo   divwo.   */
+GEN_INT_ARITH2 (divw,   0x1F, 0x0B, 0x0F);
+/* divwu  divwu.  divwuo  divwuo.  */
+GEN_INT_ARITH2 (divwu,  0x1F, 0x0B, 0x0E);
+/* mulhw  mulhw.                   */
+GEN_INT_ARITHN (mulhw,  0x1F, 0x0B, 0x02);
+/* mulhwu mulhwu.                  */
+GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
+/* mullw  mullw.  mullwo  mullwo.  */
+GEN_INT_ARITH2 (mullw,  0x1F, 0x0B, 0x07);
+/* neg    neg.    nego    nego.    */
+GEN_INT_ARITH1 (neg,    0x1F, 0x08, 0x03);
+/* subf   subf.   subfo   subfo.   */
+GEN_INT_ARITH2 (subf,   0x1F, 0x08, 0x01);
+/* subfc  subfc.  subfco  subfco.  */
+GEN_INT_ARITH2 (subfc,  0x1F, 0x08, 0x00);
+/* subfe  subfe.  subfeo  subfeo.  */
+GEN_INT_ARITH2 (subfe,  0x1F, 0x08, 0x04);
+/* subfme subfme. subfmeo subfmeo. */
+GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
+/* subfze subfze. subfzeo subfzeo. */
+GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
+/* addi */
+GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    int32_t simm = SIMM(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T0(simm);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_addi(simm);
+    }
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* addic */
+GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_addic(SIMM(ctx->opcode));
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* addic. */
+GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_addic(SIMM(ctx->opcode));
+    gen_op_set_Rc0();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* addis */
+GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    int32_t simm = SIMM(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T0(simm << 16);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_addi(simm << 16);
+    }
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* mulli */
+GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_mulli(SIMM(ctx->opcode));
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* subfic */
+GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_subfic(SIMM(ctx->opcode));
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/***                           Integer comparison                          ***/
+#define GEN_CMP(name, opc)                                                    \
+GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER)                   \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_crf(crfD(ctx->opcode));                                   \
+    SET_RETVAL(0);                                                            \
+}
+
+/* cmp */
+GEN_CMP(cmp, 0x00);
+/* cmpi */
+GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_cmpi(SIMM(ctx->opcode));
+    gen_op_store_T0_crf(crfD(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* cmpl */
+GEN_CMP(cmpl, 0x01);
+/* cmpli */
+GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_cmpli(UIMM(ctx->opcode));
+    gen_op_store_T0_crf(crfD(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/***                            Integer logical                            ***/
+#define __GEN_LOGICAL2(name, opc2, opc3)                                      \
+GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER)                  \
+{                                                                             \
+    gen_op_load_gpr_T0(rS(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    gen_op_##name();                                                          \
+    if (Rc(ctx->opcode) != 0)                                                 \
+        gen_op_set_Rc0();                                                     \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+#define GEN_LOGICAL2(name, opc)                                               \
+__GEN_LOGICAL2(name, 0x1C, opc)
+
+#define GEN_LOGICAL1(name, opc)                                               \
+GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER)                   \
+{                                                                             \
+    gen_op_load_gpr_T0(rS(ctx->opcode));                                      \
+    gen_op_##name();                                                          \
+    if (Rc(ctx->opcode) != 0)                                                 \
+        gen_op_set_Rc0();                                                     \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+/* and & and. */
+GEN_LOGICAL2(and, 0x00);
+/* andc & andc. */
+GEN_LOGICAL2(andc, 0x01);
+/* andi. */
+GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_andi_(UIMM(ctx->opcode));
+    gen_op_set_Rc0();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* andis. */
+GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_andi_(UIMM(ctx->opcode) << 16);
+    gen_op_set_Rc0();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/* cntlzw */
+GEN_LOGICAL1(cntlzw, 0x00);
+/* eqv & eqv. */
+GEN_LOGICAL2(eqv, 0x08);
+/* extsb & extsb. */
+GEN_LOGICAL1(extsb, 0x1D);
+/* extsh & extsh. */
+GEN_LOGICAL1(extsh, 0x1C);
+/* nand & nand. */
+GEN_LOGICAL2(nand, 0x0E);
+/* nor & nor. */
+GEN_LOGICAL2(nor, 0x03);
+/* or & or. */
+GEN_LOGICAL2(or, 0x0D);
+/* orc & orc. */
+GEN_LOGICAL2(orc, 0x0C);
+/* xor & xor. */
+GEN_LOGICAL2(xor, 0x09);
+/* ori */
+GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    uint32_t uimm = UIMM(ctx->opcode);
+
+#if 0
+    if (uimm == 0) {
+        if (rA(ctx->opcode) != rS(ctx->opcode)) {
+            gen_op_load_gpr_T0(rS(ctx->opcode));
+            gen_op_store_T0_gpr(rA(ctx->opcode));
+        }
+    } else
+#endif
+    {
+        gen_op_load_gpr_T0(rS(ctx->opcode));
+        gen_op_ori(uimm);
+        gen_op_store_T0_gpr(rA(ctx->opcode));
+    }
+    SET_RETVAL(0);
+}
+/* oris */
+GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    uint32_t uimm = UIMM(ctx->opcode);
+
+#if 0
+    if (uimm == 0) {
+        if (rA(ctx->opcode) != rS(ctx->opcode)) {
+            gen_op_load_gpr_T0(rS(ctx->opcode));
+            gen_op_store_T0_gpr(rA(ctx->opcode));
+        }
+    } else
+#endif
+    {
+        gen_op_load_gpr_T0(rS(ctx->opcode));
+        gen_op_ori(uimm << 16);
+        gen_op_store_T0_gpr(rA(ctx->opcode));
+    }
+    SET_RETVAL(0);
+}
+/* xori */
+GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_xori(UIMM(ctx->opcode));
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/* xoris */
+GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_xori(UIMM(ctx->opcode) << 16);
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/***                             Integer rotate                            ***/
+/* rlwimi & rlwimi. */
+GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    uint32_t mb, me;
+
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
+    if (Rc(ctx->opcode) != 0)
+        gen_op_set_Rc0();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* rlwinm & rlwinm. */
+GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    uint32_t mb, me, sh;
+    
+    sh = SH(ctx->opcode);
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (loglevel > 0) {
+        fprintf(logfile, "%s sh=%u mb=%u me=%u MASK=0x%08x\n",
+                __func__, sh, mb, me, MASK(mb, me));
+    }
+    if (mb == 0) {
+        if (me == 31) {
+            gen_op_rotlwi(sh);
+            goto store;
+        } else if (me == (31 - sh)) {
+            gen_op_slwi(sh);
+            goto store;
+        } else if (sh == 0) {
+            gen_op_andi_(MASK(0, me));
+            goto store;
+        }
+    } else if (me == 31) {
+        if (sh == (32 - mb)) {
+            gen_op_srwi(mb);
+            goto store;
+        } else if (sh == 0) {
+            gen_op_andi_(MASK(mb, 31));
+            goto store;
+        }
+    }
+    gen_op_rlwinm(sh, MASK(mb, me));
+store:
+    if (Rc(ctx->opcode) != 0)
+        gen_op_set_Rc0();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* rlwnm & rlwnm. */
+GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    uint32_t mb, me;
+
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    if (mb == 0 && me == 31) {
+        gen_op_rotl();
+    } else
+    {
+        gen_op_rlwnm(MASK(mb, me));
+    }
+    if (Rc(ctx->opcode) != 0)
+        gen_op_set_Rc0();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/***                             Integer shift                             ***/
+/* slw & slw. */
+__GEN_LOGICAL2(slw, 0x18, 0x00);
+/* sraw & sraw. */
+__GEN_LOGICAL2(sraw, 0x18, 0x18);
+/* srawi & srawi. */
+GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
+    if (Rc(ctx->opcode) != 0)
+        gen_op_set_Rc0();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    SET_RETVAL(0);
+}
+/* srw & srw. */
+__GEN_LOGICAL2(srw, 0x18, 0x10);
+
+/***                       Floating-Point arithmetic                       ***/
+/* fadd */
+GEN_HANDLER(fadd, 0x3F, 0x15, 0xFF, 0x000007C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fadds */
+GEN_HANDLER(fadds, 0x3B, 0x15, 0xFF, 0x000007C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fdiv */
+GEN_HANDLER(fdiv, 0x3F, 0x12, 0xFF, 0x000007C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fdivs */
+GEN_HANDLER(fdivs, 0x3B, 0x12, 0xFF, 0x000007C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fmul */
+GEN_HANDLER(fmul, 0x3F, 0x19, 0xFF, 0x0000F800, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fmuls */
+GEN_HANDLER(fmuls, 0x3B, 0x19, 0xFF, 0x0000F800, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fres */
+GEN_HANDLER(fres, 0x3B, 0x18, 0xFF, 0x001807C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* frsqrte */
+GEN_HANDLER(frsqrte, 0x3F, 0x1A, 0xFF, 0x001807C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fsel */
+GEN_HANDLER(fsel, 0x3F, 0x17, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fsub */
+GEN_HANDLER(fsub, 0x3F, 0x14, 0xFF, 0x000007C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fsubs */
+GEN_HANDLER(fsubs, 0x3B, 0x14, 0xFF, 0x000007C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* Optional: */
+/* fsqrt */
+GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001807C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fsqrts */
+GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001807C0, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                     Floating-Point multiply-and-add                   ***/
+/* fmadd */
+GEN_HANDLER(fmadd, 0x3F, 0x1D, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fmadds */
+GEN_HANDLER(fmadds, 0x3B, 0x1D, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fmsub */
+GEN_HANDLER(fmsub, 0x3F, 0x1C, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fmsubs */
+GEN_HANDLER(fmsubs, 0x3B, 0x1C, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fnmadd */
+GEN_HANDLER(fnmadd, 0x3F, 0x1F, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fnmadds */
+GEN_HANDLER(fnmadds, 0x3B, 0x1F, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fnmsub */
+GEN_HANDLER(fnmsub, 0x3F, 0x1E, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fnmsubs */
+GEN_HANDLER(fnmsubs, 0x3B, 0x1E, 0xFF, 0x00000000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                     Floating-Point round & convert                    ***/
+/* fctiw */
+GEN_HANDLER(fctiw, 0x3F, 0x0E, 0xFF, 0x001F0000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fctiwz */
+GEN_HANDLER(fctiwz, 0x3F, 0x0F, 0xFF, 0x001F0000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* frsp */
+GEN_HANDLER(frsp, 0x3F, 0x0C, 0xFF, 0x001F0000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                         Floating-Point compare                        ***/
+/* fcmpo */
+GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fcmpu */
+GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                  Floating-Point status & ctrl register                ***/
+/* mcrfs */
+GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* mffs */
+GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
+{
+    gen_op_load_fpscr(rD(ctx->opcode));
+    if (Rc(ctx->opcode)) {
+        /* Update CR1 */
+    }
+    SET_RETVAL(0);
+}
+
+/* mtfsb0 */
+GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* mtfsb1 */
+GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* mtfsf */
+GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
+{
+    gen_op_store_fpscr(FM(ctx->opcode), rB(ctx->opcode));
+    if (Rc(ctx->opcode)) {
+        /* Update CR1 */
+    }
+    SET_RETVAL(0);
+}
+
+/* mtfsfi */
+GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                             Integer load                              ***/
+#define GEN_ILDZ(width, opc)                                                  \
+GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)               \
+{                                                                             \
+    uint32_t simm = SIMM(ctx->opcode);                                        \
+    if (rA(ctx->opcode) == 0) {                                               \
+        gen_op_l##width##_z(simm);                                            \
+    } else {                                                                  \
+        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
+        gen_op_l##width (simm);                                               \
+    }                                                                         \
+    gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_ILDZU(width, opc)                                                 \
+GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)            \
+{                                                                             \
+    if (rA(ctx->opcode) == 0 ||                                               \
+        rA(ctx->opcode) == rD(ctx->opcode))                                   \
+        SET_RETVAL(EXCP_INVAL);                                               \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_l##width(SIMM(ctx->opcode));                                       \
+    gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_ILDZUX(width, opc)                                                \
+GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
+{                                                                             \
+    if (rA(ctx->opcode) == 0 ||                                               \
+        rA(ctx->opcode) == rD(ctx->opcode))                                   \
+        SET_RETVAL(EXCP_INVAL);                                               \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    gen_op_l##width##x();                                                     \
+    gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_ILDZX(width, opc2, opc3)                                          \
+GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)           \
+{                                                                             \
+    if (rA(ctx->opcode) == 0) {                                               \
+        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
+        gen_op_l##width##x_z();                                               \
+    } else {                                                                  \
+        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
+        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
+        gen_op_l##width##x();                                                 \
+    }                                                                         \
+    gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_ILD(width, op)                                                    \
+GEN_ILDZ(width, op | 0x20)                                                    \
+GEN_ILDZU(width, op | 0x21)                                                   \
+GEN_ILDZUX(width, op | 0x01)                                                  \
+GEN_ILDZX(width, 0x17, op | 0x00)
+
+/* lbz lbzu lbzux lbzx */
+GEN_ILD(bz, 0x02);
+/* lha lhau lhaux lhax */
+GEN_ILD(ha, 0x0A);
+/* lhz lhzu lhzux lhzx */
+GEN_ILD(hz, 0x08);
+/* lwz lwzu lwzux lwzx */
+GEN_ILD(wz, 0x00);
+
+/***                              Integer store                            ***/
+#define GEN_IST(width, opc)                                                   \
+GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)              \
+{                                                                             \
+    uint32_t simm = SIMM(ctx->opcode);                                        \
+    if (rA(ctx->opcode) == 0) {                                               \
+        gen_op_load_gpr_T0(rS(ctx->opcode));                                  \
+        gen_op_st##width##_z(simm);                                           \
+    } else {                                                                  \
+        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
+        gen_op_load_gpr_T1(rS(ctx->opcode));                                  \
+        gen_op_st##width(simm);                                               \
+    }                                                                         \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_ISTU(width, opc)                                                  \
+GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
+{                                                                             \
+    if (rA(ctx->opcode) == 0)                                                 \
+        SET_RETVAL(EXCP_INVAL);                                               \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
+    gen_op_st##width(SIMM(ctx->opcode));                                      \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_ISTUX(width, opc)                                                 \
+GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
+{                                                                             \
+    if (rA(ctx->opcode) == 0)                                                 \
+        SET_RETVAL(EXCP_INVAL);                                               \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    gen_op_load_gpr_T2(rS(ctx->opcode));                                      \
+    gen_op_st##width##x();                                                    \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_ISTX(width, opc2, opc3)                                           \
+GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)          \
+{                                                                             \
+    if (rA(ctx->opcode) == 0) {                                               \
+        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
+        gen_op_load_gpr_T1(rS(ctx->opcode));                                  \
+        gen_op_st##width##x_z();                                              \
+    } else {                                                                  \
+        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
+        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
+        gen_op_load_gpr_T2(rS(ctx->opcode));                                  \
+        gen_op_st##width##x();                                                \
+    }                                                                         \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_ISTO(width, opc)                                                  \
+GEN_IST(width, opc | 0x20)                                                    \
+GEN_ISTU(width, opc | 0x21)                                                   \
+GEN_ISTUX(width, opc | 0x01)                                                  \
+GEN_ISTX(width, 0x17, opc | 0x00)
+
+/* stb stbu stbux stbx */
+GEN_ISTO(b, 0x06);
+/* sth sthu sthux sthx */
+GEN_ISTO(h, 0x0C);
+/* stw stwu stwux stwx */
+GEN_ISTO(w, 0x04);
+
+/***                Integer load and store with byte reverse               ***/
+/* lhbrx */
+GEN_ILDZX(hbr, 0x16, 0x18);
+/* lwbrx */
+GEN_ILDZX(wbr, 0x16, 0x10);
+/* sthbrx */
+GEN_ISTX(hbr, 0x16, 0x1C);
+/* stwbrx */
+GEN_ISTX(wbr, 0x16, 0x14);
+
+/***                    Integer load and store multiple                    ***/
+/* lmw */
+GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T0(0);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+    }
+    gen_op_lmw(rD(ctx->opcode), SIMM(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/* stmw */
+GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T0(0);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+    }
+    gen_op_stmw(rS(ctx->opcode), SIMM(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/***                    Integer load and store strings                     ***/
+/* lswi */
+GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
+{
+    int nb = NB(ctx->opcode);
+    int start = rD(ctx->opcode);
+    int nr;
+
+    if (nb == 0)
+        nb = 32;
+    nr = nb / 4;
+    if ((start + nr) > 32) {
+        /* handle wrap around r0 */
+        if (rA(ctx->opcode) == 0) {
+            gen_op_set_T0(0);
+        } else {
+            gen_op_load_gpr_T0(rA(ctx->opcode));
+        }
+        gen_op_lswi(start, 4 * (32 - start));
+        nb -= 4 * (32 - start);
+        start = 0;
+    }
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T0(0);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+    }
+    gen_op_lswi(start, nb);
+    SET_RETVAL(0);
+}
+
+/* lswx */
+GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
+{
+    gen_op_load_xer_bc();
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T2(0);
+    } else {
+        gen_op_load_gpr_T2(rA(ctx->opcode));
+    }
+    gen_op_lswx(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/* stswi */
+GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
+{
+    int nb = NB(ctx->opcode);
+    int start = rS(ctx->opcode);
+    int nr;
+
+    if (nb == 0)
+        nb = 32;
+    nr = nb / 4;
+    if ((start + nr) > 32) {
+        /* handle wrap around r0 */
+        if (rA(ctx->opcode) == 0) {
+            gen_op_set_T0(0);
+        } else {
+            gen_op_load_gpr_T0(rA(ctx->opcode));
+        }
+        gen_op_stswi(start, 4 * (32 - start));
+        nb -= 4 * (32 - start);
+        start = 0;
+    }
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T0(0);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+    }
+    gen_op_stswi(start, nb);
+    SET_RETVAL(0);
+}
+
+/* stswx */
+GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
+{
+    gen_op_load_xer_bc();
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T2(0);
+    } else {
+        gen_op_load_gpr_T2(rA(ctx->opcode));
+    }
+    gen_op_stswx(rS(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/***                        Memory synchronisation                         ***/
+/* eieio */
+GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM)
+{
+    /* Do a branch to next instruction */
+    gen_op_b((uint32_t)ctx->nip);
+    SET_RETVAL(EXCP_BRANCH);
+}
+
+/* isync */
+GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
+{
+    /* Do a branch to next instruction */
+    gen_op_b((uint32_t)ctx->nip);
+    SET_RETVAL(EXCP_BRANCH);
+}
+
+/* lwarx */
+GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_MEM)
+{
+    reserve = 1;
+    if (rA(ctx->opcode) == 0) {
+        gen_op_load_gpr_T0(rB(ctx->opcode));
+        gen_op_lwzx_z();
+        gen_op_set_reservation();
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rB(ctx->opcode));
+        gen_op_lwzx();
+        gen_op_set_reservation();
+    }
+    gen_op_store_T1_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/* stwcx. */
+GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_MEM)
+{
+    if (reserve == 0) {
+        gen_op_reset_Rc0();
+    } else {
+        if (rA(ctx->opcode) == 0) {
+            gen_op_load_gpr_T0(rB(ctx->opcode));
+            gen_op_load_gpr_T1(rS(ctx->opcode));
+            gen_op_stwx_z();
+        } else {
+            gen_op_load_gpr_T0(rA(ctx->opcode));
+            gen_op_load_gpr_T1(rB(ctx->opcode));
+            gen_op_load_gpr_T2(rS(ctx->opcode));
+            gen_op_stwx();
+        }
+        gen_op_set_Rc0_1();
+        gen_op_reset_reservation();
+    }
+    SET_RETVAL(0);
+}
+
+/* sync */
+GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
+{
+    /* Do a branch to next instruction */
+    gen_op_b((uint32_t)ctx->nip);
+    SET_RETVAL(EXCP_BRANCH);
+}
+
+/***                         Floating-point load                           ***/
+#define GEN_LF(width, opc)                                                    \
+GEN_HANDLER(lf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)                \
+{                                                                             \
+    uint32_t simm = SIMM(ctx->opcode);                                        \
+    if (rA(ctx->opcode) == 0) {                                               \
+        gen_op_lf##width##_z(simm, rD(ctx->opcode));                          \
+    } else {                                                                  \
+        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
+        gen_op_lf##width(simm, rD(ctx->opcode));                              \
+    }                                                                         \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_LFU(width, opc)                                                   \
+GEN_HANDLER(lf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)             \
+{                                                                             \
+    if (rA(ctx->opcode) == 0 ||                                               \
+        rA(ctx->opcode) == rD(ctx->opcode))                                   \
+        SET_RETVAL(EXCP_INVAL);                                               \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_lf##width(SIMM(ctx->opcode), rD(ctx->opcode));                     \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_LFUX(width, opc)                                                  \
+GEN_HANDLER(lf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)            \
+{                                                                             \
+    if (rA(ctx->opcode) == 0 ||                                               \
+        rA(ctx->opcode) == rD(ctx->opcode))                                   \
+        SET_RETVAL(EXCP_INVAL);                                               \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    gen_op_lf##width##x(rD(ctx->opcode));                                     \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_LFX(width, opc)                                                   \
+GEN_HANDLER(lf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)             \
+{                                                                             \
+    if (rA(ctx->opcode) == 0) {                                               \
+        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
+        gen_op_lf##width##x_z(rD(ctx->opcode));                               \
+    } else {                                                                  \
+        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
+        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
+        gen_op_lf##width##x(rD(ctx->opcode));                                 \
+    }                                                                         \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_LDF(width, opc)                                                   \
+GEN_LF(width, opc | 0x20)                                                     \
+GEN_LFU(width, opc | 0x21)                                                    \
+GEN_LFUX(width, opc | 0x01)                                                   \
+GEN_LFX(width, opc | 0x00)
+
+/* lfd lfdu lfdux lfdx */
+GEN_LDF(d, 0x12);
+/* lfs lfsu lfsux lfsx */
+#define gen_op_lfs_z(a, b)
+#define gen_op_lfs(a, b)
+#define gen_op_lfsx_z(a)
+#define gen_op_lfsx(a)
+GEN_LDF(s, 0x10);
+
+/***                         Floating-point store                          ***/
+#define GEN_STF(width, opc)                                                   \
+GEN_HANDLER(stf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)               \
+{                                                                             \
+    uint32_t simm = SIMM(ctx->opcode);                                        \
+    if (rA(ctx->opcode) == 0) {                                               \
+        gen_op_stf##width##_z(simm, rS(ctx->opcode));                         \
+    } else {                                                                  \
+        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
+        gen_op_stf##width(simm, rS(ctx->opcode));                             \
+    }                                                                         \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_STFU(width, opc)                                                  \
+GEN_HANDLER(stf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)            \
+{                                                                             \
+    if (rA(ctx->opcode) == 0)                                                 \
+        SET_RETVAL(EXCP_INVAL);                                               \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_stf##width(SIMM(ctx->opcode), rS(ctx->opcode));                    \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_STFUX(width, opc)                                                 \
+GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)           \
+{                                                                             \
+    if (rA(ctx->opcode) == 0)                                                 \
+        SET_RETVAL(EXCP_INVAL);                                               \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    gen_op_stf##width##x(rS(ctx->opcode));                                    \
+    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_STFX(width, opc)                                                  \
+GEN_HANDLER(stf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)            \
+{                                                                             \
+    if (rA(ctx->opcode) == 0) {                                               \
+        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
+        gen_op_stf##width##x_z(rS(ctx->opcode));                              \
+    } else {                                                                  \
+        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
+        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
+        gen_op_stf##width##x(rS(ctx->opcode));                                \
+    }                                                                         \
+    SET_RETVAL(0);                                                            \
+}
+
+#define GEN_STOF(width, opc)                                                  \
+GEN_STF(width, opc | 0x20)                                                    \
+GEN_STFU(width, opc | 0x21)                                                   \
+GEN_STFUX(width, opc | 0x01)                                                  \
+GEN_STFX(width, opc | 0x00)
+
+/* stfd stfdu stfdux stfdx */
+GEN_STOF(d, 0x16);
+/* stfs stfsu stfsux stfsx */
+#define gen_op_stfs_z(a, b)
+#define gen_op_stfs(a, b)
+#define gen_op_stfsx_z(a)
+#define gen_op_stfsx(a)
+GEN_STOF(s, 0x14);
+
+/* Optional: */
+/* stfiwx */
+GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                         Floating-point move                           ***/
+/* fabs */
+GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fmr */
+GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fnabs */
+GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* fneg */
+GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                                Branch                                 ***/
+#define GEN_BCOND(name, opc1, opc2, opc3, prologue,                           \
+   bl_ctr,       b_ctr,       bl_ctrz,       b_ctrz,       b,                 \
+   bl_ctr_true,  b_ctr_true,  bl_ctrz_true,  b_ctrz_true,  bl_true,  b_true,  \
+   bl_ctr_false, b_ctr_false, bl_ctrz_false, b_ctrz_false, bl_false, b_false) \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x00000000, PPC_FLOW)                     \
+{                                                                             \
+    __attribute__ ((unused)) uint32_t target;                                 \
+    uint32_t bo = BO(ctx->opcode);                                            \
+    uint32_t bi = BI(ctx->opcode);                                            \
+    uint32_t mask;                                                            \
+    prologue;                                                                 \
+    if ((bo & 0x4) == 0)                                                      \
+        gen_op_dec_ctr();                                                     \
+    if (bo & 0x10) {                                                          \
+        /* No CR condition */                                                 \
+        switch (bo & 0x6) {                                                   \
+        case 0:                                                               \
+            if (LK(ctx->opcode)) {                                            \
+                bl_ctr;                                                       \
+            } else {                                                          \
+                b_ctr;                                                        \
+            }                                                                 \
+            break;                                                            \
+        case 2:                                                               \
+            if (LK(ctx->opcode)) {                                            \
+                bl_ctrz;                                                      \
+            } else {                                                          \
+                b_ctrz;                                                       \
+            }                                                                 \
+            break;                                                            \
+        case 4:                                                               \
+        case 6:                                                               \
+            b;                                                                \
+            if (LK(ctx->opcode))                                              \
+                gen_op_load_lr((uint32_t)ctx->nip);                           \
+            break;                                                            \
+        default:                                                              \
+            printf("ERROR: %s: unhandled ba case (%d)\n", __func__, bo);      \
+            SET_RETVAL(EXCP_INVAL);                                           \
+            break;                                                            \
+        }                                                                     \
+    } else {                                                                  \
+        mask = 1 << (3 - (bi & 0x03));                                        \
+        gen_op_load_crf_T0(bi >> 2);                                          \
+        if (bo & 0x8) {                                                       \
+            switch (bo & 0x6) {                                               \
+            case 0:                                                           \
+                if (LK(ctx->opcode)) {                                        \
+                    bl_ctr_true;                                              \
+                } else {                                                      \
+                    b_ctr_true;                                               \
+                }                                                             \
+                break;                                                        \
+            case 2:                                                           \
+                if (LK(ctx->opcode)) {                                        \
+                    bl_ctrz_true;                                             \
+                } else {                                                      \
+                    b_ctrz_true;                                              \
+                }                                                             \
+                break;                                                        \
+            case 4:                                                           \
+            case 6:                                                           \
+                if (LK(ctx->opcode)) {                                        \
+                    bl_true;                                                  \
+                } else {                                                      \
+                    b_true;                                                   \
+                }                                                             \
+                break;                                                        \
+            default:                                                          \
+                printf("ERROR: %s: unhandled b case (%d)\n", __func__, bo);   \
+                SET_RETVAL(EXCP_INVAL);                                       \
+                break;                                                        \
+            }                                                                 \
+        } else {                                                              \
+            switch (bo & 0x6) {                                               \
+            case 0:                                                           \
+                if (LK(ctx->opcode)) {                                        \
+                    bl_ctr_false;                                             \
+                } else {                                                      \
+                    b_ctr_false;                                              \
+                }                                                             \
+                break;                                                        \
+            case 2:                                                           \
+                if (LK(ctx->opcode)) {                                        \
+                    bl_ctrz_false;                                            \
+                } else {                                                      \
+                    b_ctrz_false;                                             \
+                }                                                             \
+                break;                                                        \
+            case 4:                                                           \
+            case 6:                                                           \
+                if (LK(ctx->opcode)) {                                        \
+                    bl_false;                                                 \
+                } else {                                                      \
+                    b_false;                                                  \
+                }                                                             \
+                break;                                                        \
+            default:                                                          \
+                printf("ERROR: %s: unhandled bn case (%d)\n", __func__, bo);  \
+                SET_RETVAL(EXCP_INVAL);                                       \
+                break;                                                        \
+            }                                                                 \
+        }                                                                     \
+    }                                                                         \
+    SET_RETVAL(EXCP_BRANCH);                                                  \
+}
+
+/* b ba bl bla */
+GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
+{
+    uint32_t li = s_ext24(LI(ctx->opcode)), target;
+
+    if (AA(ctx->opcode) == 0)
+        target = (uint32_t)ctx->nip + li - 4;
+    else
+        target = s_ext24(LI(ctx->opcode));
+    gen_op_b(target);
+    if (LK(ctx->opcode))
+        gen_op_load_lr((uint32_t)ctx->nip);
+    SET_RETVAL(EXCP_BRANCH);
+}
+
+/* bc bca bcl bcla */
+GEN_BCOND(bc, 0x10, 0xFF, 0xFF,
+          do {
+              uint32_t li = s_ext16(BD(ctx->opcode));
+              if (AA(ctx->opcode) == 0) {
+                  target = (uint32_t)ctx->nip + li - 4;
+              } else {
+                  target = li;
+              }
+          } while (0),
+          gen_op_bl_ctr((uint32_t)ctx->nip, target),
+          gen_op_b_ctr((uint32_t)ctx->nip, target),
+          gen_op_bl_ctrz((uint32_t)ctx->nip, target),
+          gen_op_b_ctrz((uint32_t)ctx->nip, target),
+          gen_op_b(target),
+          gen_op_bl_ctr_true((uint32_t)ctx->nip, target, mask),
+          gen_op_b_ctr_true((uint32_t)ctx->nip, target, mask),
+          gen_op_bl_ctrz_true((uint32_t)ctx->nip, target, mask),
+          gen_op_b_ctrz_true((uint32_t)ctx->nip, target, mask),
+          gen_op_bl_true((uint32_t)ctx->nip, target, mask),
+          gen_op_b_true((uint32_t)ctx->nip, target, mask),
+          gen_op_bl_ctr_false((uint32_t)ctx->nip, target, mask),
+          gen_op_b_ctr_false((uint32_t)ctx->nip, target, mask),
+          gen_op_bl_ctrz_false((uint32_t)ctx->nip, target, mask),
+          gen_op_b_ctrz_false((uint32_t)ctx->nip, target, mask),
+          gen_op_bl_false((uint32_t)ctx->nip, target, mask),
+          gen_op_b_false((uint32_t)ctx->nip, target, mask));
+
+/* bcctr bcctrl */
+GEN_BCOND(bcctr, 0x13, 0x10, 0x10, do { } while (0),
+          gen_op_bctrl_ctr((uint32_t)ctx->nip),
+          gen_op_bctr_ctr((uint32_t)ctx->nip),
+          gen_op_bctrl_ctrz((uint32_t)ctx->nip),
+          gen_op_bctr_ctrz((uint32_t)ctx->nip),
+          gen_op_bctr(),
+          gen_op_bctrl_ctr_true((uint32_t)ctx->nip, mask),
+          gen_op_bctr_ctr_true((uint32_t)ctx->nip, mask),
+          gen_op_bctrl_ctrz_true((uint32_t)ctx->nip, mask),
+          gen_op_bctr_ctrz_true((uint32_t)ctx->nip, mask),
+          gen_op_bctrl_true((uint32_t)ctx->nip, mask),
+          gen_op_bctr_true((uint32_t)ctx->nip, mask),
+          gen_op_bctrl_ctr_false((uint32_t)ctx->nip, mask),
+          gen_op_bctr_ctr_false((uint32_t)ctx->nip, mask),
+          gen_op_bctrl_ctrz_false((uint32_t)ctx->nip, mask),
+          gen_op_bctr_ctrz_false((uint32_t)ctx->nip, mask),
+          gen_op_bctrl_false((uint32_t)ctx->nip, mask),
+          gen_op_bctr_false((uint32_t)ctx->nip, mask))
+
+/* bclr bclrl */
+GEN_BCOND(bclr, 0x13, 0x10, 0x00, do { } while (0),
+          gen_op_blrl_ctr((uint32_t)ctx->nip),
+          gen_op_blr_ctr((uint32_t)ctx->nip),
+          gen_op_blrl_ctrz((uint32_t)ctx->nip),
+          gen_op_blr_ctrz((uint32_t)ctx->nip),
+          gen_op_blr(),
+          gen_op_blrl_ctr_true((uint32_t)ctx->nip, mask),
+          gen_op_blr_ctr_true((uint32_t)ctx->nip, mask),
+          gen_op_blrl_ctrz_true((uint32_t)ctx->nip, mask),
+          gen_op_blr_ctrz_true((uint32_t)ctx->nip, mask),
+          gen_op_blrl_true((uint32_t)ctx->nip, mask),
+          gen_op_blr_true((uint32_t)ctx->nip, mask),
+          gen_op_blrl_ctr_false((uint32_t)ctx->nip, mask),
+          gen_op_blr_ctr_false((uint32_t)ctx->nip, mask),
+          gen_op_blrl_ctrz_false((uint32_t)ctx->nip, mask),
+          gen_op_blr_ctrz_false((uint32_t)ctx->nip, mask),
+          gen_op_blrl_false((uint32_t)ctx->nip, mask),
+          gen_op_blr_false((uint32_t)ctx->nip, mask))
+
+/***                      Condition register logical                       ***/
+#define GEN_CRLOGIC(op, opc)                                                  \
+GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)                 \
+{                                                                             \
+    gen_op_load_crf_T0(crbA(ctx->opcode) >> 2);                               \
+    gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03));                         \
+    gen_op_load_crf_T1(crbB(ctx->opcode) >> 2);                               \
+    gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03));                         \
+    gen_op_##op();                                                            \
+    gen_op_load_crf_T1(crbD(ctx->opcode) >> 2);                               \
+    gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))),                \
+                     3 - (crbD(ctx->opcode) & 0x03));                         \
+    gen_op_store_T1_crf(crbD(ctx->opcode) >> 2);                              \
+    SET_RETVAL(0);                                                            \
+}
+
+/* crand */
+GEN_CRLOGIC(and, 0x08)
+/* crandc */
+GEN_CRLOGIC(andc, 0x04)
+/* creqv */
+GEN_CRLOGIC(eqv, 0x09)
+/* crnand */
+GEN_CRLOGIC(nand, 0x07)
+/* crnor */
+GEN_CRLOGIC(nor, 0x01)
+/* cror */
+GEN_CRLOGIC(or, 0x0E)
+/* crorc */
+GEN_CRLOGIC(orc, 0x0D)
+/* crxor */
+GEN_CRLOGIC(xor, 0x06)
+/* mcrf */
+GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
+{
+    gen_op_load_crf_T0(crfS(ctx->opcode));
+    gen_op_store_T0_crf(crfD(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/***                           System linkage                              ***/
+/* rfi (supervisor only) */
+GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* sc */
+GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
+{
+    gen_op_b((uint32_t)ctx->nip);
+    SET_RETVAL(EXCP_SYSCALL);
+}
+
+/***                                Trap                                   ***/
+/* tw */
+GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* twi */
+GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                          Processor control                            ***/
+static inline int check_spr_access (int spr, int rw, int supervisor)
+{
+    uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
+
+    rights = rights >> (2 * supervisor);
+    rights = rights >> rw;
+
+    return rights & 1;
+}
+
+/* mcrxr */
+GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
+{
+    gen_op_load_xer_cr();
+    gen_op_store_T0_crf(crfD(ctx->opcode));
+    gen_op_clear_xer_cr();
+    SET_RETVAL(0);
+}
+
+/* mfcr */
+GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
+{
+    gen_op_load_cr();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/* mfmsr */
+GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
+{
+    if (!ctx->supervisor)
+        SET_RETVAL(EXCP_PRIV);
+    gen_op_load_msr();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/* mfspr */
+GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
+{
+    uint32_t sprn = SPR(ctx->opcode);
+
+    if (check_spr_access(sprn, 0, ctx->supervisor) == 0)
+        SET_RETVAL(EXCP_PRIV);
+    /* XXX: make this more generic */
+    switch (sprn) {
+    case SPR_ENCODE(1):
+        if (loglevel > 0) {
+            fprintf(logfile, "LOAD XER at %p\n", ctx->nip - 1);
+        }
+        gen_op_load_xer();
+        break;
+    case SPR_ENCODE(268):
+        /* We need to update the time base before reading it */
+        gen_op_update_tb(ctx->tb_offset);
+        ctx->tb_offset = 0;
+        break;
+    case SPR_ENCODE(269):
+        gen_op_update_tb(ctx->tb_offset);
+        ctx->tb_offset = 0;
+        break;
+    default:
+        gen_op_load_spr(sprn);
+        break;
+    }
+    gen_op_store_T0_gpr(rD(ctx->opcode)); //
+    SET_RETVAL(0);
+}
+
+/* mftb */
+GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC)
+{
+    uint32_t sprn = SPR(ctx->opcode);
+
+    if (check_spr_access(sprn, 0, ctx->supervisor) == 0)
+        SET_RETVAL(EXCP_PRIV);
+    switch (sprn) {
+    case SPR_ENCODE(268):
+        /* We need to update the time base before reading it */
+        gen_op_update_tb(ctx->tb_offset);
+        ctx->tb_offset = 0;
+        break;
+    case SPR_ENCODE(269):
+        gen_op_update_tb(ctx->tb_offset);
+        ctx->tb_offset = 0;
+        break;
+    default:
+        SET_RETVAL(EXCP_INVAL);
+        break;
+    }
+    SET_RETVAL(0);
+}
+
+/* mtcrf */
+GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_store_cr(CRM(ctx->opcode));
+    SET_RETVAL(0);
+}
+
+/* mtmsr */
+GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
+{
+    if (!ctx->supervisor)
+        SET_RETVAL(EXCP_PRIV);
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_store_msr();
+    /* Must stop the translation as machine state (may have) changed */
+    SET_RETVAL(EXCP_MTMSR);
+}
+
+/* mtspr */
+GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
+{
+    uint32_t sprn = SPR(ctx->opcode);
+
+    if (check_spr_access(sprn, 1, ctx->supervisor) == 0)
+        SET_RETVAL(EXCP_PRIV);
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (sprn == SPR_ENCODE(1)) {
+        gen_op_store_xer();
+    } else {
+        gen_op_store_spr(sprn);
+    }
+    SET_RETVAL(0);
+}
+
+/***                         Cache management                              ***/
+/* For now, all those will be implemented as nop:
+ * this is valid, regarding the PowerPC specs...
+ */
+/* dcbf */
+GEN_HANDLER(dcbf, 0x1F, 0x16, 0x17, 0x03E00001, PPC_MEM)
+{
+    SET_RETVAL(0);
+}
+
+/* dcbi (Supervisor only) */
+GEN_HANDLER(dcbi, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_MEM)
+{
+    SET_RETVAL(0);
+}
+
+/* dcdst */
+GEN_HANDLER(dcbst, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_MEM)
+{
+    SET_RETVAL(0);
+}
+
+/* dcbt */
+GEN_HANDLER(dcbt, 0x1F, 0x16, 0x01, 0x03E00001, PPC_MEM)
+{
+    SET_RETVAL(0);
+}
+
+/* dcbtst */
+GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x02, 0x03E00001, PPC_MEM)
+{
+    SET_RETVAL(0);
+}
+
+/* dcbz */
+GEN_HANDLER(dcbz, 0x1F, 0x16, 0x08, 0x03E00001, PPC_MEM)
+{
+    SET_RETVAL(0);
+}
+
+/* icbi */
+GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_MEM)
+{
+    SET_RETVAL(0);
+}
+
+/* Optional: */
+/* dcba */
+GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_MEM)
+{
+    SET_RETVAL(0);
+}
+
+/***                    Segment register manipulation                      ***/
+/* Supervisor only: */
+/* mfsr */
+GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* mfsrin */
+GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x0010F001, PPC_SEGMENT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* mtsr */
+GEN_HANDLER(mtsr, 0x1F, 0x12, 0x02, 0x0010F801, PPC_SEGMENT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* mtsrin */
+GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x0010F001, PPC_SEGMENT)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                      Lookaside buffer management                      ***/
+/* Optional & supervisor only: */
+/* tlbia */
+GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* tlbie */
+GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF8001, PPC_MEM)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* tlbsync */
+GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFFC01, PPC_MEM)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/***                              External control                         ***/
+/* Optional: */
+/* eciwx */
+GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* ecowx */
+GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
+{
+    SET_RETVAL(EXCP_INVAL);
+}
+
+/* End opcode list */
+GEN_OPCODE_MARK(end);
+
+/*****************************************************************************/
+
+#include <string.h>
+extern FILE *stderr;
+void free (void *p);
+int fflush (FILE *f);
+
+/* Main ppc opcodes table:
+ * at init, all opcodes are invalids
+ */
+static opc_handler_t *ppc_opcodes[0x40];
+
+/* Opcode types */
+enum {
+    PPC_DIRECT   = 0, /* Opcode routine        */
+    PPC_INDIRECT = 1, /* Indirect opcode table */
+};
+
+static inline int is_indirect_opcode (void *handler)
+{
+    return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
+}
+
+static inline opc_handler_t **ind_table(void *handler)
+{
+    return (opc_handler_t **)((unsigned long)handler & ~3);
+}
+
+/* Opcodes tables creation */
+static void fill_new_table (opc_handler_t **table, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        table[i] = &invalid_handler;
+}
+
+static int create_new_table (opc_handler_t **table, unsigned char idx)
+{
+    opc_handler_t **tmp;
+
+    tmp = malloc(0x20 * sizeof(opc_handler_t));
+    if (tmp == NULL)
+        return -1;
+    fill_new_table(tmp, 0x20);
+    table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
+
+    return 0;
+}
+
+static int insert_in_table (opc_handler_t **table, unsigned char idx,
+                            opc_handler_t *handler)
+{
+    if (table[idx] != &invalid_handler)
+        return -1;
+    table[idx] = handler;
+
+    return 0;
+}
+
+static int register_direct_insn (unsigned char idx, opc_handler_t *handler)
+{
+    if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
+        fprintf(stderr, "*** ERROR: opcode %02x already assigned in main "
+                "opcode table\n", idx);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_ind_in_table (opc_handler_t **table,
+                                  unsigned char idx1, unsigned char idx2,
+                                  opc_handler_t *handler)
+{
+    if (table[idx1] == &invalid_handler) {
+        if (create_new_table(table, idx1) < 0) {
+            fprintf(stderr, "*** ERROR: unable to create indirect table "
+                    "idx=%02x\n", idx1);
+            return -1;
+        }
+    } else {
+        if (!is_indirect_opcode(table[idx1])) {
+            fprintf(stderr, "*** ERROR: idx %02x already assigned to a direct "
+                    "opcode\n", idx1);
+            return -1;
+        }
+    }
+    if (handler != NULL &&
+        insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
+        fprintf(stderr, "*** ERROR: opcode %02x already assigned in "
+                "opcode table %02x\n", idx2, idx1);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_ind_insn (unsigned char idx1, unsigned char idx2,
+                               opc_handler_t *handler)
+{
+    int ret;
+
+    ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
+
+    return ret;
+}
+
+static int register_dblind_insn (unsigned char idx1, unsigned char idx2,
+                                  unsigned char idx3, opc_handler_t *handler)
+{
+    if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
+        fprintf(stderr, "*** ERROR: unable to join indirect table idx "
+                "[%02x-%02x]\n", idx1, idx2);
+        return -1;
+    }
+    if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
+                              handler) < 0) {
+        fprintf(stderr, "*** ERROR: unable to insert opcode "
+                "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_insn (opcode_t *insn)
+{
+    if (insn->opc2 != 0xFF) {
+        if (insn->opc3 != 0xFF) {
+            if (register_dblind_insn(insn->opc1, insn->opc2, insn->opc3,
+                                     &insn->handler) < 0)
+                return -1;
+        } else {
+            if (register_ind_insn(insn->opc1, insn->opc2, &insn->handler) < 0)
+                return -1;
+        }
+    } else {
+        if (register_direct_insn(insn->opc1, &insn->handler) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+static int test_opcode_table (opc_handler_t **table, int len)
+{
+    int i, count, tmp;
+
+    for (i = 0, count = 0; i < len; i++) {
+        /* Consistency fixup */
+        if (table[i] == NULL)
+            table[i] = &invalid_handler;
+        if (table[i] != &invalid_handler) {
+            if (is_indirect_opcode(table[i])) {
+                tmp = test_opcode_table(ind_table(table[i]), 0x20);
+                if (tmp == 0) {
+                    free(table[i]);
+                    table[i] = &invalid_handler;
+                } else {
+                    count++;
+                }
+            } else {
+                count++;
+            }
+        }
+    }
+
+    return count;
+}
+
+static void fix_opcode_tables (void)
+{
+    if (test_opcode_table(ppc_opcodes, 0x40) == 0)
+        fprintf(stderr, "*** WARNING: no opcode defined !\n");
+}
+
+#define SPR_RIGHTS(rw, priv) ((2 * (priv)) + (rw))
+#define SPR_UR SPR_RIGHTS(0, 0)
+#define SPR_UW SPR_RIGHTS(1, 0)
+#define SPR_SR SPR_RIGHTS(0, 1)
+#define SPR_SW SPR_RIGHTS(1, 1)
+
+#define spr_set_rights(spr, rights)                            \
+do {                                                           \
+    spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \
+} while (0)
+
+static void init_spr_rights (void)
+{
+    /* XER    (SPR 1) */
+    spr_set_rights(SPR_ENCODE(1), SPR_UR | SPR_UW | SPR_SR | SPR_SW);
+    /* LR     (SPR 8) */
+    spr_set_rights(SPR_ENCODE(8), SPR_UR | SPR_UW | SPR_SR | SPR_SW);
+    /* CTR    (SPR 9) */
+    spr_set_rights(SPR_ENCODE(9), SPR_UR | SPR_UW | SPR_SR | SPR_SW);
+    /* TBL    (SPR 268) */
+    spr_set_rights(SPR_ENCODE(268), SPR_UR | SPR_SR);
+    /* TBU    (SPR 269) */
+    spr_set_rights(SPR_ENCODE(269), SPR_UR | SPR_SR);
+    /* DSISR  (SPR 18) */
+    spr_set_rights(SPR_ENCODE(18), SPR_SR | SPR_SW);
+    /* DAR    (SPR 19) */
+    spr_set_rights(SPR_ENCODE(19), SPR_SR | SPR_SW);
+    /* DEC    (SPR 22) */
+    spr_set_rights(SPR_ENCODE(22), SPR_SR | SPR_SW);
+    /* SDR1   (SPR 25) */
+    spr_set_rights(SPR_ENCODE(25), SPR_SR | SPR_SW);
+    /* SPRG0  (SPR 272) */
+    spr_set_rights(SPR_ENCODE(272), SPR_SR | SPR_SW);
+    /* SPRG1  (SPR 273) */
+    spr_set_rights(SPR_ENCODE(273), SPR_SR | SPR_SW);
+    /* SPRG2  (SPR 274) */
+    spr_set_rights(SPR_ENCODE(274), SPR_SR | SPR_SW);
+    /* SPRG3  (SPR 275) */
+    spr_set_rights(SPR_ENCODE(275), SPR_SR | SPR_SW);
+    /* ASR    (SPR 280) */
+    spr_set_rights(SPR_ENCODE(281), SPR_SR | SPR_SW);
+    /* EAR    (SPR 282) */
+    spr_set_rights(SPR_ENCODE(282), SPR_SR | SPR_SW);
+    /* IBAT0U (SPR 528) */
+    spr_set_rights(SPR_ENCODE(528), SPR_SR | SPR_SW);
+    /* IBAT0L (SPR 529) */
+    spr_set_rights(SPR_ENCODE(529), SPR_SR | SPR_SW);
+    /* IBAT1U (SPR 530) */
+    spr_set_rights(SPR_ENCODE(530), SPR_SR | SPR_SW);
+    /* IBAT1L (SPR 531) */
+    spr_set_rights(SPR_ENCODE(531), SPR_SR | SPR_SW);
+    /* IBAT2U (SPR 532) */
+    spr_set_rights(SPR_ENCODE(532), SPR_SR | SPR_SW);
+    /* IBAT2L (SPR 533) */
+    spr_set_rights(SPR_ENCODE(533), SPR_SR | SPR_SW);
+    /* IBAT3U (SPR 534) */
+    spr_set_rights(SPR_ENCODE(534), SPR_SR | SPR_SW);
+    /* IBAT3L (SPR 535) */
+    spr_set_rights(SPR_ENCODE(535), SPR_SR | SPR_SW);
+    /* DBAT0U (SPR 536) */
+    spr_set_rights(SPR_ENCODE(536), SPR_SR | SPR_SW);
+    /* DBAT0L (SPR 537) */
+    spr_set_rights(SPR_ENCODE(537), SPR_SR | SPR_SW);
+    /* DBAT1U (SPR 538) */
+    spr_set_rights(SPR_ENCODE(538), SPR_SR | SPR_SW);
+    /* DBAT1L (SPR 539) */
+    spr_set_rights(SPR_ENCODE(539), SPR_SR | SPR_SW);
+    /* DBAT2U (SPR 540) */
+    spr_set_rights(SPR_ENCODE(540), SPR_SR | SPR_SW);
+    /* DBAT2L (SPR 541) */
+    spr_set_rights(SPR_ENCODE(541), SPR_SR | SPR_SW);
+    /* DBAT3U (SPR 542) */
+    spr_set_rights(SPR_ENCODE(542), SPR_SR | SPR_SW);
+    /* DBAT3L (SPR 543) */
+    spr_set_rights(SPR_ENCODE(543), SPR_SR | SPR_SW);
+    /* DABR   (SPR 1013) */
+    spr_set_rights(SPR_ENCODE(1013), SPR_SR | SPR_SW);
+    /* FPECR  (SPR 1022) */
+    spr_set_rights(SPR_ENCODE(1022), SPR_SR | SPR_SW);
+    /* PIR    (SPR 1023) */
+    spr_set_rights(SPR_ENCODE(1023), SPR_SR | SPR_SW);
+    /* PVR    (SPR 287) */
+    spr_set_rights(SPR_ENCODE(287), SPR_SR);
+    /* TBL    (SPR 284) */
+    spr_set_rights(SPR_ENCODE(284), SPR_SW);
+    /* TBU    (SPR 285) */
+    spr_set_rights(SPR_ENCODE(285), SPR_SW);
+}
+
+/* PPC "main stream" common instructions */
+#define PPC_COMMON  (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \
+                     PPC_MISC | PPC_EXTERN | PPC_SEGMENT)
+
+typedef struct ppc_proc_t {
+    int flags;
+    void *specific;
+} ppc_proc_t;
+
+typedef struct ppc_def_t {
+    unsigned long pvr;
+    unsigned long pvr_mask;
+    ppc_proc_t *proc;
+} ppc_def_t;
+
+static ppc_proc_t ppc_proc_common = {
+    .flags    = PPC_COMMON,
+    .specific = NULL,
+};
+
+static ppc_def_t ppc_defs[] =
+{
+    /* Fallback */
+    {
+        .pvr      = 0x00000000,
+        .pvr_mask = 0x00000000,
+        .proc     = &ppc_proc_common,
+    },
+};
+
+static int create_ppc_proc (unsigned long pvr)
+{
+    opcode_t *opc;
+    int i, flags;
+
+    fill_new_table(ppc_opcodes, 0x40);
+    for (i = 0; ; i++) {
+        if ((ppc_defs[i].pvr & ppc_defs[i].pvr_mask) ==
+            (pvr & ppc_defs[i].pvr_mask)) {
+            flags = ppc_defs[i].proc->flags;
+            break;
+        }
+    }
+    
+    for (opc = &opc_start + 1; opc != &opc_end; opc++) {
+        if ((opc->type & flags) != 0)
+            if (register_insn(opc) < 0) {
+                fprintf(stderr, "*** ERROR initializing PPC instruction "
+                        "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
+                        opc->opc3);
+                return -1;
+            }
+    }
+    fix_opcode_tables();
+
+    return 0;
+}
+
+/*****************************************************************************/
+uint32_t do_load_xer (void);
+
+void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags)
+{
+    int i;
+
+    if (loglevel > 0) {
+        fprintf(logfile, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x\n",
+                env->nip, env->LR, env->CTR, do_load_xer());
+        for (i = 0; i < 32; i++) {
+            if ((i & 7) == 0)
+                fprintf(logfile, "GPR%02d:", i);
+            fprintf(logfile, " %08x", env->gpr[i]);
+            if ((i & 7) == 7)
+                fprintf(logfile, "\n");
+        }
+        fprintf(logfile, "CR: 0x");
+        for (i = 0; i < 8; i++)
+            fprintf(logfile, "%01x", env->crf[i]);
+        fprintf(logfile, "  [");
+        for (i = 0; i < 8; i++) {
+            char a = '-';
+            
+            if (env->crf[i] & 0x08)
+                a = 'L';
+            else if (env->crf[i] & 0x04)
+                a = 'G';
+            else if (env->crf[i] & 0x02)
+                a = 'E';
+            fprintf(logfile, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
+        }
+        fprintf(logfile, " ] ");
+        fprintf(logfile, "TB: 0x%08x %08x\n", env->spr[SPR_ENCODE(269)],
+                env->spr[SPR_ENCODE(268)]);
+        for (i = 0; i < 16; i++) {
+            if ((i & 3) == 0)
+                fprintf(logfile, "FPR%02d:", i);
+            fprintf(logfile, " %016llx", env->fpr[i]);
+            if ((i & 3) == 3)
+                fprintf(logfile, "\n");
+        }
+        fflush(logfile);
+    }
+}
+
+CPUPPCState *cpu_ppc_init(void)
+{
+    CPUPPCState *env;
+
+    cpu_exec_init();
+
+    env = malloc(sizeof(CPUPPCState));
+    if (!env)
+        return NULL;
+    memset(env, 0, sizeof(CPUPPCState));
+    env->PVR = 0;
+    if (create_ppc_proc(0) < 0)
+        return NULL;
+    init_spr_rights();
+
+    return env;
+}
+
+void cpu_ppc_close(CPUPPCState *env)
+{
+    /* Should also remove all opcode tables... */
+    free(env);
+}
+
+int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
+                                    int search_pc)
+{
+    DisasContext ctx;
+    opc_handler_t **table, *handler;
+    uint32_t pc_start;
+    uint16_t *gen_opc_end;
+    int j, lj = -1;
+    int ret = 0;
+
+    pc_start = tb->pc;
+    gen_opc_ptr = gen_opc_buf;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    gen_opparam_ptr = gen_opparam_buf;
+    ctx.nip = (uint32_t *)pc_start;
+    ctx.tb_offset = 0;
+    ctx.supervisor = msr_ip;
+    ctx.tb = tb;
+    ctx.exception = 0;
+
+    while (ret == 0 && gen_opc_ptr < gen_opc_end) {
+        if (search_pc) {
+            if (loglevel > 0)
+                fprintf(logfile, "Search PC...\n");
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+                gen_opc_pc[lj] = (uint32_t)ctx.nip;
+                gen_opc_instr_start[lj] = 1;
+            }
+        }
+        ctx.opcode = __be32_to_cpu(*ctx.nip);
+#ifdef DEBUG_DISAS
+        if (loglevel > 0) {
+            fprintf(logfile, "----------------\n");
+            fprintf(logfile, "%p: translate opcode %08x\n",
+                    ctx.nip, ctx.opcode);
+        }
+#endif
+        ctx.nip++;
+        table = ppc_opcodes;
+        handler = table[opc1(ctx.opcode)];
+        if (is_indirect_opcode(handler)) {
+            table = ind_table(handler);
+            handler = table[opc2(ctx.opcode)];
+            if (is_indirect_opcode(handler)) {
+                table = ind_table(handler);
+                handler = table[opc3(ctx.opcode)];
+            }
+        }
+        /* Is opcode *REALLY* valid ? */
+        if ((ctx.opcode & handler->inval) != 0) {
+            if (loglevel > 0) {
+                if (handler->handler == &gen_invalid) {
+                    fprintf(logfile, "invalid/unsupported opcode: "
+                            "%02x -%02x - %02x (%08x)\n", opc1(ctx.opcode),
+                            opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode);
+                } else {
+                    fprintf(logfile, "invalid bits: %08x for opcode: "
+                            "%02x -%02x - %02x (%p)\n",
+                            ctx.opcode & handler->inval, opc1(ctx.opcode),
+                            opc2(ctx.opcode), opc3(ctx.opcode),
+                            handler->handler);
+                }
+            }
+            ret = GET_RETVAL(gen_invalid, ctx.opcode);
+        } else {
+            ret = GET_RETVAL(*(handler->handler), ctx.opcode);
+        }
+        ctx.tb_offset++;
+#if defined (DO_SINGLE_STEP)
+        break;
+#endif
+    }
+#if defined (DO_STEP_FLUSH)
+        tb_flush();
+#endif
+    /* We need to update the time base */
+    if (!search_pc)
+        gen_op_update_tb(ctx.tb_offset);
+    /* If we are in step-by-step mode, do a branch to the next instruction
+     * so the nip will be up-to-date
+     */
+#if defined (DO_SINGLE_STEP)
+    if (ret == 0) {
+        gen_op_b((uint32_t)ctx.nip);
+        ret = EXCP_BRANCH;
+    }
+#endif
+    /* If the exeption isn't a PPC one,
+     * generate it now.
+     */
+    if (ret != EXCP_BRANCH) {
+        gen_op_set_T0(0);
+        if ((ret & 0x2000) == 0)
+            gen_op_raise_exception(ret);
+    }
+    /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
+     *              do bad business and then qemu crashes !
+     */
+    gen_op_set_T0(0);
+    /* Generate the return instruction */
+    gen_op_exit_tb();
+    *gen_opc_ptr = INDEX_op_end;
+    if (!search_pc)
+        tb->size = (uint32_t)ctx.nip - pc_start;
+    else
+        tb->size = 0;
+//    *gen_opc_ptr = INDEX_op_end;
+#ifdef DEBUG_DISAS
+    if (loglevel > 0) {
+        fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start));
+	disas(logfile, (void *)pc_start, (uint32_t)ctx.nip - pc_start, 0, 0);
+        fprintf(logfile, "\n");
+
+        fprintf(logfile, "OP:\n");
+        dump_ops(gen_opc_buf, gen_opparam_buf);
+        fprintf(logfile, "\n");
+    }
+#endif
+
+    return 0;
+}
+
+int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb)
+{
+    return gen_intermediate_code_internal(env, tb, 0);
+}
+
+int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb)
+{
+    return gen_intermediate_code_internal(env, tb, 1);
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (21 preceding siblings ...)
  2003-11-18  7:59   ` J. Mayer
@ 2003-11-18  8:00   ` J. Mayer
  2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
                     ` (2 subsequent siblings)
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:00 UTC (permalink / raw)
  To: qemu-devel

translate-all.c.diff

Fix for PPC target support.

diff -urNbB -x CVS qemu-current/translate-all.c qemu/translate-all.c
--- qemu-current/translate-all.c	Tue Nov 18 06:51:10 2003
+++ qemu/translate-all.c	Tue Nov 11 00:10:49 2003
@@ -191,6 +191,8 @@
     env->regs[15] = gen_opc_pc[j];
 #elif defined(TARGET_SPARC)
 	env->pc = gen_opc_pc[j];
+#elif defined(TARGET_PPC)
+    env->gpr[1] = gen_opc_pc[j];
 #endif
     return 0;
 }

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] tests for PPC target.
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (22 preceding siblings ...)
  2003-11-18  8:00   ` J. Mayer
@ 2003-11-18  8:02   ` J. Mayer
  2003-11-18  8:06     ` J. Mayer
                       ` (5 more replies)
  2003-11-18  8:24   ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
  2003-11-18  9:37   ` Gwenole Beauchesne
  25 siblings, 6 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:02 UTC (permalink / raw)
  To: qemu-devel

Here's a set of tests programs for PPC target emulation.
Here's the file list:
target-ppc__tests__compile_ppc_test.diff
target-ppc__tests__ctrace.c.diff
target-ppc__tests__env-test.c.diff
target-ppc__tests__hello-ppc.c.diff
target-ppc__tests__ppc-test.c.diff

Please note that target-ppc__tests__ppc-test.c.diff is bigger than 40
kb, so the post will need approbation.

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] tests for PPC target.
  2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
@ 2003-11-18  8:06     ` J. Mayer
  2003-11-18  8:08     ` J. Mayer
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:06 UTC (permalink / raw)
  To: qemu-devel

target-ppc__tests__compile_ppc_test.diff

Little shell script to compile test programs.

diff -urNbB -x CVS qemu-current/target-ppc/tests/compile_ppc_test qemu/target-ppc/tests/compile_ppc_test
--- qemu-current/target-ppc/tests/compile_ppc_test	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/tests/compile_ppc_test	Wed Nov 12 10:37:56 2003
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+powerpc-linux-gcc -g -O2 -Wall -nostdlib -nostdinc -nostartfiles -nodefaultlibs -o hello-ppc hello-ppc.c || exit 1;
+powerpc-linux-gcc -g -O2 -Wall -nostdlib -nostdinc -nostartfiles -nodefaultlibs -o env-test env-test.c   || exit 1;
+powerpc-linux-gcc -g -O2 -Wall -nostdlib -nostdinc -nostartfiles -nodefaultlibs -o ppc-test ppc-test.c   || exit 1;
+gcc -g -O2 -Wall -o ctrace ctrace.c || exit 1;

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] tests for PPC target.
  2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
  2003-11-18  8:06     ` J. Mayer
@ 2003-11-18  8:08     ` J. Mayer
  2003-11-18  8:08     ` J. Mayer
                       ` (3 subsequent siblings)
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:08 UTC (permalink / raw)
  To: qemu-devel

target-ppc__tests__ctrace.c.diff

This is a program which follows the execution of it's child and
print the state of the CPU for each executed instruction.
The output can be compared with qemu.log to find qemu bugs...

diff -urNbB -x CVS qemu-current/target-ppc/tests/ctrace.c qemu/target-ppc/tests/ctrace.c
--- qemu-current/target-ppc/tests/ctrace.c	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/tests/ctrace.c	Wed Nov 12 10:37:09 2003
@@ -0,0 +1,177 @@
+/*
+ *  CPU trace debugger.
+ * 
+ *  Copyright (c) 2003 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * This utility traces the CPU state for each execution step of a program.
+ * Of course, this is awfully slow.
+ * This can be used to compare the result of the execution of a native program
+ * vs the same one emulated by qemu.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#if defined (__powerpc__)
+static void dump_cpu_state (int child)
+{
+    unsigned long GPR[32];
+    unsigned long nip, LR, CTR, CR;
+    unsigned long opcode = 0, tmp;
+    int i;
+    
+    /* Retrieve GPR's */
+    for (i = 0; i < 32; i++)
+        GPR[i] = ptrace(PTRACE_PEEKUSR, child, (void *)(i << 2), &GPR[i]);
+
+    /* Retrieve nip */
+    nip = ptrace(PTRACE_PEEKUSR, child, (void *)(32 << 2), &nip);
+    /* Retrieve LR  */
+    LR = ptrace(PTRACE_PEEKUSR, child, (void *)(36 << 2), &LR);
+    /* Retrieve CTR  */
+    CTR = ptrace(PTRACE_PEEKUSR, child, (void *)(35 << 2), &CTR);
+    /* Retrieve CR  */
+    CR = ptrace(PTRACE_PEEKUSR, child, (void *)(38 << 2), &CR);
+    /* Retrieve current opcode */
+    if (nip == -1)
+        return;
+
+    opcode = ptrace(PTRACE_PEEKTEXT, child, nip - 4, NULL);
+    /* Dump all */
+    printf("nip=0x%08lx LR=0x%08lx CTR=0x%08lx\n",
+           nip, LR, CTR);
+    for (i = 0; i < 32; i++) {
+        if ((i & 7) == 0)
+            printf("GPR%02d: ", i);
+        printf("%08lx ", GPR[i]);
+        if ((i & 7) == 7)
+            printf("\n");
+    }
+    printf("0x%08lx: translate opcode %08lx\n", nip, opcode);
+}
+#elif defined (__i386__)
+static void dump_cpu_state (int child)
+{
+    struct user_regs_struct regs;
+
+    memset(&regs, 0, sizeof(regs));
+    if (ptrace(PTRACE_GETREGS, child, NULL, &regs) < 0) {
+        printf("PTRACE_GETREGS: %m\n");
+        return;
+    }
+    printf("nip=0x%08lx\n", regs.eip);
+    printf("eax=0x%08lx ebx=0x%08lx ecx=0x%08lx edx=0x%08lx\n",
+           regs.eax, regs.ebx, regs.ecx, regs.edx);
+    printf("esi=0x%08lx edi=0x%08lx esp=0x%08lx ebp=0x%08lx\n",
+           regs.esi, regs.edi, regs.esp, regs.ebp);
+    fflush(stdout);
+}
+#else
+#error "Unsupported target CPU"
+#endif
+
+/* Main loop */
+__attribute__((noreturn))
+int main (int argc, char **argv)
+{
+    pid_t child, me;
+    int status;
+
+    me = getpid();
+    if (argc < 2) {
+        fprintf(stderr, "Usage : ctrace prog args...\n");
+        fprintf(stderr, "Need a program to be inspected !\n");
+        fflush(stderr);
+        exit(1);
+    }
+    if (access(argv[1], R_OK | X_OK) < 0) {
+        fprintf(stderr, "Can't execute %s\n", argv[1]);
+        fflush(stderr);
+        exit(1);
+    }
+    fflush(stdout);
+
+    child = fork();
+    switch (child) {
+    case 0:
+        /* Child */
+        /* Initiate trace */
+        if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) {
+            fprintf(stderr, "Ptrace failed : %m\n");
+            fflush(stderr);
+            exit(1);
+        }
+        /* Launch the program to be traced */
+        execv(argv[1], &argv[1]);
+        /* Can't come here ! */
+        fprintf(stderr, "Exec failed: %m\n");
+        fflush(stderr);
+        exit(1);
+    case -1:
+        /* Error case... */
+        fprintf(stderr, "Can't fork to execute %s\n", argv[1]);
+        fflush(stderr);
+        exit(1);
+    default:
+        break;
+    }
+    /* Wait for the child to be launched */
+    while (0) {
+        while (waitpid(child, &status, WUNTRACED) != child)
+            continue;
+        if (WIFSTOPPED(status))
+            break;
+    }
+    /* Now, trace it ! */
+    while (1) {
+        while (waitpid(child, &status, WUNTRACED) != child)
+            continue;
+        if (!WIFSTOPPED(status) && WSTOPSIG(status) != SIGTRAP)
+            break;
+        if (WSTOPSIG(status) != SIGTRAP) {
+            printf("%d: seen signal %d\n", me, WSTOPSIG(status));
+            fflush(stdout);
+        }
+        dump_cpu_state(child);
+        while (ptrace(PTRACE_SINGLESTEP, child, 1, SIGCONT) < 0)
+            continue;
+    }
+    printf("process %s ", argv[1]);
+    fflush(stdout);
+    if (WIFEXITED(status)) {
+        printf("ended with code: %d\n", WEXITSTATUS(status));
+        fflush(stdout);
+    } else if (WIFSIGNALED(status)) {
+        printf("killed by signal: %d\n", WTERMSIG(status));
+        fflush(stdout);
+    } else if (WIFSTOPPED(status)) {
+        /* Should never happen */
+        printf("stopped\n");
+        fflush(stdout);
+    }
+
+    exit(0);
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] tests for PPC target.
  2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
  2003-11-18  8:06     ` J. Mayer
  2003-11-18  8:08     ` J. Mayer
@ 2003-11-18  8:08     ` J. Mayer
  2003-11-18  8:09     ` J. Mayer
                       ` (2 subsequent siblings)
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:08 UTC (permalink / raw)
  To: qemu-devel

target-ppc__tests__env-test.c.diff

Tiny test programs which dumps its environment.

diff -urNbB -x CVS qemu-current/target-ppc/tests/env-test.c qemu/target-ppc/tests/env-test.c
--- qemu-current/target-ppc/tests/env-test.c	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/tests/env-test.c	Wed Nov 12 10:47:39 2003
@@ -0,0 +1,368 @@
+/*
+ * This test only wants to dump the stack and environment
+ * at process start time. This allows to check that qemu env
+ * is valid, compared to kernel env.
+ */
+
+static const char logfname[] = "/tmp/env-test.log";
+static const char first_mess[] = "Qemu execution environment test\n";
+
+#if defined (__i386__)
+/* ix86 definitions */
+
+register unsigned long __spp  __asm__ ("ebp");
+
+#define __syscall_return(type, res) \
+do { \
+	if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+		errno = -(res); \
+		res = -1; \
+	} \
+	return (type) (res); \
+} while (0)
+
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+long __res; \
+__asm__ volatile ("int $0x80" \
+	: "=a" (__res) \
+	: "0" (__NR_##name)); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+long __res; \
+__asm__ volatile ("int $0x80" \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"b" ((long)(arg1))); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1,type2 arg2) \
+{ \
+long __res; \
+__asm__ volatile ("int $0x80" \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1,type2 arg2,type3 arg3) \
+{ \
+long __res; \
+__asm__ volatile ("int $0x80" \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
+		  "d" ((long)(arg3))); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+long __res; \
+__asm__ volatile ("int $0x80" \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
+	  "d" ((long)(arg3)),"S" ((long)(arg4))); \
+__syscall_return(type,__res); \
+} 
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+	  type5,arg5) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
+{ \
+long __res; \
+__asm__ volatile ("int $0x80" \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
+	  "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+	  type5,arg5,type6,arg6) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
+{ \
+long __res; \
+__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \
+	: "=a" (__res) \
+	: "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
+	  "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
+	  "0" ((long)(arg6))); \
+__syscall_return(type,__res); \
+}
+
+#elif defined (__powerpc__)
+/* PowerPC definitions */
+
+register unsigned long __spp  __asm__ ("r1");
+
+#define __syscall_nr(nr, type, name, args...)                           \
+        unsigned long __sc_ret, __sc_err = 0;                           \
+        {                                                               \
+                register unsigned long __sc_0  __asm__ ("r0");          \
+                register unsigned long __sc_3  __asm__ ("r3");          \
+                register unsigned long __sc_4  __asm__ ("r4");          \
+                register unsigned long __sc_5  __asm__ ("r5");          \
+                register unsigned long __sc_6  __asm__ ("r6");          \
+                register unsigned long __sc_7  __asm__ ("r7");          \
+                                                                        \
+                __sc_loadargs_##nr(name, args);                         \
+                __asm__ __volatile__                                    \
+                        ("sc           \n\t"                            \
+                         "mfcr %0      "                                \
+                        : "=&r" (__sc_0),                               \
+                          "=&r" (__sc_3),  "=&r" (__sc_4),              \
+                          "=&r" (__sc_5),  "=&r" (__sc_6),              \
+                          "=&r" (__sc_7)                                \
+                        : __sc_asm_input_##nr                           \
+                        : "cr0", "ctr", "memory",                       \
+                          "r8", "r9", "r10","r11", "r12");              \
+                __sc_ret = __sc_3;                                      \
+        }                                                               \
+        if (__sc_err & 0x10000000)                                      \
+        {                                                               \
+                errno = __sc_ret;                                       \
+                __sc_ret = -1;                                          \
+        }                                                               \
+        return (type) __sc_ret
+
+#define __sc_loadargs_0(name, dummy...)                                 \
+        __sc_0 = __NR_##name
+#define __sc_loadargs_1(name, arg1)                                     \
+        __sc_loadargs_0(name);                                          \
+        __sc_3 = (unsigned long) (arg1)
+#define __sc_loadargs_2(name, arg1, arg2)                               \
+        __sc_loadargs_1(name, arg1);                                    \
+        __sc_4 = (unsigned long) (arg2)
+#define __sc_loadargs_3(name, arg1, arg2, arg3)                         \
+        __sc_loadargs_2(name, arg1, arg2);                              \
+        __sc_5 = (unsigned long) (arg3)
+#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4)                   \
+        __sc_loadargs_3(name, arg1, arg2, arg3);                        \
+        __sc_6 = (unsigned long) (arg4)
+#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5)             \
+        __sc_loadargs_4(name, arg1, arg2, arg3, arg4);                  \
+        __sc_7 = (unsigned long) (arg5)
+
+#define __sc_asm_input_0 "0" (__sc_0)
+#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3)
+#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4)
+#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5)
+#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6)
+#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7)
+
+#define _syscall0(type,name)                                            \
+type name(void)                                                         \
+{                                                                       \
+        __syscall_nr(0, type, name);                                    \
+}
+
+#define _syscall1(type,name,type1,arg1)                                 \
+type name(type1 arg1)                                                   \
+{                                                                       \
+        __syscall_nr(1, type, name, arg1);                              \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)                      \
+type name(type1 arg1, type2 arg2)                                       \
+{                                                                       \
+        __syscall_nr(2, type, name, arg1, arg2);                        \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)           \
+type name(type1 arg1, type2 arg2, type3 arg3)                           \
+{                                                                       \
+        __syscall_nr(3, type, name, arg1, arg2, arg3);                  \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4)               \
+{                                                                       \
+        __syscall_nr(4, type, name, arg1, arg2, arg3, arg4);            \
+}
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)   \
+{                                                                       \
+        __syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5);      \
+}
+#else
+#error "Architecture not supported by now."
+#endif
+
+#define NULL ((void *)0)
+
+#define O_ACCMODE          0003
+#define O_RDONLY             00
+#define O_WRONLY             01
+#define O_RDWR               02
+#define O_CREAT            0100 /* not fcntl */
+
+#define __NR_exit                 1
+#define __NR_read                 3
+#define __NR_write                4
+#define __NR_open                 5
+#define __NR_close                6
+#define __NR_unlink              10
+#define __NR_sync                36
+#define __NR_fsync              118
+
+int errno;
+unsigned long *__sp;
+
+_syscall1(void, exit, int, status);
+static inline _syscall3(int, read, int, fd, void *, buf, int, count);
+static inline _syscall3(int, write, int, fd, const void *, buf, int, count);
+static inline _syscall3(int, open, const unsigned char *, pathname, int, flags, int, mode);
+static inline _syscall1(int, close, int, fd);
+static inline _syscall1(int, unlink, const unsigned char *, pathname);
+static inline _syscall0(int, sync);
+static inline _syscall1(int, fsync, int, fd);
+
+static int strlen (const unsigned char *string)
+{
+    int len;
+
+    for (len = 0; string[len] != '\0'; len++)
+        continue;
+
+    return len;
+}
+
+static int outstr (int fd, const unsigned char *string, int len)
+{
+    return write(fd, string, len);
+}
+
+static int outhex (int fd, unsigned long value)
+{
+    char tmpbuf[9], *pos = tmpbuf;
+    unsigned long tmp;
+    int i;
+
+    for (i = 28; i >= 0; i -=4 , pos++) {
+        tmp = (value >> i) & 0xf;
+        if (tmp < 0xa) {
+            *pos = '0' + tmp;
+        } else {
+            *pos = ('a' - 10) + tmp;
+        }
+    }
+    *pos = '\0';
+
+    return write(fd, tmpbuf, 8);
+}
+
+/* We walk through the stack until we reach a page-aligned address */
+static void dump_stack (int fd, int argc, char *const *argv, char *const *envp)
+{
+    unsigned long sp, *cur;
+    int i, j;
+
+    __asm__ __volatile__ ("mr %0, 1" : "=r"(sp));
+    /* Dump stack, argv and envp pointers */
+    outstr(fd, "Stack: ", strlen("Stack: "));
+    outhex(fd, sp);
+    outstr(fd, " ", 1);
+    outhex(fd, (unsigned long)__sp);
+    outstr(fd, "\n", 1);
+    fsync(fd);
+    cur = __sp - 32;
+    for (i = 0; ((unsigned long)cur & 0xff0) != 0xff0 && i < 256; i++) {
+        outhex(fd, (unsigned long)cur);
+        outstr(fd, ": ", 2);
+        for (j = 0; j < 4; j++) {
+            outhex(fd, *cur++);
+            outstr(fd, " ", 1);
+        }
+        outstr(fd, "\n", 1);
+    }
+}
+
+static void dump_env (int fd, int argc, char *const *argv, char *const *envp)
+{
+    int i;
+
+    outstr(fd, " argv: ", strlen(" argv: "));
+    outhex(fd, (unsigned long)argv);
+    outstr(fd, " envp: ", strlen(" envp: "));
+    outhex(fd, (unsigned long)envp);
+    outstr(fd, "\n", 1);
+    /* Dump args and environment */
+    outhex(fd, argc);
+    outstr(fd, " args\n", strlen(" args\n"));
+    for (i = 0; i < argc; i++) {
+        outstr(fd, " arg ", 5);
+        outhex(fd, i);
+        outstr(fd, " : ", 3);
+        outstr(fd, argv[i], strlen(argv[i]));
+        outstr(fd, "\n", 1);
+    }
+    outstr(fd, "Env\n", strlen("Env\n"));
+    for (i = 0; envp[i] != NULL; i++) {
+        outstr(fd, "envstr ", 7);
+        outhex(fd, i);
+        outstr(fd, " : ", 3);
+        outstr(fd, envp[i], strlen(envp[i]));
+        outstr(fd, "\n", 1);
+    }
+}
+
+int main (int argc, char **argv, char **envp)
+{
+    int logfile;
+
+    unlink(logfname);
+    logfile = open(logfname, O_WRONLY | O_CREAT, 0644);
+    if (logfile < 0)
+        return 1;
+    sync();
+    outstr(logfile, first_mess, strlen(first_mess));
+    fsync(logfile);
+    dump_stack(logfile, argc, argv, envp);
+    fsync(logfile);
+    dump_env(logfile, argc, argv, envp);
+    fsync(logfile);
+    close(logfile);
+
+    return 0;
+}
+
+/* Here's the program's entry point.
+ * As one can see, no asm is needed here.
+ */
+void _start (void)
+{
+    unsigned long *cur;
+    unsigned long *__argv, *__envp, __argc;
+    int __status, i;
+    
+    __sp = (unsigned long *)*((unsigned long *)__spp);
+    cur = __sp;
+    __argc = *cur;
+    __argv = cur + 1;
+    __envp = cur + 2 + __argc;
+    /* Linux is *STILL* buggy and doesn't respect the API */
+    if (*__argv == 0) {
+        unsigned long tmp = *__envp;
+
+        while (*(unsigned long *)tmp != 0)
+            tmp--;
+        tmp += 4;
+        for (i = 0; i < __argc; i++) {
+            __argv[i] = (unsigned long)tmp;
+            while (*(unsigned char *)tmp)
+                tmp++;
+            tmp++;
+        }
+    }
+    __status = main(__argc, (char **)__argv, (char **)__envp);
+    exit(__status);
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] tests for PPC target.
  2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
                       ` (2 preceding siblings ...)
  2003-11-18  8:08     ` J. Mayer
@ 2003-11-18  8:09     ` J. Mayer
  2003-11-18  8:10     ` J. Mayer
  2003-11-18  8:25     ` J. Mayer
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:09 UTC (permalink / raw)
  To: qemu-devel

target-ppc__tests__hello-ppc.c.diff

Say hello to the world...

diff -urNbB -x CVS qemu-current/target-ppc/tests/hello-ppc.c qemu/target-ppc/tests/hello-ppc.c
--- qemu-current/target-ppc/tests/hello-ppc.c	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/tests/hello-ppc.c	Wed Jun 25 11:40:03 2003
@@ -0,0 +1,25 @@
+#include "/usr/src/linux/include/asm-ppc/unistd.h"
+
+static void _exit(int status)
+{
+    __asm__ __volatile__ ("mr 3, %1 ; li 0, %0 ; sc ;" \
+                          :: "i"(__NR_exit), "r"(status));
+}
+
+static int _write(int fd, const char * buf, int len)
+{
+    int status;
+
+    __asm__ __volatile__ ("mr 3, %2 ; mr 4, %3 ; mr 5, %4 ; li 0, %1 ; sc ;" \
+                          "mr %0, 3 ;" \
+                          : "=r"(status) \
+                          : "i"(__NR_write), "r"(fd), "r"(buf), "r"(len));
+
+    return status;
+}
+
+void _start(void)
+{
+    _write(1, "Hello World\n", 12);
+    _exit(0);
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] tests for PPC target.
  2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
                       ` (3 preceding siblings ...)
  2003-11-18  8:09     ` J. Mayer
@ 2003-11-18  8:10     ` J. Mayer
  2003-11-18  8:25     ` J. Mayer
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:10 UTC (permalink / raw)
  To: qemu-devel

target-ppc__tests__ppc-test.c.diff

This program intends to test qemu PPC target,
executing a lot of different instructions and dumping
the CPU state.

diff -urNbB -x CVS qemu-current/target-ppc/tests/ppc-test.c qemu/target-ppc/tests/ppc-test.c
--- qemu-current/target-ppc/tests/ppc-test.c	Thu Jan  1 01:00:00 1970
+++ qemu/target-ppc/tests/ppc-test.c	Wed Nov 12 10:40:26 2003
@@ -0,0 +1,3291 @@
+/* Wonderfull micro libc */
+int errno;
+
+#define NULL ((void *)0)
+
+#define O_ACCMODE          0003
+#define O_RDONLY             00
+#define O_WRONLY             01
+#define O_RDWR               02
+#define O_CREAT            0100 /* not fcntl */
+
+#define __NR_exit                 1
+#define __NR_read                 3
+#define __NR_write                4
+#define __NR_open                 5
+#define __NR_close                6
+#define __NR_unlink              10
+#define __NR_sync                36
+#define __NR_fsync              118
+
+unsigned long *__sp;
+register long r16  __asm__ ("r16");
+register long r17  __asm__ ("r17");
+register long r18  __asm__ ("r18");
+register long r19  __asm__ ("r19");
+register long r20  __asm__ ("r20");
+register long r21  __asm__ ("r21");
+
+unsigned char buffer[65536];
+
+#define __syscall_nr(nr, type, name, args...)                           \
+        unsigned long __sc_ret, __sc_err = 0;                           \
+        {                                                               \
+                register unsigned long __sc_0  __asm__ ("r0");          \
+                register unsigned long __sc_3  __asm__ ("r3");          \
+                register unsigned long __sc_4  __asm__ ("r4");          \
+                register unsigned long __sc_5  __asm__ ("r5");          \
+                register unsigned long __sc_6  __asm__ ("r6");          \
+                register unsigned long __sc_7  __asm__ ("r7");          \
+                                                                        \
+                __sc_loadargs_##nr(name, args);                         \
+                __asm__ __volatile__                                    \
+                        ("sc           \n\t"                            \
+                         "mfcr %0      "                                \
+                        : "=&r" (__sc_0),                               \
+                          "=&r" (__sc_3),  "=&r" (__sc_4),              \
+                          "=&r" (__sc_5),  "=&r" (__sc_6),              \
+                          "=&r" (__sc_7)                                \
+                        : __sc_asm_input_##nr                           \
+                        : "cr0", "ctr", "memory",                       \
+                          "r8", "r9", "r10","r11", "r12");              \
+                __sc_ret = __sc_3;                                      \
+        }                                                               \
+        if (__sc_err & 0x10000000)                                      \
+        {                                                               \
+                errno = __sc_ret;                                       \
+                __sc_ret = -1;                                          \
+        }                                                               \
+        return (type) __sc_ret
+
+#define __sc_loadargs_0(name, dummy...)                                 \
+        __sc_0 = __NR_##name
+#define __sc_loadargs_1(name, arg1)                                     \
+        __sc_loadargs_0(name);                                          \
+        __sc_3 = (unsigned long) (arg1)
+#define __sc_loadargs_2(name, arg1, arg2)                               \
+        __sc_loadargs_1(name, arg1);                                    \
+        __sc_4 = (unsigned long) (arg2)
+#define __sc_loadargs_3(name, arg1, arg2, arg3)                         \
+        __sc_loadargs_2(name, arg1, arg2);                              \
+        __sc_5 = (unsigned long) (arg3)
+#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4)                   \
+        __sc_loadargs_3(name, arg1, arg2, arg3);                        \
+        __sc_6 = (unsigned long) (arg4)
+#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5)             \
+        __sc_loadargs_4(name, arg1, arg2, arg3, arg4);                  \
+        __sc_7 = (unsigned long) (arg5)
+
+#define __sc_asm_input_0 "0" (__sc_0)
+#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3)
+#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4)
+#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5)
+#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6)
+#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7)
+
+#define _syscall0(type,name)                                            \
+type name(void)                                                         \
+{                                                                       \
+        __syscall_nr(0, type, name);                                    \
+}
+
+#define _syscall1(type,name,type1,arg1)                                 \
+type name(type1 arg1)                                                   \
+{                                                                       \
+        __syscall_nr(1, type, name, arg1);                              \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2)                      \
+type name(type1 arg1, type2 arg2)                                       \
+{                                                                       \
+        __syscall_nr(2, type, name, arg1, arg2);                        \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)           \
+type name(type1 arg1, type2 arg2, type3 arg3)                           \
+{                                                                       \
+        __syscall_nr(3, type, name, arg1, arg2, arg3);                  \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4)               \
+{                                                                       \
+        __syscall_nr(4, type, name, arg1, arg2, arg3, arg4);            \
+}
+
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)   \
+{                                                                       \
+        __syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5);      \
+}
+
+_syscall1(void, exit, int, status);
+static inline _syscall3(int, read, int, fd, void *, buf, int, count);
+static inline _syscall3(int, write, int, fd, const void *, buf, int, count);
+static inline _syscall3(int, open, const char *, pathname, int, flags, int, mode);
+static inline _syscall1(int, close, int, fd);
+static inline _syscall1(int, unlink, const char *, pathname);
+static inline _syscall0(int, sync);
+static inline _syscall1(int, fsync, int, fd);
+
+static const char logfname[] = "/tmp/ppc-test.log";
+static const char first_mess[] = "PPC testsuite\n";
+static const char test_mess[] = "------------------------------\n";
+static const char sep_mess[] = " ---\n";
+static const char error_mess[] = "TESTSUITE IS BUGGY ! \n";
+static const char test1_err[] = "One operand tests error\n";
+static const char test2_err[] = "Two operands tests error\n";
+static const char testi_err[] =
+"Two operands with 16 bits immediate tests error\n";
+static const char testm_err[] = "Misc tests error\n";
+static const char part1_err[] = "Part 1 failed\n";
+static const char part2_err[] = "Part 2 failed\n";
+static const char part3_err[] = "Part 3 failed\n";
+static const char part4_err[] = "Part 4 failed\n";
+
+static int strlen (const char *string)
+{
+    int len;
+
+    for (len = 0; string[len] != '\0'; len++)
+        continue;
+
+    return len;
+}
+
+static int outstr (int fd, const char *string, int len)
+{
+    return write(fd, string, len);
+}
+
+static int outhex (int fd, unsigned long value)
+{
+    char tmpbuf[9], *pos = tmpbuf;
+    unsigned long tmp;
+    int i;
+
+    for (i = 28; i >= 0; i -=4 , pos++) {
+        tmp = (value >> i) & 0xf;
+        if (tmp < 0xa) {
+            *pos = '0' + tmp;
+        } else {
+            *pos = ('a' - 10) + tmp;
+        }
+    }
+    *pos = '\0';
+
+    return write(fd, tmpbuf, 8);
+}
+
+static inline void dump_ppc_state (int logfile)
+{
+    unsigned long LR, CTR, XER, CR;
+
+    __asm__ __volatile__ ("mflr  %0 ; "
+                          "mfctr %1 ; "
+                          "mfxer %2 ; "
+                          "mfcr  %3 ; "
+                          : "=r"(LR), "=r"(CTR), "=r"(XER), "=r"(CR));
+    /* Don't dump LR: this causes differences between native and
+     * emulated process in the log file...
+     */
+//    outstr(logfile, "LR=0x", 5);
+//    outhex(logfile, LR);
+    outstr(logfile, " CTR=0x", 7);
+    outhex(logfile, CTR);
+    outstr(logfile, " XER=0x", 7);
+    outhex(logfile, XER);
+    outstr(logfile, " CR=0x", 6);
+    outhex(logfile, CR);
+    outstr(logfile, "\n", 1);
+    outstr(logfile, "GPR 16: 0x", 10);
+    outhex(logfile, r16);
+    outstr(logfile, " 0x", 3);
+    outhex(logfile, r17);
+    outstr(logfile, " 0x", 3);
+    outhex(logfile, r18);
+    outstr(logfile, " 0x", 3);
+    outhex(logfile, r19);
+    outstr(logfile, " 0x", 3);
+    outhex(logfile, r20);
+    outstr(logfile, " 0x", 3);
+    outhex(logfile, r21);
+    outstr(logfile, "\n", 1);
+}
+
+static inline void init_ppc (int xer)
+{
+    unsigned long LR = 0, CTR = 0, XER = xer << 29, CR = 0;
+
+    r16 = 0;
+    r17 = 0;
+    r18 = 0;
+    r19 = 0;
+    r20 = 0;
+    r21 = 0;
+    __asm__ __volatile__ ("mtlr  %0 ; "
+                          "mtctr %1 ; "
+                          "mtxer %2 ; "
+                          "mtcr  %3 ; "
+                          :: "r"(LR), "r"(CTR), "r"(XER), "r"(CR));
+}
+
+static inline __volatile__ void flush_icache (void *addr)
+{
+    /* flush icache */
+    __asm__ __volatile__ ("dcbst 0,%0"
+                          :: "r"(addr)
+                          : "memory");
+    __asm__ __volatile__ ("sync"
+                          ::: "memory");
+    __asm__ __volatile__ ("icbi 0,%0"
+                          :: "r"(addr)
+                          : "memory");
+    __asm__ __volatile__ ("sync"
+                          ::: "memory");
+    __asm__ __volatile__ ("isync"
+                          ::: "memory");
+}
+
+static inline __volatile__ void patch_imm16 (void *dst, void *src, int imm16)
+{
+    *((unsigned long *)dst + 0) =
+        ((*((unsigned long *)src + 0)) & 0xFFFF0000) | (imm16 & 0x0000FFFF);
+    *((unsigned long *)dst + 1) = *((unsigned long *)src + 1);
+}
+
+/* One operand opcodes */
+/* Integer arithmetic tests */
+static void test_addme (void)
+{
+    __asm__ __volatile__ ("addme 17, 16");
+}
+
+static void test_addme_ (void)
+{
+    __asm__ __volatile__ ("addme. 17, 16");
+}
+
+static void test_addmeo (void)
+{
+    __asm__ __volatile__ ("addmeo 17, 16");
+}
+
+static void test_addmeo_ (void)
+{
+    __asm__ __volatile__ ("addmeo. 17, 16");
+}
+
+static void test_addze (void)
+{
+    __asm__ __volatile__ ("addze 17, 16");
+}
+
+static void test_addze_ (void)
+{
+    __asm__ __volatile__ ("addze. 17, 16");
+}
+
+static void test_addzeo (void)
+{
+    __asm__ __volatile__ ("addzeo 17, 16");
+}
+
+static void test_addzeo_ (void)
+{
+    __asm__ __volatile__ ("addzeo. 17, 16");
+}
+
+static void test_neg (void)
+{
+    __asm__ __volatile__ ("neg 17, 16");
+}
+
+static void test_neg_ (void)
+{
+    __asm__ __volatile__ ("neg. 17, 16");
+}
+
+static void test_nego (void)
+{
+    __asm__ __volatile__ ("nego 17, 16");
+}
+
+static void test_nego_ (void)
+{
+    __asm__ __volatile__ ("nego. 17, 16");
+}
+
+static void test_subfme (void)
+{
+    __asm__ __volatile__ ("subfme 17, 16");
+}
+
+static void test_subfme_ (void)
+{
+    __asm__ __volatile__ ("subfme. 17, 16");
+}
+
+static void test_subfmeo (void)
+{
+    __asm__ __volatile__ ("subfmeo 17, 16");
+}
+
+static void test_subfmeo_ (void)
+{
+    __asm__ __volatile__ ("subfmeo. 17, 16");
+}
+
+static void test_subfze (void)
+{
+    __asm__ __volatile__ ("subfze 17, 16");
+}
+
+static void test_subfze_ (void)
+{
+    __asm__ __volatile__ ("subfze. 17, 16");
+}
+
+static void test_subfzeo (void)
+{
+    __asm__ __volatile__ ("subfzeo 17, 16");
+}
+
+static void test_subfzeo_ (void)
+{
+    __asm__ __volatile__ ("subfzeo. 17, 16");
+}
+
+/* Integer logical tests */
+static void test_cntlzw (void)
+{
+    __asm__ __volatile__ ("cntlzw 17, 16");
+}
+
+static void test_cntlzw_ (void)
+{
+    __asm__ __volatile__ ("cntlzw. 17, 16");
+}
+
+static void test_extsb (void)
+{
+    __asm__ __volatile__ ("extsb 17, 16");
+}
+
+static void test_extsb_ (void)
+{
+    __asm__ __volatile__ ("extsb. 17, 16");
+}
+
+static void test_extsh (void)
+{
+    __asm__ __volatile__ ("extsh 17, 16");
+}
+
+static void test_extsh_ (void)
+{
+    __asm__ __volatile__ ("extsh. 17, 16");
+}
+
+/* One operand opcodes with dest=src */
+/* Integer arithmetic tests */
+static void test_addme2 (void)
+{
+    __asm__ __volatile__ ("addme 16, 16");
+}
+
+static void test_addme_2 (void)
+{
+    __asm__ __volatile__ ("addme. 16, 16");
+}
+
+static void test_addmeo2 (void)
+{
+    __asm__ __volatile__ ("addmeo 16, 16");
+}
+
+static void test_addmeo_2 (void)
+{
+    __asm__ __volatile__ ("addmeo. 16, 16");
+}
+
+static void test_addze2 (void)
+{
+    __asm__ __volatile__ ("addze 16, 16");
+}
+
+static void test_addze_2 (void)
+{
+    __asm__ __volatile__ ("addze. 16, 16");
+}
+
+static void test_addzeo2 (void)
+{
+    __asm__ __volatile__ ("addzeo 16, 16");
+}
+
+static void test_addzeo_2 (void)
+{
+    __asm__ __volatile__ ("addzeo. 16, 16");
+}
+
+static void test_neg2 (void)
+{
+    __asm__ __volatile__ ("neg 16, 16");
+}
+
+static void test_neg_2 (void)
+{
+    __asm__ __volatile__ ("neg. 16, 16");
+}
+
+static void test_nego2 (void)
+{
+    __asm__ __volatile__ ("nego 16, 16");
+}
+
+static void test_nego_2 (void)
+{
+    __asm__ __volatile__ ("nego. 16, 16");
+}
+
+static void test_subfme2 (void)
+{
+    __asm__ __volatile__ ("subfme 16, 16");
+}
+
+static void test_subfme_2 (void)
+{
+    __asm__ __volatile__ ("subfme. 16, 16");
+}
+
+static void test_subfmeo2 (void)
+{
+    __asm__ __volatile__ ("subfmeo 16, 16");
+}
+
+static void test_subfmeo_2 (void)
+{
+    __asm__ __volatile__ ("subfmeo. 16, 16");
+}
+
+static void test_subfze2 (void)
+{
+    __asm__ __volatile__ ("subfze 16, 16");
+}
+
+static void test_subfze_2 (void)
+{
+    __asm__ __volatile__ ("subfze. 16, 16");
+}
+
+static void test_subfzeo2 (void)
+{
+    __asm__ __volatile__ ("subfzeo 16, 16");
+}
+
+static void test_subfzeo_2 (void)
+{
+    __asm__ __volatile__ ("subfzeo. 16, 16");
+}
+
+/* Integer logical tests */
+static void test_cntlzw2 (void)
+{
+    __asm__ __volatile__ ("cntlzw 17, 16");
+}
+
+static void test_cntlzw_2 (void)
+{
+    __asm__ __volatile__ ("cntlzw. 17, 16");
+}
+
+static void test_extsb2 (void)
+{
+    __asm__ __volatile__ ("extsb 17, 16");
+}
+
+static void test_extsb_2 (void)
+{
+    __asm__ __volatile__ ("extsb. 17, 16");
+}
+
+static void test_extsh2 (void)
+{
+    __asm__ __volatile__ ("extsh 17, 16");
+}
+
+static void test_extsh_2 (void)
+{
+    __asm__ __volatile__ ("extsh. 17, 16");
+}
+
+/* Two operands opcodes */
+/* Integer arithmetic tests */
+static void test_add (void)
+{
+    __asm__ __volatile__ ("add 18, 16, 17");
+}
+
+static void test_add_ (void)
+{
+    __asm__ __volatile__ ("add. 18, 16, 17");
+}
+
+static void test_addo (void)
+{
+    __asm__ __volatile__ ("addo 18, 16, 17");
+}
+
+static void test_addo_ (void)
+{
+    __asm__ __volatile__ ("addo. 18, 16, 17");
+}
+
+static void test_addc (void)
+{
+    __asm__ __volatile__ ("addc 18, 16, 17");
+}
+
+static void test_addc_ (void)
+{
+    __asm__ __volatile__ ("addc. 18, 16, 17");
+}
+
+static void test_addco (void)
+{
+    __asm__ __volatile__ ("addco 18, 16, 17");
+}
+
+static void test_addco_ (void)
+{
+    __asm__ __volatile__ ("addco. 18, 16, 17");
+}
+
+static void test_adde (void)
+{
+    __asm__ __volatile__ ("adde 18, 16, 17");
+}
+
+static void test_adde_ (void)
+{
+    __asm__ __volatile__ ("adde. 18, 16, 17");
+}
+
+static void test_addeo (void)
+{
+    __asm__ __volatile__ ("addeo 18, 16, 17");
+}
+
+static void test_addeo_ (void)
+{
+    __asm__ __volatile__ ("addeo. 18, 16, 17");
+}
+
+static void test_divw (void)
+{
+    __asm__ __volatile__ ("divw 18, 16, 17");
+}
+
+static void test_divw_ (void)
+{
+    __asm__ __volatile__ ("divw. 18, 16, 17");
+}
+
+static void test_divwo (void)
+{
+    __asm__ __volatile__ ("divwo 18, 16, 17");
+}
+
+static void test_divwo_ (void)
+{
+    __asm__ __volatile__ ("divwo. 18, 16, 17");
+}
+
+static void test_divwu (void)
+{
+    __asm__ __volatile__ ("divwu 18, 16, 17");
+}
+
+static void test_divwu_ (void)
+{
+    __asm__ __volatile__ ("divwu. 18, 16, 17");
+}
+
+static void test_divwuo (void)
+{
+    __asm__ __volatile__ ("divwuo 18, 16, 17");
+}
+
+static void test_divwuo_ (void)
+{
+    __asm__ __volatile__ ("divwuo. 18, 16, 17");
+}
+
+static void test_mulhw (void)
+{
+    __asm__ __volatile__ ("mulhw 18, 16, 17");
+}
+
+static void test_mulhw_ (void)
+{
+    __asm__ __volatile__ ("mulhw. 18, 16, 17");
+}
+
+static void test_mulhwu (void)
+{
+    __asm__ __volatile__ ("mulhwu 18, 16, 17");
+}
+
+static void test_mulhwu_ (void)
+{
+    __asm__ __volatile__ ("mulhwu. 18, 16, 17");
+}
+
+static void test_mullw (void)
+{
+    __asm__ __volatile__ ("mullw 18, 16, 17");
+}
+
+static void test_mullw_ (void)
+{
+    __asm__ __volatile__ ("mullw. 18, 16, 17");
+}
+
+static void test_mullwo (void)
+{
+    __asm__ __volatile__ ("mullwo 18, 16, 17");
+}
+
+static void test_mullwo_ (void)
+{
+    __asm__ __volatile__ ("mullwo. 18, 16, 17");
+}
+
+static void test_subf (void)
+{
+    __asm__ __volatile__ ("subf 18, 16, 17");
+}
+
+static void test_subf_ (void)
+{
+    __asm__ __volatile__ ("subf. 18, 16, 17");
+}
+
+static void test_subfo (void)
+{
+    __asm__ __volatile__ ("subfo 18, 16, 17");
+}
+
+static void test_subfo_ (void)
+{
+    __asm__ __volatile__ ("subfo. 18, 16, 17");
+}
+
+static void test_subfc (void)
+{
+    __asm__ __volatile__ ("subfc 18, 16, 17");
+}
+
+static void test_subfc_ (void)
+{
+    __asm__ __volatile__ ("subfc. 18, 16, 17");
+}
+
+static void test_subfco (void)
+{
+    __asm__ __volatile__ ("subfco 18, 16, 17");
+}
+
+static void test_subfco_ (void)
+{
+    __asm__ __volatile__ ("subfco. 18, 16, 17");
+}
+
+static void test_subfe (void)
+{
+    __asm__ __volatile__ ("subfe 18, 16, 17");
+}
+
+static void test_subfe_ (void)
+{
+    __asm__ __volatile__ ("subfe. 18, 16, 17");
+}
+
+static void test_subfeo (void)
+{
+    __asm__ __volatile__ ("subfeo 18, 16, 17");
+}
+
+static void test_subfeo_ (void)
+{
+    __asm__ __volatile__ ("subfeo. 18, 16, 17");
+}
+
+/* Integer comparison tests */
+static void test_cmp (void)
+{
+    __asm__ __volatile__ ("cmp 2, 16, 17");
+}
+
+static void test_cmpl (void)
+{
+    __asm__ __volatile__ ("cmpl 2, 16, 17");
+}
+
+/* Integer logical tests */
+static void test_and (void)
+{
+    __asm__ __volatile__ ("and 18, 16, 17");
+}
+
+static void test_and_ (void)
+{
+    __asm__ __volatile__ ("and. 18, 16, 17");
+}
+
+static void test_andc (void)
+{
+    __asm__ __volatile__ ("andc 18, 16, 17");
+}
+
+static void test_andc_ (void)
+{
+    __asm__ __volatile__ ("andc. 18, 16, 17");
+}
+
+static void test_eqv (void)
+{
+    __asm__ __volatile__ ("eqv 18, 16, 17");
+}
+
+static void test_eqv_ (void)
+{
+    __asm__ __volatile__ ("eqv. 18, 16, 17");
+}
+
+static void test_nand (void)
+{
+    __asm__ __volatile__ ("nand 18, 16, 17");
+}
+
+static void test_nand_ (void)
+{
+    __asm__ __volatile__ ("nand. 18, 16, 17");
+}
+
+static void test_nor (void)
+{
+    __asm__ __volatile__ ("nor 18, 16, 17");
+}
+
+static void test_nor_ (void)
+{
+    __asm__ __volatile__ ("nor. 18, 16, 17");
+}
+
+static void test_or (void)
+{
+    __asm__ __volatile__ ("or 18, 16, 17");
+}
+
+static void test_or_ (void)
+{
+    __asm__ __volatile__ ("or. 18, 16, 17");
+}
+
+static void test_orc (void)
+{
+    __asm__ __volatile__ ("orc 18, 16, 17");
+}
+
+static void test_orc_ (void)
+{
+    __asm__ __volatile__ ("orc. 18, 16, 17");
+}
+
+static void test_xor (void)
+{
+    __asm__ __volatile__ ("xor 18, 16, 17");
+}
+
+static void test_xor_ (void)
+{
+    __asm__ __volatile__ ("xor. 18, 16, 17");
+}
+
+/* Integer shift */
+static void test_slw (void)
+{
+    __asm__ __volatile__ ("slw 18, 16, 17");
+}
+
+static void test_slw_ (void)
+{
+    __asm__ __volatile__ ("slw. 18, 16, 17");
+}
+
+static void test_sraw (void)
+{
+    __asm__ __volatile__ ("sraw 18, 16, 17");
+}
+
+static void test_sraw_ (void)
+{
+    __asm__ __volatile__ ("sraw. 18, 16, 17");
+}
+
+static void test_srw (void)
+{
+    __asm__ __volatile__ ("srw 18, 16, 17");
+}
+
+static void test_srw_ (void)
+{
+    __asm__ __volatile__ ("srw. 18, 16, 17");
+}
+
+/* Integer rotate */
+static void test_rotlw (void)
+{
+    __asm__ __volatile__ ("rotlw 18, 16, 17");
+}
+
+static void test_rotlw_ (void)
+{
+    __asm__ __volatile__ ("rotlw. 18, 16, 17");
+}
+
+/* Two operands opcodes with src=dest */
+/* Integer arithmetic tests */
+static void test_add2 (void)
+{
+    __asm__ __volatile__ ("add 16, 16, 17");
+}
+
+static void test_add_2 (void)
+{
+    __asm__ __volatile__ ("add. 16, 16, 17");
+}
+
+static void test_addo2 (void)
+{
+    __asm__ __volatile__ ("addo 16, 16, 17");
+}
+
+static void test_addo_2 (void)
+{
+    __asm__ __volatile__ ("addo. 16, 16, 17");
+}
+
+static void test_addc2 (void)
+{
+    __asm__ __volatile__ ("addc 16, 16, 17");
+}
+
+static void test_addc_2 (void)
+{
+    __asm__ __volatile__ ("addc. 16, 16, 17");
+}
+
+static void test_addco2 (void)
+{
+    __asm__ __volatile__ ("addco 16, 16, 17");
+}
+
+static void test_addco_2 (void)
+{
+    __asm__ __volatile__ ("addco. 16, 16, 17");
+}
+
+static void test_adde2 (void)
+{
+    __asm__ __volatile__ ("adde 16, 16, 17");
+}
+
+static void test_adde_2 (void)
+{
+    __asm__ __volatile__ ("adde. 16, 16, 17");
+}
+
+static void test_addeo2 (void)
+{
+    __asm__ __volatile__ ("addeo 16, 16, 17");
+}
+
+static void test_addeo_2 (void)
+{
+    __asm__ __volatile__ ("addeo. 16, 16, 17");
+}
+
+static void test_divw2 (void)
+{
+    __asm__ __volatile__ ("divw 16, 16, 17");
+}
+
+static void test_divw_2 (void)
+{
+    __asm__ __volatile__ ("divw. 16, 16, 17");
+}
+
+static void test_divwo2 (void)
+{
+    __asm__ __volatile__ ("divwo 16, 16, 17");
+}
+
+static void test_divwo_2 (void)
+{
+    __asm__ __volatile__ ("divwo. 16, 16, 17");
+}
+
+static void test_divwu2 (void)
+{
+    __asm__ __volatile__ ("divwu 16, 16, 17");
+}
+
+static void test_divwu_2 (void)
+{
+    __asm__ __volatile__ ("divwu. 16, 16, 17");
+}
+
+static void test_divwuo2 (void)
+{
+    __asm__ __volatile__ ("divwuo 16, 16, 17");
+}
+
+static void test_divwuo_2 (void)
+{
+    __asm__ __volatile__ ("divwuo. 16, 16, 17");
+}
+
+static void test_mulhw2 (void)
+{
+    __asm__ __volatile__ ("mulhw 16, 16, 17");
+}
+
+static void test_mulhw_2 (void)
+{
+    __asm__ __volatile__ ("mulhw. 16, 16, 17");
+}
+
+static void test_mulhwu2 (void)
+{
+    __asm__ __volatile__ ("mulhwu 16, 16, 17");
+}
+
+static void test_mulhwu_2 (void)
+{
+    __asm__ __volatile__ ("mulhwu. 16, 16, 17");
+}
+
+static void test_mullw2 (void)
+{
+    __asm__ __volatile__ ("mullw 16, 16, 17");
+}
+
+static void test_mullw_2 (void)
+{
+    __asm__ __volatile__ ("mullw. 16, 16, 17");
+}
+
+static void test_mullwo2 (void)
+{
+    __asm__ __volatile__ ("mullwo 16, 16, 17");
+}
+
+static void test_mullwo_2 (void)
+{
+    __asm__ __volatile__ ("mullwo. 16, 16, 17");
+}
+
+static void test_subf2 (void)
+{
+    __asm__ __volatile__ ("subf 16, 16, 17");
+}
+
+static void test_subf_2 (void)
+{
+    __asm__ __volatile__ ("subf. 16, 16, 17");
+}
+
+static void test_subfo2 (void)
+{
+    __asm__ __volatile__ ("subfo 16, 16, 17");
+}
+
+static void test_subfo_2 (void)
+{
+    __asm__ __volatile__ ("subfo. 16, 16, 17");
+}
+
+static void test_subfc2 (void)
+{
+    __asm__ __volatile__ ("subfc 16, 16, 17");
+}
+
+static void test_subfc_2 (void)
+{
+    __asm__ __volatile__ ("subfc. 16, 16, 17");
+}
+
+static void test_subfco2 (void)
+{
+    __asm__ __volatile__ ("subfco 16, 16, 17");
+}
+
+static void test_subfco_2 (void)
+{
+    __asm__ __volatile__ ("subfco. 16, 16, 17");
+}
+
+static void test_subfe2 (void)
+{
+    __asm__ __volatile__ ("subfe 16, 16, 17");
+}
+
+static void test_subfe_2 (void)
+{
+    __asm__ __volatile__ ("subfe. 16, 16, 17");
+}
+
+static void test_subfeo2 (void)
+{
+    __asm__ __volatile__ ("subfeo 16, 16, 17");
+}
+
+static void test_subfeo_2 (void)
+{
+    __asm__ __volatile__ ("subfeo. 16, 16, 17");
+}
+
+/* Integer logical tests */
+static void test_and2 (void)
+{
+    __asm__ __volatile__ ("and 16, 16, 17");
+}
+
+static void test_and_2 (void)
+{
+    __asm__ __volatile__ ("and. 16, 16, 17");
+}
+
+static void test_andc2 (void)
+{
+    __asm__ __volatile__ ("andc 16, 16, 17");
+}
+
+static void test_andc_2 (void)
+{
+    __asm__ __volatile__ ("andc. 16, 16, 17");
+}
+
+static void test_eqv2 (void)
+{
+    __asm__ __volatile__ ("eqv 16, 16, 17");
+}
+
+static void test_eqv_2 (void)
+{
+    __asm__ __volatile__ ("eqv. 16, 16, 17");
+}
+
+static void test_nand2 (void)
+{
+    __asm__ __volatile__ ("nand 16, 16, 17");
+}
+
+static void test_nand_2 (void)
+{
+    __asm__ __volatile__ ("nand. 16, 16, 17");
+}
+
+static void test_nor2 (void)
+{
+    __asm__ __volatile__ ("nor 16, 16, 17");
+}
+
+static void test_nor_2 (void)
+{
+    __asm__ __volatile__ ("nor. 16, 16, 17");
+}
+
+static void test_or2 (void)
+{
+    __asm__ __volatile__ ("or 16, 16, 17");
+}
+
+static void test_or_2 (void)
+{
+    __asm__ __volatile__ ("or. 16, 16, 17");
+}
+
+static void test_orc2 (void)
+{
+    __asm__ __volatile__ ("orc 16, 16, 17");
+}
+
+static void test_orc_2 (void)
+{
+    __asm__ __volatile__ ("orc. 16, 16, 17");
+}
+
+static void test_xor2 (void)
+{
+    __asm__ __volatile__ ("xor 16, 16, 17");
+}
+
+static void test_xor_2 (void)
+{
+    __asm__ __volatile__ ("xor. 16, 16, 17");
+}
+
+/* Integer shift */
+static void test_slw2 (void)
+{
+    __asm__ __volatile__ ("slw 16, 16, 17");
+}
+
+static void test_slw_2 (void)
+{
+    __asm__ __volatile__ ("slw. 16, 16, 17");
+}
+
+static void test_sraw2 (void)
+{
+    __asm__ __volatile__ ("sraw 16, 16, 17");
+}
+
+static void test_sraw_2 (void)
+{
+    __asm__ __volatile__ ("sraw. 16, 16, 17");
+}
+
+static void test_srw2 (void)
+{
+    __asm__ __volatile__ ("srw 16, 16, 17");
+}
+
+static void test_srw_2 (void)
+{
+    __asm__ __volatile__ ("srw. 16, 16, 17");
+}
+
+/* Integer rotate */
+static void test_rotlw2 (void)
+{
+    __asm__ __volatile__ ("rotlw 16, 16, 17");
+}
+
+static void test_rotlw_2 (void)
+{
+    __asm__ __volatile__ ("rotlw. 16, 16, 17");
+}
+
+/* Two operands opcodes with op1=op2 */
+/* Integer arithmetic tests */
+static void test_add3 (void)
+{
+    __asm__ __volatile__ ("add 17, 16, 16");
+}
+
+static void test_add_3 (void)
+{
+    __asm__ __volatile__ ("add. 17, 16, 16");
+}
+
+static void test_addo3 (void)
+{
+    __asm__ __volatile__ ("addo 17, 16, 16");
+}
+
+static void test_addo_3 (void)
+{
+    __asm__ __volatile__ ("addo. 17, 16, 16");
+}
+
+static void test_addc3 (void)
+{
+    __asm__ __volatile__ ("addc 17, 16, 16");
+}
+
+static void test_addc_3 (void)
+{
+    __asm__ __volatile__ ("addc. 17, 16, 16");
+}
+
+static void test_addco3 (void)
+{
+    __asm__ __volatile__ ("addco 17, 16, 16");
+}
+
+static void test_addco_3 (void)
+{
+    __asm__ __volatile__ ("addco. 17, 16, 16");
+}
+
+static void test_adde3 (void)
+{
+    __asm__ __volatile__ ("adde 17, 16, 16");
+}
+
+static void test_adde_3 (void)
+{
+    __asm__ __volatile__ ("adde. 17, 16, 16");
+}
+
+static void test_addeo3 (void)
+{
+    __asm__ __volatile__ ("addeo 17, 16, 16");
+}
+
+static void test_addeo_3 (void)
+{
+    __asm__ __volatile__ ("addeo. 17, 16, 16");
+}
+
+static void test_divw3 (void)
+{
+    __asm__ __volatile__ ("divw 17, 16, 16");
+}
+
+static void test_divw_3 (void)
+{
+    __asm__ __volatile__ ("divw. 17, 16, 16");
+}
+
+static void test_divwo3 (void)
+{
+    __asm__ __volatile__ ("divwo 17, 16, 16");
+}
+
+static void test_divwo_3 (void)
+{
+    __asm__ __volatile__ ("divwo. 17, 16, 16");
+}
+
+static void test_divwu3 (void)
+{
+    __asm__ __volatile__ ("divwu 17, 16, 16");
+}
+
+static void test_divwu_3 (void)
+{
+    __asm__ __volatile__ ("divwu. 17, 16, 16");
+}
+
+static void test_divwuo3 (void)
+{
+    __asm__ __volatile__ ("divwuo 17, 16, 16");
+}
+
+static void test_divwuo_3 (void)
+{
+    __asm__ __volatile__ ("divwuo. 17, 16, 16");
+}
+
+static void test_mulhw3 (void)
+{
+    __asm__ __volatile__ ("mulhw 17, 16, 16");
+}
+
+static void test_mulhw_3 (void)
+{
+    __asm__ __volatile__ ("mulhw. 17, 16, 16");
+}
+
+static void test_mulhwu3 (void)
+{
+    __asm__ __volatile__ ("mulhwu 17, 16, 16");
+}
+
+static void test_mulhwu_3 (void)
+{
+    __asm__ __volatile__ ("mulhwu. 17, 16, 16");
+}
+
+static void test_mullw3 (void)
+{
+    __asm__ __volatile__ ("mullw 17, 16, 16");
+}
+
+static void test_mullw_3 (void)
+{
+    __asm__ __volatile__ ("mullw. 17, 16, 16");
+}
+
+static void test_mullwo3 (void)
+{
+    __asm__ __volatile__ ("mullwo 17, 16, 16");
+}
+
+static void test_mullwo_3 (void)
+{
+    __asm__ __volatile__ ("mullwo. 17, 16, 16");
+}
+
+static void test_subf3 (void)
+{
+    __asm__ __volatile__ ("subf 17, 16, 16");
+}
+
+static void test_subf_3 (void)
+{
+    __asm__ __volatile__ ("subf. 17, 16, 16");
+}
+
+static void test_subfo3 (void)
+{
+    __asm__ __volatile__ ("subfo 17, 16, 16");
+}
+
+static void test_subfo_3 (void)
+{
+    __asm__ __volatile__ ("subfo. 17, 16, 16");
+}
+
+static void test_subfc3 (void)
+{
+    __asm__ __volatile__ ("subfc 17, 16, 16");
+}
+
+static void test_subfc_3 (void)
+{
+    __asm__ __volatile__ ("subfc. 17, 16, 16");
+}
+
+static void test_subfco3 (void)
+{
+    __asm__ __volatile__ ("subfco 17, 16, 16");
+}
+
+static void test_subfco_3 (void)
+{
+    __asm__ __volatile__ ("subfco. 17, 16, 16");
+}
+
+static void test_subfe3 (void)
+{
+    __asm__ __volatile__ ("subfe 17, 16, 16");
+}
+
+static void test_subfe_3 (void)
+{
+    __asm__ __volatile__ ("subfe. 17, 16, 16");
+}
+
+static void test_subfeo3 (void)
+{
+    __asm__ __volatile__ ("subfeo 17, 16, 16");
+}
+
+static void test_subfeo_3 (void)
+{
+    __asm__ __volatile__ ("subfeo. 17, 16, 16");
+}
+
+/* Integer comparison tests */
+static void test_cmp3 (void)
+{
+    __asm__ __volatile__ ("cmp 2, 16, 16");
+}
+
+static void test_cmpl3 (void)
+{
+    __asm__ __volatile__ ("cmpl 2, 16, 16");
+}
+
+/* Integer logical tests */
+static void test_and3 (void)
+{
+    __asm__ __volatile__ ("and 17, 16, 16");
+}
+
+static void test_and_3 (void)
+{
+    __asm__ __volatile__ ("and. 17, 16, 16");
+}
+
+static void test_andc3 (void)
+{
+    __asm__ __volatile__ ("andc 17, 16, 16");
+}
+
+static void test_andc_3 (void)
+{
+    __asm__ __volatile__ ("andc. 17, 16, 16");
+}
+
+static void test_eqv3 (void)
+{
+    __asm__ __volatile__ ("eqv 17, 16, 16");
+}
+
+static void test_eqv_3 (void)
+{
+    __asm__ __volatile__ ("eqv. 17, 16, 16");
+}
+
+static void test_nand3 (void)
+{
+    __asm__ __volatile__ ("nand 17, 16, 16");
+}
+
+static void test_nand_3 (void)
+{
+    __asm__ __volatile__ ("nand. 17, 16, 16");
+}
+
+static void test_nor3 (void)
+{
+    __asm__ __volatile__ ("nor 17, 16, 16");
+}
+
+static void test_nor_3 (void)
+{
+    __asm__ __volatile__ ("nor. 17, 16, 16");
+}
+
+static void test_or3 (void)
+{
+    __asm__ __volatile__ ("or 17, 16, 16");
+}
+
+static void test_or_3 (void)
+{
+    __asm__ __volatile__ ("or. 17, 16, 16");
+}
+
+static void test_orc3 (void)
+{
+    __asm__ __volatile__ ("orc 17, 16, 16");
+}
+
+static void test_orc_3 (void)
+{
+    __asm__ __volatile__ ("orc. 17, 16, 16");
+}
+
+static void test_xor3 (void)
+{
+    __asm__ __volatile__ ("xor 17, 16, 16");
+}
+
+static void test_xor_3 (void)
+{
+    __asm__ __volatile__ ("xor. 17, 16, 16");
+}
+
+/* Integer shift */
+static void test_slw3 (void)
+{
+    __asm__ __volatile__ ("slw 17, 16, 16");
+}
+
+static void test_slw_3 (void)
+{
+    __asm__ __volatile__ ("slw. 17, 16, 16");
+}
+
+static void test_sraw3 (void)
+{
+    __asm__ __volatile__ ("sraw 17, 16, 16");
+}
+
+static void test_sraw_3 (void)
+{
+    __asm__ __volatile__ ("sraw. 17, 16, 16");
+}
+
+static void test_srw3 (void)
+{
+    __asm__ __volatile__ ("srw 17, 16, 16");
+}
+
+static void test_srw_3 (void)
+{
+    __asm__ __volatile__ ("srw. 17, 16, 16");
+}
+
+/* Integer rotate */
+static void test_rotlw3 (void)
+{
+    __asm__ __volatile__ ("rotlw 17, 16, 16");
+}
+
+static void test_rotlw_3 (void)
+{
+    __asm__ __volatile__ ("rotlw. 17, 16, 16");
+}
+
+/* Two operands opcodes with op1=op2=dst */
+/* Integer arithmetic tests */
+static void test_add4 (void)
+{
+    __asm__ __volatile__ ("add 16, 16, 16");
+}
+
+static void test_add_4 (void)
+{
+    __asm__ __volatile__ ("add. 16, 16, 16");
+}
+
+static void test_addo4 (void)
+{
+    __asm__ __volatile__ ("addo 16, 16, 16");
+}
+
+static void test_addo_4 (void)
+{
+    __asm__ __volatile__ ("addo. 16, 16, 16");
+}
+
+static void test_addc4 (void)
+{
+    __asm__ __volatile__ ("addc 16, 16, 16");
+}
+
+static void test_addc_4 (void)
+{
+    __asm__ __volatile__ ("addc. 16, 16, 16");
+}
+
+static void test_addco4 (void)
+{
+    __asm__ __volatile__ ("addco 16, 16, 16");
+}
+
+static void test_addco_4 (void)
+{
+    __asm__ __volatile__ ("addco. 16, 16, 16");
+}
+
+static void test_adde4 (void)
+{
+    __asm__ __volatile__ ("adde 16, 16, 16");
+}
+
+static void test_adde_4 (void)
+{
+    __asm__ __volatile__ ("adde. 16, 16, 16");
+}
+
+static void test_addeo4 (void)
+{
+    __asm__ __volatile__ ("addeo 16, 16, 16");
+}
+
+static void test_addeo_4 (void)
+{
+    __asm__ __volatile__ ("addeo. 16, 16, 16");
+}
+
+static void test_divw4 (void)
+{
+    __asm__ __volatile__ ("divw 16, 16, 16");
+}
+
+static void test_divw_4 (void)
+{
+    __asm__ __volatile__ ("divw. 16, 16, 16");
+}
+
+static void test_divwo4 (void)
+{
+    __asm__ __volatile__ ("divwo 16, 16, 16");
+}
+
+static void test_divwo_4 (void)
+{
+    __asm__ __volatile__ ("divwo. 16, 16, 16");
+}
+
+static void test_divwu4 (void)
+{
+    __asm__ __volatile__ ("divwu 16, 16, 16");
+}
+
+static void test_divwu_4 (void)
+{
+    __asm__ __volatile__ ("divwu. 16, 16, 16");
+}
+
+static void test_divwuo4 (void)
+{
+    __asm__ __volatile__ ("divwuo 16, 16, 16");
+}
+
+static void test_divwuo_4 (void)
+{
+    __asm__ __volatile__ ("divwuo. 16, 16, 16");
+}
+
+static void test_mulhw4 (void)
+{
+    __asm__ __volatile__ ("mulhw 16, 16, 16");
+}
+
+static void test_mulhw_4 (void)
+{
+    __asm__ __volatile__ ("mulhw. 16, 16, 16");
+}
+
+static void test_mulhwu4 (void)
+{
+    __asm__ __volatile__ ("mulhwu 16, 16, 16");
+}
+
+static void test_mulhwu_4 (void)
+{
+    __asm__ __volatile__ ("mulhwu. 16, 16, 16");
+}
+
+static void test_mullw4 (void)
+{
+    __asm__ __volatile__ ("mullw 16, 16, 16");
+}
+
+static void test_mullw_4 (void)
+{
+    __asm__ __volatile__ ("mullw. 16, 16, 16");
+}
+
+static void test_mullwo4 (void)
+{
+    __asm__ __volatile__ ("mullwo 16, 16, 16");
+}
+
+static void test_mullwo_4 (void)
+{
+    __asm__ __volatile__ ("mullwo. 16, 16, 16");
+}
+
+static void test_subf4 (void)
+{
+    __asm__ __volatile__ ("subf 16, 16, 16");
+}
+
+static void test_subf_4 (void)
+{
+    __asm__ __volatile__ ("subf. 16, 16, 16");
+}
+
+static void test_subfo4 (void)
+{
+    __asm__ __volatile__ ("subfo 16, 16, 16");
+}
+
+static void test_subfo_4 (void)
+{
+    __asm__ __volatile__ ("subfo. 16, 16, 16");
+}
+
+static void test_subfc4 (void)
+{
+    __asm__ __volatile__ ("subfc 16, 16, 16");
+}
+
+static void test_subfc_4 (void)
+{
+    __asm__ __volatile__ ("subfc. 16, 16, 16");
+}
+
+static void test_subfco4 (void)
+{
+    __asm__ __volatile__ ("subfco 16, 16, 16");
+}
+
+static void test_subfco_4 (void)
+{
+    __asm__ __volatile__ ("subfco. 16, 16, 16");
+}
+
+static void test_subfe4 (void)
+{
+    __asm__ __volatile__ ("subfe 16, 16, 16");
+}
+
+static void test_subfe_4 (void)
+{
+    __asm__ __volatile__ ("subfe. 16, 16, 16");
+}
+
+static void test_subfeo4 (void)
+{
+    __asm__ __volatile__ ("subfeo 16, 16, 16");
+}
+
+static void test_subfeo_4 (void)
+{
+    __asm__ __volatile__ ("subfeo. 16, 16, 16");
+}
+
+/* Integer logical tests */
+static void test_and4 (void)
+{
+    __asm__ __volatile__ ("and 16, 16, 16");
+}
+
+static void test_and_4 (void)
+{
+    __asm__ __volatile__ ("and. 16, 16, 16");
+}
+
+static void test_andc4 (void)
+{
+    __asm__ __volatile__ ("andc 16, 16, 16");
+}
+
+static void test_andc_4 (void)
+{
+    __asm__ __volatile__ ("andc. 16, 16, 16");
+}
+
+static void test_eqv4 (void)
+{
+    __asm__ __volatile__ ("eqv 16, 16, 16");
+}
+
+static void test_eqv_4 (void)
+{
+    __asm__ __volatile__ ("eqv. 16, 16, 16");
+}
+
+static void test_nand4 (void)
+{
+    __asm__ __volatile__ ("nand 16, 16, 16");
+}
+
+static void test_nand_4 (void)
+{
+    __asm__ __volatile__ ("nand. 16, 16, 16");
+}
+
+static void test_nor4 (void)
+{
+    __asm__ __volatile__ ("nor 16, 16, 16");
+}
+
+static void test_nor_4 (void)
+{
+    __asm__ __volatile__ ("nor. 16, 16, 16");
+}
+
+static void test_or4 (void)
+{
+    __asm__ __volatile__ ("or 16, 16, 16");
+}
+
+static void test_or_4 (void)
+{
+    __asm__ __volatile__ ("or. 16, 16, 16");
+}
+
+static void test_orc4 (void)
+{
+    __asm__ __volatile__ ("orc 16, 16, 16");
+}
+
+static void test_orc_4 (void)
+{
+    __asm__ __volatile__ ("orc. 16, 16, 16");
+}
+
+static void test_xor4 (void)
+{
+    __asm__ __volatile__ ("xor 16, 16, 16");
+}
+
+static void test_xor_4 (void)
+{
+    __asm__ __volatile__ ("xor. 16, 16, 16");
+}
+
+/* Integer shift */
+static void test_slw4 (void)
+{
+    __asm__ __volatile__ ("slw 16, 16, 16");
+}
+
+static void test_slw_4 (void)
+{
+    __asm__ __volatile__ ("slw. 16, 16, 16");
+}
+
+static void test_sraw4 (void)
+{
+    __asm__ __volatile__ ("sraw 16, 16, 16");
+}
+
+static void test_sraw_4 (void)
+{
+    __asm__ __volatile__ ("sraw. 16, 16, 16");
+}
+
+static void test_srw4 (void)
+{
+    __asm__ __volatile__ ("srw 16, 16, 16");
+}
+
+static void test_srw_4 (void)
+{
+    __asm__ __volatile__ ("srw. 16, 16, 16");
+}
+
+/* Integer rotate */
+static void test_rotlw4 (void)
+{
+    __asm__ __volatile__ ("rotlw 16, 16, 16");
+}
+
+static void test_rotlw_4 (void)
+{
+    __asm__ __volatile__ ("rotlw. 16, 16, 16");
+}
+
+/* Two operands opcodes with 1 16 bits immediate */
+/* Integer arithmetic tests */
+static void test_addi (void)
+{
+    __asm__ __volatile__ ("addi 17, 16, 0");
+}
+
+static void test_addic (void)
+{
+    __asm__ __volatile__ ("addic 17, 16, 0");
+}
+
+static void test_addic_ (void)
+{
+    __asm__ __volatile__ ("addic. 17, 16, 0");
+}
+
+static void test_addis (void)
+{
+    __asm__ __volatile__ ("addis 17, 16, 0");
+}
+
+static void test_mulli (void)
+{
+    __asm__ __volatile__ ("mulli 17, 16, 0");
+}
+
+static void test_subfic (void)
+{
+    __asm__ __volatile__ ("subfic 17, 16, 0");
+}
+
+static void test_cmpi (void)
+{
+    __asm__ __volatile__ ("cmpi 3, 16, 0");
+}
+
+static void test_cmpli (void)
+{
+    __asm__ __volatile__ ("cmpli 4, 16, 0");
+}
+
+static void test_andi_ (void)
+{
+    __asm__ __volatile__ ("andi. 17, 16, 0");
+}
+
+static void test_andis_ (void)
+{
+    __asm__ __volatile__ ("andis. 17, 16, 0");
+}
+
+static void test_ori (void)
+{
+    __asm__ __volatile__ ("ori 17, 16, 0");
+}
+
+static void test_oris (void)
+{
+    __asm__ __volatile__ ("oris 17, 16, 0");
+}
+
+static void test_xori (void)
+{
+    __asm__ __volatile__ ("xori 17, 16, 0");
+}
+
+static void test_xoris (void)
+{
+    __asm__ __volatile__ ("xoris 17, 16, 0");
+}
+
+/* Two operands opcodes with 1 16 bits immediate with src=dst */
+/* Integer arithmetic tests */
+static void test_addi2 (void)
+{
+    __asm__ __volatile__ ("addi 16, 16, 0");
+}
+
+static void test_addic2 (void)
+{
+    __asm__ __volatile__ ("addic 16, 16, 0");
+}
+
+static void test_addic_2 (void)
+{
+    __asm__ __volatile__ ("addic. 16, 16, 0");
+}
+
+static void test_addis2 (void)
+{
+    __asm__ __volatile__ ("addis 16, 16, 0");
+}
+
+static void test_mulli2 (void)
+{
+    __asm__ __volatile__ ("mulli 16, 16, 0");
+}
+
+static void test_subfic2 (void)
+{
+    __asm__ __volatile__ ("subfic 16, 16, 0");
+}
+
+static void test_andi_2 (void)
+{
+    __asm__ __volatile__ ("andi. 16, 16, 0");
+}
+
+static void test_andis_2 (void)
+{
+    __asm__ __volatile__ ("andis. 16, 16, 0");
+}
+
+static void test_ori2 (void)
+{
+    __asm__ __volatile__ ("ori 16, 16, 0");
+}
+
+static void test_oris2 (void)
+{
+    __asm__ __volatile__ ("oris 16, 16, 0");
+}
+
+static void test_xori2 (void)
+{
+    __asm__ __volatile__ ("xori 16, 16, 0");
+}
+
+static void test_xoris2 (void)
+{
+    __asm__ __volatile__ ("xoris 16, 16, 0");
+}
+
+/* Misc opcodes */
+/* Integer rotate */
+static void test_clrlwi1 (void)
+{
+    __asm__ __volatile__ ("clrlwi 17, 16, 0");
+}
+
+static void test_clrlwi2 (void)
+{
+    __asm__ __volatile__ ("clrlwi 17, 16, 12");
+}
+
+static void test_clrlwi3 (void)
+{
+    __asm__ __volatile__ ("clrlwi 17, 16, 17");
+}
+
+static void test_clrlwi4 (void)
+{
+    __asm__ __volatile__ ("clrlwi 17, 16, 31");
+}
+
+static void test_clrlwi_1 (void)
+{
+    __asm__ __volatile__ ("clrlwi. 17, 16, 0");
+}
+
+static void test_clrlwi_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi. 17, 16, 12");
+}
+
+static void test_clrlwi_3 (void)
+{
+    __asm__ __volatile__ ("clrlwi. 17, 16, 17");
+}
+
+static void test_clrlwi_4 (void)
+{
+    __asm__ __volatile__ ("clrlwi. 17, 16, 31");
+}
+
+static void test_clrlslwi1 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 17, 16, 0, 0");
+}
+
+static void test_clrlslwi2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 17, 16, 7, 0");
+}
+
+static void test_clrlslwi3 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 17, 16, 31, 0");
+}
+
+static void test_clrlslwi4 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 17, 16, 13, 12");
+}
+
+static void test_clrlslwi5 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 17, 16, 13, 12");
+}
+
+static void test_clrlslwi6 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 17, 16, 31, 17");
+}
+
+static void test_clrlslwi7 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 17, 16, 31, 31");
+}
+
+static void test_clrlslwi_1 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 17, 16, 0, 0");
+}
+
+static void test_clrlslwi_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 17, 16, 7, 0");
+}
+
+static void test_clrlslwi_3 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 17, 16, 31, 0");
+}
+
+static void test_clrlslwi_4 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 17, 16, 13, 12");
+}
+
+static void test_clrlslwi_5 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 17, 16, 13, 12");
+}
+
+static void test_clrlslwi_6 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 17, 16, 31, 17");
+}
+
+static void test_clrlslwi_7 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 17, 16, 31, 31");
+}
+
+static void test_clrrwi (void)
+{
+    __asm__ __volatile__ ("clrrwi 17, 16, 7");
+}
+
+static void test_clrrwi_ (void)
+{
+    __asm__ __volatile__ ("clrrwi. 17, 16, 7");
+}
+
+static void test_extlwi (void)
+{
+    __asm__ __volatile__ ("extlwi 17, 16, 7, 8");
+}
+
+static void test_extrwi_ (void)
+{
+    __asm__ __volatile__ ("extrwi. 17, 16, 7, 8");
+}
+
+static void test_extrwi (void)
+{
+    __asm__ __volatile__ ("extrwi 17, 16, 7, 8");
+}
+
+static void test_extlwi_ (void)
+{
+    __asm__ __volatile__ ("extlwi. 17, 16, 7, 8");
+}
+
+static void test_rotlwi (void)
+{
+    __asm__ __volatile__ ("rotlwi 17, 16, 7");
+}
+
+static void test_rotlwi_ (void)
+{
+    __asm__ __volatile__ ("rotlwi. 17, 16, 7");
+}
+
+static void test_rotrwi (void)
+{
+    __asm__ __volatile__ ("rotrwi 17, 16, 7");
+}
+
+static void test_rotrwi_ (void)
+{
+    __asm__ __volatile__ ("rotrwi. 17, 16, 7");
+}
+
+static void test_slwi (void)
+{
+    __asm__ __volatile__ ("slwi 17, 16, 7");
+}
+
+static void test_slwi_ (void)
+{
+    __asm__ __volatile__ ("slwi. 17, 16, 7");
+}
+
+static void test_srwi (void)
+{
+    __asm__ __volatile__ ("srwi 17, 16, 7");
+}
+
+static void test_srwi_ (void)
+{
+    __asm__ __volatile__ ("srwi. 17, 16, 7");
+}
+
+static void test_rlwnm0 (void)
+{
+    __asm__ __volatile__ ("rlwnm 18, 16, 17, 2, 15");
+}
+
+static void test_rlwnm0_ (void)
+{
+    __asm__ __volatile__ ("rlwnm. 18, 16, 17, 3, 15");
+}
+
+static void test_rlwnm16 (void)
+{
+    __asm__ __volatile__ ("rlwnm 18, 16, 17, 16, 29");
+}
+
+static void test_rlwnm16_ (void)
+{
+    __asm__ __volatile__ ("rlwnm. 18, 16, 17, 16, 29");
+}
+
+/* Misc opcodes */
+/* Integer rotate */
+static void test_clrlwi1_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi 16, 16, 0");
+}
+
+static void test_clrlwi2_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi 16, 16, 12");
+}
+
+static void test_clrlwi3_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi 16, 16, 17");
+}
+
+static void test_clrlwi4_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi 16, 16, 31");
+}
+
+static void test_clrlwi_1_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi. 16, 16, 0");
+}
+
+static void test_clrlwi_2_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi. 16, 16, 12");
+}
+
+static void test_clrlwi_3_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi. 16, 16, 17");
+}
+
+static void test_clrlwi_4_2 (void)
+{
+    __asm__ __volatile__ ("clrlwi. 16, 16, 31");
+}
+
+static void test_clrlslwi1_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 16, 16, 0, 0");
+}
+
+static void test_clrlslwi2_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 16, 16, 7, 0");
+}
+
+static void test_clrlslwi3_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 16, 16, 31, 0");
+}
+
+static void test_clrlslwi4_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 16, 16, 13, 12");
+}
+
+static void test_clrlslwi5_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 16, 16, 13, 12");
+}
+
+static void test_clrlslwi6_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 16, 16, 31, 17");
+}
+
+static void test_clrlslwi7_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi 16, 16, 31, 31");
+}
+
+static void test_clrlslwi_1_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 16, 16, 0, 0");
+}
+
+static void test_clrlslwi_2_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 16, 16, 7, 0");
+}
+
+static void test_clrlslwi_3_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 16, 16, 31, 0");
+}
+
+static void test_clrlslwi_4_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 16, 16, 13, 12");
+}
+
+static void test_clrlslwi_5_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 16, 16, 13, 12");
+}
+
+static void test_clrlslwi_6_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 16, 16, 31, 17");
+}
+
+static void test_clrlslwi_7_2 (void)
+{
+    __asm__ __volatile__ ("clrlslwi. 16, 16, 31, 31");
+}
+
+static void test_clrrwi_2 (void)
+{
+    __asm__ __volatile__ ("clrrwi 16, 16, 7");
+}
+
+static void test_clrrwi__2 (void)
+{
+    __asm__ __volatile__ ("clrrwi. 16, 16, 7");
+}
+
+static void test_extlwi_2 (void)
+{
+    __asm__ __volatile__ ("extlwi 16, 16, 7, 8");
+}
+
+static void test_extrwi__2 (void)
+{
+    __asm__ __volatile__ ("extrwi. 16, 16, 7, 8");
+}
+
+static void test_extrwi_2 (void)
+{
+    __asm__ __volatile__ ("extrwi 16, 16, 7, 8");
+}
+
+static void test_extlwi__2 (void)
+{
+    __asm__ __volatile__ ("extlwi. 16, 16, 7, 8");
+}
+
+static void test_rotlwi_2 (void)
+{
+    __asm__ __volatile__ ("rotlwi 16, 16, 7");
+}
+
+static void test_rotlwi__2 (void)
+{
+    __asm__ __volatile__ ("rotlwi. 16, 16, 7");
+}
+
+static void test_rotrwi_2 (void)
+{
+    __asm__ __volatile__ ("rotrwi 16, 16, 7");
+}
+
+static void test_rotrwi__2 (void)
+{
+    __asm__ __volatile__ ("rotrwi. 16, 16, 7");
+}
+
+static void test_slwi_2 (void)
+{
+    __asm__ __volatile__ ("slwi 16, 16, 7");
+}
+
+static void test_slwi__2 (void)
+{
+    __asm__ __volatile__ ("slwi. 16, 16, 7");
+}
+
+static void test_srwi_2 (void)
+{
+    __asm__ __volatile__ ("srwi 16, 16, 7");
+}
+
+static void test_srwi__2 (void)
+{
+    __asm__ __volatile__ ("srwi. 16, 16, 7");
+}
+
+static void test_rlwnm0_2 (void)
+{
+    __asm__ __volatile__ ("rlwnm 16, 16, 17, 2, 15");
+}
+
+static void test_rlwnm0__2 (void)
+{
+    __asm__ __volatile__ ("rlwnm. 16, 16, 17, 3, 15");
+}
+
+static void test_rlwnm16_2 (void)
+{
+    __asm__ __volatile__ ("rlwnm 16, 16, 17, 16, 29");
+}
+
+static void test_rlwnm16__2 (void)
+{
+    __asm__ __volatile__ ("rlwnm. 16, 16, 17, 16, 29");
+}
+
+static void test_rlwinm1 (void)
+{
+    __asm__ __volatile__ ("rlwinm 17, 16, 1, 31, 0");
+}
+
+static void test_rlwinm2 (void)
+{
+    __asm__ __volatile__ ("rlwinm 17, 16, 1, 0, 15");
+}
+
+static void test_rlwinm3 (void)
+{
+    __asm__ __volatile__ ("rlwinm 17, 16, 15, 15, 30");
+}
+
+static void test_rlwinm4 (void)
+{
+    __asm__ __volatile__ ("rlwinm 17, 16, 31, 31, 31");
+}
+
+static void test_rlwinm_1 (void)
+{
+    __asm__ __volatile__ ("rlwinm. 17, 16, 1, 31, 0");
+}
+
+static void test_rlwinm_2 (void)
+{
+    __asm__ __volatile__ ("rlwinm. 17, 16, 1, 0, 15");
+}
+
+static void test_rlwinm_3 (void)
+{
+    __asm__ __volatile__ ("rlwinm. 17, 16, 15, 15, 30");
+}
+
+static void test_rlwinm_4 (void)
+{
+    __asm__ __volatile__ ("rlwinm. 17, 16, 31, 31, 31");
+}
+
+typedef void (*test_t)(void);
+
+typedef struct tests_t {
+    int flags;
+    const char *name;
+    void *test;
+} tests_t;
+
+enum {
+    FL_NR    = 0x000F,
+    FL_IMM16 = 0x0010,
+    FL_MEM   = 0x0020,
+};
+
+/* One operand tests */
+static tests_t tests_1a[] = {
+    /* Integer arithmetic tests */
+    { 0x0001, "addme", &test_addme, },
+    { 0x0001, "addme.", &test_addme_, },
+    { 0x0001, "addmeo", &test_addmeo, },
+    { 0x0001, "addmeo.", &test_addmeo_, },
+    { 0x0001, "addze", &test_addze, },
+    { 0x0001, "addze.", &test_addze_, },
+    { 0x0001, "addzeo", &test_addzeo, },
+    { 0x0001, "addzeo.", &test_addzeo_, },
+    { 0x0001, "neg", &test_neg, },
+    { 0x0001, "neg.", &test_neg_, },
+    { 0x0001, "nego", &test_nego, },
+    { 0x0001, "nego.", &test_nego_, },
+    { 0x0001, "subfme", &test_subfme, },
+    { 0x0001, "subfme.", &test_subfme_, },
+    { 0x0001, "subfmeo", &test_subfmeo, },
+    { 0x0001, "subfmeo.", &test_subfmeo_, },
+    { 0x0001, "subfze", &test_subfze, },
+    { 0x0001, "subfze.", &test_subfze_, },
+    { 0x0001, "subfzeo", &test_subfzeo, },
+    { 0x0001, "subfzeo.", &test_subfzeo_, },
+    /* Integer logical tests */
+    { 0x0001, "cntlzw", &test_cntlzw, },
+    { 0x0001, "cntlzw.", &test_cntlzw_, },
+    { 0x0001, "extsb", &test_extsb, },
+    { 0x0001, "extsb.", &test_extsb_, },
+    { 0x0001, "extsh", &test_extsh, },
+    { 0x0001, "extsh.", &test_extsh_, },
+    { -1, NULL, NULL, },
+};
+
+/* One operand tests with dest=src */
+static tests_t tests_1b[] = {
+    /* Integer arithmetic tests */
+    { 0x0001, "addme 2", &test_addme2, },
+    { 0x0001, "addme. 2", &test_addme_2, },
+    { 0x0001, "addmeo 2", &test_addmeo2, },
+    { 0x0001, "addmeo. 2", &test_addmeo_2, },
+    { 0x0001, "addze 2", &test_addze2, },
+    { 0x0001, "addze. 2", &test_addze_2, },
+    { 0x0001, "addzeo 2", &test_addzeo2, },
+    { 0x0001, "addzeo. 2", &test_addzeo_2, },
+    { 0x0001, "neg 2", &test_neg2, },
+    { 0x0001, "neg. 2", &test_neg_2, },
+    { 0x0001, "nego 2", &test_nego2, },
+    { 0x0001, "nego. 2", &test_nego_2, },
+    { 0x0001, "subfme 2", &test_subfme2, },
+    { 0x0001, "subfme. 2", &test_subfme_2, },
+    { 0x0001, "subfmeo 2", &test_subfmeo2, },
+    { 0x0001, "subfmeo. 2", &test_subfmeo_2, },
+    { 0x0001, "subfze 2", &test_subfze2, },
+    { 0x0001, "subfze. 2", &test_subfze_2, },
+    { 0x0001, "subfzeo 2", &test_subfzeo2, },
+    { 0x0001, "subfzeo. 2", &test_subfzeo_2, },
+    /* Integer logical tests */
+    { 0x0001, "cntlzw 2", &test_cntlzw2, },
+    { 0x0001, "cntlzw. 2", &test_cntlzw_2, },
+    { 0x0001, "extsb 2", &test_extsb2, },
+    { 0x0001, "extsb. 2", &test_extsb_2, },
+    { 0x0001, "extsh 2", &test_extsh2, },
+    { 0x0001, "extsh. 2", &test_extsh_2, },
+    { -1, NULL, NULL, },
+};
+
+/* Two operands tests */
+static tests_t tests_2a[] = {
+    /* Integer arithmetic tests */
+    { 0x0002, "add", &test_add, },
+    { 0x0002, "add.", &test_add_, },
+    { 0x0002, "addo", &test_addo, },
+    { 0x0002, "addo.", &test_addo_, },
+    { 0x0002, "addc", &test_addc, },
+    { 0x0002, "addc.", &test_addc_, },
+    { 0x0002, "addco", &test_addco, },
+    { 0x0002, "addco.", &test_addco_, },
+    { 0x0002, "adde", &test_adde, },
+    { 0x0002, "adde.", &test_adde_, },
+    { 0x0002, "addeo", &test_addeo, },
+    { 0x0002, "addeo.", &test_addeo_, },
+    { 0x0002, "divw", &test_divw, },
+    { 0x0002, "divw.", &test_divw_, },
+    { 0x0002, "divwo", &test_divwo, },
+    { 0x0002, "divwo.", &test_divwo_, },
+    { 0x0002, "divwu", &test_divwu, },
+    { 0x0002, "divwu.", &test_divwu_, },
+    { 0x0002, "divwuo", &test_divwuo, },
+    { 0x0002, "divwuo.", &test_divwuo_, },
+    { 0x0002, "mulhw", &test_mulhw, },
+    { 0x0002, "mulhw.", &test_mulhw_, },
+    { 0x0002, "mulhwu", &test_mulhwu, },
+    { 0x0002, "mulhwu.", &test_mulhwu_, },
+    { 0x0002, "mullw", &test_mullw, },
+    { 0x0002, "mullw.", &test_mullw_, },
+    { 0x0002, "mullwo", &test_mullwo, },
+    { 0x0002, "mullwo.", &test_mullwo_, },
+    { 0x0002, "subf", &test_subf, },
+    { 0x0002, "subf.", &test_subf_, },
+    { 0x0002, "subfo", &test_subfo, },
+    { 0x0002, "subfo.", &test_subfo_, },
+    { 0x0002, "subfc", &test_subfc, },
+    { 0x0002, "subfc.", &test_subfc_, },
+    { 0x0002, "subfco", &test_subfco, },
+    { 0x0002, "subfco.", &test_subfco_, },
+    { 0x0002, "subfe", &test_subfe, },
+    { 0x0002, "subfe.", &test_subfe_, },
+    { 0x0002, "subfeo", &test_subfeo, },
+    { 0x0002, "subfeo.", &test_subfeo_, },
+    /* Integer comparison tests */
+    { 0x0002, "cmp", &test_cmp, },
+    { 0x0002, "cmpl", &test_cmpl, },
+    /* Integer logical tests */
+    { 0x0002, "and", &test_and, },
+    { 0x0002, "and.", &test_and_, },
+    { 0x0002, "andc", &test_andc, },
+    { 0x0002, "andc.", &test_andc_, },
+    { 0x0002, "eqv", &test_eqv, },
+    { 0x0002, "eqv.", &test_eqv_, },
+    { 0x0002, "nand", &test_nand, },
+    { 0x0002, "nand.", &test_nand_, },
+    { 0x0002, "nor", &test_nor, },
+    { 0x0002, "nor.", &test_nor_, },
+    { 0x0002, "or", &test_or, },
+    { 0x0002, "or.", &test_or_, },
+    { 0x0002, "orc", &test_orc, },
+    { 0x0002, "orc.", &test_orc_, },
+    { 0x0002, "xor", &test_xor, },
+    { 0x0002, "xor.", &test_xor_, },
+    { 0x0002, "rotlw", &test_rotlw, },
+    { 0x0002, "rotlw.", &test_rotlw_, },
+    /* Integer shift */
+    { 0x0002, "slw", &test_slw, },
+    { 0x0002, "slw.", &test_slw_, },
+    { 0x0002, "sraw", &test_sraw, },
+    { 0x0002, "sraw.", &test_sraw_, },
+    { 0x0002, "srw", &test_srw, },
+    { 0x0002, "srw.", &test_srw_, },
+    { -1, NULL, NULL, },
+};
+
+/* Two operands tests with src=dst */
+static tests_t tests_2b[] = {
+    /* Integer arithmetic tests */
+    { 0x0002, "add 2", &test_add2, },
+    { 0x0002, "add. 2", &test_add_2, },
+    { 0x0002, "addo 2", &test_addo2, },
+    { 0x0002, "addo. 2", &test_addo_2, },
+    { 0x0002, "addc 2", &test_addc2, },
+    { 0x0002, "addc. 2", &test_addc_2, },
+    { 0x0002, "addco 2", &test_addco2, },
+    { 0x0002, "addco. 2", &test_addco_2, },
+    { 0x0002, "adde 2", &test_adde2, },
+    { 0x0002, "adde. 2", &test_adde_2, },
+    { 0x0002, "addeo 2", &test_addeo2, },
+    { 0x0002, "addeo. 2", &test_addeo_2, },
+    { 0x0002, "divw 2", &test_divw2, },
+    { 0x0002, "divw. 2", &test_divw_2, },
+    { 0x0002, "divwo 2", &test_divwo2, },
+    { 0x0002, "divwo. 2", &test_divwo_2, },
+    { 0x0002, "divwu 2", &test_divwu2, },
+    { 0x0002, "divwu. 2", &test_divwu_2, },
+    { 0x0002, "divwuo 2", &test_divwuo2, },
+    { 0x0002, "divwuo. 2", &test_divwuo_2, },
+    { 0x0002, "mulhw 2", &test_mulhw2, },
+    { 0x0002, "mulhw. 2", &test_mulhw_2, },
+    { 0x0002, "mulhwu 2", &test_mulhwu2, },
+    { 0x0002, "mulhwu. 2", &test_mulhwu_2, },
+    { 0x0002, "mullw 2", &test_mullw2, },
+    { 0x0002, "mullw. 2", &test_mullw_2, },
+    { 0x0002, "mullwo 2", &test_mullwo2, },
+    { 0x0002, "mullwo. 2", &test_mullwo_2, },
+    { 0x0002, "subf 2", &test_subf2, },
+    { 0x0002, "subf. 2", &test_subf_2, },
+    { 0x0002, "subfo 2", &test_subfo2, },
+    { 0x0002, "subfo. 2", &test_subfo_2, },
+    { 0x0002, "subfc 2", &test_subfc2, },
+    { 0x0002, "subfc. 2", &test_subfc_2, },
+    { 0x0002, "subfco 2", &test_subfco2, },
+    { 0x0002, "subfco. 2", &test_subfco_2, },
+    { 0x0002, "subfe 2", &test_subfe2, },
+    { 0x0002, "subfe. 2", &test_subfe_2, },
+    { 0x0002, "subfeo 2", &test_subfeo2, },
+    { 0x0002, "subfeo. 2", &test_subfeo_2, },
+    /* Integer logical tests */
+    { 0x0002, "and 2", &test_and2, },
+    { 0x0002, "and. 2", &test_and_2, },
+    { 0x0002, "andc 2", &test_andc2, },
+    { 0x0002, "andc. 2", &test_andc_2, },
+    { 0x0002, "eqv 2", &test_eqv2, },
+    { 0x0002, "eqv. 2", &test_eqv_2, },
+    { 0x0002, "nand 2", &test_nand2, },
+    { 0x0002, "nand. 2", &test_nand_2, },
+    { 0x0002, "nor 2", &test_nor2, },
+    { 0x0002, "nor. 2", &test_nor_2, },
+    { 0x0002, "or 2", &test_or2, },
+    { 0x0002, "or. 2", &test_or_2, },
+    { 0x0002, "orc 2", &test_orc2, },
+    { 0x0002, "orc. 2", &test_orc_2, },
+    { 0x0002, "xor 2", &test_xor2, },
+    { 0x0002, "xor. 2", &test_xor_2, },
+    { 0x0002, "rotlw 2", &test_rotlw2, },
+    { 0x0002, "rotlw. 2", &test_rotlw_2, },
+    /* Integer shift */
+    { 0x0002, "slw 2", &test_slw2, },
+    { 0x0002, "slw. 2", &test_slw_2, },
+    { 0x0002, "sraw 2", &test_sraw2, },
+    { 0x0002, "sraw. 2", &test_sraw_2, },
+    { 0x0002, "srw 2", &test_srw2, },
+    { 0x0002, "srw. 2", &test_srw_2, },
+    { -1, NULL, NULL, },
+};
+
+/* Two operands tests with op1=op2 */
+static tests_t tests_2c[] = {
+    /* Integer arithmetic tests */
+    { 0x0001, "add 3", &test_add3, },
+    { 0x0001, "add. 3", &test_add_3, },
+    { 0x0001, "addo 3", &test_addo3, },
+    { 0x0001, "addo. 3", &test_addo_3, },
+    { 0x0001, "addc 3", &test_addc3, },
+    { 0x0001, "addc. 3", &test_addc_3, },
+    { 0x0001, "addco 3", &test_addco3, },
+    { 0x0001, "addco. 3", &test_addco_3, },
+    { 0x0001, "adde 3", &test_adde3, },
+    { 0x0001, "adde. 3", &test_adde_3, },
+    { 0x0001, "addeo 3", &test_addeo3, },
+    { 0x0001, "addeo. 3", &test_addeo_3, },
+    { 0x0001, "divw 3", &test_divw3, },
+    { 0x0001, "divw. 3", &test_divw_3, },
+    { 0x0001, "divwo 3", &test_divwo3, },
+    { 0x0001, "divwo. 3", &test_divwo_3, },
+    { 0x0001, "divwu 3", &test_divwu3, },
+    { 0x0001, "divwu. 3", &test_divwu_3, },
+    { 0x0001, "divwuo 3", &test_divwuo3, },
+    { 0x0001, "divwuo. 3", &test_divwuo_3, },
+    { 0x0001, "mulhw 3", &test_mulhw3, },
+    { 0x0001, "mulhw. 3", &test_mulhw_3, },
+    { 0x0001, "mulhwu 3", &test_mulhwu3, },
+    { 0x0001, "mulhwu. 3", &test_mulhwu_3, },
+    { 0x0001, "mullw 3", &test_mullw3, },
+    { 0x0001, "mullw. 3", &test_mullw_3, },
+    { 0x0001, "mullwo 3", &test_mullwo3, },
+    { 0x0001, "mullwo. 3", &test_mullwo_3, },
+    { 0x0001, "subf 3", &test_subf3, },
+    { 0x0001, "subf. 3", &test_subf_3, },
+    { 0x0001, "subfo 3", &test_subfo3, },
+    { 0x0001, "subfo. 3", &test_subfo_3, },
+    { 0x0001, "subfc 3", &test_subfc3, },
+    { 0x0001, "subfc. 3", &test_subfc_3, },
+    { 0x0001, "subfco 3", &test_subfco3, },
+    { 0x0001, "subfco. 3", &test_subfco_3, },
+    { 0x0001, "subfe 3", &test_subfe3, },
+    { 0x0001, "subfe. 3", &test_subfe_3, },
+    { 0x0001, "subfeo 3", &test_subfeo3, },
+    { 0x0001, "subfeo. 3", &test_subfeo_3, },
+    /* Integer comparison tests */
+    { 0x0001, "cmp 3", &test_cmp3, },
+    { 0x0001, "cmpl 3", &test_cmpl3, },
+    /* Integer logical tests */
+    { 0x0001, "and 3", &test_and3, },
+    { 0x0001, "and. 3", &test_and_3, },
+    { 0x0001, "andc 3", &test_andc3, },
+    { 0x0001, "andc. 3", &test_andc_3, },
+    { 0x0001, "eqv 3", &test_eqv3, },
+    { 0x0001, "eqv. 3", &test_eqv_3, },
+    { 0x0001, "nand 3", &test_nand3, },
+    { 0x0001, "nand. 3", &test_nand_3, },
+    { 0x0001, "nor 3", &test_nor3, },
+    { 0x0001, "nor. 3", &test_nor_3, },
+    { 0x0001, "or 3", &test_or3, },
+    { 0x0001, "or. 3", &test_or_3, },
+    { 0x0001, "orc 3", &test_orc3, },
+    { 0x0001, "orc. 3", &test_orc_3, },
+    { 0x0001, "xor 3", &test_xor3, },
+    { 0x0001, "xor. 3", &test_xor_3, },
+    { 0x0001, "rotlw 3", &test_rotlw3, },
+    { 0x0001, "rotlw. 3", &test_rotlw_3, },
+    /* Integer shift */
+    { 0x0001, "slw 3", &test_slw3, },
+    { 0x0001, "slw. 3", &test_slw_3, },
+    { 0x0001, "sraw 3", &test_sraw3, },
+    { 0x0001, "sraw. 3", &test_sraw_3, },
+    { 0x0001, "srw 3", &test_srw3, },
+    { 0x0001, "srw. 3", &test_srw_3, },
+    { -1, NULL, NULL, },
+};
+
+/* Two operands tests with op1=op2=dst */
+static tests_t tests_2d[] = {
+    /* Integer arithmetic tests */
+    { 0x0001, "add 4", &test_add4, },
+    { 0x0001, "add. 4", &test_add_4, },
+    { 0x0001, "addo 4", &test_addo4, },
+    { 0x0001, "addo. 4", &test_addo_4, },
+    { 0x0001, "addc 4", &test_addc4, },
+    { 0x0001, "addc. 4", &test_addc_4, },
+    { 0x0001, "addco 4", &test_addco4, },
+    { 0x0001, "addco. 4", &test_addco_4, },
+    { 0x0001, "adde 4", &test_adde4, },
+    { 0x0001, "adde. 4", &test_adde_4, },
+    { 0x0001, "addeo 4", &test_addeo4, },
+    { 0x0001, "addeo. 4", &test_addeo_4, },
+    { 0x0001, "divw 4", &test_divw4, },
+    { 0x0001, "divw. 4", &test_divw_4, },
+    { 0x0001, "divwo 4", &test_divwo4, },
+    { 0x0001, "divwo. 4", &test_divwo_4, },
+    { 0x0001, "divwu 4", &test_divwu4, },
+    { 0x0001, "divwu. 4", &test_divwu_4, },
+    { 0x0001, "divwuo 4", &test_divwuo4, },
+    { 0x0001, "divwuo. 4", &test_divwuo_4, },
+    { 0x0001, "mulhw 4", &test_mulhw4, },
+    { 0x0001, "mulhw. 4", &test_mulhw_4, },
+    { 0x0001, "mulhwu 4", &test_mulhwu4, },
+    { 0x0001, "mulhwu. 4", &test_mulhwu_4, },
+    { 0x0001, "mullw 4", &test_mullw4, },
+    { 0x0001, "mullw. 4", &test_mullw_4, },
+    { 0x0001, "mullwo 4", &test_mullwo4, },
+    { 0x0001, "mullwo. 4", &test_mullwo_4, },
+    { 0x0001, "subf 4", &test_subf4, },
+    { 0x0001, "subf. 4", &test_subf_4, },
+    { 0x0001, "subfo 4", &test_subfo4, },
+    { 0x0001, "subfo. 4", &test_subfo_4, },
+    { 0x0001, "subfc 4", &test_subfc4, },
+    { 0x0001, "subfc. 4", &test_subfc_4, },
+    { 0x0001, "subfco 4", &test_subfco4, },
+    { 0x0001, "subfco. 4", &test_subfco_4, },
+    { 0x0001, "subfe 4", &test_subfe4, },
+    { 0x0001, "subfe. 4", &test_subfe_4, },
+    { 0x0001, "subfeo 4", &test_subfeo4, },
+    { 0x0001, "subfeo. 4", &test_subfeo_4, },
+    /* Integer logical tests */
+    { 0x0001, "and 4", &test_and4, },
+    { 0x0001, "and. 4", &test_and_4, },
+    { 0x0001, "andc 4", &test_andc4, },
+    { 0x0001, "andc. 4", &test_andc_4, },
+    { 0x0001, "eqv 4", &test_eqv4, },
+    { 0x0001, "eqv. 4", &test_eqv_4, },
+    { 0x0001, "nand 4", &test_nand4, },
+    { 0x0001, "nand. 4", &test_nand_4, },
+    { 0x0001, "nor 4", &test_nor4, },
+    { 0x0001, "nor. 4", &test_nor_4, },
+    { 0x0001, "or 4", &test_or4, },
+    { 0x0001, "or. 4", &test_or_4, },
+    { 0x0001, "orc 4", &test_orc4, },
+    { 0x0001, "orc. 4", &test_orc_4, },
+    { 0x0001, "xor 4", &test_xor4, },
+    { 0x0001, "xor. 4", &test_xor_4, },
+    { 0x0001, "rotlw 4", &test_rotlw4, },
+    { 0x0001, "rotlw. 4", &test_rotlw_4, },
+    /* Integer shift */
+    { 0x0001, "slw 4", &test_slw4, },
+    { 0x0001, "slw. 4", &test_slw_4, },
+    { 0x0001, "sraw 4", &test_sraw4, },
+    { 0x0001, "sraw. 4", &test_sraw_4, },
+    { 0x0001, "srw 4", &test_srw4, },
+    { 0x0001, "srw. 4", &test_srw_4, },
+    { -1, NULL, NULL, },
+};
+
+/* Two operand with 16 bits immediate tests */
+static tests_t tests_ia[] = {
+    { 0x0002 | FL_IMM16, "addi", &test_addi, },
+    { 0x0002 | FL_IMM16, "addic", &test_addic, },
+    { 0x0002 | FL_IMM16, "addic.", &test_addic_, },
+    { 0x0002 | FL_IMM16, "addis", &test_addis, },
+    { 0x0002 | FL_IMM16, "mulli", &test_mulli, },
+    { 0x0002 | FL_IMM16, "subfic", &test_subfic, },
+    { 0x0002 | FL_IMM16, "cmpi", &test_cmpi, },
+    { 0x0002 | FL_IMM16, "cmpli", &test_cmpli, },
+    { 0x0002 | FL_IMM16, "andi.", &test_andi_, },
+    { 0x0002 | FL_IMM16, "andis.", &test_andis_, },
+    { 0x0002 | FL_IMM16, "ori", &test_ori, },
+    { 0x0002 | FL_IMM16, "oris", &test_oris, },
+    { 0x0002 | FL_IMM16, "xori", &test_xori, },
+    { 0x0002 | FL_IMM16, "xoris", &test_xoris, },
+    { -1, NULL, NULL, },
+};
+
+/* Two operand with 16 bits immediate tests with src=dst*/
+static tests_t tests_ib[] = {
+    { 0x0002 | FL_IMM16, "addi 2", &test_addi2, },
+    { 0x0002 | FL_IMM16, "addic 2", &test_addic2, },
+    { 0x0002 | FL_IMM16, "addic. 2", &test_addic_2, },
+    { 0x0002 | FL_IMM16, "addis 2", &test_addis2, },
+    { 0x0002 | FL_IMM16, "mulli 2", &test_mulli2, },
+    { 0x0002 | FL_IMM16, "subfic 2", &test_subfic2, },
+    { 0x0002 | FL_IMM16, "andi. 2", &test_andi_2, },
+    { 0x0002 | FL_IMM16, "andis. 2", &test_andis_2, },
+    { 0x0002 | FL_IMM16, "ori 2", &test_ori2, },
+    { 0x0002 | FL_IMM16, "oris 2", &test_oris2, },
+    { 0x0002 | FL_IMM16, "xori 2", &test_xori2, },
+    { 0x0002 | FL_IMM16, "xoris 2", &test_xoris2, },
+    { -1, NULL, NULL, },
+};
+
+/* Misc tests */
+static tests_t tests_m[] = {
+#if 1
+    /* Integer rotate: TODO */
+    { 0x0001, "clrlwi 1", &test_clrlwi1, },
+    { 0x0001, "clrlwi 2", &test_clrlwi2, },
+    { 0x0001, "clrlwi 3", &test_clrlwi3, },
+    { 0x0001, "clrlwi 4", &test_clrlwi4, },
+    { 0x0001, "clrlwi. 1", &test_clrlwi_1, },
+    { 0x0001, "clrlwi. 2", &test_clrlwi_2, },
+    { 0x0001, "clrlwi. 3", &test_clrlwi_3, },
+    { 0x0001, "clrlwi. 4", &test_clrlwi_4, },
+    { 0x0001, "clrlslwi 1", &test_clrlslwi1, },
+    { 0x0001, "clrlslwi 2", &test_clrlslwi2, },
+    { 0x0001, "clrlslwi 3", &test_clrlslwi3, },
+    { 0x0001, "clrlslwi 4", &test_clrlslwi4, },
+    { 0x0001, "clrlslwi 5", &test_clrlslwi5, },
+    { 0x0001, "clrlslwi 6", &test_clrlslwi6, },
+    { 0x0001, "clrlslwi 7", &test_clrlslwi7, },
+    { 0x0001, "clrlslwi. 1", &test_clrlslwi_1, },
+    { 0x0001, "clrlslwi. 2", &test_clrlslwi_2, },
+    { 0x0001, "clrlslwi. 3", &test_clrlslwi_3, },
+    { 0x0001, "clrlslwi. 4", &test_clrlslwi_4, },
+    { 0x0001, "clrlslwi. 5", &test_clrlslwi_5, },
+    { 0x0001, "clrlslwi. 6", &test_clrlslwi_6, },
+    { 0x0001, "clrlslwi. 7", &test_clrlslwi_7, },
+    { 0x0001, "clrrwi", &test_clrrwi, },
+    { 0x0001, "clrrwi.", &test_clrrwi_, },
+    { 0x0001, "extlwi", &test_extlwi, },
+    { 0x0001, "extlwi.", &test_extlwi_, },
+    { 0x0001, "extrwi", &test_extrwi, },
+    { 0x0001, "extrwi.", &test_extrwi_, },
+    { 0x0001, "rotlwi", &test_rotlwi, },
+    { 0x0001, "rotlwi.", &test_rotlwi_, },
+    { 0x0001, "rotrwi", &test_rotrwi, },
+    { 0x0001, "rotrwi.", &test_rotrwi_, },
+    { 0x0001, "slwi", &test_slwi, },
+    { 0x0001, "slwi.", &test_slwi_, },
+    { 0x0001, "srwi", &test_srwi, },
+    { 0x0001, "srwi.", &test_srwi_, },
+    { 0x0002, "rlwnm 0, 15", &test_rlwnm0, },
+    { 0x0002, "rlwnm. 0, 15", &test_rlwnm0_, },
+    { 0x0002, "rlwnm 16, 31", &test_rlwnm16, },
+    { 0x0002, "rlwnm. 16, 31", &test_rlwnm16_, },
+    /* Integer rotate: TODO */
+    { 0x0001, "clrlwi 1 2", &test_clrlwi1_2, },
+    { 0x0001, "clrlwi 2 2", &test_clrlwi2_2, },
+    { 0x0001, "clrlwi 3 2", &test_clrlwi3_2, },
+    { 0x0001, "clrlwi 4 2", &test_clrlwi4_2, },
+    { 0x0001, "clrlwi. 1 2", &test_clrlwi_1_2, },
+    { 0x0001, "clrlwi. 2 2", &test_clrlwi_2_2, },
+    { 0x0001, "clrlwi. 3 2", &test_clrlwi_3_2, },
+    { 0x0001, "clrlwi. 4 2", &test_clrlwi_4_2, },
+    { 0x0001, "clrlslwi 1 2", &test_clrlslwi1_2, },
+    { 0x0001, "clrlslwi 2 2", &test_clrlslwi2_2, },
+    { 0x0001, "clrlslwi 3 2", &test_clrlslwi3_2, },
+    { 0x0001, "clrlslwi 4 2", &test_clrlslwi4_2, },
+    { 0x0001, "clrlslwi 5 2", &test_clrlslwi5_2, },
+    { 0x0001, "clrlslwi 6 2", &test_clrlslwi6_2, },
+    { 0x0001, "clrlslwi 7 2", &test_clrlslwi7_2, },
+    { 0x0001, "clrlslwi. 1 2", &test_clrlslwi_1_2, },
+    { 0x0001, "clrlslwi. 2 2", &test_clrlslwi_2_2, },
+    { 0x0001, "clrlslwi. 3 2", &test_clrlslwi_3_2, },
+    { 0x0001, "clrlslwi. 4 2", &test_clrlslwi_4_2, },
+    { 0x0001, "clrlslwi. 5 2", &test_clrlslwi_5_2, },
+    { 0x0001, "clrlslwi. 6 2", &test_clrlslwi_6_2, },
+    { 0x0001, "clrlslwi. 7 2", &test_clrlslwi_7_2, },
+    { 0x0001, "clrrwi 2", &test_clrrwi_2, },
+    { 0x0001, "clrrwi. 2", &test_clrrwi__2, },
+    { 0x0001, "extlwi 2", &test_extlwi_2, },
+    { 0x0001, "extlwi. 2", &test_extlwi__2, },
+    { 0x0001, "extrwi 2", &test_extrwi_2, },
+    { 0x0001, "extrwi. 2", &test_extrwi__2, },
+    { 0x0001, "rotlwi 2", &test_rotlwi_2, },
+    { 0x0001, "rotlwi. 2", &test_rotlwi__2, },
+    { 0x0001, "rotrwi 2", &test_rotrwi_2, },
+    { 0x0001, "rotrwi. 2", &test_rotrwi__2, },
+    { 0x0001, "slwi 2", &test_slwi_2, },
+    { 0x0001, "slwi. 2", &test_slwi__2, },
+    { 0x0001, "srwi 2", &test_srwi_2, },
+    { 0x0001, "srwi. 2", &test_srwi__2, },
+    { 0x0002, "rlwnm 0, 15 2", &test_rlwnm0_2, },
+    { 0x0002, "rlwnm. 0, 15 2", &test_rlwnm0__2, },
+    { 0x0002, "rlwnm 16, 31 2", &test_rlwnm16_2, },
+    { 0x0002, "rlwnm. 16, 31 2", &test_rlwnm16__2, },
+#endif
+    { 0x0001, "rlwinm 1", &test_rlwinm1, },
+    { 0x0001, "rlwinm 2", &test_rlwinm2, },
+    { 0x0001, "rlwinm 3", &test_rlwinm3, },
+    { 0x0001, "rlwinm 4", &test_rlwinm4, },
+    { 0x0001, "rlwinm. 1", &test_rlwinm_1, },
+    { 0x0001, "rlwinm. 2", &test_rlwinm_2, },
+    { 0x0001, "rlwinm. 3", &test_rlwinm_3, },
+    { 0x0001, "rlwinm. 4", &test_rlwinm_4, },
+    { -1, NULL, NULL, },
+};
+
+#if 0
+    { 0x0002 | FL_MEM, "lbzx", &test_lbzx, },
+    { 0x0002 | FL_MEM, "lbzux", &test_lbzux, },
+    { 0x0002 | FL_MEM, "lhax", &test_lhzx, },
+    { 0x0002 | FL_MEM, "lhaux", &test_lhzux, },
+    { 0x0002 | FL_MEM, "lhzx", &test_lhzx, },
+    { 0x0002 | FL_MEM, "lhzux", &test_lhzux, },
+    { 0x0002 | FL_MEM, "lwzx", &test_lwzx, },
+    { 0x0002 | FL_MEM, "lwzux", &test_lwzux, },
+    { 0x0003 | FL_MEM, "stbx", &test_stb, },
+    { 0x0003 | FL_MEM, "stbux", &test_stbu, },
+    { 0x0003 | FL_MEM, "sthx", &test_sth, },
+    { 0x0003 | FL_MEM, "sthux", &test_sthu, },
+    { 0x0003 | FL_MEM, "stwx", &test_stw, },
+    { 0x0003 | FL_MEM, "stwux", &test_sthw, },
+#endif
+
+static unsigned long operands[] = {
+    0x00000000,
+    0x00000001,
+    0x0000000f,
+    0x00000010,
+    0x0000001f,
+    0x00000020,
+    0x00000064,
+    0x0000006f,
+    0x0000007f,
+    0x00000080,
+    0x000000ff,
+    0x00000100,
+    0x00007fff,
+    0x00008000,
+    0x0000ffff,
+    0x00010000,
+    0x007fffff,
+    0x00800000,
+    0x00ffffff,
+    0x01000000,
+    0x7fffffff,
+    0x80000000,
+    0xffffffff,
+};
+
+static unsigned long ops16[] = {
+    0x00000000,
+    0x00000001,
+    0x0000000f,
+    0x00000010,
+    0x0000001f,
+    0x00000020,
+    0x0000002f,
+    0x0000003f,
+    0x0000007f,
+    0x00000080,
+    0x000000ff,
+    0x00000100,
+    0x00000101,
+    0x000003ff,
+    0x000007ff,
+    0x00000800,
+    0x00000fff,
+    0x00001000,
+    0x00003fff,
+    0x00007fff,
+    0x0000ffff,
+};
+
+unsigned long testbuf[2];
+static int do_test (int fd, tests_t *test_table)
+{
+    test_t test = NULL;
+    unsigned long keep;
+    int i, j, k, l, xer = 0;
+
+change_xer:
+    for (i = 0; test_table[i].test != NULL; i++) {
+        outstr(fd, test_mess, strlen(test_mess));
+        outstr(fd, "test: ", 6);
+        outstr(fd, test_table[i].name, strlen(test_table[i].name));
+        outstr(fd, "\n", 1);
+        switch (test_table[i].flags & FL_NR) {
+        case 0:
+            outstr(fd, test_table[i].name, strlen(test_table[i].name));
+            outstr(fd, " ", 1);
+            outstr(fd, "\n", 1);
+            init_ppc(xer);
+            dump_ppc_state(fd);
+            test = test_table[i].test;
+            init_ppc(xer);
+            (*test)();
+            dump_ppc_state(fd);
+            break;
+        case 1:
+            for (j = 0;; j++) {
+                outstr(fd, test_table[i].name, strlen(test_table[i].name));
+                outstr(fd, " 0x", 3);
+                outhex(fd, operands[j]);
+                outstr(fd, "\n", 1);
+                init_ppc(xer);
+                r16 = operands[j];
+                dump_ppc_state(fd);
+                init_ppc(xer);
+                test = test_table[i].test;
+                r16 = operands[j];
+                (*test)();
+                dump_ppc_state(fd);
+                if (operands[j] == 0xffffffff)
+                    break;
+                outstr(fd, sep_mess, strlen(sep_mess));
+            }
+            break;
+        case 2:
+            for (j = 0;; j++) {
+                for (k = 0;; k++) {
+                    outstr(fd, test_table[i].name, strlen(test_table[i].name));
+                    outstr(fd, " 0x", 3);
+                    outhex(fd, operands[j]);
+                    outstr(fd, ", 0x", 4);
+                    if ((test_table[i].flags & FL_IMM16) != 0) {
+                        outhex(fd, ops16[k]);
+                    } else {
+                        outhex(fd, operands[k]);
+                    }
+                    outstr(fd, "\n", 1);
+                    if ((test_table[i].flags & FL_IMM16) != 0) {
+                        patch_imm16(testbuf, test_table[i].test, ops16[k]);
+                        test = (void *)testbuf;
+                        flush_icache(test);
+                        keep = 0;
+                    } else {
+                        test = test_table[i].test;
+                        keep = operands[k];
+                    }
+                    init_ppc(xer);
+                    r16 = operands[j];
+                    r17 = keep;
+                    dump_ppc_state(fd);
+                    init_ppc(xer);
+                    r16 = operands[j];
+                    r17 = keep;
+                    (*test)();
+                    dump_ppc_state(fd);
+                    if (operands[k] == 0xffffffff)
+                        break;
+                    outstr(fd, sep_mess, strlen(sep_mess));
+                }
+                if (operands[j] == 0xffffffff)
+                    break;
+                outstr(fd, sep_mess, strlen(sep_mess));
+            }
+            break;
+        case 3:
+            for (j = 0;; j++) {
+                for (k = 0;; k++) {
+                    for (l = 0;; l++) {
+                        outstr(fd, test_table[i].name,
+                               strlen(test_table[i].name));
+                        outstr(fd, " 0x", 3);
+                        outhex(fd, operands[j]);
+                        outstr(fd, ", 0x", 4);
+                        outhex(fd, operands[k]);
+                        outstr(fd, ", 0x", 4);
+                        if ((test_table[i].flags & FL_IMM16) != 0) {
+                            outhex(fd, ops16[l]);
+                        } else {
+                            outhex(fd, operands[l]);
+                        }
+                        outstr(fd, "\n", 1);
+                        init_ppc(xer);
+                        r16 = operands[j];
+                        r17 = operands[k];
+                        keep = 0;
+                        if ((test_table[i].flags & FL_IMM16) != 0) {
+                            testbuf[0] = *((unsigned long *)test + 0);
+                            patch_imm16(testbuf, test_table[i].test, ops16[l]);
+                            test = (void *)testbuf;
+                            flush_icache(test);
+                            keep = 0;
+                        } else {
+                            test = test_table[i].test;
+                            keep = operands[k];
+                        }
+                        r18 = keep;
+                        dump_ppc_state(fd);
+                        init_ppc(xer);
+                        r16 = operands[j];
+                        r17 = operands[k];
+                        r18 = keep;
+                        outstr(fd, "test\n", 5);
+                        (*test)();
+                        dump_ppc_state(fd);
+                        if (operands[l] == 0xffffffff)
+                            break;
+                        outstr(fd, sep_mess, strlen(sep_mess));
+                    }
+                    if (operands[k] == 0xffffffff)
+                        break;
+                    outstr(fd, sep_mess, strlen(sep_mess));
+                }
+                if (operands[j] == 0xffffffff)
+                    break;
+                outstr(fd, sep_mess, strlen(sep_mess));
+            }
+            break;
+        default:
+            outstr(fd, error_mess, strlen(error_mess));
+            return -1;
+        }
+    }
+    if (++xer < 4)
+        goto change_xer;
+    
+    return 0;
+}
+
+static void dump_env (int fd, int argc, char *const *argv, char *const *envp)
+{
+    unsigned long sp, *cur;
+    int i, j;
+
+    __asm__ __volatile__ ("mr %0, 1" : "=r"(sp));
+    /* Dump stack, argv and envp pointers */
+    outstr(fd, "Stack: ", strlen("Stack: "));
+    outhex(fd, sp);
+    outstr(fd, " ", 1);
+    outhex(fd, (unsigned long)__sp);
+    outstr(fd, "\n", 1);
+    fsync(fd);
+    cur = __sp - 32;
+    for (i = 0; ((unsigned long)cur & 0xfff) != 0; i++) {
+        outhex(fd, (unsigned long)cur);
+        outstr(fd, ": ", 2);
+        for (j = 0; j < 4; j++) {
+            outhex(fd, *cur++);
+            outstr(fd, " ", 1);
+        }
+        outstr(fd, "\n", 1);
+    }
+    outstr(fd, " argv: ", strlen(" argv: "));
+    outhex(fd, (unsigned long)argv);
+    outstr(fd, " envp: ", strlen(" envp: "));
+    outhex(fd, (unsigned long)envp);
+    outstr(fd, "\n", 1);
+    /* Dump args and environment */
+    outhex(fd, argc);
+    outstr(fd, " args\n", strlen(" args\n"));
+#if 1
+    for (i = 0; i < argc; i++) {
+        outstr(fd, " arg ", 5);
+        outhex(fd, i);
+        outstr(fd, " : ", 3);
+        outhex(fd, (unsigned long)argv[i]);
+        outstr(fd, " : ", 3);
+        outstr(fd, argv[i], strlen(argv[i]));
+        outstr(fd, "\n", 1);
+    }
+#endif
+    outstr(fd, "Env\n", strlen("Env\n"));
+    for (i = 0; envp[i] != NULL; i++) {
+        outstr(fd, "envstr ", 4);
+        outhex(fd, i);
+        outstr(fd, " : ", 3);
+        outhex(fd, (unsigned long)envp[i]);
+        outstr(fd, " : ", 3);
+        outstr(fd, envp[i], strlen(envp[i]));
+        outstr(fd, "\n", 1);
+    }
+}
+
+int main (int argc, char **argv, char **envp)
+{
+    int logfile;
+
+    unlink(logfname);
+    logfile = open(logfname, O_WRONLY | O_CREAT, 0644);
+    if (logfile < 0)
+        return 1;
+    sync();
+    outstr(logfile, first_mess, strlen(first_mess));
+    fsync(logfile);
+#if 0
+    dump_env(logfile, argc, argv, envp);
+#endif
+    if (do_test(logfile, tests_1a) < 0) {
+        outstr(logfile, test1_err, strlen(test1_err));
+        outstr(logfile, part1_err, strlen(part1_err));
+        goto out;
+    }
+    if (do_test(logfile, tests_1b) < 0) {
+        outstr(logfile, test1_err, strlen(test1_err));
+        outstr(logfile, part2_err, strlen(part2_err));
+        goto out;
+    }
+    if (do_test(logfile, tests_2a) < 0) {
+        outstr(logfile, test2_err, strlen(test2_err));
+        outstr(logfile, part1_err, strlen(part1_err));
+        goto out;
+    }
+    if (do_test(logfile, tests_2b) < 0) {
+        outstr(logfile, test2_err, strlen(test2_err));
+        outstr(logfile, part2_err, strlen(part2_err));
+        goto out;
+    }
+    if (do_test(logfile, tests_2c) < 0) {
+        outstr(logfile, test2_err, strlen(test2_err));
+        outstr(logfile, part3_err, strlen(part3_err));
+        goto out;
+    }
+    if (do_test(logfile, tests_2d) < 0) {
+        outstr(logfile, test2_err, strlen(test2_err));
+        outstr(logfile, part4_err, strlen(part4_err));
+        goto out;
+    }
+    if (do_test(logfile, tests_ia) < 0) {
+        outstr(logfile, testi_err, strlen(testi_err));
+        outstr(logfile, part1_err, strlen(part1_err));
+        goto out;
+    }
+    if (do_test(logfile, tests_ib) < 0) {
+        outstr(logfile, testi_err, strlen(testi_err));
+        outstr(logfile, part2_err, strlen(part2_err));
+        goto out;
+    }
+    if (do_test(logfile, tests_m) < 0) {
+        outstr(logfile, test1_err, strlen(test1_err));
+        goto out;
+    }
+ out:
+    close(logfile);
+
+    return 0;
+}
+
+void _start (void)
+{
+    register unsigned long __spp  __asm__ ("r1");
+    unsigned long *cur;
+    unsigned long *__argv, *__envp, __argc;
+    int __status, i;
+    
+    __sp = (unsigned long *)*((unsigned long *)__spp);
+    cur = __sp;
+    __argc = *cur;
+    __argv = cur + 1;
+    __envp = cur + 2 + __argc;
+    /* Linux is *STILL* buggy and doesn't respect the API */
+    if (*__argv == 0) {
+        unsigned long tmp = *__envp;
+
+        while (*(unsigned long *)tmp != 0)
+            tmp--;
+        tmp += 4;
+        for (i = 0; i < __argc; i++) {
+            __argv[i] = (unsigned long)tmp;
+            while (*(unsigned char *)tmp)
+                tmp++;
+            tmp++;
+        }
+    }
+    __status = main(__argc, (char **)__argv, (char **)__envp);
+    exit(__status);
+}

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Term prompt for qemu
  2003-11-18  7:29 ` [Qemu-devel] [PATCH] Term prompt for qemu J. Mayer
@ 2003-11-18  8:11   ` J. Mayer
  2003-11-18  8:11   ` J. Mayer
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:11 UTC (permalink / raw)
  To: qemu-devel

cpu-all.h.diff

Added cpu_reset_log to close the qemu log file.

diff -urNbB -x CVS qemu-current/cpu-all.h qemu/cpu-all.h
--- qemu-current/cpu-all.h	Tue Nov 18 06:51:06 2003
+++ qemu/cpu-all.h	Sun Nov 16 04:08:35 2003
@@ -418,6 +427,7 @@
 
 #define CPU_LOG_ALL 1
 void cpu_set_log(int log_flags);
+void cpu_reset_log (void);
 void cpu_set_log_filename(const char *filename);
 
 /* memory API */

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Term prompt for qemu
  2003-11-18  7:29 ` [Qemu-devel] [PATCH] Term prompt for qemu J. Mayer
  2003-11-18  8:11   ` J. Mayer
@ 2003-11-18  8:11   ` J. Mayer
  2003-11-18  8:13   ` J. Mayer
  2003-11-18  8:25   ` J. Mayer
  3 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:11 UTC (permalink / raw)
  To: qemu-devel

exec.c.diff

cpu_reset_log implementation

diff -urNbB -x CVS qemu-current/exec.c qemu/exec.c
--- qemu-current/exec.c	Tue Nov 18 06:51:07 2003
+++ qemu/exec.c	Sun Nov 16 04:10:03 2003
@@ -710,6 +710,15 @@
     logfilename = strdup(filename);
 }
 
+void cpu_reset_log (void)
+{
+    if (logfile != NULL) {
+        fclose(logfile);
+        logfile = NULL;
+    }
+    loglevel = 0;
+}
+
 /* mask must never be zero */
 void cpu_interrupt(CPUState *env, int mask)
 {

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Term prompt for qemu
  2003-11-18  7:29 ` [Qemu-devel] [PATCH] Term prompt for qemu J. Mayer
  2003-11-18  8:11   ` J. Mayer
  2003-11-18  8:11   ` J. Mayer
@ 2003-11-18  8:13   ` J. Mayer
  2003-11-18  8:25   ` J. Mayer
  3 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:13 UTC (permalink / raw)
  To: qemu-devel

vl.c.diff

Add term prompt for user commands during emulation.
Also add <CTRL><a>+<d> to turn on/off log. This is useful
to know if qemu is still translating code, long time after the
boot.

diff -urNbB -x CVS qemu-current/vl.c qemu/vl.c
--- qemu-current/vl.c	Tue Nov 18 06:51:10 2003
+++ qemu/vl.c	Tue Nov 18 02:19:33 2003
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
+#include <ctype.h>
 #include <getopt.h>
 #include <inttypes.h>
 #include <unistd.h>
@@ -1422,23 +1483,124 @@
 }
 
 #define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
-static int term_got_escape;
+static int term_got_escape, term_command;
+static unsigned char term_cmd_buf[128];
+
+typedef struct term_cmd_t {
+    const unsigned char *name;
+    void (*handler)(unsigned char *params);
+} term_cmd_t;
+
+static void do_change_cdrom (unsigned char *params);
+static void do_change_fd0 (unsigned char *params);
+static void do_change_fd1 (unsigned char *params);
+
+static term_cmd_t term_cmds[] = {
+    { "changecd", &do_change_cdrom, },
+    { "changefd0", &do_change_fd0, },
+    { "changefd1", &do_change_fd1, },
+    { NULL, NULL, },
+};
 
 void term_print_help(void)
 {
     printf("\n"
            "C-a h    print this help\n"
            "C-a x    exit emulatior\n"
+           "C-a d    switch on/off debug log\n"
 	   "C-a s    save disk data back to file (if -snapshot)\n"
            "C-a b    send break (magic sysrq)\n"
+           "C-a c    send qemu internal command\n"
            "C-a C-a  send C-a\n"
            );
 }
 
+static void do_change_cdrom (unsigned char *params)
+{
+    /* Dunno how to do it... */
+}
+
+static void do_change_fd (int fd, unsigned char *params)
+{
+    unsigned char *name_start, *name_end, *ros;
+    int ro;
+
+    for (name_start = params;
+         isspace(*name_start); name_start++)
+        continue;
+    if (*name_start == '\0')
+        return;
+    for (name_end = name_start;
+         !isspace(*name_end) && *name_end != '\0'; name_end++)
+        continue;
+    for (ros = name_end + 1; isspace(*ros); ros++)
+        continue;
+    if (ros[0] == 'r' && ros[1] == 'o')
+        ro = 1;
+    else
+        ro = 0;
+    *name_end = '\0';
+    printf("Change fd %d to %s (%s)\n", fd, name_start, params);
+    fdctrl_disk_change(fd, name_start, ro);
+}
+
+static void do_change_fd0 (unsigned char *params)
+{
+    do_change_fd(0, params);
+}
+
+static void do_change_fd1 (unsigned char *params)
+{
+    do_change_fd(1, params);
+}
+
+static void serial_treat_command ()
+{
+    unsigned char *cmd_start, *cmd_end;
+    int i;
+
+    for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++)
+        continue;
+    for (cmd_end = cmd_start;
+         !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++)
+        continue;
+    for (i = 0; term_cmds[i].name != NULL; i++) {
+        if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) &&
+            memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) {
+            (*term_cmds[i].handler)(cmd_end + 1);
+            return;
+        }
+    }
+    *cmd_end = '\0';
+    printf("Unknown term command: %s\n", cmd_start);
+}
+
+extern FILE *logfile;
+
 /* called when a char is received */
 void serial_received_byte(SerialState *s, int ch)
 {
-    if (term_got_escape) {
+    if (term_command) {
+        if (ch == '\n' || ch == '\r' || term_command == 127) {
+            printf("\n");
+            serial_treat_command();
+            term_command = 0;
+        } else {
+            if (ch == 0x7F || ch == 0x08) {
+                if (term_command > 0) {
+                    term_cmd_buf[--term_command] = '\0';
+                    printf("\r                                               "
+                           "                               ");
+                    printf("\r> %s", term_cmd_buf);
+                }
+            } else if (ch > 0x1f) {
+                term_cmd_buf[term_command++ - 1] = ch;
+                term_cmd_buf[term_command - 1] = '\0';
+                printf("\r> %s", term_cmd_buf);
+            }
+            fflush(stdout);
+        }
+    } else if (term_got_escape) {
         term_got_escape = 0;
         switch(ch) {
         case 'h':
@@ -1447,6 +1609,14 @@
         case 'x':
             exit(0);
             break;
+        case 'd':
+            if (logfile == NULL) {
+                printf("Turn logging ON\n");
+                cpu_set_log(CPU_LOG_ALL);
+            } else {
+                printf("Turn logging OFF\n");
+                cpu_reset_log();
+            }
 	case 's': 
             {
                 int i;
@@ -1462,6 +1632,11 @@
             s->lsr |= UART_LSR_BI | UART_LSR_DR;
             serial_update_irq();
             break;
+        case 'c':
+            printf("> ");
+            fflush(stdout);
+            term_command = 1;
+            break;
         case TERM_ESCAPE:
             goto send_char;
         }
@@ -2178,12 +2373,14 @@
             val |= 0x20;
         kbd_queue(s, val, 0);
         break;
+#ifdef TARGET_I386
     case KBD_CCMD_ENABLE_A20:
         cpu_x86_set_a20(env, 1);
         break;
     case KBD_CCMD_DISABLE_A20:
         cpu_x86_set_a20(env, 0);
         break;
+#endif
     case KBD_CCMD_RESET:
         reset_requested = 1;
         cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT);
@@ -2516,7 +2713,9 @@
         kbd_queue(s, val, 1);
         break;
     case KBD_CCMD_WRITE_OUTPORT:
+#ifdef TARGET_I386
         cpu_x86_set_a20(env, (val >> 1) & 1);
+#endif
         if (!(val & 1)) {
             reset_requested = 1;
             cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT);
@@ -2559,7 +2758,7 @@
 
 /***********************************************************/
 /* Bochs BIOS debug ports */
-
+#ifdef TARGET_I386
 void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val)
 {
     switch(addr) {
@@ -2601,6 +2800,7 @@
     register_ioport_write(0x500, 1, bochs_bios_write, 1);
     register_ioport_write(0x503, 1, bochs_bios_write, 1);
 }
+#endif
 
 /***********************************************************/
 /* dumb display */

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Fixes for qemu
  2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
                     ` (4 preceding siblings ...)
  2003-11-18  7:34   ` J. Mayer
@ 2003-11-18  8:24   ` J. Mayer
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:24 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 155 bytes --]

Here's a tarball with the whole patch inside
(attached, yes I know it's bad but may be easier to get...)

-- 
J. Mayer <l_indien@magic.fr>
Never organized

[-- Attachment #2: fixes.tgz --]
[-- Type: application/x-compressed-tar, Size: 1355 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] floppy disk emulation
  2003-11-18  7:22 ` [Qemu-devel] [ADD] floppy disk emulation J. Mayer
                     ` (3 preceding siblings ...)
  2003-11-18  7:39   ` J. Mayer
@ 2003-11-18  8:24   ` J. Mayer
  4 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:24 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 156 bytes --]

Here's a tarball with the whole patch inside
(attached, yes I know it's bad but may be easier to get...)


-- 
J. Mayer <l_indien@magic.fr>
Never organized

[-- Attachment #2: fdc.tgz --]
[-- Type: application/x-compressed-tar, Size: 10723 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (23 preceding siblings ...)
  2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
@ 2003-11-18  8:24   ` J. Mayer
  2003-11-18  9:37   ` Gwenole Beauchesne
  25 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:24 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 156 bytes --]

Here's a tarball with the whole patch inside
(attached, yes I know it's bad but may be easier to get...)


-- 
J. Mayer <l_indien@magic.fr>
Never organized

[-- Attachment #2: ppc.tgz --]
[-- Type: application/x-compressed-tar, Size: 36556 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] tests for PPC target.
  2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
                       ` (4 preceding siblings ...)
  2003-11-18  8:10     ` J. Mayer
@ 2003-11-18  8:25     ` J. Mayer
  5 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:25 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 156 bytes --]

Here's a tarball with the whole patch inside
(attached, yes I know it's bad but may be easier to get...)


-- 
J. Mayer <l_indien@magic.fr>
Never organized

[-- Attachment #2: ppc_tests.tgz --]
[-- Type: application/x-compressed-tar, Size: 14005 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [PATCH] Term prompt for qemu
  2003-11-18  7:29 ` [Qemu-devel] [PATCH] Term prompt for qemu J. Mayer
                     ` (2 preceding siblings ...)
  2003-11-18  8:13   ` J. Mayer
@ 2003-11-18  8:25   ` J. Mayer
  3 siblings, 0 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18  8:25 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 156 bytes --]

Here's a tarball with the whole patch inside
(attached, yes I know it's bad but may be easier to get...)


-- 
J. Mayer <l_indien@magic.fr>
Never organized

[-- Attachment #2: misc.tgz --]
[-- Type: application/x-compressed-tar, Size: 2458 bytes --]

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
                     ` (24 preceding siblings ...)
  2003-11-18  8:24   ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
@ 2003-11-18  9:37   ` Gwenole Beauchesne
  2003-11-18 10:37     ` J. Mayer
  25 siblings, 1 reply; 65+ messages in thread
From: Gwenole Beauchesne @ 2003-11-18  9:37 UTC (permalink / raw)
  To: qemu-devel

On Tue, 18 Nov 2003, J. Mayer wrote:

> Here's a set of patches which adds PPC processor as a new target.
> The emulation is not complete:

Hehe, interesting. Since I hadn't seen news so far, I decided to implement
my own version for the SheepShaver core CPU emulator this weekend. ;-)

I have a test program that covers around 600K variants with specific
values to trigger flags updates. It requires a PPC host for now to
validate results. It helped a lot to first write a correct interpreter and
discover some hidden semantics in rare cases.

I will first fix Microlib's core and try to have a look at QEMU's 
afterwards.

> there is no supervisor mode support for now

Assuming supervisor is OEA, how do you plan to emulate the TBR (at least
for VEA)? Currently, I make TBU=0/TBL=clock() loaded at MFTBR time. This
is enough to make MacOS classic happy. An alternative would be to use
gettimeofday() for seconds/microseconds. Any ideas?

Bye,
Gwenole.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18  9:37   ` Gwenole Beauchesne
@ 2003-11-18 10:37     ` J. Mayer
  2003-11-18 11:39       ` Raymond W. Lucke IV
  2003-11-18 12:24       ` Gwenole Beauchesne
  0 siblings, 2 replies; 65+ messages in thread
From: J. Mayer @ 2003-11-18 10:37 UTC (permalink / raw)
  To: qemu-devel

On Tue, 2003-11-18 at 10:37, Gwenole Beauchesne wrote:
> On Tue, 18 Nov 2003, J. Mayer wrote:
> 
> > Here's a set of patches which adds PPC processor as a new target.
> > The emulation is not complete:
> 
> Hehe, interesting. Since I hadn't seen news so far, I decided to implement
> my own version for the SheepShaver core CPU emulator this weekend. ;-)
> 
Damned :=)

> I have a test program that covers around 600K variants with specific
> values to trigger flags updates. It requires a PPC host for now to
> validate results. It helped a lot to first write a correct interpreter and
> discover some hidden semantics in rare cases.
> 
The program, ppc_test does this with a lot of different instruction,
using a huge set of values. With the ctrace program, I could check that
it runs the same on my Ibook and on my PC with qemu. Where could I find
yours to make more tests ?
You found hidden semantics, as you say. What is confusing, also, is that
Motorola's implementation isn't the same than IBM's one for some strange
cases...

> I will first fix Microlib's core and try to have a look at QEMU's 
> afterwards.
> 
> > there is no supervisor mode support for now
> 
> Assuming supervisor is OEA, how do you plan to emulate the TBR (at least
> for VEA)? Currently, I make TBU=0/TBL=clock() loaded at MFTBR time. This
> is enough to make MacOS classic happy. An alternative would be to use
> gettimeofday() for seconds/microseconds. Any ideas?
> 
My TBL/TBU implementation isn't a real time clock, but is a cycle
counter, as on "real" PPC. That means that the CPU will seem to run with
a variable clock, if a program compares its value to the one given by a
real-time clock. It's updated at the end of a translated block, or when
I see a mftbl/mftbu
instruction.
This way of doing seems closer to real PPC implementation, but may look
strange for some OS's...

Regards.

 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 10:37     ` J. Mayer
@ 2003-11-18 11:39       ` Raymond W. Lucke IV
  2003-11-18 12:13         ` J. Mayer
  2003-11-18 12:24       ` Gwenole Beauchesne
  1 sibling, 1 reply; 65+ messages in thread
From: Raymond W. Lucke IV @ 2003-11-18 11:39 UTC (permalink / raw)
  To: qemu-devel

That's really cool that you have the preliminary PPC emulation, and I 
noticed that you have cleaned a few things up. I wonder if your changes 
will make my port to Darwin any easier. ;-)

Ray


On Nov 18, 2003, at 2:37 AM, J. Mayer wrote:

> On Tue, 2003-11-18 at 10:37, Gwenole Beauchesne wrote:
>> On Tue, 18 Nov 2003, J. Mayer wrote:
>>
>>> Here's a set of patches which adds PPC processor as a new target.
>>> The emulation is not complete:
>>
>> Hehe, interesting. Since I hadn't seen news so far, I decided to 
>> implement
>> my own version for the SheepShaver core CPU emulator this weekend. ;-)
>>
> Damned :=)
>
>> I have a test program that covers around 600K variants with specific
>> values to trigger flags updates. It requires a PPC host for now to
>> validate results. It helped a lot to first write a correct 
>> interpreter and
>> discover some hidden semantics in rare cases.
>>
> The program, ppc_test does this with a lot of different instruction,
> using a huge set of values. With the ctrace program, I could check that
> it runs the same on my Ibook and on my PC with qemu. Where could I find
> yours to make more tests ?
> You found hidden semantics, as you say. What is confusing, also, is 
> that
> Motorola's implementation isn't the same than IBM's one for some 
> strange
> cases...
>
>> I will first fix Microlib's core and try to have a look at QEMU's
>> afterwards.
>>
>>> there is no supervisor mode support for now
>>
>> Assuming supervisor is OEA, how do you plan to emulate the TBR (at 
>> least
>> for VEA)? Currently, I make TBU=0/TBL=clock() loaded at MFTBR time. 
>> This
>> is enough to make MacOS classic happy. An alternative would be to use
>> gettimeofday() for seconds/microseconds. Any ideas?
>>
> My TBL/TBU implementation isn't a real time clock, but is a cycle
> counter, as on "real" PPC. That means that the CPU will seem to run 
> with
> a variable clock, if a program compares its value to the one given by a
> real-time clock. It's updated at the end of a translated block, or when
> I see a mftbl/mftbu
> instruction.
> This way of doing seems closer to real PPC implementation, but may look
> strange for some OS's...
>
> Regards.
>
>
> J. Mayer <l_indien@magic.fr>
> Never organized
>
>
>
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://mail.nongnu.org/mailman/listinfo/qemu-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 11:39       ` Raymond W. Lucke IV
@ 2003-11-18 12:13         ` J. Mayer
  2003-11-18 20:24           ` Raymond W. Lucke IV
  0 siblings, 1 reply; 65+ messages in thread
From: J. Mayer @ 2003-11-18 12:13 UTC (permalink / raw)
  To: qemu-devel

On Tue, 2003-11-18 at 12:39, Raymond W. Lucke IV wrote:
> That's really cool that you have the preliminary PPC emulation, and I 
> noticed that you have cleaned a few things up. I wonder if your changes 
> will make my port to Darwin any easier. ;-)
> 
I'm sorry, but I don't think so.
The biggest problem to make qemu run under Darwin isn't to make it
compile, this is really easy. The problem is to emulate Linux syscalls.
There is a huge work to do there to make it usable. And you have to
consider that you need one syscall remapper for each emulated
architecture (not true, but not so far...). An alternative solution is
_not_ to make the port and say that qemu for Linux PPC will run directly
with Panther, as it includes the Linux emulation from FreeBSD.

You can notice that the syscall emulation is, by now, far from correct,
for PPC target, in qemu... I didn't spent time on this point, because
it's really a big problem and it's not so funny to do...

Regards

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 10:37     ` J. Mayer
  2003-11-18 11:39       ` Raymond W. Lucke IV
@ 2003-11-18 12:24       ` Gwenole Beauchesne
  2003-11-18 12:57         ` Johan Rydberg
  2003-11-18 14:59         ` Jocelyn Mayer
  1 sibling, 2 replies; 65+ messages in thread
From: Gwenole Beauchesne @ 2003-11-18 12:24 UTC (permalink / raw)
  To: qemu-devel

On Tue, 18 Nov 2003, J. Mayer wrote:

> > I have a test program that covers around 600K variants with specific
> > values to trigger flags updates. It requires a PPC host for now to
> > validate results. It helped a lot to first write a correct interpreter and
> > discover some hidden semantics in rare cases.
> > 
> The program, ppc_test does this with a lot of different instruction,
> using a huge set of values. With the ctrace program, I could check that
> it runs the same on my Ibook and on my PC with qemu. Where could I find
> yours to make more tests ?

An oldish version is available here:
<http://down.physik.uni-mainz.de/cgi-bin/viewcvs.cgi/SheepShaver/src/kpx_cpu/src/test/test-powerpc.cpp>

I will commit a newer version tonight. The "JIT1" engine is not committed
yet either.

> You found hidden semantics, as you say. What is confusing, also, is that
> Motorola's implementation isn't the same than IBM's one for some strange
> cases...

Nevermind, you got divw implementation right at first sight, so forget 
about it. ;-)

> My TBL/TBU implementation isn't a real time clock, but is a cycle
> counter, as on "real" PPC.

Doesn't a real PPC increments TBR after a time comparable to at least 4 
addi instructions? I think there was an Apple TN# about it.

> That means that the CPU will seem to run with a variable clock, if a
> program compares its value to the one given by a real-time clock. It's
> updated at the end of a translated block, or when I see a mftbl/mftbu
> instruction.

Sounds reasonable.

Bye,
Gwenole.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 12:24       ` Gwenole Beauchesne
@ 2003-11-18 12:57         ` Johan Rydberg
  2003-11-18 14:52           ` Gwenole Beauchesne
  2003-11-18 14:59         ` Jocelyn Mayer
  1 sibling, 1 reply; 65+ messages in thread
From: Johan Rydberg @ 2003-11-18 12:57 UTC (permalink / raw)
  To: qemu-devel

Gwenole Beauchesne <gbeauchesne@mandrakesoft.com> wrote:

: I will commit a newer version tonight. The "JIT1" engine is not committed
: yet either.

How have you implemented the JIT1?  As QEMU, translating basic blocks?  Or
do you use the trace approach as described in:

http://citeseer.nj.nec.com/bala00dynamo.html

What performance have achived?  And how do you hande condition codes?

-- 
Johan Rydberg, Free Software Developer, Sweden
http://rtmk.sf.net | http://www.nongnu.org/guss/

Playing TOOL - Cesaro Summability

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 12:57         ` Johan Rydberg
@ 2003-11-18 14:52           ` Gwenole Beauchesne
  0 siblings, 0 replies; 65+ messages in thread
From: Gwenole Beauchesne @ 2003-11-18 14:52 UTC (permalink / raw)
  To: Johan Rydberg; +Cc: qemu-devel

On Tue, 18 Nov 2003, Johan Rydberg wrote:

> Gwenole Beauchesne <gbeauchesne@mandrakesoft.com> wrote:
> 
> : I will commit a newer version tonight. The "JIT1" engine is not committed
> : yet either.
> 
> How have you implemented the JIT1?  As QEMU, translating basic blocks?

The initial plan was to write a simple JIT comparable to the B2/JIT with
some improvements I had started (e.g. lazy byteswapping, fixing interblock
register reallocation). But due to lack of time, I switched to dyngen-like
translation for now. When time comes, next level will use stats gathered
with jit1 and optimize specific traces.

The goal is to provide decent MacOS Classic emulation with SheepShaver:
- fix remaining little endian & 64-bit bugs in SheepShaver core
- determine how "new" NewWorld ROMs (the parcels based ones) work
- possibly teach MacOS 9 to work without address translation like MacOS 
8.6 currently
- possibly port native quickdraw acceleration code from BeOS version to 
Unix video code.

Next, I can experiment with JIT2 and other things but spare time
converging towards zero, that will be hard.

BTW, I have no intention to emulate the PowerPC MMU.

> What performance have achived?

There is no block chaining yet and mul/div/sub are missing right now.
Performance improvement over a predecode cache mechanism (storing pointers
to instruction handlers into a table) is only around 2.1x at this time on
a ppc 7410/400 (with the ssbench "coin 1 100" test). The former having a
slow-down factor around 20 vs. native execution, IIRC.

I will make proper benchmarks later as I first want to review currently
generated code and implement the following host-specific optimizations:

- Optimize immediate related instructions. i.e. hand assemble addi & the
like instructions. I already have runtime assemblers for AMD64, IA-32, and
PPC so that's not a trouble.

- Asm optimize condition codes related operations. e.g. current emulation
of "adde" & friends is costly and can easily make use of host flags to
compute ppc flags.

>  And how do you hande condition codes?

The current approach is to compute them when Rc bit is set.

Bye,
Gwenole.

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 12:24       ` Gwenole Beauchesne
  2003-11-18 12:57         ` Johan Rydberg
@ 2003-11-18 14:59         ` Jocelyn Mayer
  1 sibling, 0 replies; 65+ messages in thread
From: Jocelyn Mayer @ 2003-11-18 14:59 UTC (permalink / raw)
  To: qemu mailing list

On Tue, 2003-11-18 at 13:24, Gwenole Beauchesne wrote: 
> On Tue, 18 Nov 2003, J. Mayer wrote:
> 
> > > I have a test program that covers around 600K variants with specific
> > > values to trigger flags updates. It requires a PPC host for now to
> > > validate results. It helped a lot to first write a correct interpreter and
> > > discover some hidden semantics in rare cases.
> > > 
> > The program, ppc_test does this with a lot of different instruction,
> > using a huge set of values. With the ctrace program, I could check that
> > it runs the same on my Ibook and on my PC with qemu. Where could I find
> > yours to make more tests ?
> 
> An oldish version is available here:
> <http://down.physik.uni-mainz.de/cgi-bin/viewcvs.cgi/SheepShaver/src/kpx_cpu/src/test/test-powerpc.cpp>
> 
> I will commit a newer version tonight. The "JIT1" engine is not committed
> yet either.

Well, I'll take a look... and 'll try qemu with this test !

> > You found hidden semantics, as you say. What is confusing, also, is that
> > Motorola's implementation isn't the same than IBM's one for some strange
> > cases...
> 
> Nevermind, you got divw implementation right at first sight, so forget 
> about it. ;-)

There are some strange things with string and load/store multiples too:
IBM allows the memory operand to be in the range of loaded registers as
Motorolla says this is invalid. IBM says this reg won't be modified. I'm
sure my implementation is false for both point of vues !

> > My TBL/TBU implementation isn't a real time clock, but is a cycle
> > counter, as on "real" PPC.
> 
> Doesn't a real PPC increments TBR after a time comparable to at least 4 
> addi instructions? I think there was an Apple TN# about it.

In fact, I though the spec said that it increments at each clock tick,
but I just checked and I see: "The VEA does not specify a relathionship between
the frequency at which the time base is updated and other clocks, such as
the processor clock. The TB update frequency is not required to be constant;
... one of two things is required:
* the system provides an implementation dependant exception to software whenever
  the update frequency of the time base changes and a means to determine the
  current update frequency
or
* the system software controls the update frequency of the time base"

So things aren't so simple... I wonder if MacOS would run on all PPCs...


-- 

Jocelyn Mayer <l_indien@magic.fr>

Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 12:13         ` J. Mayer
@ 2003-11-18 20:24           ` Raymond W. Lucke IV
  2003-11-18 20:44             ` Jocelyn Mayer
  0 siblings, 1 reply; 65+ messages in thread
From: Raymond W. Lucke IV @ 2003-11-18 20:24 UTC (permalink / raw)
  To: qemu-devel

Hmm...

My goal is not necessarily to run Linux binaries directly on Darwin, 
that would truly mean doing Linux syscall emulation. But from what I 
understand, trying to make vl would actually be in a number of ways 
much simpler, since it does not translate syscalls one by one, but 
instead the operating system being executed handles it's own, and calls 
virtual hardware provided by vl.

Ray


On Nov 18, 2003, at 4:13 AM, J. Mayer wrote:

> On Tue, 2003-11-18 at 12:39, Raymond W. Lucke IV wrote:
>> That's really cool that you have the preliminary PPC emulation, and I
>> noticed that you have cleaned a few things up. I wonder if your 
>> changes
>> will make my port to Darwin any easier. ;-)
>>
> I'm sorry, but I don't think so.
> The biggest problem to make qemu run under Darwin isn't to make it
> compile, this is really easy. The problem is to emulate Linux syscalls.
> There is a huge work to do there to make it usable. And you have to
> consider that you need one syscall remapper for each emulated
> architecture (not true, but not so far...). An alternative solution is
> _not_ to make the port and say that qemu for Linux PPC will run 
> directly
> with Panther, as it includes the Linux emulation from FreeBSD.
>
> You can notice that the syscall emulation is, by now, far from correct,
> for PPC target, in qemu... I didn't spent time on this point, because
> it's really a big problem and it's not so funny to do...
>
> Regards
>
> -- 
> J. Mayer <l_indien@magic.fr>
> Never organized
>
>
>
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://mail.nongnu.org/mailman/listinfo/qemu-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 20:24           ` Raymond W. Lucke IV
@ 2003-11-18 20:44             ` Jocelyn Mayer
  2003-11-18 21:48               ` Chad Page
  0 siblings, 1 reply; 65+ messages in thread
From: Jocelyn Mayer @ 2003-11-18 20:44 UTC (permalink / raw)
  To: qemu mailing list

On Tue, 2003-11-18 at 21:24, Raymond W.Lucke IV wrote:
> Hmm...
> 
> My goal is not necessarily to run Linux binaries directly on Darwin, 
> that would truly mean doing Linux syscall emulation. But from what I 
> understand, trying to make vl would actually be in a number of ways 
> much simpler, since it does not translate syscalls one by one, but 
> instead the operating system being executed handles it's own, and calls 
> virtual hardware provided by vl.
> 
> Ray

Well, you're right, in some way:
there is no syscall emulation to do for vl. But you have to emulate
a machine that looks like a real one. I think most of the softmmu code
for ix86 could be re-used for PPC and that peripheral emulation could be
separated into hardware emulation, independant from the target, and 
bus-glue, which defines how the device will be accessed for a given
target. I think that trying to have some code to emulate a CHRP or a
PREP machine would be a good start, but we _need_ PCI for those targets.
But, if we get one of those hardware emulated, with improvements for
the CPU emulation to handle supervisor instructions and exceptions,
we would be able to try to boot AIX, Linux, maybe AUX & old MacOSes.

It would be great to do this !

In my opinion, the hardest points are: PPC emulation improvement,
cleaning the current vl code to separate x86 dedicated parts from
generic ones and PCI. But I don't think we have to worry about PCI: x86
emulation will need it too :=)

Regards.
-- 
Jocelyn Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 20:44             ` Jocelyn Mayer
@ 2003-11-18 21:48               ` Chad Page
  2003-11-18 22:50                 ` J. Mayer
  0 siblings, 1 reply; 65+ messages in thread
From: Chad Page @ 2003-11-18 21:48 UTC (permalink / raw)
  To: qemu mailing list


On 18 Nov 2003, Jocelyn Mayer wrote:

> Well, you're right, in some way:
> there is no syscall emulation to do for vl. But you have to emulate
> a machine that looks like a real one. I think most of the softmmu code
> for ix86 could be re-used for PPC and that peripheral emulation could be
> separated into hardware emulation, independant from the target, and 
> bus-glue, which defines how the device will be accessed for a given
> target. I think that trying to have some code to emulate a CHRP or a
> PREP machine would be a good start, but we _need_ PCI for those targets.
> But, if we get one of those hardware emulated, with improvements for
> the CPU emulation to handle supervisor instructions and exceptions,
> we would be able to try to boot AIX, Linux, maybe AUX & old MacOSes.
> 
> It would be great to do this !

	AUX was 68K only IIRC.  But on the MacOS front if we can glom code
from MacOnLinux - or beef up user space mode and emulate the MOL kernel
module - then we could get everything from 8.6 to 10.3 working.  The older
MacOS's are actually tougher because you have to have a Mac ROM.

	MOL can't run a "stock" Linux kernel, yet... the problem with
LinuxPPC is there *is* no such thing as a stock kernel, unless you
actually emulate Mac HW.

> In my opinion, the hardest points are: PPC emulation improvement,
> cleaning the current vl code to separate x86 dedicated parts from
> generic ones and PCI. But I don't think we have to worry about PCI: x86
> emulation will need it too :=)

	Yup... it's kind of surreal to play with Linux under qemu - "ppro"
cpu, but with 486-era peripherals... and more importantly using bus
mastered IO will be much more efficient.  I wonder if the bochs code could
be used as a reference for at least some of it, although I think they
mostly emulate ISA stuff too (and yet need the speed boost much more ;) )

	- Chad
 
> Regards.
> -- 
> Jocelyn Mayer <l_indien@magic.fr>
> Never organized
> 
> 
> 
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://mail.nongnu.org/mailman/listinfo/qemu-devel
> 

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 21:48               ` Chad Page
@ 2003-11-18 22:50                 ` J. Mayer
  2003-11-19  1:11                   ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 65+ messages in thread
From: J. Mayer @ 2003-11-18 22:50 UTC (permalink / raw)
  To: qemu-devel

On Tue, 2003-11-18 at 22:48, Chad Page wrote:
> On 18 Nov 2003, Jocelyn Mayer wrote:
> 
> > Well, you're right, in some way:
> > there is no syscall emulation to do for vl. But you have to emulate
> > a machine that looks like a real one. I think most of the softmmu code
> > for ix86 could be re-used for PPC and that peripheral emulation could be
> > separated into hardware emulation, independant from the target, and 
> > bus-glue, which defines how the device will be accessed for a given
> > target. I think that trying to have some code to emulate a CHRP or a
> > PREP machine would be a good start, but we _need_ PCI for those targets.
> > But, if we get one of those hardware emulated, with improvements for
> > the CPU emulation to handle supervisor instructions and exceptions,
> > we would be able to try to boot AIX, Linux, maybe AUX & old MacOSes.
> > 
> > It would be great to do this !
> 
> 	AUX was 68K only IIRC.

Ooops, you're right...

>   But on the MacOS front if we can glom code
> from MacOnLinux - or beef up user space mode and emulate the MOL kernel
> module - then we could get everything from 8.6 to 10.3 working.  The older
> MacOS's are actually tougher because you have to have a Mac ROM.
> 
Well, we'll need somthing like an OpenFirmware for recent MacOS too. I
don't think there is a free firmware available for PPC which would be as
complete as freebios... OpenBios seems far from this, as far as I
know...

> 	MOL can't run a "stock" Linux kernel, yet... the problem with
> LinuxPPC is there *is* no such thing as a stock kernel, unless you
> actually emulate Mac HW.
> 
But a real Mac would be difficult to fully emulate, as I think it uses
some obscure components. We can imagine the way it runs, looking at
Darwin's code, sure...
But MacOs is supposed to run on PREP, which is well described and share
a lot of components with PC hardwares. That's why I think it would be a
good start to emulate this platform...

> > In my opinion, the hardest points are: PPC emulation improvement,
> > cleaning the current vl code to separate x86 dedicated parts from
> > generic ones and PCI. But I don't think we have to worry about PCI: x86
> > emulation will need it too :=)
> 
> 	Yup... it's kind of surreal to play with Linux under qemu - "ppro"
> cpu, but with 486-era peripherals... and more importantly using bus
> mastered IO will be much more efficient.  I wonder if the bochs code could
> be used as a reference for at least some of it, although I think they
> mostly emulate ISA stuff too (and yet need the speed boost much more ;) )
> 
Yes, and we miss AGP & hyper-transport too :=).
Seriously, I also think bochs is mainly based on ISA. I took a look to
FreeBios: it doesn't allocate PCI ressources at boot time,
so all PCI stuff are quite hardcoded in the drivers. There are a few:
PCI host bridge, PCI to ISA bridge, VGA controler and USB.

-- 
J. Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-18 22:50                 ` J. Mayer
@ 2003-11-19  1:11                   ` Benjamin Herrenschmidt
  2003-11-19 15:35                     ` Jocelyn Mayer
  0 siblings, 1 reply; 65+ messages in thread
From: Benjamin Herrenschmidt @ 2003-11-19  1:11 UTC (permalink / raw)
  To: qemu-devel


> >   But on the MacOS front if we can glom code
> > from MacOnLinux - or beef up user space mode and emulate the MOL kernel
> > module - then we could get everything from 8.6 to 10.3 working.  The older
> > MacOS's are actually tougher because you have to have a Mac ROM.
> > 
> Well, we'll need somthing like an OpenFirmware for recent MacOS too. I
> don't think there is a free firmware available for PPC which would be as
> complete as freebios... OpenBios seems far from this, as far as I
> know...

You don't need much. You need a device-tree and a few client interface
calls. MOL does that already and it makes all MacOS "newworld" and
OS X happy.

> > 	MOL can't run a "stock" Linux kernel, yet... the problem with
> > LinuxPPC is there *is* no such thing as a stock kernel, unless you
> > actually emulate Mac HW.

Well... You can since MOL do have the option of emulating some Mac HW ;)

The "native" bridge drivers were added to MOL later on, first versions
did indeed only HW emulation
 
> But a real Mac would be difficult to fully emulate, as I think it uses
> some obscure components. We can imagine the way it runs, looking at
> Darwin's code, sure...

And the linux/ppc one :) Actually, you really don't need to emulate
much HW to get any of the MacOSes up. Especially true with Darwin
where you can feed the Mach kernel with proper platform drivers at
boot time. For MacOS 9, you need some bits (PCI config space,
interrupt controller, via-cuda, ...) but for most things like block
storage, networking, etc..., MOL just feeds MacOS with special
drivers from the device-tree that do the bridging. It's all in
MOL source which is GPL and so can be reused here.

> But MacOs is supposed to run on PREP, which is well described and share
> a lot of components with PC hardwares. That's why I think it would be a
> good start to emulate this platform...

I don't think it's that nice ;) I'd rather go the mac way :)

> > > In my opinion, the hardest points are: PPC emulation improvement,
> > > cleaning the current vl code to separate x86 dedicated parts from
> > > generic ones and PCI. But I don't think we have to worry about PCI: x86
> > > emulation will need it too :=)
> > 
> > 	Yup... it's kind of surreal to play with Linux under qemu - "ppro"
> > cpu, but with 486-era peripherals... and more importantly using bus
> > mastered IO will be much more efficient.  I wonder if the bochs code could
> > be used as a reference for at least some of it, although I think they
> > mostly emulate ISA stuff too (and yet need the speed boost much more ;) )
> > 
> Yes, and we miss AGP & hyper-transport too :=).
> Seriously, I also think bochs is mainly based on ISA. I took a look to
> FreeBios: it doesn't allocate PCI ressources at boot time,
> so all PCI stuff are quite hardcoded in the drivers. There are a few:
> PCI host bridge, PCI to ISA bridge, VGA controler and USB.
-- 
Benjamin Herrenschmidt <benh@kernel.crashing.org>

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [Qemu-devel] [ADD] PPC processor emulation
  2003-11-19  1:11                   ` Benjamin Herrenschmidt
@ 2003-11-19 15:35                     ` Jocelyn Mayer
  0 siblings, 0 replies; 65+ messages in thread
From: Jocelyn Mayer @ 2003-11-19 15:35 UTC (permalink / raw)
  To: benh, qemu mailing list

On Wed, 2003-11-19 at 02:11, Benjamin Herrenschmidt wrote:
... 
> > But a real Mac would be difficult to fully emulate, as I think it uses
> > some obscure components. We can imagine the way it runs, looking at
> > Darwin's code, sure...
> 
> And the linux/ppc one :) Actually, you really don't need to emulate
> much HW to get any of the MacOSes up. Especially true with Darwin
> where you can feed the Mach kernel with proper platform drivers at
> boot time. For MacOS 9, you need some bits (PCI config space,
> interrupt controller, via-cuda, ...) but for most things like block
> storage, networking, etc..., MOL just feeds MacOS with special
> drivers from the device-tree that do the bridging. It's all in
> MOL source which is GPL and so can be reused here.
> 
> > But MacOs is supposed to run on PREP, which is well described and share
> > a lot of components with PC hardwares. That's why I think it would be a
> > good start to emulate this platform...
> 
> I don't think it's that nice ;) I'd rather go the mac way :)

Well, I'd say that you are right, regarding what real use of qemu will
be... That's better for users to be able to launch MacOSX on a PC, but
I'd like to also have a complete PPC box emulation to be able to launch
any OS, quite like qemu does for x86 target.
But, to have something to show, OK, it may be better to start up doing
the same as MOL does...

-- 
Jocelyn Mayer <l_indien@magic.fr>
Never organized

^ permalink raw reply	[flat|nested] 65+ messages in thread

end of thread, other threads:[~2003-11-19 16:40 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-11-17  9:51 [Qemu-devel] new knoppix SegFault Jens Arm
2003-11-18  7:15 ` [Qemu-devel] [PATCH] Fixes for qemu J. Mayer
2003-11-18  7:30   ` J. Mayer
2003-11-18  7:31   ` Chad Page
2003-11-18  7:32   ` J. Mayer
2003-11-18  7:33   ` J. Mayer
2003-11-18  7:34   ` J. Mayer
2003-11-18  8:24   ` J. Mayer
2003-11-18  7:22 ` [Qemu-devel] [ADD] floppy disk emulation J. Mayer
2003-11-18  7:37   ` J. Mayer
2003-11-18  7:38   ` J. Mayer
2003-11-18  7:39   ` J. Mayer
2003-11-18  7:39   ` J. Mayer
2003-11-18  8:24   ` J. Mayer
2003-11-18  7:28 ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
2003-11-18  7:43   ` J. Mayer
2003-11-18  7:43   ` J. Mayer
2003-11-18  7:44   ` J. Mayer
2003-11-18  7:45   ` J. Mayer
2003-11-18  7:45   ` J. Mayer
2003-11-18  7:46   ` J. Mayer
2003-11-18  7:46   ` J. Mayer
2003-11-18  7:48   ` J. Mayer
2003-11-18  7:48   ` J. Mayer
2003-11-18  7:49   ` J. Mayer
2003-11-18  7:50   ` J. Mayer
2003-11-18  7:50   ` J. Mayer
2003-11-18  7:51   ` J. Mayer
2003-11-18  7:53   ` J. Mayer
2003-11-18  7:54   ` J. Mayer
2003-11-18  7:55   ` J. Mayer
2003-11-18  7:56   ` J. Mayer
2003-11-18  7:56   ` J. Mayer
2003-11-18  7:57   ` J. Mayer
2003-11-18  7:58   ` J. Mayer
2003-11-18  7:59   ` J. Mayer
2003-11-18  7:59   ` J. Mayer
2003-11-18  8:00   ` J. Mayer
2003-11-18  8:02   ` [Qemu-devel] [ADD] tests for PPC target J. Mayer
2003-11-18  8:06     ` J. Mayer
2003-11-18  8:08     ` J. Mayer
2003-11-18  8:08     ` J. Mayer
2003-11-18  8:09     ` J. Mayer
2003-11-18  8:10     ` J. Mayer
2003-11-18  8:25     ` J. Mayer
2003-11-18  8:24   ` [Qemu-devel] [ADD] PPC processor emulation J. Mayer
2003-11-18  9:37   ` Gwenole Beauchesne
2003-11-18 10:37     ` J. Mayer
2003-11-18 11:39       ` Raymond W. Lucke IV
2003-11-18 12:13         ` J. Mayer
2003-11-18 20:24           ` Raymond W. Lucke IV
2003-11-18 20:44             ` Jocelyn Mayer
2003-11-18 21:48               ` Chad Page
2003-11-18 22:50                 ` J. Mayer
2003-11-19  1:11                   ` Benjamin Herrenschmidt
2003-11-19 15:35                     ` Jocelyn Mayer
2003-11-18 12:24       ` Gwenole Beauchesne
2003-11-18 12:57         ` Johan Rydberg
2003-11-18 14:52           ` Gwenole Beauchesne
2003-11-18 14:59         ` Jocelyn Mayer
2003-11-18  7:29 ` [Qemu-devel] [PATCH] Term prompt for qemu J. Mayer
2003-11-18  8:11   ` J. Mayer
2003-11-18  8:11   ` J. Mayer
2003-11-18  8:13   ` J. Mayer
2003-11-18  8:25   ` J. Mayer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).