* [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
* 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] [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
* [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
* 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] 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
* [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
* 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 = ®types[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(®s, 0, sizeof(regs)); + if (ptrace(PTRACE_GETREGS, child, NULL, ®s) < 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] [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] [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] 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 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
* 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
* [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] 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] 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
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).